使用HoughCircles和FindContours查找不同曝光的圈子

问题描述

我是图像处理和边缘检测的新手,所以希望你们能帮助我对opencv python有所了解。免责声明:这是一个工作项目。

这是关于霍夫圆,轮廓和图像处理的3部分问题。完整的代码将在文本墙的结尾。

部分A,请考虑此image AA。对于此图像,阈值化很容易,并且可以仅隔离大的外圆和两个内圆。这样,使用霍夫圆很容易找到圆。但是,我从来没有运气好好地调整Hough Circle函数包括dp,mindist,param1,param2,minRad和maxRad,以适用于不同的图像。我仅使用2个参数使用Hough函数,尽管效果很好,但我感觉我没有利用该函数的全部功能。它足够强大,可以在其他image BB上工作,但是在image CC上却很挣扎。相同的参数可以获得正确的2/3个圆。所以我的问题是,怎样调整Hough Circles函数以获得一组可以正常工作的参数?我是否必须强行使用它并保持手动调校,直到找到可行的方法?有没有一种方法可以告诉霍夫圆只在左侧区域找到圆而忽略其他所有内容

B部分,我知道,如果不知道最小半径和最大半径(HoughCircles can't detect circles on this image),则霍夫圆有一定的局限性,要使一组参数适用于所有对象,将很困难。这就是为什么我考虑改用Contours的原因。据我了解,轮廓仅适用于黑色的白色边缘图像。因此,将图像处理为仅具有白色边缘非常重要。我的问题是have trouble separating the two inner circle as two separate circlewhite image threshold seems to be touching的轮廓看起来像。我应该如何解决此问题以优化轮廓以检测两个单独的圆,而不是将它们分组为一个圆?

PART C,到目前为止,我提供的图像是最好的情况,即内圈比大圈更亮。假设现在我有不同的图像image DDimage EE。现在,将此图像阈值化以仅隔离内圆要困难得多。我现有的A部分和B部分代码均无效。看来我需要处理更多图像。我尝试了自适应阈值,扩张,腐蚀,坎尼,打开,关闭,渐变的方法,但仍然无法按预期工作。实际上,最接近使它起作用的是我尝试了179个块大小和5 c的自适应阈值,并进行了6次迭代的腐蚀和扩张。这样,我可以找到圆圈,但无法准确找到。因此,我希望就我需要哪种类型的图像处理或者应该拍摄更好的图像提出建议。

在这是我使用的代码。感谢您抽出宝贵的时间阅读我的问题,希望大家能帮助我。

import numpy as np
import cv2

# https://stackoverflow.com/questions/28327020/opencv-detect-mouse-position-clicking-over-a-picture
def onMouse(event,x,y,flags,param):
    if event == cv2.EVENT_LBUTTONDOWN:
       print('x = %d,y = %d'%(x,y))

def createCircle(img,out,dp,mindist):
    circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,mindist)
    if circles is not None:
        circles = np.round(circles[0,:]).astype("int") #convert the (x,y) coordinates and radius of the circles to integers

    for (x,r) in circles:
        cv2.circle(out,(x,y),r,(0,255,0),4) # draw the circle in the output image
        
    return x,r 
        
