Неоднозначные случаи в алгоритме Marching Square - PullRequest
2 голосов
/ 13 июля 2020
image

If we take В статье в Википедии о Маршевой площади мы видим, что случай № 5 и случай № 10 считаются неоднозначными.

Я реализовал Marching Square следующим образом, и я не понимаю, как может возникнуть неоднозначный случай:

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;
        }
    }
}
    

Здесь вы можете видеть, что каждый из случаев рассматривается индивидуально.

Вывод:

Может ли кто-нибудь сказать мне, что мне не хватает?

Программа драйвера:

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]);
            }
        } 
    }
}

Изменить: В случае следующих данных (как указано @ 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 }

моя программа выдала следующий результат:

Ответы [ 2 ]

2 голосов
/ 15 июля 2020

В вашем примере нет неоднозначных случаев. Какой результат вы ожидаете от следующего ввода:

{ 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 }

Обводит вокруг единиц? Кружки вокруг двойки? Диагональные линии?

Изменить ;

Из вашего кода;

            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;

Вы можете поменять местами эти ярлыки корпуса. Вы можете выбрать одно, удалить другое и объединить дела. Вы можете посмотреть на другие окружающие пиксели, чтобы выбрать один. Вы можете бросить случайное число, чтобы выбрать, как его нарисовать.

Но вы этого не сделали. Вы произвольно решили, что всегда будете рисовать эти гильзы таким образом.

1 голос
/ 17 июля 2020

Ой, я тебя понимаю. Удивительно, это хороший вопрос!

Неопределенность становится очевидной в тот момент, когда вы решаете, является ли «значение выше isvalue» черным или белым и противоположным для «значения ниже значение ".

Позвольте мне объяснить, что я имею в виду. Если вы выполните алгоритм вручную, вы можете получить следующие результаты. Единственный выбор, который вы делаете, следуя алгоритму, описанному в вики, - это решить, какой цвет использовать при рисовании узлов.

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

не имеет неоднозначных случаев , поэтому выбор не имеет значения - результирующее изображение будет одинаковым независимо от того, является ли «1» «черной точкой» или «белой точкой». no ambiguity

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. all cells are ambiguous

I think moment of choice is in normalize function at

 if (data[i, j] > 1)

Если вы измените «> » на « <</strong>», вы получите изменение изображения для неоднозначных случаев. И для однозначных случаев это ничего не изменит. Двусмысленность легче понять, если вы посмотрите на идею методов, а не на алгоритм. Посмотрите на седловую точку - контур рисунка неоднозначен, потому что с одной стороны седловая точка является минимумом, а с другой - максимумом - зависит от направления измерений.

Надеюсь, что это поможет чтобы устранить путаницу.

Изменить: Я уточнил в комментариях, но для наглядности я дублирую его здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...