我有大量的像素颜色(96种不同的颜色):
我希望获得某种数学定义的概率区域,例如this question:
我现在看到的主要障碍 - Google上的所有方法主要是关于可视化和二维空间,但是没有找到方程系数的算法,如:
a 1 x 2 + b 1 y 2 + c 1 < / sub> y 2 + a 2 xy + b 2 xz + c 2 yz + a 3 x + b 3 y + c 3 z = 0
this paper对我来说太难以在python中实现它。 :(
无论如何,我只想确定一些像素是否或多或少存在于我的辩护中。
我尝试使用scikit群集,但由于只有一个,我失败了 可能是一组数据。并创建一个256 3 元素的数组 代表每个像素颜色似乎是错误的方式。
我想知道是否有一种简单的方法来确定这个点群的边界? 或者,也许我只是在思考它,而且还有像OpenCV这样的东西 cv2.inRange()函数?
答案 0 :(得分:1)
这可以通过优化和拟合椭球多项式来解决。但是,我会从更快的几何方法开始:
找到平均点位置
这将是椭圆体的中心
p0 = sum (p[i]) / n // average
i = { 0,1,2,3,...,n-1 } // of all points
如果您的点密度不均匀,则使用边界框中心更安全。所以找xmin,ymin,zmin,xmax,ymax,zmax
,他们之间的中间是你的中心。
找到最远点的中心
将为您提供主轴半轴
pa = p[j];
|p[j]-p0| >= |p[i]-p0| // max
i = { 0,1,2,3,...,n-1 } // of all points
找到第二个半轴
因此向量pa-p0
与其他半轴应该在的平面垂直。因此,从该平面找到最远点p0
:
pb = p[j];
|p[j]-p0| >= |p[i]-p0| // max
dot(pa-p0,p[j]-p0) == 0 // but inly if inside plane
i = { 0,1,2,3,...,n-1 } // from all points
请注意,dot产品的结果可能不会精确为零,因此最好对此类测试进行测试:
|dot(pa-p0,p[j]-p0)| <= 1e-3
您可以使用任何您想要的阈值(应该基于椭圆体大小)。
找到最后一个半轴
所以我们知道最后一个半轴应该垂直于两个
(pa-p0) AND (pb-p0)
所以找到点:
pc = p[j];
|p[j]-p0| >= |p[i]-p0| // max
dot(pa-p0,p[j]-p0) == 0 // but inly if inside plane
dot(pb-p0,p[j]-p0) == 0 // and perpendicular also to b semi-axis
i = { 0,1,2,3,...,n-1 } // from all points
<强>椭球强>
现在您拥有形成椭球所需的所有参数。载体
(pa-p0),(pb-p0),(pc-p0)
是椭圆体的基础向量(可以使用叉积使它们垂直)。它们的大小为您提供半径。 p0
是中心。您也可以使用此参数方程式:
a=pa-p0;
b=pb-p0;
c=pc-p0;
p(u,v) = p0 + a*cos(u)*cos(v)
+ b*cos(u)*sin(v)
+ c*sin(u);
u = < -0.5*PI , +0.5*PI >
v = < 0.0 , 2.0*PI >
整个过程只是O(n)
,结果可以作为优化和拟合的起点,以加快它们的速度而不会降低精度。如果您想进一步提高准确度,请参阅:
子链接显示了适合的例子......
您还可以看一下:
这与你的任务基本类似,但只在2D中仍然可以带给你一些想法。
答案 1 :(得分:1)
有一种方法可以仅基于两个焦点来查找非完美的对称椭球。 可能对大量积分有好处。 至少,这非常简单(基于某种随机搜索):
3DPoints - Array of some Amount of points
vecCenter - average of 3DPoints
AngleCosine - cos of angle between two vectors
RandomOrder(3DPoints)
vecFocus := (0, 0, 0)
for i := 0 to Amount:
vecRadius := 3DPoints[i] - vecCenter
// Change vecRadius direction to parallel if it's not
if AngleCosine(vecFocus, vecRadius) < 0 then
vecRadius *= -1
vecFocus += (vecRadius - vecFocus) / Amount
通过向后第二次传递数组可以改善结果
然后将焦点放在vecCenter
+/- vecFocus
处。
然后可以通过一些系数提出到病灶的距离,或者通过第二遍计算病灶的距离,如下所示:
FinalRadius := 0
for i := 0 to Amount:
vecRadius := (3DPoints[i] - vecFoci1) + (3DPoints[i] - vecFoci2)
FinalRadius := Max(FinalRadius, Length(vecRadius))