Как массив байтов (1 байт на пиксель (изображение в оттенках серого) запихнуть в Bitmap и отобразить в PicterBox? - C#
Формулировка задачи:
Bitmap
, я так понял, нет такой возможности? В нем только один конструктор принимающий указатель на начало массива байтов, и в этом же конструкторе имеется перечисление PixelFormat, который максимум что принимает подходящие в моем случае, это Format16bppGrayScale и Format8bppIndexed, последний указывает, что массив байтов - индексы на цвета (может можно как-нибудь сделать из этого, что-нибудь подходящие?).//Вспомогательная структура
struct Pixel
{
public byte R { get; set; }
public byte G { get; set; }
public byte B { get; set; }
public byte A { get; set; }
public Pixel(byte Red, byte Green, byte Blue, byte Alpha) : this()
{
R = Red;
G = Green;
B = Blue;
A = Alpha;
}
}//Вспомогательные методы для 24бит на пиксель
private Pixel GetPixelRGB(int x, int y)
{
Pixel pixel = new Pixel();
int i = ImageData.Stride * y + x * 3;
pixel.R = RGB[i++];
pixel.G = RGB[i++];
pixel.B = RGB[i];
return pixel;
}
private void SetPixelRGB(int x, int y, Pixel pixel)
{
int i = ImageData.Stride * y + x * 3;
RGB[i++] = pixel.R;
RGB[i++] = pixel.G;
RGB[i] = pixel.B;
}// Конвертация изображения в изображение в оттенках серого (Проблема в том,что приходится хранить на каждый //пиксель три одинаковых величины R=G=B=GREY, а хотелось бы одну GREY)
// Взятие массива байтов изображения
Bitmap image = new Bitmap(FileName);
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
ImageData = image.LockBits(rect, ImageLockMode.ReadWrite, image.PixelFormat);
IntPtr Ptr = ImageData.Scan0;
int Bytes = ImageData.Stride * image.Height;
RGB = new byte[Bytes];
System.Runtime.InteropServices.Marshal.Copy(Ptr, RGB, 0, Bytes);
// Создание изображения на основе массива трех компонент R = G = B = Градации серого.
Y = new byte[image.Height * ImageData.Stride]; // Массив той же размерности, что и RGB
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
Pixel pixel = GetPixelRGB(j, i);
byte Grey = (byte)((pixel.R + pixel.G + pixel.B) / 3);
pixel.R = Grey;
pixel.G = Grey;
pixel.B = Grey;
SetPixelRGB(j,i,pixel);
}
}
System.Runtime.InteropServices.Marshal.Copy(RGB, 0, Ptr, Bytes);
image.UnlockBits(ImageData);//Попытка конвертировать изображение в изображение в оттенках серого при помощи нового объекта Bitmap с //указанием нового формата изображения PixelFormat.Format8bppIndexed (Фотка рисуется, но разноцветная, т.к. //Bitmap в данном формате выходит массивом индексов цветов, хотелось бы, чтобы эти индексы представляли //как-нибудь значения серого...)
Bitmap image = new Bitmap(FileName);
Rectangle rect = new Rectangle(0, 0, image.Width, image.Height);
ImageData = image.LockBits(rect, ImageLockMode.ReadWrite, image.PixelFormat);
IntPtr Ptr = ImageData.Scan0;
int Bytes = ImageData.Stride * image.Height;
RGB = new byte[Bytes];
System.Runtime.InteropServices.Marshal.Copy(Ptr, RGB, 0, Bytes);
System.Runtime.InteropServices.Marshal.Copy(RGB, 0, Ptr, Bytes);
image.UnlockBits(ImageData);
Y = new byte[image.Height * image.Width];
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
Pixel pixel = GetPixelRGB(j, i);
byte Grey = (byte)((pixel.R + pixel.G + pixel.B) / 3);
int index = image.Width * i+ j;
Y[index] = Grey;
}
}
//Пришлось и новое пустое изображение загружать/выгружать, т.к. не понял, как устранить ошибку: "Попытка //чтения или записи в защищенную память. Это часто свидетельствует о том, что другая память повреждена."
//при использовании одной лишь строки для создания Bitmap:
//b = new Bitmap(image.Width, image.Height, stride, PixelFormat.Format8bppIndexed, (IntPtr)Y[0]); Как это устранить?
//Без загрузки/разгрузки как показанно ниже?
int stride = image.Width;
b = new Bitmap(image.Width,image.Height,PixelFormat.Format8bppIndexed);
Rectangle r = new Rectangle(0, 0, image.Width, image.Height);
System.Drawing.Imaging.BitmapData imageData = b.LockBits(r, ImageLockMode.ReadWrite, b.PixelFormat);
IntPtr ptr = imageData.Scan0;
int bytes = b.Width * b.Height;
System.Runtime.InteropServices.Marshal.Copy(Y, 0, ptr, bytes);
b.UnlockBits(imageData);//Попытка конвертировать изображение в изображение в оттенках серого при помощи объекта Graphics (Проблема в том, что непонятно как нарисованное на picterBox или еще где-нибудь сохранить как изображение куда-нибудь)
Graphics p = pictureBox1.CreateGraphics();
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
Pixel pixel = GetPixelRGB(j, i);
byte Grey = (byte)((pixel.R + pixel.G + pixel.B) / 3); // не точная формула, но сойдет.
p.DrawLine(new Pen(Color.FromArgb(Grey,Grey,Grey)),new Point(j,i),new Point(j + 1,i + 1));
}
}//Попытка конвертировать изображение в изображение в оттенках серого при помощи нового объекта Bitmap с //указанием нового формата изображения Format16bppGrayScale (вообще не рисуется)
1. Y массив byte
Y = new byte[image.Height * image.Width * 2];
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
Pixel pixel = GetPixelRGB(j, i);
byte Grey = (byte)((pixel.R + pixel.G + pixel.B) / 3);
int index = image.Width * i+ j *2;
Y[index] = Grey;
Y[index] = 0;
}
}
int stride = image.Width * 2;
b = new Bitmap(image.Width, image.Height, PixelFormat.Format16bppGrayScale);
//...2. Y массив unshort
Y = new unshort[image.Height * image.Width];
for (int i = 0; i < image.Height; i++)
{
for (int j = 0; j < image.Width; j++)
{
Pixel pixel = GetPixelRGB(j, i);
unshort Grey = (pixel.R + pixel.G + pixel.B) / 3;
int index = image.Width * i+ j;
Y[index] = Grey;
}
}
int stride = image.Width * 2;
b = new Bitmap(image.Width, image.Height, PixelFormat.Format16bppGrayScale);
//...Решение задачи: «Как массив байтов (1 байт на пиксель (изображение в оттенках серого) запихнуть в Bitmap и отобразить в PicterBox?»
public void Save(BitmapSource image, string filePath)
{
using (var filestream = new FileStream(filePath, FileMode.Create))
{
BitmapEncoder encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(filestream);
}
}