I는 다른 맵의 비트 맵의 사본을 생성하고 변경이 짧은 스크립트 PixelFormat
에서 Format32bppArgb
행 (원래의 입력 화상) Format48bppRgb
. 그런 다음 Red
값 목록을 만들고 출력합니다.
Format32bppArgb
8 bits
채널당 사용 및 Format48bppRgb
16
. 하지만 내 빨강 채널 출력 값 사이 0
와 255
두 포맷, 왜 그렇게 무엇입니까?
Bitmap bitmap = (Bitmap) Bitmap.FromFile(@"minibottle.png");
Bitmap bitmapCopy = new Bitmap(bitmap.Width, bitmap.Height ,PixelFormat.Format48bppRgb);
using (Graphics gr = Graphics.FromImage(bitmapCopy)) {
gr.DrawImage(bitmap, new Rectangle(0, 0, bitmapCopy.Width, bitmapCopy.Height));
}
Console.WriteLine("Original PixelFormat: " + bitmap.PixelFormat); // Format32bppArgb
Console.WriteLine("Copy PixelFormat: " + bitmapCopy.PixelFormat); //Format48bppRgb
List<int> rPixels = new List<int>();
for (int row = 0; row < bitmapCopy.Width; row++) {
for (int column = 0; column < bitmapCopy.Height; column++) {
var r = bitmapCopy.GetPixel(row, column).R;
rPixels.Add(r);
}
}
bitmap.Dispose();
bitmapCopy.Dispose();
var str = "";
foreach (int px in rPixels) {
str = str + px + ", ";
}
Console.WriteLine("R values of all pixels: " + str); // 237, 238, 238, 236, 232, 234,...
}
내 빨간색 채널 출력 값은 두 형식 모두에 대해 0에서 255 사이입니다. 그 이유는 무엇입니까?
값을 가져 오는 데 사용하는 방법이에서 Color
반환 된 값 GetPixel()
은 16 비트 색상 채널을 나타낼 수 없습니다. Color
과 같은 의 각 구성 요소 속성은 8 비트의 데이터 만 저장할 수 Color.R
있는 byte
값 을 반환합니다 . 따라서 비트 맵의 내부 픽셀 값은 Color
사용 하는 픽셀 당 8 비트 범위로 다시 변환됩니다 .
실제 색상 채널 값을 보려면 픽셀 데이터를 직접 확인해야합니다. GetPixel()
방법이 매우 느리기 때문에 어쨌든 전체 비트 맵의 가치가있는 데이터를 다룰 때 더 나은 접근 방식 입니다. 이 LockBits()
메서드는 픽셀 데이터를 훨씬 더 효율적으로 직접 볼 수 있도록 비트 맵 데이터에 대한 포인터를 반환합니다.
다음은 픽셀 당 48 비트 비트 맵에 대한 실제 색상 채널 값을 반환하는 코드 버전입니다.
using (Bitmap bitmap = (Bitmap)Bitmap.FromFile(@"minibottle.png"))
using (Bitmap bitmapCopy = new Bitmap(bitmap.Width, bitmap.Height, PixelFormat.Format48bppRgb))
{
using (Graphics gr = Graphics.FromImage(bitmapCopy))
{
gr.DrawImage(bitmap, bitmapCopy.Size.ToRect());
}
Console.WriteLine($"Original PixelFormat: {bitmap.PixelFormat}"); // Format32bppArgb
Console.WriteLine($"Copy PixelFormat: {bitmapCopy.PixelFormat}"); //Format48bppRgb
List<int> rPixels = GetRedValuesWithLockBits(bitmapCopy);
Console.WriteLine($"R values of all pixels: {string.Join(", ", rPixels)}"); // 237, 238, 238, 236, 232, 234,...
}
비트 맵 처리를 자체 방법으로 옮긴 곳 :
private static List<int> GetRedValuesWithLockBits(Bitmap bitmap)
{
List<int> result = new List<int>();
BitmapData bitmapData = bitmap.LockBits(bitmap.Size.ToRect(), ImageLockMode.Read, bitmap.PixelFormat);
try
{
unsafe
{
byte* ppixelRow = (byte *)bitmapData.Scan0;
for (int y = 0; y < bitmap.Height; y++)
{
ushort* ppixelData = (ushort *)ppixelRow;
for (int x = 0; x < bitmap.Width; x++)
{
// components are stored in BGR order, i.e. red component last
result.Add(ppixelData[2]);
ppixelData += 3;
}
ppixelRow += bitmapData.Stride;
}
}
return result;
}
finally
{
bitmap.UnlockBits(bitmapData);
}
}
그리고 약간의 도우미 확장 방법을 포함했습니다.
static class Extensions
{
public static Rectangle ToRect(this Size size)
{
return new Rectangle(new Point(), size);
}
}
메모:
PixelFormat48bppRGB, PixelFormat64bppARGB 및 PixelFormat64bppPARGB는 색상 구성 요소 (채널) 당 16 비트를 사용합니다. GDI + 버전 1.0 및 1.1은 채널당 16 비트 이미지를 읽을 수 있지만 이러한 이미지는 처리, 표시 및 저장을 위해 채널당 8 비트 형식으로 변환됩니다. 각 16 비트 색상 채널은 0 ~ 2 ^ 13 범위의 값을 보유 할 수 있습니다. [강조 광산] .
즉, GDI +는 색상 채널에서 0에서 8192까지의 값만 허용합니다. 시도해 보면 실제로 8193에서 32767까지의 값을 허용한다는 것을 실험적으로 결정할 수 있습니다. 이는 기술적으로 15 비트의 색상 정밀도입니다. 그러나 8192보다 큰 값은 8192 인 것처럼 처리됩니다. 32767보다 큰 값은 검은 색으로 표시됩니다.
예제에서와 같이 GDI + 자체가 비트 맵을 생성 할 때 문서화 된 최대 값 인 8192보다 큰 값은 사용하지 않습니다.
마지막으로 이것은 엄격하게 GDI + 제한 사항이라는 점을 강조 할 가치가 있습니다. Windows는 다른 비트 맵 처리 API를 제공하며 .NET의 WPF 비트 맵 처리는 GDI + 대신 WIC (Windows Imaging Component)를 기반으로합니다. WIC에는 이러한 제한이 없습니다. 진정한 48bpp 컬러 해상도를 처리합니다.
다음은 System.Windows.Media.Imaging.BitmapSource
Winforms API에서 GDI + 기반 API를 사용하는 대신 WPF API의 일부인 클래스 를 사용하는 픽셀 값 추출 버전입니다 .
private static List<int> GetRedValues(BitmapSource bitmap)
{
List<int> result = new List<int>();
int ushortStride = bitmap.PixelWidth * 3, rowIndex = 0;
ushort[] pixelData = new ushort[bitmap.PixelHeight * ushortStride];
bitmap.CopyPixels(pixelData, ushortStride * sizeof(ushort), 0);
for (int y = 0; y < bitmap.Height; y++)
{
int pixelIndex = rowIndex;
for (int x = 0; x < bitmap.Width; x++)
{
// In WPF's Rgb48 format, components are stored in RGB order, i.e. red component first
result.Add(pixelData[pixelIndex]);
pixelIndex += 3;
}
rowIndex += ushortStride;
}
return result;
}
당연히 해당 버전을 호출하려면 WPF 메커니즘을 사용하여 비트 맵 형식을로드하고 변환해야합니다. 자세한 내용은 BitmapImage
및 FormatConvertedBitmap
클래스를 참조하십시오.
FormatConvertedBitmap
클래스를 사용하여 원본 비트 맵을 48bpp로 변환 한 다음 새 비트 맵을 위의 메서드에 전달하면 픽셀의 구성 요소 값이 0에서 65535 사이임을 알 수 있습니다. 비트 컬러 성분. 물론 이전에 언급했듯이 가장 가까운 두 색상 구성 요소 값 간의 차이가 257이되기 때문에 여전히 8 비트의 색상 정밀도 만있을 것입니다 (256이 아니기 때문입니다. 의 8 비트 색상 구성 요소 값 은 필요한 실제 최대 값 대신 0xff
으로 만 표시됩니다 .0xff00
0xffff
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다