基于OpenCV的带蓝色边框文档图像裁剪技术问题求助
问题描述
示例图像:

各位好,我是一名学生,正在开展项目开发,任务是编写函数读取大量此类文档图像中的文本。我原本计划裁剪掉图像的蓝色边框,将其转换为矩形图像,但尝试后失败。由于拍摄光照角度不同,多数图像的蓝色边框呈现不同色调,难以找到最优参数设置;尝试检测蓝色轮廓也因色调差异无法成功,恳请各位提供解决方案。
我的尝试代码:
import cv2 import numpy as np def find_blue_contour(image): # Convert the image to HSV color space hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # Define the blue color range in HSV lower_blue = np.array([110, 50, 50]) upper_blue = np.array([130, 255, 255]) # Create a mask for the blue color mask = cv2.inRange(hsv, lower_blue, upper_blue) cv2.imshow("mask",mask) cv2.waitKey(0) cv2.destroyAllWindows() # Find contours in the mask contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # If no contours are found, return None if not contours: return None # Find the largest contour largest_contour = max(contours, key=cv2.contourArea) return largest_contour def crop_image_around_contour(image, contour): # Get the bounding rectangle of the contour x, y, w, h = cv2.boundingRect(contour) # Crop the image around the bounding rectangle cropped_image = image[y:y+h, x:x+w] return cropped_image # Image path image_path = 'dene1.JPeG' # Load the image image = cv2.imread(image_path) if image is None: print(f"Error: Could not load image {image_path}.") exit() # Find the blue contour blue_contour = find_blue_contour(image) if blue_contour is None: print("Error: Could not find blue contour.") exit() # Crop the image around the blue contour cropped_image = crop_image_around_contour(image, blue_contour) # Display the original and cropped images cv2.imshow("Original Image", image) cv2.imshow("Cropped Image", cropped_image) cv2.waitKey(0) cv2.destroyAllWindows()
解决方案
针对光照导致蓝色色调变化的问题,可尝试以下几种优化方案:
1. 扩展HSV蓝色范围并结合形态学操作
放宽HSV的蓝色阈值范围,同时用形态学操作消除mask噪点、强化边框轮廓:
def find_blue_contour(image): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 扩展蓝色范围,覆盖不同光照下的色调 lower_blue = np.array([90, 30, 30]) upper_blue = np.array([140, 255, 255]) mask = cv2.inRange(hsv, lower_blue, upper_blue) # 形态学操作:先膨胀再腐蚀,填充mask漏洞 kernel = np.ones((5,5), np.uint8) mask = cv2.dilate(mask, kernel, iterations=2) mask = cv2.erode(mask, kernel, iterations=1) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None largest_contour = max(contours, key=cv2.contourArea) return largest_contour
2. 使用Lab颜色空间检测蓝色
Lab颜色空间的b通道对蓝色/黄色敏感,蓝色在b通道中为高值,不受光照亮度影响,稳定性更强:
def find_blue_contour_lab(image): lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) # 提取b通道 b_channel = lab[:,:,2] # 对b通道做阈值处理,提取蓝色区域 _, mask = cv2.threshold(b_channel, 150, 255, cv2.THRESH_BINARY) kernel = np.ones((7,7), np.uint8) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None largest_contour = max(contours, key=cv2.contourArea) return largest_contour
3. 边缘检测+轮廓近似(不依赖颜色)
如果颜色检测始终不稳定,可跳过颜色识别,直接通过边缘检测寻找文档的四边形轮廓,再做透视变换纠正为矩形:
def find_document_contour(image): # 灰度化+模糊去噪 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray, (5,5), 0) # 边缘检测 edges = cv2.Canny(blur, 50, 150) # 形态学操作强化边缘 kernel = np.ones((5,5), np.uint8) edges = cv2.dilate(edges, kernel, iterations=1) contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None # 筛选面积最大的轮廓,并近似为四边形 largest_contour = max(contours, key=cv2.contourArea) perimeter = cv2.arcLength(largest_contour, True) approx = cv2.approxPolyDP(largest_contour, 0.02*perimeter, True) # 确保是四边形 if len(approx) == 4: return approx else: return None # 透视变换纠正为矩形(适配梯形边框) def warp_perspective(image, contour): # 整理四个顶点顺序(左上、右上、右下、左下) pts = contour.reshape(4,2) rect = np.zeros((4,2), dtype="float32") s = pts.sum(axis=1) rect[0] = pts[np.argmin(s)] rect[2] = pts[np.argmax(s)] diff = np.diff(pts, axis=1) rect[1] = pts[np.argmin(diff)] rect[3] = pts[np.argmax(diff)] # 计算目标矩形的尺寸 width1 = np.linalg.norm(rect[1] - rect[0]) width2 = np.linalg.norm(rect[2] - rect[3]) max_width = max(int(width1), int(width2)) height1 = np.linalg.norm(rect[3] - rect[0]) height2 = np.linalg.norm(rect[2] - rect[1]) max_height = max(int(height1), int(height2)) # 目标顶点 dst = np.array([ [0,0], [max_width-1,0], [max_width-1, max_height-1], [0, max_height-1] ], dtype="float32") # 计算透视变换矩阵并应用 M = cv2.getPerspectiveTransform(rect, dst) warped = cv2.warpPerspective(image, M, (max_width, max_height)) return warped
使用时替换原函数即可,示例:
document_contour = find_document_contour(image) if document_contour is None: print("Error: Could not find document contour.") exit() cropped_image = warp_perspective(image, document_contour)
4. 自适应阈值优化
如果文档内容与边框对比度明显,可尝试对灰度图做自适应阈值分割,再提取轮廓,进一步提升鲁棒性。
内容的提问来源于stack exchange,提问作者ali rıza kurt
相关产品推荐
相关产品推荐

