You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用OpenCV从牛的俯视图深度图中分割头部并提取身体区域?

问题描述

我正在使用OpenCV处理牛的图像,以提取最大区域并去除背景信息,这些图像用于估算牛的体重。为了准确估重,我需要从待处理图像中去除牛的头部。目前我已能提取出包含头部的牛的最大区域(图1),但希望仅提取牛的身体区域(图2)。现有代码如下:

img = cv2.imread(subdir + '\' + img_name + '.png')
cv2.imshow('img', img)
cv2.waitKey()

#Convert to hue, saturation, and value
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h,s,v = cv2.split(hsv_img)
hsv_split = np.concatenate((h,s,v),axis=1)

# Use the hue value to convert to binary
thresh = 20
thresh, thresh_img = cv2.threshold(h, thresh, 255, cv2.THRESH_BINARY)
                    
# Finding Contours
# Use a copy of the image since findContours alters the image

contours, _ = cv2.findContours(thresh_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
                        
#Extract the largest area
c = max(contours, key=cv2.contourArea) 

请问是否可以使用OpenCV实现去除头部、提取身体区域的操作?

解决方案

完全可以用OpenCV实现这个需求,以下是几种实用的思路和代码实现:

思路1:形态学开运算切除突出头部

适合头部与身体连接处较窄的场景,利用形态学操作去除轮廓的“突出部分”:

  1. 先基于现有轮廓生成牛的整体掩码:
    mask = np.zeros_like(img[:, :, 0])
    cv2.drawContours(mask, [c], -1, 255, thickness=cv2.FILLED)
    
  2. 创建横向椭圆形的结构化元素,执行开运算(先腐蚀再膨胀)切除头部:
    # 结构化元素尺寸需根据图像实际大小调整,确保能覆盖头部宽度
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (60, 120))
    body_mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
    
  3. 提取处理后掩码的最大轮廓,得到仅包含身体的区域:
    body_contours, _ = cv2.findContours(body_mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    body_c = max(body_contours, key=cv2.contourArea)
    
    # 可视化结果
    result = img.copy()
    cv2.drawContours(result, [body_c], -1, (0, 255, 0), 2)
    cv2.imshow('Body Only', result)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

思路2:基于最小外接矩形的区域分割

适合拍摄姿态固定(比如侧面站立)的牛,通过截取外接矩形的大部分区域去除头部:

  1. 获取牛整体轮廓的最小外接矩形:
    rect = cv2.minAreaRect(c)
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    width, height = int(rect[1][0]), int(rect[1][1])
    
  2. 假设头部占整体长度的1/5,调整矩形边界去除头部一侧(以横向矩形为例):
    body_ratio = 0.8  # 保留80%的区域作为身体
    adjust_pixel = int(width * (1 - body_ratio))
    new_box = box.copy()
    
    # 判断头部所在方向(左侧或右侧)
    if box[0][0] < box[2][0]:
        # 头部在左侧,右移左边界
        new_box[0][0] += adjust_pixel
        new_box[3][0] += adjust_pixel
    else:
        # 头部在右侧,左移右边界
        new_box[1][0] -= adjust_pixel
        new_box[2][0] -= adjust_pixel
    
  3. 生成新的身体掩码并与原掩码取交集,过滤背景:
    temp_mask = np.zeros_like(mask)
    cv2.drawContours(temp_mask, [new_box], -1, 255, cv2.FILLED)
    body_mask = cv2.bitwise_and(temp_mask, mask)
    

思路3:颜色差异分割头部

如果头部与身体颜色差异明显(比如头部有白色斑块),可以通过HSV二次分割去除头部:

  1. 针对头部颜色设置HSV范围(需根据实际图像调整):
    # 示例:针对浅色头部的HSV阈值
    lower_head = np.array([0, 0, 190])
    upper_head = np.array([180, 40, 255])
    head_mask = cv2.inRange(hsv_img, lower_head, upper_head)
    
  2. 从整体掩码中减去头部区域:
    body_mask = cv2.bitwise_and(mask, cv2.bitwise_not(head_mask))
    
  3. 用形态学闭运算清理掩码中的小噪点:
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15,15))
    body_mask = cv2.morphologyEx(body_mask, cv2.MORPH_CLOSE, kernel)
    

内容的提问来源于stack exchange,提问作者Katie Price

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 02:10:16