首页 > 解决方案 > 灰度图像导致 HoughCircles() 方法不准确

问题描述

这是openCV 多边形检测的后续。对于第二张图像,我没有检测到任何矩形,但那是因为我的阈值对于该图像不正确。

我使用了 otsu 阈值,并添加了一个约束来删除检测到的小矩形和其他不相关的矩形。

import numpy as np
import cv2 as cv
import math

img = cv.imread("t1.jpeg")



n=0

#rectangle parameters
width=0 
height=0

start_x=0 
start_y=0
end_x=0 
end_y=0

#houghcircles parameters     
minr=0 
maxr=0
mind=0

maxarea=0
area=0

output = img.copy()
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret2,th = cv.threshold(gray,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)



#rectangle detection

contours, _ = cv.findContours(th, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)

for contour in contours:

    approx = cv.approxPolyDP(contour, 0.01* cv.arcLength(contour, True), True)
    
    cv.drawContours(img, [approx], 0, (0, 0, 0), 5)
    
    x = approx.ravel()[0]
    y = approx.ravel()[1]

    x1 ,y1, w, h = cv.boundingRect(approx)
    a=w*h    
    if len(approx) == 4 and x>15  :
            
        aspectRatio = float(w)/h
        if  aspectRatio >= 2.5 and a>50:          
          print(x1,y1,w,h)
          width=w
          height=h   
          start_x=x1
          start_y=y1
          end_x=start_x+width
          end_y=start_y+height      
          cv.rectangle(output, (start_x,start_y), (end_x,end_y), (0,0,255),3)
          cv.putText(output, "rectangle "+str(x1)+" , " +str(y1-5), (x1, y1-5), cv.FONT_HERSHEY_COMPLEX, 0.5, (0, 0, 0))
        

minr=int(17*width/192)
maxr=int(7*width/64)
mind=int(width//5)


print("start",start_x,start_y)
print("width",width)
print("height",height)
print("minr", minr)
print("maxr",maxr)
print("mind",mind)

cv.imshow("op1",output)

#circle detection,converting binary to decimal.

circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, mind,param1=50, param2=20, minRadius=minr, maxRadius=maxr)
detected_circles = np.uint16(np.around(circles))

for (x, y ,r) in detected_circles[0, :]:
    if(y>start_y and x>start_x and y<start_y+height and x<start_x+width):
        
        cf= ((x-start_x)*8)/width
        fp= cf-math.floor(cf)
        
        
        if(fp>0.50):
            idx=math.ceil(cf)
        else:
            idx=math.floor(cf)

        
        
        exp=int(4- (0.5* (idx+1)))
       
        n+= 2**exp
        print("circle",x,y,r)
        cv.circle(output, (x, y), r, (0, 0, 0), 3)
        cv.circle(output, (x, y), 2, (0, 255, 255), 3)
        
print(n)
cv.imshow("th",th)
cv.imshow("gray",gray)
cv.imshow('output',output)

cv.waitKey(0)
cv.destroyAllWindows()

最终结果是这样的:

在此处输入图像描述

现在已成功检测到矩形,但未正确检测到圆形。检测到的圆与目标圆的大小大致相同,这意味着 HoughCircles() 的参数是正确的,尽管在正确的位置没有检测到圆。

这可能是因为眩光导致圆圈在灰度图像中几乎消失(我在 HoughCircles() 方法中使用过):

在此处输入图像描述

我可以做些什么来使用这个图像的 HoughCircles() 方法?

编辑:修复了代码中的一个小错误。问题仍然存在,但是我用其他图像进行了测试,并且它适用于灰度图像足够体面的图像: 在此处输入图像描述

标签: pythonopencvhough-transform

解决方案


这是在 Python/OpenCV 中提取圆的一种方法。转换为 LAB,分离 B 通道,然后在黑圈上设置阈值。

输入:

在此处输入图像描述

import cv2
import numpy as np

# load images
img = cv2.imread('4_sign.jpg')

# convert to LAB
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

# separate B channel
b = lab[:,:,2]

# threshold and invert
thresh = cv2.threshold(b, 105, 255, cv2.THRESH_BINARY)[1]
thresh = 255 - thresh

# apply morphology to clean it up
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

# get min enclosing circle
# numpy points are (y,x), so need to transpose
points = np.argwhere(morph.transpose()>0)

center, radius = cv2.minEnclosingCircle(points)
print('center:', center, 'radius:', radius)

# draw circle on copy of input
result = img.copy()
cx = int(round(center[0]))
cy = int(round(center[1]))
rr = int(round(radius))
cv2.circle(result, (cx,cy), rr, (255,255,255), 2)

# save output
cv2.imwrite('4_sign_circle.jpg', result)

# display results
cv2.imshow('thresh',thresh)
cv2.imshow('morph',morph)
cv2.imshow('result',result)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果:

在此处输入图像描述

添加

这是使用 HoughCircles 的版本。

import cv2
import numpy as np

# load images
img = cv2.imread('4_sign.jpg')
ht, wd = img.shape[:2]
minhw = min(ht,wd)

# convert to LAB
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)

# separate B channel
b = lab[:,:,2]

# threshold and invert
thresh = cv2.threshold(b, 105, 255, cv2.THRESH_BINARY)[1]
thresh = 255 - thresh

# apply morphology to clean it up
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7,7))
morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morph = cv2.morphologyEx(morph, cv2.MORPH_CLOSE, kernel)

# get circle from HoughCircles
min_dist = int(minhw/20)
circles = cv2.HoughCircles(morph, cv2.HOUGH_GRADIENT, 1, minDist=min_dist, param1=100, param2=10, minRadius=30, maxRadius=60)
#print(circles)

result = img.copy()
for circle in circles[0]:
    # draw the circle on copy of input
    (x,y,r) = circle
    center = (x,y)
    radius = r
    print('center:', center, 'radius:', radius)
    x = int(x)
    y = int(y)
    cv2.circle(result, center, radius, (255, 255, 255), 2)

# save output
cv2.imwrite('4_sign_circle2.jpg', result)

# display results
cv2.imshow('thresh',thresh)
cv2.imshow('morph',morph)
cv2.imshow('result',result)
cv2.waitKey(0)

结果:

在此处输入图像描述

文字信息:

center: (410.5, 686.5) radius: 54.4

推荐阅读