Как читать только данные пикселей, а не метаданные из 16-битного изображения в C #? - PullRequest
0 голосов
/ 18 декабря 2018

У меня 16-битное изображение глубины, из которого я хочу прочитать только данные пикселей и сохранить его в байтах []

Я попробовал следующий код:

FileInfo fileInfo = new FileInfo("C:\\Image stitch API\\Temp\\output.tif");
byte[] data = new byte[fileInfo.Length];

Я также попробовал следующее:

Image img;
img = Image.FromFile("C:\\Image stitch API\\Temp\\output.tif");
ImageConverter ic = new ImageConverter();
byte[] data = (byte[])ic.ConvertTo(img, typeof(byte[]))

Здесь все данные поступают с изображения, но мне нужны только данные в пикселях?

Может ли кто-нибудь помочь в этом?

Ответы [ 2 ]

0 голосов
/ 24 декабря 2018

Самый быстрый способ получить данные изображения из изображения - это использовать LockBits и Marshal.Copy.

I настоятельно совет против использования GetPixel.Смотрите, LockBits работает, резервируя память для помещения байтов изображения и копирования туда байтов изображения.UnlockBits затем очистит эту зарезервированную память.

Теперь проблема в том, что GetPixel выполняет ту же самую операцию блокировки и разблокировки для каждого пикселя, к которому вы обращаетесь .Использование LockBits один раз довольно быстро, но использование его снова и снова для десятков тысяч пикселей действительно замедляет процесс.

Обратите внимание, что есть два способа использования LockBits;либо вы получаете данные в исходном пиксельном формате, используя sourceImage.PixelFormat, либо вы заставляете LockBits преобразовывать данные в нужный вам формат, задавая другой.В этом коде я вынуждаю вывод в формате пикселей Format32bppArgb.

/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageDataAs32bppArgb(Bitmap sourceImage)
{
    BitmapData sourceData = sourceImage.LockBits(
        new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    Byte[] data = new Byte[sourceData.Stride * sourceImage.Height];
    Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
    sourceImage.UnlockBits(sourceData);
    return data;
}

Stride обычно может отличаться от width * bpp, поскольку строки растровых изображений всегда выровнены с кратными 4 байтами, поэтому обычновам также нужно это вернуть и отследить, но, поскольку это 32-битный формат, его данные всегда выровнены до 4 байтов, поэтому здесь никакой реальной разницы нет.

Обратите внимание, в вашем вопросе никогда не указывается порядок , в котором вам нужны данные.Типичные данные ARGB на самом деле имеют порядок байтов B, G, R, A, потому что обычное целочисленное сохранение в архитектуре IBM PC имеет младший порядок, что означает, что фактические байты значения Int32 "FFEEDDCC" обращаются в памяти к [CC DDEE FF].Но ваш комментарий к другому ответу, приведенному здесь, похоже, указывает на то, что вы выбрали порядок байтов [RR, GG, BB, AA] или «ABGR», который, честно говоря, не является форматом, который я когда-либо видел до.Но если вам нужно изменить это, это просто дополнительный дополнительный цикл для замены красного и синего:

for (Int32 i = 0; i < data.Length; i += 4)
{
    Byte b = data[i]; // save Blue
    data[i] = data[i + 2]; // set first component to the Red value
    data[i + 2] = b; // set third component to the Blue value
}
0 голосов
/ 18 декабря 2018

Если вы можете загрузить свое изображение как растровое изображение, довольно просто получить информацию о пикселях, как показано ниже.

    Bitmap bitmap = new Bitmap("somefile.ext");
    Color color = bitmap.GetPixel(x,y) 

GetPixel () вернет тип Color (struct) и вы можете получить значения отдельных каналовкак показано в байте, как показано ниже.

    byte g = slateBlue.G;
    byte b = slateBlue.B;
    byte r = slateBlue.R;
    byte a = slateBlue.A;

Что касается вашего комментария, я предлагаю вам использовать Netvips для манипулирования изображением в виде байтового массива (это намного лучше и быстрее, чем system.drawing).Таким образом вы можете получить полосы изображения в виде байтовых массивов, как показано ниже.

    var imageBands = inputImage.Bandsplit();
    var R = imageBands [0];
    var B = imageBands [1];
    var G = imageBands [2];

Если вы не хотите переключать библиотеки, вы можете получить байтовый массив с System.Drawing, как показано ниже.

byte[] image = new[] {R, B, G};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...