让我们首先介绍一下我要做的事情。我希望能够以透明背景拍摄PNG文件,并找到沿着图像主体边缘的90到360点的任何位置。这是我的意思的一个粗略的例子。鉴于马里奥和耀西的这种形象:
我想制作一个以图像中心为中心的圆,其直径略大于图像的最大边,以作为参考。然后,我想以设定的间隔环绕圆圈,并向中心描绘一条直线,直到它碰到一个不透明的像素。这是什么样的:
我试图在几个不同的时间实现这一点,所有这些都失败了,我希望得到一些关于我做错的指导或见解。这是我在代码后面使用的数学图像(对不起,如果质量不好,我没有扫描仪):
第1行是图像的上边,下边,左边或右边,第2行以给定角度穿过圆的中心。第1行和第2行相交的点应位于图像的边缘,这是我们应该开始寻找图像主体边缘的位置。
以下是我从这个想法中得出的代码。我是用Java编写的,因为BufferedImage非常易于使用,但我将把它翻译成C#(XNA)以获得最终产品。
public class Mesh {
private int angleA, angleB, angleC, angleD;
private BufferedImage image;
private Point center;
public ArrayList<Point> points = new ArrayList<>();
public Mesh(BufferedImage image) {
center = new Point(image.getWidth() / 2, image.getHeight() / 2);
angleA = (int) (Math.atan(center.y / center.x) * (180 / Math.PI));
angleB = 180 - angleA;
angleC = 180 + angleA;
angleD = 360 - angleA;
this.image = image;
for(int angle = 0; angle <= 360; angle+=4){
Point point = getNext(angle);
if(point != null) points.add(point);
}
}
private Point getNext(int angle) {
double radians = angle * Math.PI / 180;
double xStep = Math.cos(radians);
double yStep = Math.sin(radians);
int addX = angle >= 90 && angle <= 270 ? 1 : -1;
int addY = angle >= 0 && angle <= 180 ? 1 : -1;
double x, y;
if (xStep != 0) {
double slope = yStep / xStep;
double intercept = center.y - (slope * center.x);
if (angle >= angleA && angle <= angleB) {
y = 0;
x = -intercept / slope;
} else if (angle > angleB && angle < angleC) {
x = 0;
y = intercept;
} else if (angle >= angleC && angle <= angleD) {
y = image.getHeight() - 1;
x = (y - intercept) / slope;
} else {
x = image.getWidth() - 1;
y = slope * x + intercept;
}
} else {
x = center.x;
y = angle <= angleB ? 0 : image.getHeight();
}
if (x < 0) x = 0;
if (x > image.getWidth() - 1) x = image.getWidth() - 1;
if (y < 0) y = 0;
if (y > image.getHeight() - 1) y = image.getHeight() - 1;
double distance = Math.sqrt(Math.pow(x - center.x, 2) + Math.pow(y - center.y, 2));
double stepSize = Math.sqrt(Math.pow(xStep, 2) + Math.pow(yStep, 2));
int totalSteps = (int) Math.floor(distance / stepSize);
for (int step = 0; step < totalSteps; step++) {
int xVal = (int) x;
int yVal = (int) y;
if(xVal < 0) xVal = 0;
if(xVal > image.getWidth() -1) xVal = image.getWidth() -1;
if(yVal < 0) yVal = 0;
if(yVal > image.getHeight()-1) yVal = image.getHeight() -1;
int pixel = image.getRGB(xVal, yVal);
if ((pixel >> 24) == 0x00) {
x += (Math.abs(xStep) * addX);
y += (Math.abs(yStep) * addY);
} else {
return new Point(xVal, yVal);
}
}
return null;
}
}
该算法应该返回所有以逆时针方向旋转(并且不重叠)排序的正点,但是我未能得到所需的输出(这是我最近的尝试)所以只是为了重述问题,是否存在这样做的正式方式,或者有人能找到我在逻辑中犯的错误。对于视觉参考, Mario和Yoshi Traced 图像是最终输出应该是什么样的,但是有更多的点(这将为网格提供更多细节)。