如何用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:形态学开运算切除突出头部
适合头部与身体连接处较窄的场景,利用形态学操作去除轮廓的“突出部分”:
- 先基于现有轮廓生成牛的整体掩码:
mask = np.zeros_like(img[:, :, 0]) cv2.drawContours(mask, [c], -1, 255, thickness=cv2.FILLED) - 创建横向椭圆形的结构化元素,执行开运算(先腐蚀再膨胀)切除头部:
# 结构化元素尺寸需根据图像实际大小调整,确保能覆盖头部宽度 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (60, 120)) body_mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) - 提取处理后掩码的最大轮廓,得到仅包含身体的区域:
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:基于最小外接矩形的区域分割
适合拍摄姿态固定(比如侧面站立)的牛,通过截取外接矩形的大部分区域去除头部:
- 获取牛整体轮廓的最小外接矩形:
rect = cv2.minAreaRect(c) box = cv2.boxPoints(rect) box = np.int0(box) width, height = int(rect[1][0]), int(rect[1][1]) - 假设头部占整体长度的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 - 生成新的身体掩码并与原掩码取交集,过滤背景:
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二次分割去除头部:
- 针对头部颜色设置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) - 从整体掩码中减去头部区域:
body_mask = cv2.bitwise_and(mask, cv2.bitwise_not(head_mask)) - 用形态学闭运算清理掩码中的小噪点:
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (15,15)) body_mask = cv2.morphologyEx(body_mask, cv2.MORPH_CLOSE, kernel)
内容的提问来源于stack exchange,提问作者Katie Price
相关产品推荐
相关产品推荐

