Нахождение определенных пиксельных цветов BitmapImage

Если под мобильным устройством вы понимаете сенсорное, то вы можете определить его, проверив наличие сенсорных обработчиков:

let deviceType = (('ontouchstart' in window)
                 || (navigator.maxTouchPoints > 0)
                 || (navigator.msMaxTouchPoints > 0)
                 ) ? 'touchable' : 'desktop';

jQuery для него не нужен.

42
задан Drew Noakes 18 October 2012 в 11:48
поделиться

3 ответа

Интерпретация результирующего массива байтов зависит от формата пикселей исходного растрового изображения, но в простейшем случае 32-битного изображения ARGB каждый пиксель будет состоять из четырех байтов в массиве байтов. Первый пиксель будет интерпретироваться следующим образом:

alpha = pixelByteArray[0];
red   = pixelByteArray[1];
green = pixelByteArray[2];
blue  = pixelByteArray[3];

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

Некоторые типы растровых изображений объединяют несколько пикселей в один байт. Например, монохромное изображение содержит восемь пикселей в каждом байте. Если вам нужно иметь дело с изображениями, отличными от 24/32 бит на пиксель (простыми), то я бы посоветовал найти хорошую книгу, которая описывает базовую двоичную структуру растровых изображений.

14
ответ дан 26 November 2019 в 23:33
поделиться

Вот как я мог бы манипулировать пикселями в C #, используя многомерные массивы:

[StructLayout(LayoutKind.Sequential)]
public struct PixelColor
{
  public byte Blue;
  public byte Green;
  public byte Red;
  public byte Alpha;
}

public PixelColor[,] GetPixels(BitmapSource source)
{
  if(source.Format!=PixelFormats.Bgra32)
    source = new FormatConvertedBitmap(source, PixelFormats.Bgra32, null, 0);

  int width = source.PixelWidth;
  int height = source.PixelHeight;
  PixelColor[,] result = new PixelColor[width, height];

  source.CopyPixels(result, width * 4, 0);
  return result;
}

использование:

var pixels = GetPixels(image);
if(pixels[7, 3].Red > 4)
  ...

Если вы хотите обновить пиксели, работает очень похожий код, за исключением того, что вы создаете WritableBitmap и используете его:

public void PutPixels(WritableBitmap bitmap, PixelColor[,] pixels, int x, int y)
{
  int width = pixels.GetLength(0);
  int height = pixels.GetLength(1);
  bitmap.WritePixels(new Int32Rect(0, 0, width, height), pixels, width*4, x, y);
}

таким образом:

var pixels = new PixelColor[4, 3];
pixel[2,2] = new PixelColor { Red=128, Blue=0, Green=255, Alpha=255 };

PutPixels(bitmap, pixels, 7, 7);

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

Обновление

Поскольку BitmapSource.CopyPixels не работает. Не принимайте двумерный массив, необходимо преобразовать массив между одномерным и двумерным. Следующий метод расширения должен помочь:

public static class BitmapSourceHelper
{
#if UNSAFE
  public unsafe static void CopyPixels(this BitmapSource source, PixelColor[,] pixels, int stride, int offset)
  {
    fixed(PixelColor* buffer = &pixels[0, 0])
      source.CopyPixels(
        new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight),
        (IntPtr)(buffer + offset),
        pixels.GetLength(0) * pixels.GetLength(1) * sizeof(PixelColor),
        stride);
  }
#else
  public static void CopyPixels(this BitmapSource source, PixelColor[,] pixels, int stride, int offset)
  {
    var height = source.PixelHeight;
    var width = source.PixelWidth;
    var pixelBytes = new byte[height * width * 4];
    source.CopyPixels(pixelBytes, stride, 0);
    int y0 = offset / width;
    int x0 = offset - width * y0;
    for(int y=0; y<height; y++)
      for(int x=0; x<width; x++)
        pixels[x+x0, y+y0] = new PixelColor
        {
          Blue  = pixelBytes[(y*width + x) * 4 + 0],
          Green = pixelBytes[(y*width + x) * 4 + 1],
          Red   = pixelBytes[(y*width + x) * 4 + 2],
          Alpha = pixelBytes[(y*width + x) * 4 + 3],
        };
  }
#endif
}

Здесь есть две реализации: Первая быстрая, но использует небезопасный код для получения IntPtr в массив (должен компилироваться с параметром / unsafe). Второй - медленнее, но не требует небезопасного кода.

56
ответ дан 26 November 2019 в 23:33
поделиться

Я хотел бы добавить к ответу Рэя, что вы также можете объявить структуру PixelColor как объединение:

[StructLayout(LayoutKind.Explicit)]
public struct PixelColor
{
    // 32 bit BGRA 
    [FieldOffset(0)] public UInt32 ColorBGRA;
    // 8 bit components
    [FieldOffset(0)] public byte Blue;
    [FieldOffset(1)] public byte Green;
    [FieldOffset(2)] public byte Red;
    [FieldOffset(3)] public byte Alpha;
}

И таким образом вы также имеют доступ к UInit32 BGRA (для быстрого доступа к пикселям или копирования), помимо отдельных байтовых компонентов.

17
ответ дан 26 November 2019 в 23:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: