按照绕线画算法这篇博客给出的思路:
我也来尝试一下。
数据结构
struct Point2 {
int x, y;
bool operator< (const Point2 b) const
{
if (x == b.x)return y < b.y;
return x < b.x;
}
};
struct PointPair {
Point2 p1, p2;
PointPair(Point2 a, Point2 b)
{
if (a < b)p1 = a, p2 = b;
else p1 = b, p2 = a;
}
bool operator< (const PointPair b)const
{
if (p1 < b.p1)return true;
if (b.p1 < p1)return false;
return p2 < b.p2;
}
};
算法
Mat imgMask;
double meanPix(Mat& img, Point2 a, Point2 b)
{
int len = max(abs(a.x - b.x), abs(a.y - b.y));
double dx = (a.x - b.x) * 1.0 / len;
double dy = (a.y - b.y) * 1.0 / len;
double x = b.x, y = b.y;
int s = 0;
for (int i = 1; i < len; i++) {
x += dx, y += dy;
s += int(img.at<unsigned char>(int(x), int(y))* imgMask.at<unsigned char>(int(x), int(y)));
}
return s * 1.0 / len;
}
void subPix(Mat& img, Point2 a, Point2 b, int d)
{
int len = max(abs(a.x - b.x), abs(a.y - b.y));
double dx = (a.x - b.x) * 1.0 / len;
double dy = (a.y - b.y) * 1.0 / len;
double x = b.x, y = b.y;
int s = 0;
for (int i = 1; i < len; i++) {
x += dx, y += dy;
int pix = img.at<unsigned char>(int(x), int(y));
img.at<unsigned char>(int(x), int(y)) = max(0, pix - d);
}
}
void setPix(Mat& img, Point2 a, Point2 b, int d)
{
int len = max(abs(a.x - b.x), abs(a.y - b.y));
double dx = (a.x - b.x) * 1.0 / len;
double dy = (a.y - b.y) * 1.0 / len;
double x = b.x, y = b.y;
int s = 0;
for (int i = 1; i < len; i++) {
x += dx, y += dy;
img.at<unsigned char>(int(x), int(y)) = d;
}
}
int main()
{
const int n = 600;
int lineNum = 800;
Mat img = imread("D:/im.jpg", 0);
resize(img, img, Size(n + 1, n+ 1));
Mat src;
img = 255 - img;
imshow("img", img);
imgMask = img.clone();
blur(imgMask, imgMask, Size(19, 19));
//imshow("img2", imgMask);
vector<Point2>vp;
for (int i = 0; i < 360; i++) {
double r = i * 3.1415926 / 180;
vp.push_back({ int(n / 2 * sin(r)) + 300, int(n / 2 * cos(r)) + 300 });
}
Point2 p = vp[0];
map< Line, int>m;
for (auto& pi : vp)m[Line(pi, pi)] = 1;
Mat ans = img.clone();
ans = 255;
while (lineNum--) {
Point2 next = p;
double s0 = 0;
for (auto& pi : vp) {
if (m[Line(p, pi)])continue;
double s = meanPix(img, p, pi);
if (s0 < s)s0 = s, next = pi;
}
subPix(img, p, next, 100);
setPix(ans, p, next, 100);
m[Line(p, next)] = 1;
p = next;
}
//imshow("img3", img);
imshow("ans", ans);
waitKey(0);
return 0;
}
结果:
原图:
远处对比:
和某bao上的效果对比,还是有很大差距的。
我想了一下,上面的算法思路虽然简单,但是有效性确实有限。
比如这种情况:
要想一笔画,每一条弦都有用,就很难。
实际上应该运行一部分弦是没用的,这样就能得到这种解:
右边的2条弦没有命中目标,但是很有必要。
所以个人感觉某bao上的AI算法,应该是类似于分割算法,分割成若干直线。