python - 如何在 OpenCV 中获取轮廓检测的动态阈值
问题描述
在我的图像数据库中,需要 1)检测图像中是否存在薄片(非常黑的轮廓),以及 2)找到一个最小闭合圆来测量薄片的半径。
但是,图像的照明略有不同。
这里有些例子:
这个很容易检测和测量:
但这些更难:
我最初的想法是使用与图像像素的平均值相关的阈值。
有没有其他方法可以在 OpenCV 中计算这样的动态阈值?
解决方案
我认为您正在寻找的是cv2.adaptiveThreshold()
或Otsu 的阈值。为了满足您对#1 的要求,我们可以使用最小阈值区域来确定薄片是否存在。对于#2,一旦我们检测到轮廓,我们就可以使用矩来确定半径。这是一个简单的方法
- 将图像转换为灰度和中值模糊
- 自适应阈值
- 变形接近平滑的图像
- 扩张以增强轮廓
- 查找轮廓并使用轮廓区域进行排序
主要思想是使用大的中值模糊来去除噪声然后自适应阈值。这是您的四张照片的每张照片的结果。对于你的一些照片,黑点实际上不是一个圆圈,它更像是一个椭圆形。你可以决定你想在这种情况下做什么。
import cv2
image = cv2.imread('4.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 25)
thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,27,6)
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
dilate = cv2.dilate(close, kernel, iterations=2)
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:10]
minimum_area = 500
for c in cnts:
area = cv2.contourArea(c)
if area > minimum_area:
# Find centroid
M = cv2.moments(c)
cX = int(M["m10"] / M["m00"])
cY = int(M["m01"] / M["m00"])
cv2.circle(image, (cX, cY), 20, (36, 255, 12), 2)
x,y,w,h = cv2.boundingRect(c)
cv2.putText(image, 'Radius: {}'.format(w/2), (10,20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (36,255,12), 2)
break
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.waitKey()
推荐阅读
- c++ - 作为参数输入 (C++)
- javascript - 掷骰子结果的水平直方图
- amazon-web-services - 我可以将 Aws SQS 与 heroku、Nodejs Express 服务器一起使用吗?
- django - 使用 django-storages 在谷歌云存储中上传文件的 404
- java - 如何在javaFX的ListView中将自定义对象显示为项目
- docker - 如何使用 Codebuild 构建 Docker 映像?
- elasticsearch - 如何在 Elasticsearch 中过滤掉聚合结果
- python - 通过 Python 登录 Apple
- angular - 检测主题何时没有更多订阅
- javascript - Ajax "GET" to intra-service >> CMS serviceworker 在 OFFLINE 时回答 OK