我是新来的,还有一点编程新手。
我有一个问题。我在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模块。 感谢
答案 0 :(得分:1)
这里的主要问题是为你的半径寻找一个好的范围。 您可以查看图片并猜测半径。
从你给出的图片中我猜测180 - 220将是一个很好的范围。
您的代码如下:
cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 1, 16.0, 180, 220)
尝试为minRadius
和maxRadius
找到合适的价值,这应该可以正常使用。
答案 1 :(得分:1)
这是我的问题的解决方案
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)
答案 2 :(得分:1)
以为如果有人在将来偶然发现这个问题,我会想出另一种解决方案。
以下函数使用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)
如果您发现需要进一步修补此问题,我已经留下了一些可能派上用场的评论调试语句。
如果您的图片包含大量眩光,您可能需要使用更高的阈值。