PixelFormat.Format48bppRgb 이미지의 RGB 값이 0에서 255 사이 인 이유는 무엇입니까?

miran80

I는 다른 맵의 비트 맵의 사본을 생성하고 변경이 짧은 스크립트 PixelFormat에서 Format32bppArgb행 (원래의 입력 화상) Format48bppRgb. 그런 다음 Red목록을 만들고 출력합니다.

Format32bppArgb8 bits채널당 사용 Format48bppRgb 16. 하지만 내 빨강 채널 출력 값 사이 0255두 포맷, 왜 그렇게 무엇입니까?

            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);
    }
}

메모:

  • 프로젝트 설정 ( "Build"탭 아래)에서 "안전하지 않은 코드 허용"설정을 활성화해야합니다.
  • 반환 된 값의 범위는 0에서 8192까지입니다. 부호없는 16 비트 값의 전체 범위 인 0에서 65535까지의 값이 표시 될 것으로 예상 할 수 있습니다. 그러나 사용중인 .NET 코드에서 GDI +를 기본 그래픽 지원으로 사용하고 있으며 다음같은 제한이 있습니다 .

    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.BitmapSourceWinforms 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 메커니즘을 사용하여 비트 맵 형식을로드하고 변환해야합니다. 자세한 내용은 BitmapImageFormatConvertedBitmap클래스를 참조하십시오.

