You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:05:32