网上只找到了matlab的代码,倒是挺简单的
参考这篇博客
自己写了个C++的实现,有些问题,还没解决,记录下
链接: [Geometry] Alpha Shapes - 原理及我的实现.
结果: 把所有点都连起来了
自己写的C++实现(有问题)
struct Edge
{
Point2f a;
Point2f b;
};
class AlphaShape
{
public:
void AlphaShapes(const float& m_radius, const vector<Point2f> &points, Mat img);
vector<Point2f> m_points; // 点集S
vector<Edge> m_edges; // 边
private:
};
float squareDistance(Point2f a, Point2f b) {
return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
void normalize(Point2f pt)
{
float x = pt.x;
float y = pt.y;
float flag_x = x > 0 ? 1.0f : -1.0f;
float flag_y = y > 0 ? 1.0f : -1.0f;
pt.x =flag_x* x / (sqrt(x * x + y * y));
pt.y = flag_y * y / (sqrt(x * x + y * y));
}
void AlphaShape::AlphaShapes(const float &m_radius,const vector<Point2f> &points,Mat img)
{
m_points = points;
m_edges.clear();
for (int i = 0; i < m_points.size(); i++)
{
// k从i+1开始,减少重复计算
for (int k = i + 1; k < m_points.size(); k++)
{
// 跳过距离大于直径的情况
if (squareDistance(m_points[i],m_points[k]) > 2 * m_radius)
continue;
// 两个圆心
Point2f c1, c2;
// 线段中点
Point2f center = 0.5*(m_points[i] + m_points[k]);
//bug在这里
// 方向向量 d = (x,y)
Point2f dir = m_points[i] - m_points[k];
// 垂直向量 n = (a,b) a*dir.x+b*dir.y = 0; a = -(b*dir.y/dir.x)
Point2f normal;
normal.y=1; // 因为未知数有两个,随便给y附一个值1。
if (dir.x != 0)
normal.x=-(normal.y*dir.y) / dir.x;
else // 如果方向平行于y轴
{
normal.x=1;
normal.y=0;
}
normalize(normal); // 法向量单位化
float len = sqrt(m_radius*m_radius - (0.25*(dir.x*dir.x+ dir.y*dir.y)));
c1 = center + len * normal;
c2 = center - len * normal;
cout << "第" << i << "和" << k << "个点" << endl;
cout << "圆心c1:" << c1.x << " , " << c1.y << endl;
cout << "圆心c2:" << c2.x << " , " << c2.y << endl;
//test
circle(img, c1, m_radius, Scalar(0, 0, 255), 1);
circle(img, c2, m_radius, Scalar(0, 0, 255), 1);
// b1、b2记录是否在圆C1、C2中找到其他点。
bool b1 = false, b2 = false;//false:点在圆外;true:点在圆内
for (int m = 0; m < m_points.size(); m++)
{
if (m == i || m == k)
continue;
// 如果都有内部点,不必再继续检查了
if (b1 == true || b2 == true)
break;
if (!b1 && squareDistance( m_points[m],c1) < m_radius)
b1 = true;
if (!b2 && squareDistance(m_points[m], c2) < m_radius)
b2 = true;
}
if (!b1 ||!b2)
{
Edge edge;
edge.a = m_points[i];
edge.b = m_points[k];
m_edges.push_back(edge);
}
}
}
}
int main()
{
Mat image(1000, 1000, CV_8UC3); //创建一个高200,宽100的灰度图
vector<Point2f>pts;
pts.push_back({ 400,400 });
pts.push_back({ 400,600 });
pts.push_back({ 600,400 });
pts.push_back({ 600,600 });
pts.push_back({ 450,500 });
for (int i = 0; i < pts.size(); i++)
{
circle(image, pts[i], 2, Scalar(0, 0, 255), 2);
}
AlphaShape alpha;
alpha.AlphaShapes(200, pts,image);
for (int i = 0; i < alpha.m_edges.size(); i++)
{
line(image, alpha.m_edges[i].a, alpha.m_edges[i].b, Scalar(0, 255, 0), 2);//bug,除了边缘也画出来了
cout << alpha.m_edges[i].a.x << " , " << alpha.m_edges[i].a.y << " - "<< alpha.m_edges[i].b.x << " , " << alpha.m_edges[i].b.y<<endl;
}
imshow("原图", image);
waitKey(0);
return 0;
}