【问题标题】:python opencv-finding circle (Sun) , coordinates of center the circle from picturepython opencv-finding circle (Sun) , 图片圆心坐标
【发布时间】:2013-11-04 13:17:07
【问题描述】:

我是新来的,在编程方面有点新手。

我有一个问题。我有 Sun 的 bmp 文件和 16 位图片。图片看起来是黑色背景的白色圆圈。

我想找到一个圆并在 x,y 坐标中确定它的中心。

我有这个脚本

import cv
import numpy as np




orig = cv.LoadImage('sun0016.bmp')

grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
processed = cv.CreateImage(cv.GetSize(orig), 8, 1)

cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 5, 5)
cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)
cv.Erode(grey_scale, processed, None, 10)
cv.Dilate(processed, processed, None, 10)
cv.Canny(processed, processed, 5, 70, 3)
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)


cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 1, 16.0, 10, 140)

for i in range(0, len(np.asarray(storage))):
    print "circle #%d" %i
    Radius = int(np.asarray(storage)[i][0][2])
    x = int(np.asarray(storage)[i][0][0])
    y = int(np.asarray(storage)[i][0][1])
    center = (x, y)
    print x,y

    cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), 1, 8, 0)
    cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 1, 8, 0)

    cv.Circle(processed, center, 1, cv.CV_RGB(0, 0, 0), -1, 8, 0)
    cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

cv.ShowImage("sun0016", orig)
cv.ShowImage("processed", processed)
cv_key = cv.WaitKey(0)

当我运行这个时,我发现太阳的边缘是圆的,但非常不准确。 请知道您设置参数 HoughCircles 模块以进行精确搜索圈。 谢谢

【问题讨论】:

  • 可以给图片加个链接吗?这里的主要问题是为您的半径找到一个合适的范围。
  • 好的,这里是上传postimg.org/image/5qq6psolz/993df3d4
  • 有了清晰的图片,我只需将其阈值设置为二进制,然后找到 blob 的质心 - 不需要 Hough。或者这不是典型的图像?
  • 这是来自望远镜的图像,我想用脚本找到太阳的中心,然后这个中心到达 CCD 芯片的中心。如果我知道中心之间的差异,那么使用 mount 的提要会很容易。
  • 看看this answerthis question - 他们有帮助吗?

标签: python opencv image-processing


【解决方案1】:

这里的主要问题是为您的半径找到一个合适的范围。 您可以看看您的图片并猜出半径。

从您提供的图片中,我猜 180 - 220 会是一个不错的范围。

您的代码如下所示:

cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 1, 16.0, 180, 220)

只需尝试为 minRadiusmaxRadius 找到好的值,这应该可以正常工作。

【讨论】:

  • 这就是我写的原因,我猜到了,我没有解决,这取决于你。我只看到源图像。如果您的几个预处理步骤之一改变了半径,我没有考虑到它。您可以尝试和错误的好值,或者您打印出霍夫圆的输入图像并测量范围。如果范围是正确的,并且你没有多个圆圈,那么 houghlines 是非常准确的。
  • 我不明白。我以为 modul houghcircles 会自动找到 Sun。
  • 可以,但是如果您需要非常准确的输出,您必须选择一个好的半径范围。如果您选择了错误的半径范围,houghcircles 仍然可以找到圆圈,但它们可能会被移位或者只是不是您要查找的圆圈。
  • 我明白了。我必须通过实验找出这个范围吗?有没有find range的执行方法?
  • 通过实验或在传递给 houghcircle 方法的图像中测量它。只需以像素为单位计算对象的半径即可。
【解决方案2】:

这是我的问题的解决方案

import numpy as np
import cv2

