提取白色图像边界、边缘检测

求问如何提取图片中的白色区域的轮廓?

img

这是用红外相机拍摄的火焰图片,图中红圈区域是相机出现了问题产生的噪声。

img

我用canny算法提取边界的时候噪声会产生影响,而且边界不连续

img

机械领域研一小白,不知各位有没有方法能够去除噪声的影响,提取出白色区域的轮廓?
十分感谢!

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
您可以尝试以下几种方法:

  1. 形态学操作

a. 二值化处理:将图像转换为二值图像,使白色区域为255,黑色区域为0。可以使用阈值分割等方法进行处理。

b. 膨胀操作:使用一个结构元素对二值图像进行膨胀,可以填充白色区域中的空洞,使其更加连续。

c. 腐蚀操作:使用一个结构元素对二值图像进行腐蚀,可以消除白色区域中的噪声点,使其更加连续。

d. 边界提取:使用膨胀后的图像减去腐蚀后的图像,可以得到白色区域的边界。

下面是 Python 中使用 OpenCV 库实现形态学操作的代码:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('fire.jpg', cv2.IMREAD_GRAYSCALE)

# 二值化处理
ret, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)

# 定义结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))

# 膨胀操作
dilated = cv2.dilate(binary, kernel)
cv2.imshow('dilated', dilated)

# 腐蚀操作
eroded = cv2.erode(binary, kernel)
cv2.imshow('eroded', eroded)

# 边界提取
boundaries = dilated - eroded
cv2.imshow('boundaries', boundaries)

cv2.waitKey(0)
  1. 霍夫变换

a. 边缘检测:使用 Canny 算法等方法进行边缘检测,得到图像中所有的边缘。

b. 霍夫变换:使用霍夫变换,可以将边缘检测得到的直线转换为参数方程,这样就可以方便地对直线进行处理。

c. 直线筛选:根据直线的参数方程,可以筛选出与噪声区域相交的直线,然后把这些直线合并为一个区域。

d. 轮廓提取:对这个区域进行轮廓提取,就可以得到目标区域的轮廓。

下面是 Python 中使用 OpenCV 库实现霍夫变换的代码:

import cv2
import numpy as np

# 读取图像
img = cv2.imread('fire.jpg', cv2.IMREAD_GRAYSCALE)

# 边缘检测
edges = cv2.Canny(img, 100, 200)

# 霍夫变换
lines = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=100, minLineLength=50, maxLineGap=10)

# 直线筛选
region = np.zeros_like(img)
for line in lines:
    x1, y1, x2, y2 = line[0]
    if 450 < x1 < 600 and 450 < x2 < 600 and 200 < y1 < 400 and 200 < y2 < 400:
        cv2.line(region, (x1, y1), (x2, y2), 255, 3)

# 轮廓提取
contours, hierarchy = cv2.findContours(region, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours, -1, (255, 255, 255), 3)

cv2.imshow('result', img)
cv2.waitKey(0)

注意:

  1. 对于两种方法,两种方法只能得到白色区域的轮廓,得到的图像可能不会和原图完全重合。

  2. 针对第一种方法,结构元素的大小和形状会影响到结果,需要根据实际情况进行调整。

  3. 需要花费一定的时间来调整参数和代码,才能得到最终的结果。
    如果我的回答解决了您的问题,请采纳!

如果对您有帮助,希望您能够进行采纳!祝您工作顺利,学业有成!!!

1、可以先膨胀运算,(闭运算去掉黑点),再进行下面方式处理:
😊
思路是这样的:
将图片转换为灰度图像,并用阈值处理将白色部分分割出来。
用cv2.findContours函数找到图像中的所有轮廓,并按照轮廓面积排序。
选择最大的一个轮廓,即最外层的轮廓,并用cv2.boundingRect函数计算它的外接矩形。
用cv2.rectangle函数在原图上绘制外接矩形,或者用cv2.drawContours函数绘制轮廓本身。

import cv2
import numpy as np

# 读取图片
img = cv2.imread("image.png")

# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 用阈值处理将白色部分分割出来
ret, thresh = cv2.threshold(gray, 250, 255, cv2.THRESH_BINARY)

# 用cv2.findContours函数找到图像中的所有轮廓,并按照轮廓面积排序
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)

