如何在含噪声背景的育苗盆图像中检测并分割正方形花盆
育苗区正方形花盆分割问题
我有多张育苗区图像,想编写代码分割每个正方形花盆并保存。目前的处理流程是转灰度图、高斯模糊去噪、阈值二值化,但用cv.findContours检测时,没法精准识别每个花盆的边界,只能获取图像角落点,现有代码效果很差。之前搜的方案大多针对光照对比度充足的场景,不适用当前情况。
相关图像:原图、二值化图、结果图。
现有代码如下:
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) blurred = cv2.GaussianBlur(gray, (3, 3), 0) edges = cv2.Canny(blurred, 10, 50) thresh = cv2.adaptiveThreshold(gray, 400, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 7, 4) lines = cv2.HoughLines(thresh, rho=1, theta=np.pi/180, threshold=100) contours, hierarchy = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE) squares = [] for contour in contours: peri = cv2.arcLength(contour, True) approx = cv2.approxPolyDP(contour, 0.02 * peri, True) if len(approx) == 4: x, y, w, h = cv2.boundingRect(approx) aspect_ratio = float(w) / h if 0.98 <= aspect_ratio <= 1: # Adjust this range as per your requirement squares.append(approx) # Draw squares on the original image for square in squares: cv2.drawContours(image, [square], -1, (0, 255, 0), 2)
改进方案
针对光照不足、对比度低的场景,调整处理流程,重点强化花盆的网格线条,再提取轮廓:
步骤调整
- 灰度与模糊优化:用更大的高斯模糊核减少噪声,同时保留线条特征
- 阈值处理替换:改用
cv2.THRESH_BINARY_INV反转阈值,让花盆边框变为前景 - 形态学操作强化线条:用膨胀+腐蚀的组合(闭运算)填补线条间隙,再用开运算去除小噪点
- 轮廓筛选优化:调整轮廓近似参数,加入面积筛选,排除过小或过大的轮廓
改进代码
import cv2 import numpy as np def segment_pots(image_path): # 读取图像 image = cv2.imread(image_path) if image is None: return # 转灰度 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 高斯模糊,增大核尺寸减少噪声 blurred = cv2.GaussianBlur(gray, (5, 5), 0) # 自适应阈值,反转二值化,让边框为白色 thresh = cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2) # 形态学操作:先闭运算填补线条间隙,再开运算去噪点 kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2) opened = cv2.morphologyEx(closed, cv2.MORPH_OPEN, kernel, iterations=1) # 提取轮廓,用RETR_EXTERNAL只取最外层轮廓 contours, hierarchy = cv2.findContours(opened.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) squares = [] # 获取图像尺寸,计算花盆面积的合理范围(根据实际场景调整) img_h, img_w = gray.shape min_area = (img_w // 10) * (img_h // 10) # 假设至少是图像1/100大小 max_area = (img_w // 2) * (img_h // 2) # 不超过图像1/4大小 for contour in contours: # 计算轮廓周长 peri = cv2.arcLength(contour, True) # 轮廓近似,调整参数为0.03*peri,适配低对比度场景 approx = cv2.approxPolyDP(contour, 0.03 * peri, True) # 筛选四边形、合理宽高比、面积范围 if len(approx) == 4: x, y, w, h = cv2.boundingRect(approx) aspect_ratio = float(w) / h area = w * h if 0.9 <= aspect_ratio <= 1.1 and min_area < area < max_area: squares.append(approx) # 裁剪并保存花盆图像 pot_img = image[y:y+h, x:x+w] cv2.imwrite(f"pot_{x}_{y}.jpg", pot_img) # 在原图绘制检测到的花盆边框 cv2.drawContours(image, squares, -1, (0, 255, 0), 2) cv2.imwrite("result.jpg", image) return image # 使用示例 segment_pots("seedling_area.jpg")
关键调整说明
- 形态学操作:闭运算能把断开的花盆边框连接起来,开运算可以去掉小的噪点轮廓,解决低对比度下线条断裂的问题
- 轮廓筛选:加入面积范围过滤,排除图像角落的大轮廓和小噪点,只保留花盆大小的轮廓
- 阈值反转:让原本深色的边框变为白色前景,更适合轮廓检测
- 轮廓近似参数:把0.02调整为0.03,对低对比度下的不规则轮廓更友好
内容的提问来源于stack exchange,提问作者Muhammad
相关产品推荐
相关产品推荐