FormatConvertedBitmap클래스를 사용하여 원본 비트 맵을 48bpp로 변환 한 다음 새 비트 맵을 위의 메서드에 전달하면 픽셀의 구성 요소 값이 0에서 65535 사이임을 알 수 있습니다. 비트 컬러 성분. 물론 이전에 언급했듯이 가장 가까운 두 색상 구성 요소 값 간의 차이가 257이되기 때문에 여전히 8 비트의 색상 정밀도 만있을 것입니다 (256이 ​​아니기 때문입니다. 의 8 비트 색상 구성 요소 값 은 필요한 실제 최대 값 대신 0xff으로 만 표시됩니다 .0xff000xffff

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

실린더에 255 개의 트랙이있는 이유는 무엇입니까?

분류에서Dev

nvarchar의 기본 크기가 255 (MSSQL Server) 인 이유는 무엇입니까?

분류에서Dev

len (file.read ()) 값이 0 인 이유는 무엇입니까?

분류에서Dev

비트 맵 이미지의 RGB 값에서 배열을 얻는 방법은 무엇입니까?

분류에서Dev

이미지에서 개체의 RGB 값을 추출하는 방법은 무엇입니까?

분류에서Dev

afterRender에서 $ (element) .offset (). top == 0 인 이유는 무엇입니까?

분류에서Dev

이 목록에서 최대 값이 [3] 인 이유는 무엇입니까?

분류에서Dev

이 목록에서 최대 값이 [3] 인 이유는 무엇입니까?

분류에서Dev

배열로 구현 된 힙에서 인덱스 0이 사용되지 않는 이유는 무엇입니까?

분류에서Dev

RGB 이미지에서 RGB 채널을 분리하는 동안 & 0xff의 중요성은 무엇입니까?

분류에서Dev

내 함수에서 $ #이 항상 0 인 이유는 무엇입니까?

분류에서Dev

내 프로그램에서 출력이 0 인 이유는 무엇입니까?

분류에서Dev

0에서 4까지의 랜덤이 대부분 1 인 이유는 무엇입니까?

분류에서Dev

이미지에 Rails 자산 파이프 라인을 사용하는 이유는 무엇입니까?

분류에서Dev

"$ (())"명령의 출력이 0 인 이유는 무엇입니까?

분류에서Dev

"$ (())"명령의 출력이 0 인 이유는 무엇입니까?

분류에서Dev

값이있는 경우 indexOf (char)가 0 인 이유는 무엇입니까?

분류에서Dev

Rust에서 의미있는 값이없는 맵의 메모리 효율적인 유형은 무엇입니까?

분류에서Dev

파이썬에서 bool ( "0")이 참인 이유는 무엇입니까? 왜 이런 일이 발생합니까?

분류에서Dev

v [a] ++는 무엇을 의미합니까? 이 코드에서 모든 v [a] 값이 1 인 이유는 무엇입니까?

분류에서Dev

이 e / lval의 유형이 CIL에서 int 인 이유는 무엇입니까?

분류에서Dev

이 조건 0 = '= 1'이 참인 이유는 무엇입니까?

분류에서Dev

이 인쇄가 0 인 이유는 무엇입니까?

분류에서Dev

== true를 사용하여 변수에 값이 있는지 확인할 수없는 이유는 무엇입니까?

분류에서Dev

Android의 이미지에서 RGB 강도 그래프를 그리는 방법은 무엇입니까?

분류에서Dev

흐름에서 이미 정의 된 정의되지 않은 값을 확인하는 이유는 무엇입니까?

분류에서Dev

MATLAB에서이 인덱스의 의미는 무엇입니까?

분류에서Dev

productsCenter 변수의 값이 null 인 이유는 무엇입니까?

분류에서Dev

내 예측에서 오류가 0 인 이유는 무엇입니까?

Related 관련 기사

  1. 1

    실린더에 255 개의 트랙이있는 이유는 무엇입니까?

  2. 2

    nvarchar의 기본 크기가 255 (MSSQL Server) 인 이유는 무엇입니까?

  3. 3

    len (file.read ()) 값이 0 인 이유는 무엇입니까?

  4. 4

    비트 맵 이미지의 RGB 값에서 배열을 얻는 방법은 무엇입니까?

  5. 5

    이미지에서 개체의 RGB 값을 추출하는 방법은 무엇입니까?

  6. 6

    afterRender에서 $ (element) .offset (). top == 0 인 이유는 무엇입니까?

  7. 7

    이 목록에서 최대 값이 [3] 인 이유는 무엇입니까?

  8. 8

    이 목록에서 최대 값이 [3] 인 이유는 무엇입니까?

  9. 9

    배열로 구현 된 힙에서 인덱스 0이 사용되지 않는 이유는 무엇입니까?

  10. 10

    RGB 이미지에서 RGB 채널을 분리하는 동안 & 0xff의 중요성은 무엇입니까?

  11. 11

    내 함수에서 $ #이 항상 0 인 이유는 무엇입니까?

  12. 12

    내 프로그램에서 출력이 0 인 이유는 무엇입니까?

  13. 13

    0에서 4까지의 랜덤이 대부분 1 인 이유는 무엇입니까?

  14. 14

    이미지에 Rails 자산 파이프 라인을 사용하는 이유는 무엇입니까?

  15. 15

    "$ (())"명령의 출력이 0 인 이유는 무엇입니까?

  16. 16

    "$ (())"명령의 출력이 0 인 이유는 무엇입니까?

  17. 17

    값이있는 경우 indexOf (char)가 0 인 이유는 무엇입니까?

  18. 18

    Rust에서 의미있는 값이없는 맵의 메모리 효율적인 유형은 무엇입니까?

  19. 19

    파이썬에서 bool ( "0")이 참인 이유는 무엇입니까? 왜 이런 일이 발생합니까?

  20. 20

    v [a] ++는 무엇을 의미합니까? 이 코드에서 모든 v [a] 값이 1 인 이유는 무엇입니까?

  21. 21

    이 e / lval의 유형이 CIL에서 int 인 이유는 무엇입니까?

  22. 22

    이 조건 0 = '= 1'이 참인 이유는 무엇입니까?

  23. 23

    이 인쇄가 0 인 이유는 무엇입니까?

  24. 24

    == true를 사용하여 변수에 값이 있는지 확인할 수없는 이유는 무엇입니까?

  25. 25

    Android의 이미지에서 RGB 강도 그래프를 그리는 방법은 무엇입니까?

  26. 26

    흐름에서 이미 정의 된 정의되지 않은 값을 확인하는 이유는 무엇입니까?

  27. 27

    MATLAB에서이 인덱스의 의미는 무엇입니까?

  28. 28

    productsCenter 변수의 값이 null 인 이유는 무엇입니까?

  29. 29

    내 예측에서 오류가 0 인 이유는 무엇입니까?

뜨겁다태그

보관