计算机视觉:Opencv计算大圆圈内的小圆圈

时间:2020-07-08 11:36:35

标签: python opencv image-processing computer-vision opencv-contour

这是我一直在处理的图像 enter image description here

目标是发现大圆圈内的小圆圈。

当前我所做的是将图像转换为灰度并应用了导致此图像的阈值(cv2.THRESH_OTSU) enter image description here

此后,我使用findcontours过滤了大对象,并使用了我在stackoverflow上找到的椭圆形内核打开了Morph

结果图像是这样的 enter image description here

有人可以指导我通过正确的方法来做什么和哪里出问题了。

下面是我一直在处理的代码

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('01.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
#cv2.imwrite('thresh.jpg', thresh)

# Filter out large non-connecting objects
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    #print(area)
    if area < 200 and area > 0:
        cv2.drawContours(thresh,[c],0,0,-1)

# Morph open using elliptical shaped kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)

# Find circles 
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area > 20 and area < 50:
        ((x, y), r) = cv2.minEnclosingCircle(c)
        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 2)

cv2.namedWindow('orig', cv2.WINDOW_NORMAL)
cv2.imshow('orig', thresh)
cv2.namedWindow('image', cv2.WINDOW_NORMAL)
cv2.imshow('image', image)
cv2.waitKey()

谢谢!

3 个答案:

答案 0 :(得分:6)

通过将图像转换为灰度,您会丢弃很多有用的信息。

为什么不使用您所寻找的斑点是唯一的红色/橙色的事实呢?

我将饱和卫星通道与红色通道相乘,得到了这个图像:

enter image description here

现在发现白色斑点变得微不足道了。

对这些渠道使用不同权重的实验,或先应用阈值。有很多方法。在不同的光照,不同的背景下进行实验,直到获得理想的图像处理输入为止。

答案 1 :(得分:1)

代码中的主要问题是cv2.findContours()函数中使用的标志。

对于这样的问题,我们必须找到可以出现在另一个轮廓(大圆)内的轮廓,我们不应使用标志cv2.RETR_EXTERNAL,而应使用cv2.RETR_TREE。 Click here for detailed info.

此外,如果内存不是问题,那么最好使用cv2.CHAIN_APPROX_NONE而不是cv2.CHAIN_APPROX_SIMPLE。 Click here for detailed info.

因此,以下简单代码可用于解决此问题。

import cv2
import numpy as np

Image = cv2.imread("Adg5.jpg")
GrayImage = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)

# Applying Otsu's Thresholding
Retval, ThreshImage = cv2.threshold(GrayImage, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

# Finding Contours in the image
Contours, Hierarchy = cv2.findContours(ThreshImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# Taking only those contours which have no child contour.
FinalContours = [Contours[i] for i in range(len(Contours)) if Hierarchy[0][i][2] == -1]

# Drawing contours
Image = cv2.drawContours(Image, FinalContours, -1, (0, 255, 0), 1)

cv2.imshow("Contours", Image)
cv2.waitKey(0)

Resulting image 在这种方法中,边界处也会出现很多噪音,但是也检测到了所需的橙色点。现在的任务是消除边界噪声。

另一种在很大程度上消除边界噪声的方法类似于@Piglet的方法。 在这里,我使用HSV图像分割出橙色点,然后使用上述方法对其进行检测。

import cv2
import numpy as np

Image = cv2.imread("Adg5.jpg")
HSV_Image = cv2.cvtColor(Image, cv2.COLOR_BGR2HSV)

# Extracting orange colour using HSV Image.
ThreshImage = cv2.inRange(HSV_Image, np.array([0, 81, 0]), np.array([41, 255, 255]))

# Finding Contours
Contours, Hierarchy = cv2.findContours(ThreshImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

# Taking only those contours which have no child contour.
FinalContours = [Contours[i] for i in range(len(Contours)) if Hierarchy[0][i][2] == -1]

# Drawing Contours
Image = cv2.drawContours(Image, FinalContours, -1, (0, 255, 0), 1)

cv2.imshow("Contours", Image)
cv2.waitKey(0)

Resultant Image

答案 2 :(得分:0)

我有一个想法,可以通过滑动窗口来检测小圆圈。当小圆柱状区域占据滑动窗口的面积大于90%(内切圆和正方形)且小于100%(避免滑动窗口在较大的圆柱状区域中移动)时。这个位置是一个小圆圈。最大的滑动窗口大小是最大的小cicle大小。希望有所帮助。

另外,在Piglet的结果上,应用k-means(k = 2),您可以获得二进制图像,然后使用findcontours来计算小圆圈。

相关问题