#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 и заставить его делать то, что вам нравится.
Подробнее об этом здесь: