Linq вместо двух циклов получает цвет пикселя и точку из изображения

#c# #linq #image-processing #pixel

#c# #linq #обработка изображений #пиксель

Вопрос:

Как я могу использовать linq для перечисления всех пикселей из изображения и обработки их? Например, мы имеем:

  for (int i = 0; i < this.bitmap.Width; i  )
            {
                for (int j = 0; j < this.bitmap.Height; j  )
                {
                    bitmap.SetPixel(x, y, Color.FromArgb(1, 1, 1));
                }
            }
  

Здесь мне не нужны пиксели списка, потому что я работаю сразу, используя циклы тем временем для циклов.
Однако я не уверен, смогу ли я обработать изображение с помощью linq подобным образом.
Я понимаю, что linq получает данные, поэтому я хотел бы взять пиксель из точки и каким-то образом сохранить координаты и данные о цвете этого пикселя. Мне это нужно, потому что как я смогу тогда установить пороговое значение?

Я пытался использовать struct, но на странице http://social.msdn.microsoft.com/Forums/is/linqtosql/thread/02154de8-ef32-4420-a3f6-e4e473df66ce они сказали, что linq не работает со структурой.

Возможно, мне следует использовать список, но когда я написал List<Point, Color> list , я получил ошибку. Так что я действительно не знаю, как это сделать..

Все дело в том, чтобы оптимизировать мою функцию под этим текстом. Я прочитал в книге под названием «эффективное программирование на c #», что использование синтаксиса запроса было бы более читабельным, чем для циклов..

Это мой код, и я действительно прошу вас о помощи, как сделать его более читаемым кодом.

ps. пожалуйста, исправьте тему, если она не указана мной, извините.

private void ThreshGrayTails() {

         this.tempBitmap = new Bitmap(this.bitmap);

        for (int i = 0; i < this.bitmap.Width; i  )
        {
            for (int j = 0; j < this.bitmap.Height; j  )
            {
                SetTempPixelInt(i, 0, j, 0, this.tempBitmap);

                if (this.tempPixelInt == 252 amp;amp; (j   2) < this.bitmap.Height amp;amp; (j - 2) > 0)
                {
                    SetTempPixelInt(i, 0, j, -1, this.bitmap);

                    //if pixel above has value 252
                    if (this.tempPixelInt == 252)
                    {
                        SetTempPixelInt(i, 0, j, -2, this.bitmap);

                        //if pixel above has value 159
                        if (this.tempPixelInt == 159)
                        {
                            SetTempPixelInt(i, 0, j,  1, this.bitmap);

                            //if pixel under has value 0 or 172
                            if (this.tempPixelInt == 0 || this.tempPixelInt == 172)
                            {
                                this.tempBitmap.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                                this.tempBitmap.SetPixel(i - 1, j, Color.FromArgb(255, 255, 255));
                                this.tempBitmap.SetPixel(i - 2, j, Color.FromArgb(255, 255, 255));
                            }
                        }
                    }

                }

                //if current pixel doesnt contain value in that list, turn it on black
                if (!colorsToThreshold.Contains(this.tempBitmap.GetPixel(i, j).R))
                {
                    Color newcolor = Color.FromArgb(0, 0, 0);
                    this.tempBitmap.SetPixel(i, j, newcolor);
                }
                //if current pixel contain value in that list, turn it on white
                else
                {
                    Color newcolor = Color.FromArgb(255, 255, 255);
                    this.tempBitmap.SetPixel(i, j, newcolor);
                }

            }

        }
        this.bitmap = new Bitmap(this.tempBitmap);
        SaveImage("thresholded.bmp", this.bitmap);
    }

    private void SetTempPixelInt(int i, int pi, int j, int pj, Bitmap bitmap)
    {
        Color currentColor = bitmap.GetPixel(i   pi, j   pj);
        this.tempPixelInt = (int)(currentColor.R);
    }
  

Комментарии:

1. Почему вы хотите использовать LINQ для этого? Похоже, что ваше текущее решение с циклами намного лучше подходит для этой задачи.

Ответ №1:

Все дело в том, чтобы оптимизировать мою функцию под этим текстом

Если вы хотите повысить производительность, лучшим решением для вас было бы использовать небезопасный код для доступа к пикселям непосредственно в памяти. Для достижения этой цели вы должны использовать метод LockBits() для Bitmap. Некоторый пример быстрой обработки изображений на c # можно найти здесь: http://www.vcskicks.com/fast-image-processing.php

LINQ на самом деле не является решением такой проблемы.

Комментарии:

1. а как насчет блокировок? итак, я должен разблокировать бит, затем работать, а когда я закончу, затем заблокировать бит?

2. Когда вы блокируете биты, вы сообщаете .net, что хотите иметь прямой доступ к памяти. это дает вам указатель (как в c ) на ваше изображение. Когда вы закончите с изображением, вызовите UnlockBits(); Все четко описано на странице по ссылке, которую я вам дал. Удачи 🙂

Ответ №2:

Я думаю, что вы смотрите в неправильном направлении, когда пытаетесь улучшить код.

Пиксели на изображении недоступны как коллекция, поэтому вы не можете использовать LINQ для них из коробки. Вам нужно было бы создать что-то, что может предоставить вам пиксели в виде коллекции, чтобы использовать их в запросе. Вы можете использовать Range метод для создания запроса, в котором вы можете получить доступ к пикселям, но это будет только медленный и сложный способ выполнения того, что вы уже делаете в своих циклах.

Статья, в которой вы прочитали, что LINQ не работает со структурами, относится к LINQ to SQL, который вы не используете. Однако использование структуры на самом деле не упростило бы использование LINQ для этого.