Ash*_*all 4 python opencv image-processing
作为我正在研究的项目的一部分,我需要使用OpenCV和Python在图像中找到一些"blob"的中心点.我遇到了一些麻烦,真的很感激任何帮助或见解:)
我目前的方法是:获取图像的轮廓,在那些上叠加椭圆,使用斑点检测器找到每个图像的中心.这种效果相当不错,但偶尔我还需要忽略无关的斑点,有时斑点会相互碰触.
以下是一个很好的例子:
良好的源图像:
提取轮廓后:
检测到斑点:

当它变得很糟糕时(你可以看到它错误地将椭圆覆盖在三个blob上,并检测到一个我不想要的):
错误的源图像:
提取轮廓后:
检测到斑点:

这是我目前使用的代码.我不确定任何其他选择.
def process_and_detect(img_path):
img = cv2.imread(path)
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 50, 150, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
drawn_img = np.zeros(img.shape, np.uint8)
min_area = 50
min_ellipses = []
for cnt in contours:
if cv2.contourArea(cnt) >= min_area:
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(drawn_img,ellipse,(0,255,0),-1)
plot_img(drawn_img, size=12)
# Change thresholds
params = cv2.SimpleBlobDetector_Params()
params.filterByColor = True
params.blobColor = 255
params.filterByCircularity = True
params.minCircularity = 0.75
params.filterByArea = True
params.minArea = 150
# Set up the detector
detector = cv2.SimpleBlobDetector_create(params)
# Detect blobs.
keypoints = detector.detect(drawn_img)
for k in keypoints:
x = round(k.pt[0])
y = round(k.pt[1])
line_length = 20
cv2.line(img, (x-line_length, y), (x+line_length, y), (255, 0, 0), 2)
cv2.line(img, (x, y-line_length), (x, y+line_length), (255, 0, 0), 2)
plot_img(img, size=12)
Run Code Online (Sandbox Code Playgroud)
非常感谢你阅读这篇文章,我真诚地希望有人可以帮助我,或指出我正确的方向.谢谢!
目前,您的实施是多余的.来自SimpleBlobDetector()文档:
该类实现了一种从图像中提取blob的简单算法:
- 通过应用具有从minThreshold(包括)到maxThreshold(不包括)的几个阈值的阈值来将源图像转换为二进制图像,其中相邻阈值之间具有距离thresholdStep.
- 通过findContours()从每个二进制图像中提取连接的组件并计算它们的中心.
- 根据坐标从几个二进制图像中心分组.关闭中心形成一个对应于一个blob的组,该blob由minDistBetweenBlobs参数控制.
- 从这些组中,估计斑点及其半径的最终中心,并返回关键点的位置和大小.
所以你已经实现了部分步骤,这可能会带来一些意想不到的行为.您可以尝试使用参数来查看是否可以找出适合您的参数(尝试创建跟踪条以使用参数并使用不同的blob检测器参数获取算法的实时结果).
但是,您已经编写了大部分自己的管道,因此您可以轻松删除blob检测器并实现自己的算法.如果您只是略微降低阈值,您可以轻松获得清晰标记的圆圈,然后斑点检测就像轮廓检测一样简单.如果每个斑点都有一个单独的轮廓,则可以计算轮廓的质心moments().例如:
def process_and_detect(img_path):
img = cv2.imread(img_path)
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(imgray, 100, 255, cv2.THRESH_BINARY)
contours = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
line_length = 20
for c in contours:
if cv2.contourArea(c) >= min_area:
M = cv2.moments(c)
x = int(M['m10']/M['m00'])
y = int(M['m01']/M['m00'])
cv2.line(img, (x-line_length, y), (x+line_length, y), (255, 0, 0), 2)
cv2.line(img, (x, y-line_length), (x, y+line_length), (255, 0, 0), 2)
Run Code Online (Sandbox Code Playgroud)
可以使用相同的管道自动循环阈值,这样您就不必猜测和硬编码这些值.由于斑点看起来大致大致相同,因此您可以循环直到所有轮廓具有大致相同的区域.您可以这样做,例如通过查找中间轮廓大小,定义您允许的上下的某个百分比,并检查检测到的所有轮廓是否适合这些边界.
这gif是我的意思的动画.请注意,gif轮廓分离后停止:
然后你可以简单地找到那些分开的轮廓的质心.这是代码:
def process_and_detect(img_path):
img = cv2.imread(img_path)
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
for thresh_val in range(0, 255):
# threshold and detect contours
thresh = cv2.threshold(imgray, thresh_val, 255, cv2.THRESH_BINARY)[1]
contours = cv2.findContours(thresh,
cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)[1]
# filter contours by area
min_area = 50
filtered_contours = [c for c in contours
if cv2.contourArea(c) >= min_area]
area_contours = [cv2.contourArea(c) for c in filtered_contours]
# acceptable deviation from median contour area
median_area = np.median(area_contours)
dev = 0.3
lowerb = median_area - dev*median_area
upperb = median_area + dev*median_area
# break when all contours are within deviation from median area
if ((area_contours > lowerb) & (area_contours < upperb)).all():
break
# draw center location of blobs
line_length = 8
cross_color = (255, 0, 0)
for c in filtered_contours:
M = cv2.moments(c)
x = int(M['m10']/M['m00'])
y = int(M['m01']/M['m00'])
cv2.line(img, (x-line_length, y), (x+line_length, y), cross_color, 2)
cv2.line(img, (x, y-line_length), (x, y+line_length), cross_color, 2)
Run Code Online (Sandbox Code Playgroud)
请注意,这里我通过与所有可能的阈值循环range(0, 255)给0, 1, ..., 254,但真正你可以开始提高,并通过在用,比如一个时间几个值跳跃,range(50, 200, 5)让50, 55, ..., 195这当然会快得多.
| 归档时间: |
|
| 查看次数: |
961 次 |
| 最近记录: |