【问题标题】:Finding circles of different exposure using HoughCircles and FindContours使用 HoughCircles 和 FindContours 查找不同曝光的圆圈
【发布时间】:2020-09-08 11:54:31
【问题描述】:

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

这是一个关于 houghcircles、轮廓和图像处理的 3 部分问题。完整的代码将在这面文字墙的末尾。

A 部分,考虑一下image AA。对于此图像,阈值处理很容易,可以仅隔离大外圆和两个内圆。有了这个,很容易使用霍夫圈来找到圆圈。但是,我从来没有调整过包含 dp、minDist、param1、param2、minRad 和 maxRad 的 Hough Circle 函数以适用于不同的图像。我使用只有 2 个参数的 Hough 函数,虽然它运行良好,但我觉得我没有利用该函数的全部功能。它足够强大,可以在其他 image BB 上工作,但在 image CC 上表现不佳。相同的参数可以得到 2/3 圈正确。所以我的问题是,调整霍夫圆函数以获得一组可以正常工作的参数的方法是什么?我是否必须强行使用它并继续手动调整,直到找到有效的方法?有没有办法告诉霍夫圆只在左侧区域找到圆而忽略其他所有内容?

B 部分,我知道如果不知道最小和最大半径 (HoughCircles can't detect circles on this image),Hough Circles 会有一些限制,并且要让一组参数适用于所有这些将是困难的。这就是为什么我考虑改用 Contours 的原因。据我了解,轮廓仅适用于黑色的白色边缘图像。因此,将图像处理为只有白色边缘是很重要的。我的问题是轮廓似乎是have trouble separating the two inner circle as two separate circle,而white image threshold seems to be touching。我应该如何解决这个问题来优化轮廓以检测两个单独的圆圈而不是将它们组合为一个?

C 部分,到目前为止我提供的图像是内圈比大外圈更亮的最佳情况。假设现在我有不同的图像image DDimage EE。现在对该图像进行阈值化以仅隔离内圈要困难得多。我现有的 A 部分和 B 部分代码都不起作用。看来我需要更多地处理图像。我尝试了adaptivethreshold、dilate、erode、canny、opening、close、gradient的方法,但我仍然无法让它按预期工作。实际上,我最接近让它工作的是当我尝试 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, dp, 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, y, r) in circles:
        cv2.circle(out, (x, y), r, (0, 255, 0), 4) # draw the circle in the output image
        
    return x, y ,r 
        
def createCircle2(img,out,dp,minDist,param1,param2,minRad,maxRad):
    circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, dp, minDist,param1,param2,minRad,maxRad)
    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, y, r) in circles:
        cv2.circle(out, (x, y), r, (0, 255, 0), 4) # draw the circle in the output image
    
    return x, y, r

def showImage(name,img,sizescale):
    if sizescale == 1:
        cv2.imshow("%s"%name, img)
    else:
        cv2.imshow("%s"%name, cv2.resize(img,(0,0),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, 255, cv2.THRESH_BINARY)                  # for outer big circle
ret2, thresh2= cv2.threshold(blur, 0, 255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)   # for inner circles
canny = cv2.Canny(thresh2,canny_lower,canny_upper)                             # for inner circles

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


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

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

showImage("output", output1, scale)


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

ret3, thresh3 = cv2.threshold(blur,127, 255, 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,y),radius = cv2.minEnclosingCircle(cnt[i])
    center = (int(x),int(y))
    radius = int(radius)
    if radius > 100 :
        cv2.circle(output2,center,radius,(0,255,0),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,255,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, kernel, iterations=dil_n)

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


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

【问题讨论】:

    标签: python opencv edge-detection hough-transform opencv-contour


    【解决方案1】:

    很遗憾没有人回答我的问题。但我认为我解决了 B 部分。为了分隔两个接触的圆圈并防止它们被视为一个轮廓,我使用了分水岭函数。这是答案的链接 (https://www.pyimagesearch.com/2015/11/02/watershed-opencv/)。有了等高线+分水岭,我就能够准确的得到一个圈内的两个亮圈。有了这个,我完全放弃了 HoughCircle 方法,并确保我始终提供良好的图像。

    【讨论】:

    • 不要说这是一种耻辱。我思考了你的问题,这很有趣,但也很困难。特别是 D 和 E,无法进行二值化。其中,一个严重的困难是纤维周围的纹理,但如果设法执行纹理检测,这个困难可以转化为资产。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    相关资源
    最近更新 更多