def createCircle2(img,mindist,param1,param2,minRad,maxRad):
    circles = cv2.HoughCircles(img,maxRad)
    if circles is not None:
        circles = np.round(circles[0,4) # draw the circle in the output image
    
    return x,r

def showImage(name,img,sizescale):
    if sizescale == 1:
        cv2.imshow("%s"%name,img)
    else:
        cv2.imshow("%s"%name,cv2.resize(img,fx=sizescale,fy=sizescale))

    cv2.setMouseCallback("%s"%name,onMouse) # enable coordinate function
    cv2.waitKey(0)  # wait infinitely
    cv2.destroyAllWindows() # destroy window once any key is pressed
    
    
    
    #inner brighter (PART A and B)
img = "AA.jpg" 
# img = "BB.jpg"
# img = "CC.jpg"

    #inner darker   (PART C)
# img = "DD.jpg"
# img = "EE.jpg"

scale = 0.3               # resize images
sigma = 0.33              # best according to link below regarding image_median
cv2.destroyAllWindows()
image = cv2.imread(img)
output1 = image.copy()
output2 = image.copy()
output3 = image.copy()  
kernel = np.ones((3,3),np.uint8) 

########################################################################################## HOUGH CIRCLES (PART A)

image_gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(image_gray,(5,5),20)
image_median = np.median(blur)

#https://stackoverflow.com/questions/41893029/opencv-canny-edge-detection-not-working-properly
if image_median > 191:                                                  #light image
    canny_lower = int(max(0,(1.0 - 2*sigma) * (255-image_median)))
    canny_upper = int(min(255,(1.0 + 2*sigma) * (255-image_median)))
elif image_median > 127:
    canny_lower = int(max(0,(1.0 - sigma) * (255-image_median)))
    canny_upper = int(min(255,(1.0 + sigma) * (255-image_median)))
elif image_median < 63:                                                 # dark image
    canny_lower = int(max(0,(1.0 - 2*sigma) * image_median))
    canny_upper = int(min(255,(1.0 + 2*sigma) * image_median))
else:
    canny_lower = int(max(0,(1.0 - sigma) * image_median))
    canny_upper = int(min(255,(1.0 + sigma) * image_median))
# print(image_median,canny_lower,canny_upper)


ret,thresh1 = cv2.threshold(blur,15,cv2.THRESH_BINARY)                  # for outer big circle
ret2,thresh2= cv2.threshold(blur,cv2.THRESH_BINARY+cv2.THRESH_OTSU)   # for inner circles
canny = cv2.Canny(thresh2,canny_upper)                             # for inner circles

# showImage("thresh1",thresh1,scale)
# showImage("thresh2",thresh2,scale)
# showImage("canny",canny,scale)


createCircle(thresh1,output1,10,5000)
createCircle(thresh2,10000) 
createCircle(canny,18,50000)

# createCircle2(opening,10000,350,300,900)
# createCircle2(thresh3,20,200,500)
# createCircle2(canny,50,50000,500)

showImage("output",scale)


################################################################################################# CONTOURS (PART B)

ret3,thresh3 = cv2.threshold(blur,127,cv2.THRESH_BINARY)

contours,hierarchy = cv2.findContours(thresh3,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))
cnt = contours


for i in range (len(cnt)):
    (x,radius = cv2.minenclosingCircle(cnt[i])
    center = (int(x),int(y))
    radius = int(radius)
    if radius > 100 :
        cv2.circle(output2,center,radius,4)
        print('Circle' + str(i) + ': Center =' + str(center) + 'Radius =' + str(radius))


# showImage("thresh3",thresh3,scale)
showImage("output2",output2,scale)


################################################################################################# CONTOURS (PART C)


bs = 179   #blocksize
c = 5      #c
thresh4 = cv2.adaptiveThreshold(blur,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,bs,c)

ero_n = 6
dil_n = 6
erode = cv2.erode(thresh4,kernel,iterations=ero_n)
dilate = cv2.dilate(erode,iterations=dil_n)

contours2,hierarchy2 = cv2.findContours(dilate,cv2.CHAIN_APPROX_SIMPLE)
print(len(contours2))
cnt2 = contours2


for i in range (len(cnt2)):
    (x,radius = cv2.minenclosingCircle(cnt2[i])
    center = (int(x),int(y))
    radius = int(radius)
    if radius > 150 :
        cv2.circle(output3,4)
        print('Circle' + str(i) + ': Center =' + str(center) + 'Radius =' + str(radius))
        
showImage("output3",output3,scale)

解决方法

可惜没人回答我的问题。但是我想我解决了B部分。为了分离两个接触的圆并防止将它们视为一个轮廓,我使用了分水岭功能。这是答案(https://www.pyimagesearch.com/2015/11/02/watershed-opencv/)的链接。使用轮廓+分水岭,我能够准确地获得其中两个明亮圆的圆。这样,我就完全放弃了HoughCircle方法,并确保始终提供良好的图像。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...