C # RGB [,] к картинке - PullRequest
       10

C # RGB [,] к картинке

0 голосов
/ 26 апреля 2018

У меня есть данные, которые являются (2448 * 2048) 5-мегапиксельными данными изображения, но картинка-бокс имеет только (816 * 683) около 500 000 пикселей, поэтому я уменьшил пиксели, и мне нужно только черно-белое изображение, поэтому я использовалзначение G для создания изображения, но выводимое мной изображение показано на следующем рисунке.Какая часть моей ошибки?

 public int[,] lowered(int[,] greenar)
    {
        int[,] Sy = new int[816, 683];
        int x = 0;
        int y = 0;
        for (int i = 1; i < 2448; i += 3)
        {
            for (int j = 1; j < 2048; j += 3)
            {
                Sy[x, y] = greenar[i, j];
                y++;
            }
            y = 0;
            x++;
        }
        return Sy;
    }


static Bitmap Create(int[,] R, int[,] G, int[,] B)
    {
        int iWidth = G.GetLength(1);
        int iHeight = G.GetLength(0);
        Bitmap Result = new Bitmap(iWidth, iHeight,
        System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        Rectangle rect = new Rectangle(0, 0, iWidth, iHeight);
        System.Drawing.Imaging.BitmapData bmpData = Result.LockBits(rect,
        System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
        IntPtr iPtr = bmpData.Scan0;
        int iStride = bmpData.Stride;
        int iBytes = iWidth * iHeight * 3;
        byte[] PixelValues = new byte[iBytes];
        int iPoint = 0;
        for (int i = 0; i < iHeight; i++)
        {
            for (int j = 0; j < iWidth; j++)
            {
                int iG = G[i, j];
                int iB = G[i, j];
                int iR = G[i, j];
                PixelValues[iPoint] = Convert.ToByte(iB);
                PixelValues[iPoint + 1] = Convert.ToByte(iG);
                PixelValues[iPoint + 2] = Convert.ToByte(iR);
                iPoint += 3;
            }
        }
        System.Runtime.InteropServices.Marshal.Copy(PixelValues, 0, iPtr, iBytes);
        Result.UnlockBits(bmpData);
        return Result;

    }

https://upload.cc/i1/2018/04/26/WHOXTJ.png

Ответы [ 2 ]

0 голосов
/ 28 апреля 2018

Вы, кажется, постоянно смешиваете свои смещения x и y, чего легко избежать, просто фактически вызывая переменные вашего цикла x и y всякий раз, когда вы просматриваете данные изображения. Кроме того, данные изображения обычно сохраняются построчно, поэтому ваш внешний цикл должен быть Y-циклом, проходящим по высоте, а внутренний цикл должен обрабатывать координаты X в одной строке и, следовательно, должен проходить по всей ширине.

Кроме того, я не уверен, откуда берутся ваши исходные данные, но в большинстве случаев, которые я видел, когда данные изображения находятся в многомерных массивах, подобных этому, Y на самом деле first Индекс в массиве. Ваша фактическая функция построения изображения также предполагает это, поскольку она использует G.GetLength(0) для получения высоты изображения. Но функция изменения размера вашего канала не делает; он создает многомерный массив как new int[816, 683], который будет изображением 683 * 816, а не 816 * 683, как вы сказали. Так что это, конечно, кажется неправильным.

Поскольку вы подтвердили, что это [x, y], я адаптировал это решение, чтобы использовать его таким образом.

Кроме того, вы жестко закодировали множество значений в своих функциях, что является очень плохой практикой. Если вы знаете, что уменьшите изображение до 1/3, взяв только один из трех пикселей, просто укажите это 3 в качестве параметра.

Код сокращения:

public static Int32[,] ResizeChannel(Int32[,] origChannel, Int32 lossfactor)
{
    Int32 newWidth = origChannel.GetLength(0) / lossfactor;
    Int32 newHeight = origChannel.GetLength(1) / lossfactor;
    // to avoid rounding errors
    Int32 origHeight = newHeight * lossfactor;
    Int32 origWidth = newWidth *lossfactor;
    Int32[,] newChannel = new Int32[newWidth, newHeight];
    Int32 newX = 0;
    Int32 newY = 0;
    for (Int32 y = 1; y < origHeight; y += lossfactor)
    {
        newX = 0;
        for (Int32 x = 1; x < origWidth; x += lossfactor)
        {
            newChannel[newX, newY] = origChannel[x, y];
            newX++;
        }
        newY++;
    }
    return newChannel;
}

Фактический код сборки, отмеченный GSerg в комментариях, неверен, поскольку вы не учитываете stride. stride - это фактическая длина байта каждой строки пикселей, и это не просто width * BytesPerPixel, поскольку округляется до следующего кратного 4 байт .

Таким образом, вам нужно инициализировать массив как height * stride, а не height * width * 3, и вам нужно пропускать смещение записи до следующего кратного stride всякий раз, когда вы переходите к нижней строке Y, вместо того, чтобы предполагать он просто попадет туда автоматически, потому что ваша X-обработка добавляет 3 для каждого пикселя. Поскольку он не попадет туда автоматически , если только по стечению обстоятельств ширина вашего изображения окажется кратной 4 пикселям.

Кроме того, если вы используете для этого только один канал, нет оснований указывать ему все три канала. Просто дайте один.

public static Bitmap CreateGreyImage(Int32[,] greyChannel)
{
    Int32 width = greyChannel.GetLength(0);
    Int32 height = greyChannel.GetLength(1);
    Bitmap result = new Bitmap(width, height, PixelFormat.Format24bppRgb);
    Rectangle rect = new Rectangle(0, 0, width, height);
    BitmapData bmpData = result.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    Int32 stride = bmpData.Stride;
    // stride is the actual line width in bytes.
    Int32 bytes = stride * height;
    Byte[] pixelValues = new Byte[bytes];
    Int32 offset = 0;
    for (Int32 y = 0; y < height; y++)
    {
        Int32 workOffset = offset;
        for (Int32 x = 0; x < width; x++)
        {
            pixelValues[workOffset + 0] = (Byte)greyChannel[x, y];
            pixelValues[workOffset + 1] = (Byte)greyChannel[x, y];
            pixelValues[workOffset + 2] = (Byte)greyChannel[x, y];
            workOffset += 3;
        }
        // Add stride to get the start offset of the next line
        offset += stride;
    }
    Marshal.Copy(pixelValues, 0, bmpData.Scan0, bytes);
    result.UnlockBits(bmpData);
    return result;
}

Теперь это работает, как и ожидалось , если ваши каналы R, G и B действительно идентичны , но если это не так, вы должны понимать, что есть разница между уменьшением изображения до оттенков серого и простым построением серое изображение из зеленого канала. На цветном изображении вы получите совершенно другие результаты, если вместо этого выберете синий или красный канал.

Это код, который я выполнил для этого:

Int32[,] greyar = ResizeChannel(greenar, 3);
Bitmap newbm = CreateGreyImage(greyar);
0 голосов
/ 26 апреля 2018

Вам не нужно сокращать изображение, вы можете сделать это таким образом. Установите свойство backgroundbox BackgroundImageLayout в качестве увеличения или растяжения и назначьте его следующим образом:

picturebox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
picturebox.BackgroundImage = bitmap;

System.Windows.Forms.ImageLayout.Zoom автоматически настроит ваше растровое изображение в соответствии с размером изображения.

...