C# 获取64bpp图像颜色
我想使用BitmapData访问64bpp图像的颜色信息。我已经成功地为32bpp的图像完成了这项工作,但对于64bpp的图像来说似乎并不容易C# 获取64bpp图像颜色,c#,.net,image-processing,bitmap,C#,.net,Image Processing,Bitmap,我想使用BitmapData访问64bpp图像的颜色信息。我已经成功地为32bpp的图像完成了这项工作,但对于64bpp的图像来说似乎并不容易 static void Main(string[] args) { Bitmap bmp; using (Stream imageStreamSource = new FileStream(bitmapPath, FileMode.Open, FileAccess.Read, FileShare.Read)) //Should I u
static void Main(string[] args)
{
Bitmap bmp;
using (Stream imageStreamSource = new FileStream(bitmapPath, FileMode.Open, FileAccess.Read, FileShare.Read)) //Should I use "using" here? or do I need to keep the stream open for as long as I use the Bitmap?
{
PngBitmapDecoder decoder = new PngBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];
bmp = _bitmapFromSource(bitmapSource);
}
unsafe
{
int xIncr = Image.GetPixelFormatSize(bmp.PixelFormat) / 8; //8
xIncr /= 2;
BitmapData bData1 = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
ushort* bData1Scan0Ptr = (ushort*)bData1.Scan0.ToPointer();
ushort* nextBase = bData1Scan0Ptr + bData1.Stride;
for (int y = 0; y < bData1.Height; ++y)
{
for (int x = 0; x < bData1.Width; ++x)
{
var red = bData1Scan0Ptr[2];
var green = bData1Scan0Ptr[1];
var blue = bData1Scan0Ptr[0];
bData1Scan0Ptr += xIncr; //xIncr = 4
}
bData1Scan0Ptr = nextBase;
nextBase += bData1.Stride;
}
}
}
//http://stackoverflow.com/questions/7276212/reading-preserving-a-pixelformat-format48bpprgb-png-bitmap-in-net
private static Bitmap _bitmapFromSource(BitmapSource bitmapsource)
{
Bitmap bitmap;
using (MemoryStream outStream = new MemoryStream()) //Should I use "using" here?
{
BitmapEncoder enc = new BmpBitmapEncoder();
enc.Frames.Add(BitmapFrame.Create(bitmapsource));
enc.Save(outStream);
bitmap = new System.Drawing.Bitmap(outStream);
}
return bitmap;
}
static void Main(字符串[]args)
{
位图bmp;
使用(Stream imageStreamSource=new FileStream(位图路径,FileMode.Open,FileAccess.Read,FileShare.Read))//我应该在这里使用“using”吗?还是需要在使用位图时保持流的打开状态?
{
PngBitmapDecoder decoder=新的PngBitmapDecoder(imageStreamSource,BitmapCreateOptions.PreservePixelFormat,BitmapCacheOption.Default);
BitmapSource BitmapSource=解码器。帧[0];
bmp=_bitmapFromSource(bitmapSource);
}
不安全的
{
int xIncr=Image.GetPixelFormatSize(bmp.PixelFormat)/8;//8
xIncr/=2;
BitmapData bData1=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
ushort*bData1Scan0Ptr=(ushort*)bData1.Scan0.ToPointer();
ushort*nextBase=bData1Scan0Ptr+bData1.步幅;
对于(int y=0;y
对于白色图像(255、255、255),我得到0和32作为2个值。。。?我不知道这是否正确,我只是把它们理解错了,或者它们完全错了。(更新后的代码不再适用)
编辑:
经过更新的代码,我得到的255值为8192,128值为1768。这对我来说还是没什么意义
我还想知道在加载图像时是否应该使用“using”语句,因为它说我需要在位图的生命周期内保持流的打开状态。它现在的工作方式似乎很好,或者是因为我将位图复制到在“using”语句之外声明的另一个位图?通常,64bpp格式的每个RGBA都有16位,因此您应该真正使用
ushort
而不是byte
。例如:
BitmapData bData1 = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
byte* bData1Scan0Ptr = (byte*)bData1.Scan0.ToPointer();
byte* nextBase = bData1Scan0Ptr + bData1.Stride;
for (int y = 0; y < bData1.Height; ++y)
{
ushort* pRow = (ushort*)bData1Scan0Ptr;
for (int x = 0; x < bData1.Width; ++x)
{
var red = pRow[2];
var green = pRow[1];
var blue = pRow[0];
pRow += 4;
}
bData1Scan0Ptr = nextBase;
nextBase += bData1.Stride;
}
BitmapData bData1=bmp.LockBits(新矩形(0,0,bmp.Width,bmp.Height),ImageLockMode.ReadWrite,bmp.PixelFormat);
字节*bData1Scan0Ptr=(字节*)bData1.Scan0.ToPointer();
字节*nextBase=bData1Scan0Ptr+bData1.Stride;
对于(int y=0;y
如果不能解决您的问题,请尝试此修改并对结果进行注释,然后在必要时更新我的答案。这是一个老问题,但我在开发库的过程中遇到了相同的问题。见TL;DR答案位于“备注”部分底部的“帮助”页的“备注”部分 下面是更详细的答案:从8位到16位颜色通道的转换(实际上是13位,正如您已经注意到的)不是线性的:
- 24bpp格式以及其他高达32位的格式(以及
结构)表示伽马校正γ=2.2的颜色颜色
- 而48/64bpp格式表示具有线性伽马的颜色,即无伽马校正(伽马=1.0)
outputLevel = 8192 * Math.Pow(inputLevel / 255d, 1d / gamma)
这为inputLevel=128
和gamma=0.45提供了1770
这就是24bpp格式的橙色(255128,0)和48bpp格式的橙色(81921768,0)
注:该公式仅适用于RGB通道,不适用于A。Alpha没有“gamma校正”
事实上,Windows有点作弊,正如您可以注意到的,对于低inputLevel
值:上面的公式给出了输入级别<5的0,尽管尝试使用48/64 bpp格式和低RGB颜色值的SetPixel
,您可以看到原始RGB组件从不为零,它们总是不同的。如果将图像从32位转换为64位会丢失一些信息,这可能会非常可笑
不过,这可能因实现而异。在Linux上,libgdiplus
根本不支持48/64位格式。另一方面,ReactOS(一个免费的Windows克隆)在8->16位转换之间使用一个简单的线性转换,使用完整的16位范围,正如您可以从其上看到的那样。谢谢!我现在得到了不同的结果,但我仍然不确定它们是否正确。。我的图像是橙色(255128,0),我得到的值是:红色:8192,绿色:1768和蓝色:0我知道这是一个老问题,但对于像我这样偶然发现这个问题的人来说,8192是最大值(对于24bpp图像的白色,等于255)。