[英]Open CV trivial circle detection -- how to get least squares instead of a contour?
[英]Least squares for circle detection
我正在尝试通过对数据点的子集进行最小二乘优化从激光扫描进行圆检测。 由于仅对一个圆的一部分获得测量值,因此最小二乘法会返回错误的结果,从而报告一个比实际情况更接近激光的圆。
该算法的结果如图所示。 散点表示激光测量,圆以算法返回的点为中心。 灰色的半透明形状表示机器人正在扫描(该形状左右两边的激光)。
我只对半径为RR的圆的局部坐标感兴趣。
PS。 我假设扫描被分为几类(self.clusters [i]是一个类),它们是[x,y]激光点的列表
def circle(x, scan):
xc, yc = x
f = sqrt((scan[:,0] - xc)**2 + (scan[:,1] - yc)**2) - RR
return f
def optimize_detect_circles(self):
centre = [1,1]
for i in range(0, self.number_of_clusters):
range_points = np.array(self.clusters[i])
sol = optimize.root(circle, centre, args=(range_points), method='lm')
self.circle_candidates.append(sol.x)
print sol.x
这是图片:
1,1
与正确值相差太远; 您很可能会陷入局部最优状态。
尝试从更接近真实中心的点开始。 您可以通过首先在群集中拟合一条直线来找到它。 然后将点分成两半,根据它们投影到直线的哪一半; 接下来安装两行,每行适合您的两个新子群集之一; 并在两个垂直点的中间点找到一个交点。
这是基于您的簇是跨度不大于180度的弧(看起来像它们)。 如果不是,只需重复细分,即可得到四个和弦,而不是两个。
您可以使用圆形霍夫变换找到圆-如果您事先知道圆的半径,则这特别容易。
我从skimage的过程文档中大量借用了以下代码,这些代码可以运行,但是可能需要一些调整才能找到圆:
import numpy as np
import matplotlib.pyplot as plt
import skimage
from skimage import data, filter, io
from skimage.transform import hough_circle
from skimage.feature import peak_local_max
from skimage import data, color
from skimage.draw import circle_perimeter
theImage = np.sum(io.imread("w1s31.png"),2)/4 # Image to greyscale
hough_radii = np.arange(61, 69, 2) # These are the radii to search for
hough_res = hough_circle(theImage, hough_radii)
centers = []
accums = []
radii = []
for radius, h in zip(hough_radii, hough_res):
# For each radius, extract two circles
num_peaks = 2
peaks = peak_local_max(h, num_peaks=num_peaks)
centers.extend(peaks)
accums.extend(h[peaks[:, 0], peaks[:, 1]])
radii.extend([radius] * num_peaks)
# Draw the most prominent 5 circles
image = color.gray2rgb(theImage)
for idx in np.argsort(accums)[::-1][:5]:
center_x, center_y = centers[idx]
radius = radii[idx]
cx, cy = circle_perimeter(center_y, center_x, radius)
theImage[cy, cx] = (1)
plt.imshow(theImage, cmap=plt.cm.gray)
plt.show()
下面是实现圆检测的一个小片断这个文件。
该算法始终有效,并且不会以线性复杂度进行迭代。
var add = function(a,b){ return a+b; }; var add_uu = function(a,b){ return a+b[0]*b[0]; }; var add_uv = function(a,b){ return a+b[0]*b[1]; }; var add_vv = function(a,b){ return a+b[1]*b[1]; }; var add_uuu = function(a,b){ return a+b[0]*b[0]*b[0]; }; var add_vvv = function(a,b){ return a+b[1]*b[1]*b[1]; }; var add_uvv = function(a,b){ return a+b[0]*b[1]*b[1]; }; var add_uuv = function(a,b){ return a+b[0]*b[0]*b[1]; }; var getx = function(e){ return e[0]; }; var gety = function(e){ return e[1]; }; $(document).ready(function () { var paper = Raphael("canvas"); var points=[]; $("#canvas").mousedown(function (e) { var x = e.offsetX; var y = e.offsetY; points.push([x,y]); paper.circle(x, y, 1); }); $("#clear").click(function(){ paper.clear(); points = []; }); $("#go").click(function(){ var N = points.length; var xb = points.map(getx).reduce(add,0) / N; var yb = points.map(gety).reduce(add,0) / N; var u = points.map(function(e){return [e[0]-xb,e[1]-yb];}); var a1 = u.reduce(add_uu,0); var b1 = u.reduce(add_uv,0); var c1 = 0.5*(u.reduce(add_uuu,0) + u.reduce(add_uvv,0)); var a2 = u.reduce(add_uv,0); var b2 = u.reduce(add_vv,0); var c2 = 0.5*(u.reduce(add_vvv,0) + u.reduce(add_uuv,0)); var q = a2/a1; var vc = (c2-q*c1)/(b2-q*b1); var uc = (c1-b1*vc)/a1; var r = Math.sqrt(uc*uc+vc*vc+(a1+b2)/N); var x = uc+xb; var y = vc+yb; paper.circle(x, y, r).attr({"stroke":"#f00","stroke-width":2}); var e = points.reduce(function(p,c) { var t = r*r - (c[0]-x)*(c[0]-x) - (c[1]-y)*(c[1]-y); return p+t*t; },0); console.log("Residue = " + e); }); });
#canvas { width: 600px; height: 400px; border: 2px dotted #ccc; cursor: crosshair; }
<script src="http://cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <button id="clear">Clear</button> <button id="go">Compute circle</button> <div id="canvas"></div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.