В моем приложении я храню Bitmap
данные в двумерном целочисленном массиве (int[,]
). Получить доступ к R, G и B оценивает, я использую что-то вроде этого:
// read:
int i = _data[x, y];
byte B = (byte)(i >> 0);
byte G = (byte)(i >> 8);
byte R = (byte)(i >> 16);
// write:
_data[x, y] = BitConverter.ToInt32(new byte[] { B, G, R, 0 }, 0);
Я использую целочисленные массивы вместо фактического System.Drawing.Bitmap
потому что мое выполнение приложения на устройствах Windows Mobile, где память, доступная для создания битовых массивов, сильно ограничена.
Я задаюсь вопросом, тем не менее, если имело бы больше смысла объявлять структуру как это:
public struct RGB
{
public byte R;
public byte G;
public byte B;
}
... и затем используйте массив RGB
вместо массива int
. Таким образом, я мог легко считать и записать отдельный R, G и значения B, не имея необходимость делать смещение бита и BitConverter-луг. Я неопределенно помню что-то со дней былого о byte
переменные, выравниваемые блоком в 32-разрядных системах, так, чтобы a byte
на самом деле поднимает 4 байта памяти вместо всего 1 (но возможно это было просто вещью Visual Basic).
Был бы с помощью массива структур (как RGB
пример' выше), быть быстрее, чем использование массива ints, и это использовало бы 3/4 память или 3 раза память ints?
Если вы используете примерно скорость , то технически я бы ожидал int []
версия будет быстрее, так как есть специальная инструкция IL для получения int
из массива (см. OpCodes.Ldelem_I4
). Чтобы создать настраиваемую структуру, она должна получить адрес ( OpCodes.Ldelema
), а затем скопировать структуру ( OpCodes.Ldobj
) - обработать метаданные типа для обоих этих шагов.
Короче говоря, подход int
должен иметь лучшую оптимизацию.Но это микрооптимизация - в общем предпочитайте версию, которая делает ваш код более читабельным. Что вы могли бы рассмотреть, так это написать структуру с пользовательским статическим оператором неявного преобразования из int
в вашу структуру - тогда вы можете иметь int []
и по-прежнему делать :
MyColor col = intArr[12];
(он, конечно, выполнит статический вызов посередине)
Вы также можете рассмотреть возможность использования объединения , чтобы вам не нужно было много сдвигать:
ВАЖНО Я не проверял правильность порядка байтов в здравом уме; просто измените смещения R / G / B, чтобы изменить его.
class Program
{
static void Main()
{
int[] i = { -1 };
RGB rgb = i[0];
}
}
[StructLayout( LayoutKind.Explicit)]
public struct RGB
{
public RGB(int value) {
this.R = this.G = this.B = 0; this.Value = value;
}
[FieldOffset(0)]
public int Value;
[FieldOffset(2)]
public byte R;
[FieldOffset(1)]
public byte G;
[FieldOffset(0)]
public byte B;
public static implicit operator RGB(int value) {
return new RGB(value);
}
public static implicit operator int(RGB value) {
return value.Value;
}
}
Отдельный байт, вероятно, будет выровнен по блокам, но несколько байтов в структуре могут быть упакованы. Согласно Marshal.SizeOf, ваша структура RGB действительно занимает всего три байта памяти. (Технически это размер при маршалинге в неуправляемую память, и CLR может выбрать другой вариант размещения; но на практике я думаю, что это будет правильно.)
Однако CLR все еще может вставлять отступы между RGB и другими структур, и это поведение может зависеть от процессора, версии CLR и т. д. В системе x86 выделение массива из 300 миллионов RGB привело к тому, что диспетчер задач сообщил о выделении примерно 900 МБ, тогда как выделение массива из 300 миллионов int привело к выделению 1200 МБ. . Таким образом, похоже, что 2.0 CLR на x86 дает вам 25% экономии. (Должен признать, это меня удивило; как и Traveling Tech Guy, я ожидал, что 3-байтовые структуры будут выровнены по 4-байтовой границе. Так что я могу чего-то упустить.) Но CF может быть другим: вы действительно узнайте, только протестировав его на вашей целевой платформе.
Почему бы просто не использовать структуру Color
в System.Drawing
? С ним проще обращаться и ссылаться. Конечно, он имеет 4 байта (другое значение представляет Alpha), но то же самое относится и к вашей первой реализации, и, если я правильно помню, любые 3 байта в любом случае будут выровнены с 4-байтовым блоком. Взгляните на образец здесь .
Я думаю, это зависит от того, чего вы хотите добиться. Конечно, он более удобен для чтения, чем struct, и вы можете смело использовать его с
unsafe { }
что действительно ускорит доступ к Bitmap. (Если вы знаете, что делать - без проверки граничных условий и тому подобного). И, конечно, если вы хотите сделать операторы для умножения растровых изображений, маскирования, градации серого, фильтрации и т.д., то INT - ваш друг в плане скорости, но, к сожалению, не в плане читабельности. Матричный фильтр только умножает указанные инты (так можно написать), а не RGB значения независимо, но со структурой Marks это не должно быть проблемой в любом случае. Надеюсь, это поможет