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

如何用OpenCV准确检测灰度图像中的条纹边缘与轮廓?

问题

我有一张灰度图像,尝试用findContour、HoughLinesP等方法检测图中的条纹,但检测结果不符合预期。以下是我使用findContour的示例代码,该脚本检测出了条纹区域外的其他区域,请问该如何正确检测条纹的边缘/轮廓?

示例代码

import cv2
import imutils

img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
img = cv2.GaussianBlur(img, (5, 5), 0)

ret,thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

cnts = cv2.findContours(image=thresh, mode=cv2.RETR_EXTERNAL,
                                   method=cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key=cv2.contourArea)

img_col = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

image_copy = img_col.copy()
cv2.drawContours(image=image_copy, contours=[c], contourIdx=-1,
             color=(0, 255, 0), thickness=1, lineType=cv2.LINE_AA)
# 查看结果
cv2.imshow('Output', image_copy)
cv2.waitKey(0)

输入图像

输入图像

当前输出图像

当前输出图像

问题分析

你的代码之所以选中外框而非条纹,是因为OTSU二值化后,图像外框区域的面积远大于条纹面积,max(cnts, key=cv2.contourArea)会直接选中面积最大的外框轮廓,而非目标条纹。

解决方案

针对条纹细长、灰度差异明显的特征,可通过以下几种方式修正:

方法1:边缘检测+形态学处理+轮廓过滤

先通过Canny提取边缘,再用形态学操作连接条纹断裂部分,最后过滤掉不符合条纹特征的轮廓:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
# 高斯模糊去噪
blur = cv2.GaussianBlur(img, (3, 3), 0)
# Canny边缘检测
edges = cv2.Canny(blur, 50, 150)
# 形态学膨胀,连接条纹的断裂部分
kernel = np.ones((2, 2), np.uint8)
dilated = cv2.dilate(edges, kernel, iterations=1)
# 寻找轮廓
cnts, _ = cv2.findContours(dilated, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 过滤轮廓:保留面积在10-500之间的(可根据实际图像调整)
filtered_cnts = [cnt for cnt in cnts if 10 < cv2.contourArea(cnt) < 500]
# 绘制结果
img_col = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(img_col, filtered_cnts, -1, (0, 255, 0), 1)
# 显示结果
cv2.imshow('Stripe Contours', img_col)
cv2.waitKey(0)
cv2.destroyAllWindows()

方法2:自适应二值化+轮廓筛选

使用自适应二值化处理局部区域的灰度差异,再通过轮廓的宽高比筛选细长的条纹:

import cv2
import imutils
import numpy as np

img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (5,5), 0)
# 自适应二值化,针对局部区域提取条纹
thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)
# 开运算去除小噪点
kernel = np.ones((2,2), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
# 寻找轮廓
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
# 过滤轮廓:保留宽高比极端(细长)且面积符合的轮廓
filtered_cnts = []
for cnt in cnts:
    x, y, w, h = cv2.boundingRect(cnt)
    aspect_ratio = w / h if h != 0 else 0
    # 条纹为横向,宽高比大于5;若为纵向则小于0.2,可根据实际调整
    if (aspect_ratio > 5 or aspect_ratio < 0.2) and cv2.contourArea(cnt) > 20:
        filtered_cnts.append(cnt)
# 绘制结果
img_col = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
cv2.drawContours(img_col, filtered_cnts, -1, (0,255,0), 1)
cv2.imshow('Result', img_col)
cv2.waitKey(0)
cv2.destroyAllWindows()

方法3:优化HoughLinesP参数

针对条纹的线性特征,调整HoughLinesP的阈值、最小线段长度和最大间隙参数:

import cv2
import numpy as np

img = cv2.imread('image.png', cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(img, (3,3), 0)
# Canny边缘检测
edges = cv2.Canny(blur, 50, 150)
# HoughLinesP检测线条:调整参数适配条纹特征
lines = cv2.HoughLinesP(edges, 1, np.pi/180, threshold=30, minLineLength=20, maxLineGap=5)
img_col = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
if lines is not None:
    for line in lines:
        x1, y1, x2, y2 = line[0]
        cv2.line(img_col, (x1,y1), (x2,y2), (0,255,0), 1)
cv2.imshow('Hough Lines', img_col)
cv2.waitKey(0)
cv2.destroyAllWindows()

内容的提问来源于stack exchange,提问作者Rod

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 00:48:14