Ambiguous cases in Marching square algorithm

梦想与她 提交于 2020-08-08 07:09:12

问题


If we take Wikipedia article on Marching square into account, we see that case#5 and case#10 are said to be ambiguous cases.

I have implemented Marching Square as follows and I am not understanding how an ambiguous case can arise:

public class LinesRectangle
{
    public Graphics Graphics { get; set; }
    public Color Color { get; set; }
    public Pen Pen { get; set; }
    public int Thickness { get; set; }

    public LinesRectangle()
    {
        Color = Color.Blue;
        Thickness = 2;
        Pen = new Pen(Color, Thickness);
    }

    public void DrawLines(int x, int y, int width, int code)
    {
        int height = width;

        Graphics.DrawRectangle(Pen, new System.Drawing.Rectangle(x, y, width, height));

        int x1 = 0, y1 = 0;
        int x2 = 0, y2 = 0;

        switch (code)
        {
            case 0:
            case 15:
                break;
            case 1:
            case 14:
                x1 = x; y1 = y + height/2;
                x2 = x + width/2; y2 = y + height;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 2:
            case 13:
                x1 = x + width/2; y1 = y + height;
                x2 = x + width; y2 = y + height/2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 3:
            case 12:
                x1 = x; y1 = y + height / 2;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 4:
            case 11:
                x1 = x+width/2; y1 = y;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 5:
                x1 = x ; y1 = y + height/2;
                x2 = x + width/2; y2 = y;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                x1 = x + width / 2; y1 = y + height;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 6:
            case 9:
                x1 = x + width / 2; y1 = y;
                x2 = x + width/2; y2 = y + height;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 7:
            case 8:
                x1 = x; y1 = y + height / 2;
                x2 = x + width / 2; y2 = y;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 10:
                x1 = x + width / 2; y1 = y;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                x1 = x; y1 = y + height / 2;
                x2 = x + width / 2; y2 = y + height;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
        }
    }
}
    

You can see here each of the cases are taken care of individually.

Output:

Can anyone tell me what I am missing?


Driver Program:

public enum What
{
    lines, surface, both
}

public partial class DrawingForm : System.Windows.Forms.Form
{
    public int [,] Data { get; set; }

    public void Print(int[,] data, int xn, int yn)
    {
        for (int j = 0; j < yn; j++)
        {
            for (int i = 0; i < xn; i++)
            {
                Console.Write(data[i, j] + ", ");
            }
            Console.WriteLine();
        }
    }
    public int[,] normalize(int[,] data, int xn, int yn)
    {

        for (int j = 0; j < yn; j++)
        {
            for (int i = 0; i < xn; i++)
            {
                if (data[i, j] > 1)
                {
                    data[i, j] = 0;
                }
                else
                {
                    data[i, j] = 1;
                }
            }
        }

        return data;
    }

    public int[,] marching_square(int x, int y, int[,] data, int isovalue, What what)
    {
        int xn = x;
        int yn = y;

        data = normalize(data, xn, yn);

        int[,] bitMask = new int[xn - 1, yn - 1];

        for (int j = 0; j < yn - 1; j++)
        {
            for (int i = 0; i < xn - 1; i++)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append(data[i, j]);
                sb.Append(data[i + 1, j]);
                sb.Append(data[i + 1, j + 1]);
                sb.Append(data[i, j + 1]);

                bitMask[i, j] = Convert.ToInt32(sb.ToString(), 2);
            }
        }

        return bitMask;
    }

    public DrawingForm()
    {
        InitializeComponent();
    }

    private void MainForm_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
    {
        int[,] data = new int[,] {
                                  { 1,1,1,1,1 },
                                  { 1,2,3,2,1 },
                                  { 1,3,1,3,1 },
                                  { 1,2,3,2,1 },
                                  { 1,1,1,1,1 }
                                  };

        int[,] bitMask = marching_square(5, 5, data, 0, What.lines);

        Graphics g = this.CreateGraphics();

        LinesRectangle rect = new LinesRectangle();
        rect.Graphics = g;
        
        for (int j = 0; j < 4; j++)
        {
            for (int i = 0; i < 4; i++)
            {
                rect.DrawLines(i*50, j*50, 50, bitMask[i,j]);
            }
        } 
    }
}

Edit: In case of the following data (as pointed out by @JeremyLakeman):

{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 }

my program produced the following output:


回答1:


Oh man, I understand you. Surprisingly thats a good question!

Ambiguity is seen clearly in a moment when you decide if "value above the isovalue" is black or white and opposite for the "value below the isovalue".

Let me explain what I mean. If you do algorithm by hand you can get following results. The only choice you do while following algorithm described on wiki - is to decide what color to use when painting nodes.

{ 1, 1, 1 },
{ 1, 2, 1 },
{ 1, 1, 1 }

has no ambiguous cases so the choice does not matter - resulting image will be the same no matter if '1' is a "black dot" or a "white dot".

BUT lets see example with ambiguous cases:

{ 1, 2, 1 },
{ 2, 1, 2 },
{ 1, 2, 1 }

algorith would provide a circle around the middle point if '1's are white, and same algorithm would provide 4 arcs near the middle points if '1's are chosen to be black.

I think moment of choice is in normalize function at

 if (data[i, j] > 1)

If you change ">" to "<" you will get change of image for ambigous cases. And it would change nothing for non-ambigous cases. Ambiguity is easier to understand if you look at methods idea not algorithm. Look at saddle point - there is ambiguity in drawing contour because from the one hand saddle point is a minimum and from the other its a maximum - depends on direction of measurements.

Hope that helps to clear the confusion.

Edit: I elaborated in comments but for visibility I'm duplicating it here




回答2:


Your example doesn't include any ambiguous cases. What output would you expect with the following input;

{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 },
{ 1,2,1,2,1 },
{ 2,1,2,1,2 }

Circles around the 1's? Circles around the 2's? Diagonal lines?

Edit;

From your code;

            case 5:
                x1 = x ; y1 = y + height/2;
                x2 = x + width/2; y2 = y;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                x1 = x + width / 2; y1 = y + height;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;
            case 10:
                x1 = x + width / 2; y1 = y;
                x2 = x + width; y2 = y + height / 2;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                x1 = x; y1 = y + height / 2;
                x2 = x + width / 2; y2 = y + height;
                Graphics.DrawLine(Pen, x1, y1, x2, y2);
                break;

You could swap those case labels. You could pick one, delete the other, and merge the cases. You could look at more surrounding pixels to pick one. You could roll a random number to pick which way to draw it.

But you didn't. You arbitrarily decided that you would always draw those cases this way.



来源:https://stackoverflow.com/questions/62868990/ambiguous-cases-in-marching-square-algorithm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!