如何用OpenCV Python提取包装箱上白色运单标签的完整区域?
问题描述
我有一批印有运单标签的包装箱图片,需要提取标签的完整白色区域。作为OpenCV新手,我参考了Stack Overflow的「detect rectangle in image and crop」回答,编写了如下代码,但该代码仅能提取标签的顶部区域:
import cv2 import numpy as np path_to_image = 'IMG_0184b.jpg' img = cv2.imread(path_to_image) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.bilateralFilter(gray, 0, 17, 17) kernel = np.ones((5,5),np.uint8) erosion = cv2.erode(gray,kernel,iterations = 2) kernel = np.ones((4,4),np.uint8) dilation = cv2.dilate(erosion,kernel,iterations = 2) edged = cv2.Canny(dilation, 30, 200) cnt, h = cv2.findContours(edged,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) largestArea = [] for contour in cnt: largestArea.append(cv2.contourArea(contour)) print(sorted(largestArea, reverse=True)[0:3]) for contour in cnt: approx = cv2.approxPolyDP(contour, 0.01* cv2.arcLength(contour, True), True) area = cv2.contourArea(contour) if area == 612144.5: cv2.drawContours(img, [approx], 0, (0, 0, 0), 5) x = approx.ravel()[0] y = approx.ravel()[1] - 5 if len(approx) == 4 : x, y , w, h = cv2.boundingRect(approx) aspectRatio = float(w)/h if aspectRatio >= 0.95 and aspectRatio < 1.05: cv2.putText(img, "square", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0)) else: cv2.putText(img, "rectangle", (x, y), cv2.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0)) cv2.namedWindow('custom window', cv2.WINDOW_KEEPRATIO) cv2.imshow('custom window', img) cv2.resizeWindow('custom window', 800, 800) cv2.waitKey(0) cv2.destroyAllWindows()
原始图片:
期望结果:
如何实现完整白色标签区域的提取?
解决方案
现有代码的核心问题是硬编码了目标区域的面积值,仅适配单张特定图片,且未利用白色标签的颜色特征做精准筛选,导致只能匹配局部区域。以下是针对白色标签提取的通用方案:
核心思路
- 颜色阈值筛选白色区域:从HSV空间提取白色像素,利用白色标签与棕色包装箱的明显颜色差异,比边缘检测更精准。
- 形态学操作去噪:通过膨胀、腐蚀消除小噪点,让白色标签区域形成完整连通块。
- 筛选最大轮廓并裁剪:自动识别面积最大的连通轮廓(即白色标签),提取其外接矩形完成裁剪。
完整代码
import cv2 import numpy as np path_to_image = 'IMG_0184b.jpg' img = cv2.imread(path_to_image) original = img.copy() # 转换为HSV空间,更易筛选白色 hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 白色的HSV阈值范围(可根据实际图片微调) lower_white = np.array([0, 0, 200]) upper_white = np.array([180, 25, 255]) mask = cv2.inRange(hsv, lower_white, upper_white) # 形态学操作:先膨胀填补空洞,再腐蚀消除噪点 kernel = np.ones((7,7), np.uint8) mask = cv2.dilate(mask, kernel, iterations=2) mask = cv2.erode(mask, kernel, iterations=2) # 寻找轮廓并筛选最大的白色区域 contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) largest_contour = max(contours, key=cv2.contourArea) # 获取外接矩形并裁剪标签 x, y, w, h = cv2.boundingRect(largest_contour) cropped_label = original[y:y+h, x:x+w] # 显示并保存结果 cv2.namedWindow('Cropped Label', cv2.WINDOW_KEEPRATIO) cv2.imshow('Cropped Label', cropped_label) cv2.resizeWindow('Cropped Label', 800, 600) cv2.waitKey(0) cv2.destroyAllWindows() cv2.imwrite('cropped_label.jpg', cropped_label)
优化说明
- 阈值微调:若其他图片白色标签亮度不同,可调整
lower_white的第三个参数(亮度值),适配偏暗的白色区域。 - 倾斜矫正:如果标签存在明显倾斜,可通过
cv2.approxPolyDP提取四个顶点,再用cv2.getPerspectiveTransform做透视矫正,保证标签方正。 - 通用性提升:去掉硬编码面积值,自动筛选最大轮廓,适配不同尺寸的包装箱图片。
内容的提问来源于stack exchange,提问作者user13506452
相关产品推荐
相关产品推荐

