Создание массива указателей в C#

#c# #arrays #pointers

#c# #массивы #указатели

Вопрос:

Я работаю с некоторым кодом обработки изображений на C #. Поскольку производительность имеет решающее значение, я делаю это в небезопасном коде с указателями.

Вот некоторый код, предваряющий мой вопрос:

 Rectangle Image_Rectangle = new Rectangle(0, 0, MyImage.Width, MyImage.Height);
BitmapData Image_Data = MyImage.LockBits(Image_Rectangle, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
// ... x and y nested for-loops to work with each pixel
Byte* PixelRow = (Byte*)Image_Data.Scan0   (y * Image_Data.Stride);
  

Как только у меня будет указанный выше байтовый указатель, я могу установить его значения следующим образом:

 PixelRow[(x * 3)   2] = 255;
PixelRow[(x * 3)   1] = 255;
PixelRow[(x * 3)] = 255;
  

Однако я бы предпочел получить к ним доступ в виде массива:

 Byte[] RGB = { PixelRow[(x * PIXEL_SIZE)   2], PixelRow[(x * PIXEL_SIZE)   1], PixelRow[(x * PIXEL_SIZE)   0] };

RGB[0] = 255;
RGB[1] = 255;
RGB[2] = 255;
  

Проблема в том, что когда я пытаюсь присвоить значение, я чувствую, что больше не работаю с фактическим указателем. Как только я разблокирую биты, результирующее растровое изображение остается неизменным (при использовании метода array).

Я довольно новичок в указателях, кто-нибудь может помочь объяснить, что происходит и как правильно поддерживать указатели с помощью массива?

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

1. Вы уверены, что не изобретаете велосипед заново?

2. Я не работал с указателями в C #, но я подозреваю, что вы столкнулись с проблемой при сопоставлении указателя с указанным значением. Первый способ доступа, вероятно, работает, потому что он вычисляет адрес памяти и затем устанавливает значение 255 в этом местоположении. Во втором стиле, я полагаю, это разыменование указателя и сохранение значения в новом массиве байтов. Итак, когда вы устанавливаете значение, вы присваиваете ему сохраненную копию в стеке, а не фактическую память в куче, которую вы хотели изменить.

Ответ №1:

 Byte[] RGB = { PixelRow[(x * PIXEL_SIZE)   2], 
               PixelRow[(x * PIXEL_SIZE)   1], 
               PixelRow[(x * PIXEL_SIZE)   0] };
  

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

Ответ №2:

Думаю, вы не можете оставлять код в комментариях 🙂 Попробуйте что-то вроде

  Byte*[] RGB = { amp;PixelRow[(x * PIXEL_SIZE)   2], 
                 amp;PixelRow[(x * PIXEL_SIZE)   1], 
                 amp;PixelRow[(x * PIXEL_SIZE)   0] };
  

—4/29 Редактировать

Другой подход, который вы могли бы попробовать, — это получить указатель на индекс массива, с которого начинается интересующий вас пиксель. Затем используйте это с обозначением массива, чтобы получить доступ к значениям красного, зеленого и синего байтов, которые вас интересуют, и изменить их. Теперь предполагается, что ваши пиксели хранятся в массиве в последовательном порядке, но вы могли бы сделать это следующим образом:

 Byte* RGB = amp;PixelRow[x * PIXEL_SIZE];
RGB[0] = (byte)255;
RGB[1] = (byte)255;
RGB[2] = (byte)255;
  

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

1. К сожалению, это не сработало, попытка присвоить подобное значение RGB[0] = 255; приводит к ошибке (не удается преобразовать int в byte *).

2. Вероятно, вам придется разыменовать указатель в массиве, чтобы установить значение. Попробуйте выполнить: *RGB[0] = (байт)255;

3. @JYelton где ты смог заставить это работать? Я провел несколько тестов в LINQPad, и оба моих подхода сработали для меня.

4. Я думаю, что я только что сделал это без массива, мне придется вернуться к вашим предложениям, если я снова буду работать над этой частью проекта. Спасибо!

Ответ №3:

Вы можете переопределить оператор index и заставить его делать то, что вам нравится.

Подробнее об этом здесь:

http://social.msdn.microsoft.com/Forums/en-US/csharplanguage/thread/9bec45ef-b471-4dda-92b0-e6c99e82c356/