【发布时间】:2019-10-31 18:17:58
【问题描述】:
修改此链接中提供的代码:
这是我写的:
private void btnLoad_Click(object sender, EventArgs e)
{
if (System.IO.File.Exists(txtPicture.Text))
{
byte[] _data = System.IO.File.ReadAllBytes(txtPicture.Text);
var _rgbData = Convert16BitGrayScaleToRgb16(_data, 160, 120);
var _bmp = CreateBitmapFromBytes(_rgbData, 160, 120);
pbFrame.Image = _bmp;
}
}
private static void Convert16bitGSToRGB(UInt16 color, out byte red, out byte green, out byte blue)
{
red = (byte)(color & 0x31);
green = (byte)((color & 0x7E0) >> 5);
blue = (byte)((color & 0xF800) >> 11);
}
private static byte[] Convert16BitGrayScaleToRgb48(byte[] inBuffer, int width, int height)
{
int inBytesPerPixel = 2;
int outBytesPerPixel = 6;
byte[] outBuffer = new byte[width * height * outBytesPerPixel];
int inStride = width * inBytesPerPixel;
int outStride = width * outBytesPerPixel;
// Step through the image by row
for (int y = 0; y < height; y++)
{
// Step through the image by column
for (int x = 0; x < width; x++)
{
// Get inbuffer index and outbuffer index
int inIndex = (y * inStride) + (x * inBytesPerPixel);
int outIndex = (y * outStride) + (x * outBytesPerPixel);
byte hibyte = inBuffer[inIndex + 1];
byte lobyte = inBuffer[inIndex];
//R
outBuffer[outIndex] = lobyte;
outBuffer[outIndex + 1] = hibyte;
//G
outBuffer[outIndex + 2] = lobyte;
outBuffer[outIndex + 3] = hibyte;
//B
outBuffer[outIndex + 4] = lobyte;
outBuffer[outIndex + 5] = hibyte;
}
}
return outBuffer;
}
private static byte[] Convert16BitGrayScaleToRgb16(byte[] inBuffer, int width, int height)
{
int inBytesPerPixel = 2;
int outBytesPerPixel = 2;
byte[] outBuffer = new byte[width * height * outBytesPerPixel];
int inStride = width * inBytesPerPixel;
int outStride = width * outBytesPerPixel;
// Step through the image by row
for (int y = 0; y < height; y++)
{
// Step through the image by column
for (int x = 0; x < width; x++)
{
// Get inbuffer index and outbuffer index
int inIndex = (y * inStride) + (x * inBytesPerPixel);
int outIndex = (y * outStride) + (x * outBytesPerPixel);
byte hibyte = inBuffer[inIndex];
byte lobyte = inBuffer[inIndex+1];
outBuffer[outIndex] = lobyte;
outBuffer[outIndex+1] = hibyte;
}
}
return outBuffer;
}
private static byte[] Convert16BitGrayScaleToRgb24(byte[] inBuffer, int width, int height)
{
int inBytesPerPixel = 2;
int outBytesPerPixel = 3;
byte[] outBuffer = new byte[width * height * outBytesPerPixel];
int inStride = width * inBytesPerPixel;
int outStride = width * outBytesPerPixel;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int inIndex = (y * inStride) + (x * inBytesPerPixel);
int outIndex = (y * outStride) + (x * outBytesPerPixel);
byte hibyte = inBuffer[inIndex];
byte lobyte = inBuffer[inIndex + 1];
byte r, g, b;
UInt16 color = (UInt16)(hibyte << 8 | lobyte);
Convert16bitGSToRGB(color, out r, out g, out b);
outBuffer[outIndex] = r;
outBuffer[outIndex + 1] = g;
outBuffer[outIndex + 2] = b;
}
}
return outBuffer;
}
private static Bitmap CreateBitmapFromBytes(byte[] pixelValues, int width, int height)
{
//Create an image that will hold the image data
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format16bppRgb565);
//Get a reference to the images pixel data
Rectangle dimension = new Rectangle(0, 0, bmp.Width, bmp.Height);
BitmapData picData = bmp.LockBits(dimension, ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr pixelStartAddress = picData.Scan0;
//Copy the pixel data into the bitmap structure
Marshal.Copy(pixelValues, 0, pixelStartAddress, pixelValues.Length);
bmp.UnlockBits(picData);
return bmp;
}
但转换的结果仍然不令人满意/不正确。这是我应该得到的图片:
转换此处链接的文件:
这是使用Convert16BitGrayScaleToRgb48的结果:
这是使用Convert16BitGrayScaleToRgb16的结果:
这是使用Convert16BitGrayScaleToRgb24的结果:
很明显,颜色重映射是错误的,但我不明白问题出在哪里。
此外,我还发现图片框没有准确显示它存储的内容。顶部的第二张图片(Convert16BitGrayScaleToRgb48 结果)是图片框显示的内容,而以下图片是我保存为 PNG 格式显示的图像时获得的内容:
我认为 RAW16 灰度应该意味着 2 个字节,其中包含 16 位灰度值或在 565 或 555 映射上编码的 RGB 灰度值。但这些假设似乎都与真实情况不符。
有人提示,如何将源文件中提供的值转换成第一张一样的图片(使用ImageJ从同一来源获得)?
【问题讨论】:
-
如果您将使用
PixelFormat.Format48bppRgb构建的图像保存到 PNG 文件中,您可能会得到接近预期结果的结果。 -
@Jimi 不是。嗯……真的没有。保存的图片与图片框所描绘的有所不同,但无论如何都不正确:48bpp image
-
是的,不完全支持原始 16 位灰度图像。这就是编码器可以做的,每通道转码为 8 位。色彩空间将无法正确调整。您必须自己执行标准化。顺便说一句,您发布的原始图像,用 PhotoShop 打开,给出了相同的结果(类似于过度曝光:局部分辨率损失)。它可能针对某些特定的解码器,类似于 DICOM 图像格式(用于显微镜或 X 射线)。
-
@Jimi 不!问题是 1) 字节序 2) 亮度范围 3) 图片框。特别是最后一个(可能取决于显卡)似乎是导致 48bpp 帧渲染失败的原因。
-
:) 这就是为什么我建议使用 PNG 编码器来执行转换。并标准化色彩空间。由于没有人知道这张图片是什么,它是由什么产生的以及使用什么参数 - 考虑到 PhotoShop 产生的结果与 PNG 编码器相同 - 没有太多可以说的了。
标签: c# .net image picturebox