基于OpenCV检测掩码图像中的锐角(V形)线条问题求助
问题:从掩码图像中识别提取“V”形锐角线条区域
我需要从给定掩码图像中识别并提取类似“V”形的锐角线条区域,示例掩码图像及预期输出如下:
[示例掩码图像1]、[示例掩码图像2]
[预期输出图像1]、[预期输出图像2]
已实现的掩码生成代码
img = cv2.imread(img_f) hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) #range for red color lower_r = np.array([0,238,132]) upper_r = np.array([25,255,255]) mask = cv2.inRange(hsv,lower_r,upper_r) kernel = np.ones((5, 5), np.uint8) mask = cv2.dilate(mask, kernel, iterations=3) plt.imshow(mask,cmap='gray') plt.show()
尝试的Hough变换方案及问题
我尝试了基于Hough变换的检测方案,但未找到交点位于前景区域的线条对,代码如下:
import cv2 import numpy as np import matplotlib.pyplot as plt # Read the image img_f = 'path/to/your/image.jpg' img = cv2.imread(img_f) # Convert the image to HSV hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Define the range for red color in HSV lower_r = np.array([0, 238, 132]) upper_r = np.array([25, 255, 255]) # Create a mask for red color mask = cv2.inRange(hsv, lower_r, upper_r) # Dilate the mask to make sure it covers the entire object kernel = np.ones((5, 5), np.uint8) mask = cv2.dilate(mask, kernel, iterations=3) # Find lines using Hough Transform lines = cv2.HoughLines(mask, 1, np.pi / 180, 100) # Draw lines on the original image if the angle is less than 90 degrees if lines is not None: for line in lines: for rho, theta in line: a = np.cos(theta) b = np.sin(theta) x0 = a * rho y0 = b * rho x1 = int(x0 + 1000 * (-b)) y1 = int(y0 + 1000 * (a)) x2 = int(x0 - 1000 * (-b)) y2 = int(y0 - 1000 * (a)) # Check if the points are within the image boundaries if 0 <= y1 < mask.shape[0] and 0 <= x1 < mask.shape[1] and \ 0 <= y2 < mask.shape[0] and 0 <= x2 < mask.shape[1]: # Check if the intersection point is in the foreground (non-zero in the mask) if mask[y1, x1] > 0 and mask[y2, x2] > 0: # Calculate the angle between the lines angle = np.degrees(np.arctan2(y2 - y1, x2 - x1)) # Draw lines in red if the angle is less than 90 degrees if abs(angle) < 90: cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) # Display the result plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.show()
修改建议与替代方案
针对现有Hough变换代码的修改
- 调整Hough变换参数:原代码使用
cv2.HoughLines检测无限长直线,阈值100过高易漏检。建议改用cv2.HoughLinesP(概率霍夫变换)直接检测线段,同时降低阈值、设置合理的线段长度和间隙:lines = cv2.HoughLinesP(mask, 1, np.pi/180, threshold=50, minLineLength=20, maxLineGap=10) - 修正锐角检测逻辑:原代码错误计算单条直线的角度,需遍历线段对,计算交点并判断夹角:
if lines is not None: for i in range(len(lines)): x1, y1, x2, y2 = lines[i][0] for j in range(i+1, len(lines)): x3, y3, x4, y4 = lines[j][0] # 计算线段交点 denom = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4) if denom == 0: continue t_num = (x1-x3)*(y3-y4) - (y1-y3)*(x3-x4) u_num = (x1-x3)*(y1-y2) - (y1-y3)*(x1-x2) t = t_num / denom u = u_num / denom if 0 <= t <=1 and 0 <= u <=1: px = int(x1 + t*(x2-x1)) py = int(y1 + t*(y2-y1)) # 检查交点是否在掩码前景 if 0 <= py < mask.shape[0] and 0 <= px < mask.shape[1] and mask[py, px] > 0: # 计算线段夹角 vec1 = np.array([x2-x1, y2-y1]) vec2 = np.array([x4-x3, y4-y3]) dot = np.dot(vec1, vec2) norm1 = np.linalg.norm(vec1) norm2 = np.linalg.norm(vec2) if norm1 ==0 or norm2 ==0: continue cos_theta = dot / (norm1 * norm2) angle = np.degrees(np.arccos(np.clip(cos_theta, -1, 1))) if 0 < angle < 90: cv2.line(img, (x1,y1), (px,py), (0,0,255),2) cv2.line(img, (x3,y3), (px,py), (0,0,255),2)
替代方案:轮廓检测+角点分析
- 提取掩码轮廓:先对掩码做边缘检测,再提取外层轮廓:
edges = cv2.Canny(mask, 50, 150) contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - 多边形逼近与锐角判断:对轮廓做多边形逼近,计算每个顶点的内角,筛选出含锐角的区域:
for cnt in contours: epsilon = 0.02 * cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, epsilon, True) if len(approx) >=3: for i in range(len(approx)): p1 = approx[i][0] p2 = approx[(i+1)%len(approx)][0] p3 = approx[(i+2)%len(approx)][0] # 计算向量夹角 vec1 = p1 - p2 vec2 = p3 - p2 dot = np.dot(vec1, vec2) norm1 = np.linalg.norm(vec1) norm2 = np.linalg.norm(vec2) if norm1 ==0 or norm2 ==0: continue cos_theta = dot / (norm1 * norm2) angle = np.degrees(np.arccos(np.clip(cos_theta, -1, 1))) if 0 < angle < 90: cv2.line(img, tuple(p1), tuple(p2), (0,0,255),2) cv2.line(img, tuple(p2), tuple(p3), (0,0,255),2)
内容的提问来源于stack exchange,提问作者mojojojo
相关产品推荐
相关产品推荐

