使用OpenCV识别图像正方形时出现多目标合并问题求助
OpenCV正方形识别合并问题解决方法
问题核心原因
两个正方形被合并识别,本质是Canny边缘检测后边缘发生粘连,导致findContours将其识别为单个轮廓。你之前调整epsilon无效,是因为输入的轮廓本身就是合并后的,参数优化无法改变输入基础。
具体解决步骤
1. 修正多边形逼近的epsilon参数
你当前设置的0.34 * peri过大,会把多个轮廓的逼近结果合并成一个大形状。正方形的合理epsilon范围是0.02 * peri到0.05 * peri,同时可以通过顶点数+宽高比判断是否为正方形:
peri = cv.arcLength(cnt, True) approx = cv.approxPolyDP(cnt, 0.03 * peri, True) # 判断是否为正方形:4个顶点 + 宽高比接近1 if len(approx) == 4: aspect_ratio = float(w)/h if 0.95 < aspect_ratio < 1.05: cv.rectangle(imgContour, (x,y), (x+w,y+h), (0,255,0), 5)
2. 优化Canny阈值分离边缘
通过滑动条调整THRESH1(建议50-100)和THRESH2(建议100-150),观察Canny窗口直到两个正方形的边缘完全断开,无连通。
3. 增加形态学腐蚀断开粘连
如果阈值调整后仍有边缘粘连,在Canny检测后添加腐蚀操作:
kernel = np.ones((2,2), np.uint8) Canny = cv.erode(Canny, kernel, iterations=1)
4. 修复图像复制的潜在问题
循环中img = read会直接引用原图像,导致后续修改污染原图,改为img = read.copy()。
修改后的完整代码
import cv2 as cv import numpy as np def empty(a): pass cv.namedWindow("Params") cv.resizeWindow("Params",640,240) cv.createTrackbar("THRESH1","Params",80,255,empty) cv.createTrackbar("THRESH2","Params",120,255,empty) cv.createTrackbar("ERODE_ITER","Params",1,5,empty) read = cv.imread("esult.jpg") def getContours(img,imgContour): contours, herarchy = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE) for cnt in contours: area = cv.contourArea(cnt) if area>1000: peri = cv.arcLength(cnt, True) approx = cv.approxPolyDP(cnt, 0.03 * peri, True) x,y,w,h = cv.boundingRect(approx) if len(approx) == 4: aspect_ratio = float(w)/h if 0.95 < aspect_ratio < 1.05: cv.rectangle(imgContour, (x,y), (x+w,y+h), (0,255,0), 5) # 绘制顶点便于观察 for point in approx: cv.circle(imgContour, tuple(point[0]), 5, (0,0,255), -1) while(1): img = read.copy() imgContour = img.copy() gs = cv.cvtColor(img, cv.COLOR_BGR2GRAY) threshold1 = cv.getTrackbarPos("THRESH1","Params") threshold2 = cv.getTrackbarPos("THRESH2","Params") erode_iter = cv.getTrackbarPos("ERODE_ITER","Params") Canny = cv.Canny(gs,threshold1,threshold2) kernel = np.ones((2,2), np.uint8) Canny = cv.erode(Canny, kernel, iterations=erode_iter) getContours(Canny,imgContour) cv.imshow('gs', gs) cv.imshow('read',imgContour) cv.imshow('canny', Canny) if cv.waitKey(1) & 0xFF == ord('q'): break cv.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Zany Geko
相关产品推荐
相关产品推荐