# 选择最大的一个轮廓,即最外层的轮廓,并用cv2.boundingRect函数计算它的外接矩形
c = contours[0]
x, y, w, h = cv2.boundingRect(c)
# 用cv2.rectangle函数在原图上绘制外接矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
# 或者用cv2.drawContours函数绘制轮廓本身
# cv2.drawContours(img, [c], -1, (0, 0, 255), 2)

# 显示结果
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

也可以尝试另一种方式如下:
😊
你可以用以下方法来处理:
在用阈值处理将白色区域分割出来之前,先对图像进行一些预处理,如高斯模糊、中值滤波、双边滤波等,以去除噪声和锐化边缘。
在用cv2.findContours函数找到图像中的所有轮廓之后,先对轮廓进行一些筛选,如根据轮廓面积、周长、凸度、圆度等指标,去除一些不符合要求的轮廓。
在用cv2.boundingRect函数计算外接矩形之前,先对轮廓进行一些平滑,如用cv2.approxPolyDP函数对轮廓进行多边形逼近,或者用cv2.convexHull函数对轮廓进行凸包操作。

import cv2
import numpy as np

# 读取图片
img = cv2.imread("image.png")

# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 对图像进行高斯模糊
blur = cv2.GaussianBlur(gray, (5, 5), 0)

# 用阈值处理将白色区域分割出来
ret, thresh = cv2.threshold(blur, 250, 255, cv2.THRESH_BINARY)

# 用cv2.findContours函数找到图像中的所有轮廓,并按照轮廓面积排序
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = sorted(contours, key=cv2.contourArea, reverse=True)

# 选择最大的一个轮廓,即最外层的轮廓,并用cv2.approxPolyDP函数对轮廓进行多边形逼近
c = contours[0]
epsilon = 0.01 * cv2.arcLength(c, True)
approx = cv2.approxPolyDP(c, epsilon, True)

# 用cv2.boundingRect函数计算多边形逼近后的轮廓的外接矩形
x, y, w, h = cv2.boundingRect(approx)
# 用cv2.rectangle函数在原图上绘制外接矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
# 或者用cv2.drawContours函数绘制多边形逼近后的轮廓本身
# cv2.drawContours(img, [approx], -1, (0, 0, 255), 2)

# 显示结果
cv2.imshow("img", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 这个问题的回答你可以参考下: https://ask.csdn.net/questions/7772635
  • 这篇博客你也可以参考下:【视觉基础】直观理解图形学中的灰度图像、直方图、Canny算子和霍夫变换
  • 除此之外, 这篇博客: 计算机视觉的常用图像处理技术中的 第六张图是拉普拉斯算子,最后一张图是Canny算子,原理建议百度百科, 部分也许能够解决你的问题, 你可以仔细阅读以下内容或者直接跳转源博客中阅读:

    概述一下

    使用Sobel算子边检测器时,边缘检测并不那么理想,拉普拉斯边检测器弥补了Sobel检测器的不足,但是拉普拉斯便检测器的输出仍带有很多的噪音,它可以检测两个方向上的边,Canny边检测器在解决噪声方面优于拉普拉斯边检测器和Sobel边检测器·,Canny边检测器是一个分阶段的处理过程,他用到了迟滞性来做边数据处理,还使用了 非极大值抑制。 这一步排除非边缘像素, 仅仅保留了一些细线条(候选边缘) 。

    Canny边缘检测算子是John F.Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory ofedge detection),解释了这项技术是如何工作的。Canny边缘检测算法以Canny的名字命名,被很多人推崇为当今最优的边缘检测的算法。

    源码附上:

    import cv2
    import PIL
    
    
    img = cv2.imread('lena.jpg')
    gray = cv2.imread('lena.jpg', cv2.IMREAD_GRAYSCALE)
    gray = cv2.resize(gray, (400, 430))
    img = cv2.resize(img, (400, 430))
    sober_horizontal = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=1)
    sober_vertical = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)
    laplacian = cv2.Laplacian(img, cv2.CV_64F)
    canny = cv2.Canny(img, 50, 240)
    img_GanssianBlur = cv2.GaussianBlur(img, (3, 3), 0)
    cv2.imshow('original', img)
    cv2.imshow('Gray', gray)
    cv2.imshow('sobel horizontal', sober_horizontal)
    cv2.imshow('sobel vertical', sober_vertical)
    cv2.imshow('Laplacation', laplacian)
    cv2.imshow('Canny',canny)
    cv2.imshow('GaussianBlur', img_GanssianBlur)
    cv2.waitKey()
    
    

如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^