im = cv2.imread('sun0016.bmp')
height, width, depth = im.shape
print height, width, depth
thresh = 132
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(imgray,(5,5),0)
edges = cv2.Canny(blur,thresh,thresh*2)
contours, hierarchy = cv2.findContours(edges,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
cv2.drawContours(im,contours,-1,(0,255,0),-1)

#centroid_x = M10/M00 and centroid_y = M01/M00
M = cv2.moments(cnt)
x = int(M['m10']/M['m00'])
y = int(M['m01']/M['m00'])
print x,y
print width/2.0,height/2.0
print width/2-x,height/2-y


cv2.circle(im,(x,y),1,(0,0,255),2)
cv2.putText(im,"center of Sun contour", (x,y), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255))
cv2.circle(im,(width/2,height/2),1,(255,0,0),2)
cv2.putText(im,"center of image", (width/2,height/2), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,0,0))
cv2.imshow('contour',im)
cv2.waitKey(0)

【讨论】:

    【解决方案3】:

    我想我会提出一个替代解决方案,以防将来有人偶然发现这个问题。

    以下函数使用cv2.inRange 代替cv2.Canny,并使用cv2.minEnclosingCircle 代替cv2.moments。它通过测量候选者的最小包围圆的半径来选择cv2.findContours找到的最大轮廓。这种过滤有助于拒绝来自例如的误报。水印或灰尘,但根据您的要求,您可能希望以不同的方式执行此步骤或完全省略它。

    该函数返回 x,y 坐标以及检测到的磁盘的半径,这是我正在处理的项目的要求。

    import cv2
    
    
    def find_disk(img, threshold=10):
        """Finds the center and radius of a single solar disk present in the supplied image.
    
        Uses cv2.inRange, cv2.findContours and cv2.minEnclosingCircle to determine the centre and 
        radius of the solar disk present in the supplied image.
    
        Args:
            img (numpy.ndarray): greyscale image containing a solar disk against a background that is below `threshold`.
            threshold (int): threshold of min pixel value to consider as part of the solar disk
    
        Returns:
            tuple: center coordinates in x,y form (int) 
            int: radius
        """
        if img is None:
            raise TypeError("img argument is None - check that the path of the loaded image is correct.")
    
        if len(img.shape) > 2:
            raise TypeError("Expected single channel (grayscale) image.")
    
        blurred = cv2.GaussianBlur(img, (5, 5), 0)
        mask = cv2.inRange(blurred, threshold, 255)
        img_mod, contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
        # Find and use the biggest contour
        r = 0
        for cnt in contours:
            (c_x, c_y), c_r = cv2.minEnclosingCircle(cnt)
            # cv2.circle(img, (round(c_x), round(c_y)), round(c_r), (255, 255, 255), 2)
            if c_r > r:
                x = c_x
                y = c_y
                r = c_r
    
        # print("Number of contours found: {}".format(len(contours)))
        # cv2.imwrite("mask.jpg", mask)
        # cv2.imwrite("circled_contours.jpg", img)
    
        if x is None:
            raise RuntimeError("No disks detected in the image.")
    
        return (round(x), round(y)), round(r)
    
    
    if __name__ == "__main__":
        image = cv2.imread("path/to/your/image.jpg")
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
        center, radius = find_disk(img=gray, threshold=20)
    
        print("circle x,y: {},{}".format(center[0], center[1]))
        print("circle radius: {}".format(radius))
    
        # Output the original image with the detected disk superimposed
        cv2.circle(image, center, radius, (0, 0, 255), 1)
        cv2.rectangle(image, (center[0] - 2, center[1] - 2), (center[0] + 2, center[1] + 2), (0, 0, 255), -1)
        cv2.imwrite("disk_superimposed.jpg", image)
    

    我留下了一些带注释的调试语句,如果您发现需要进一步修改,它们可能会派上用场。

    如果您的图像包含大量眩光,您可能需要使用更高的阈值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-27
      • 2012-11-02
      • 1970-01-01
      • 2014-08-29
      • 1970-01-01
      • 1970-01-01
      • 2021-04-22
      相关资源
      最近更新 更多