Python 查找轮廓的边缘强度/大小以查找和排除模糊对象
我想使用python为灰度图像中的每个对象找到边缘强度值。我通过阈值化来检测对象,创建一个二值图像,然后打开CV findContours来获得边缘。我在每张图像中检测到的这些对象中有一些是模糊的,我想根据轮廓边缘梯度的大小排除它们(有关聚焦对象和模糊对象的示例,请参见下图)。处理每个轮廓的边缘强度以给出每个对象的边缘强度值的最佳方法是什么,这样我就可以根据我能计算出的阈值排除模糊的边缘强度Python 查找轮廓的边缘强度/大小以查找和排除模糊对象,python,opencv,image-processing,edge-detection,blurry,Python,Opencv,Image Processing,Edge Detection,Blurry,我想使用python为灰度图像中的每个对象找到边缘强度值。我通过阈值化来检测对象,创建一个二值图像,然后打开CV findContours来获得边缘。我在每张图像中检测到的这些对象中有一些是模糊的,我想根据轮廓边缘梯度的大小排除它们(有关聚焦对象和模糊对象的示例,请参见下图)。处理每个轮廓的边缘强度以给出每个对象的边缘强度值的最佳方法是什么,这样我就可以根据我能计算出的阈值排除模糊的边缘强度 contours, hierarchy = cv2.findContours(binary_img, c
contours, hierarchy = cv2.findContours(binary_img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
edges = cv2.drawContours(original_image, contours, -1, (255, 255, 255), 1)
我在通过阈值生成的二值图像上使用上述代码在原始图像上绘制边缘。下一步是发送检测到的对象进行处理,但我希望排除模糊的对象,因为它们不需要进一步分析。下面的图片显示了一幅绘制了边缘的图像,我想找到一些值来描述我找到的每个对象的每个边缘像素的平均边缘梯度,并且只进一步处理那些边缘大小高于某个阈值的对象,也就是聚焦的对象
原始图像:
边缘:
如果我正确理解你的问题,你可以尝试使用一些派生内核来获得一些阈值。例如,内核可以工作。
此外,您还可以检查Canny边缘检测算法,也许它会有所帮助。这里有一种可能的方法
- 将图像转换为灰度
- 自适应阈值获取二值图像
- 扩张以增强轮廓
- 找到轮廓并提取感兴趣区域
- 执行拉普拉斯变换以进行模糊检测
我们首先转换为灰度和自适应阈值 接下来,我们放大以增强轮廓 现在我们找到轮廓并提取每个ROI。我们使用拉普拉斯变换对ROI轮廓进行模糊检测
cv2.Laplacian(image, cv2.CV_64F).var()
本质上,我们获取图像的单个通道,并将其与以下3x3
内核进行卷积,然后获取响应的标准偏差平方。如果方差低于定义的阈值,则ROI模糊,否则ROI不模糊。更多细节,请看这个
[0 1 0]
[1 -4 1]
[0 1 0]
这是结果
ROI_编号:1,值:27.6557845590053
ROI_编号:2,值:7.385658155007905
这是另一张图片的结果
ROI_编号:1,值:23.96665214233842
ROI_编号:2,值:67.59560601952461
完整代码
import cv2
import numpy as np
image = cv2.imread('1.jpg')
result = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
ROI_num = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
value = cv2.Laplacian(ROI, cv2.CV_64F).var()
cv2.rectangle(result, (x, y), (x + w, y + h), (36,255,12), 2)
cv2.putText(result, "{0:.2f}".format(value), (x,y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (36,255,12), 2)
cv2.imshow("ROI_{}".format(ROI_num), ROI)
ROI_num += 1
print('ROI_Number: {}, Value: {}'.format(ROI_num, value))
cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('result', result)
cv2.waitKey(0)
一种简单的方法是计算梯度大小图像,并沿检测到的轮廓或在整个水滴内计算梯度。也许更好,在通过轮廓扩张获得的环内。可以添加一些中间输出(轮廓、边缘图像)和代码样本吗?在黑色背景上绘制白色轮廓,并用作遮罩,以获得其下图像的值。然后平均每个蒙版轮廓的像素值。为什么是拉普拉斯?这并不反映梯度强度。这是一种模糊检测方法,详见。根据我的理解,这种方法之所以有效,是因为拉普拉斯算子会高亮显示包含快速强度变化的图像区域,因此,如果类边缘和非类边缘的方差都很高,那么它就代表了对焦图像。类似地,如果方差很小,则图像中的边缘也很小。图像越模糊,边缘就越少。本质上,拉普拉斯算子可以用于边缘检测
[0 1 0]
[1 -4 1]
[0 1 0]
ROI_num = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
value = cv2.Laplacian(ROI, cv2.CV_64F).var()
cv2.rectangle(result, (x, y), (x + w, y + h), (36,255,12), 2)
cv2.putText(result, "{0:.2f}".format(value), (x,y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (36,255,12), 2)
cv2.imshow("ROI_{}".format(ROI_num), ROI)
ROI_num += 1
print('ROI_Number: {}, Value: {}'.format(ROI_num, value))
import cv2
import numpy as np
image = cv2.imread('1.jpg')
result = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
ROI_num = 0
for c in cnts:
x,y,w,h = cv2.boundingRect(c)
ROI = image[y:y+h, x:x+w]
value = cv2.Laplacian(ROI, cv2.CV_64F).var()
cv2.rectangle(result, (x, y), (x + w, y + h), (36,255,12), 2)
cv2.putText(result, "{0:.2f}".format(value), (x,y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (36,255,12), 2)
cv2.imshow("ROI_{}".format(ROI_num), ROI)
ROI_num += 1
print('ROI_Number: {}, Value: {}'.format(ROI_num, value))
cv2.imshow('thresh', thresh)
cv2.imshow('dilate', dilate)
cv2.imshow('result', result)
cv2.waitKey(0)