图像边缘检测算法:创建2D网格

时间:2016-07-09 17:50:23

标签: java c# algorithm image-processing xna

让我们首先介绍一下我要做的事情。我希望能够以透明背景拍摄PNG文件,并找到沿着图像主体边缘的90到360点的任何位置。这是我的意思的一个粗略的例子。鉴于马里奥和耀西的这种形象:

Mario and Yoshi

我想制作一个以图像中心为中心的圆,其直径略大于图像的最大边,以作为参考。然后,我想以设定的间隔环绕圆圈,并向中心描绘一条直线,直到它碰到一个不透明的像素。这是什么样的:

Mario and Yoshi Traced

我试图在几个不同的时间实现这一点,所有这些都失败了,我希望得到一些关于我做错的指导或见解。这是我在代码后面使用的数学图像(对不起,如果质量不好,我没有扫描仪):

Math

第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 图像是最终输出应该是什么样的,但是有更多的点(这将为网格提供更多细节)。

0 个答案:

没有答案