2017-11-01 3 views
0

임의의 이미지로 분석해야합니다. 가장 쉬운 예부터 시작하겠습니다. 이미지를 picturebox에 복사하십시오. original_image 후 : after_image 이미지가 원래 을 왜곡 내 프로그램의 결과에 Bitmap.LockBits 함수로 액세스되는 기본 버퍼를 사용하는 C#의 비트 맵 처리

Bitmap foreImg = new Bitmap("input.jpg"); 
//output image 
Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height); 
unsafe 
{ 
    BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat); 
    BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat); 

    System.Threading.Tasks.Parallel.For(0, foreImg.Width * foreImg.Height, j => 
    { 
     Pixel* pxOne = (Pixel*)((byte*)oneBits.Scan0 + j * sizeof(Pixel)); 
     Pixel* pxRes = (Pixel*)((byte*)thrBits.Scan0 + j * sizeof(Pixel)); 
     pxRes->Green = pxOne->Green; 
     pxRes->Red = pxOne->Red; 
     pxRes->Blue = pxOne->Blue; 

    }); 

    foreImg.UnlockBits(oneBits); 
    resImg.UnlockBits(thrBits); 
} 

. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

+0

최대 이미지 처리 유형을 설명해 주시겠습니까? –

+1

'픽셀'이란 무엇입니까? – harold

+0

Pixel 구조체에 알파 바이트가 없습니다. – Adrian

답변

1

감사합니다. 문제는 입력 이미지의 PixelFormat이 내 구조체 Pixel과 일치하지 않는다는 것입니다. 실제로 알파 바이트를 추가하지 않았습니다.이 경우에는 Format24bppRgb을 사용하려고합니다.

+0

질문에 대한 새로운 대답으로 의견을 게시하지 마십시오. 대답 아래에있는 "덧글 추가"링크를 사용하십시오. – Nyerguds

+1

당신이 대답을 유용하다고 생각한다면 대답으로 표시하고 결국 그것을 업 그레 이드 할 수 있습니다. –

0

귀하의 이미지 복사본 코드에는 복사 된 특정 이미지에 맞지 않는 가정으로 인해 몇 가지 오류가 있습니다.

Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height);

대신해야한다 : 당신이 복사 작업을위한 새로운 목표 이미지를 만들 때하지 않습니다 때로는 진정한 있지만, 많은 경우에 어떻게 될 것인가 소스 이미지와 정확히 같은 픽셀 표현을해야합니다 첫 번째 가정 우리를 : 또는 이미지에 따라 잘못 설정하지 않을 수도 있습니다

Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat);

다음 가정은 원본 이미지 PixelFormat의 크기가 정확히 3 바이트임을 암시 가정하고 PixelFormat.Format24bppRgb 형식에 해당 (또는 Pixel 구조의 Red, Green 또는 Blue 채널의 크기가 무엇인지 알 수 없으므로 3 바이트의 배수가되며 PixelFormat.Format48bppRgb 형식 일 수 있습니다) 따라서 바이트는 원본 이미지에서이 위치에 따라 대상 이미지로 복사됩니다 인수.

정확하게 복사하려면 원본 이미지에서 대상 이미지로 정확히 같은 바이트 수를 복사해야하며 기본 Pixel 구조를 사용할 필요가 없으며 대신 정수 복사본을 기반으로 할 수 있습니다. 마지막으로 목표는 대신 가장 빠른 방법은 전문 메모리 복사 기능을 사용하여 픽셀에 의해 내용 픽셀입니다있어 분석의 이미지를 복사하는 경우 : 다음은 코드가있는 복사합니다 코드가 나열되어

System.Buffer.MemoryCopy((void*)oneBits.Scan0, (void*)thrBits.Scan0, byteLength, byteLength);

을 이미지는 ulongcarrier으로 사용합니다. Pixel 크기를 바이트로 반환하는 함수를 추가했습니다.이 함수는 바이트 단위로 이미지 크기를 계산하고 정확한 복사를 수행하는 데 사용됩니다. 그러나 이미지 데이터를 분석하는 데 사용할 수있는 것보다 일치하는 Pixel 구조를 선택하는 데 사용할 수 있습니다. 예를 들어, 이미지가 PixelFormat.Format24bppRgb 인 경우 Pixel 구조를 3 바이트 크기 및 RGB 색상으로 사용할 수 있습니다. 다른 형식의 경우 이미지 Pixel 형식을 직접 복제하는 다른 Pixel 구조를 정의해야합니다.

using System; 
using System.Drawing; 
using System.Drawing.Imaging; 

namespace DrawingImagingOperations 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Bitmap foreImg = new Bitmap(@"..\..\YaHI9.jpg"); 
      //output image 
      Bitmap resImg = new Bitmap(foreImg.Width, foreImg.Height, foreImg.PixelFormat); 
      unsafe 
      { 
       BitmapData oneBits = foreImg.LockBits(new Rectangle(0, 0, foreImg.Width, foreImg.Height), ImageLockMode.ReadOnly, foreImg.PixelFormat); 
       BitmapData thrBits = resImg.LockBits(new Rectangle(0, 0, resImg.Width, resImg.Height), ImageLockMode.WriteOnly, resImg.PixelFormat); 
       int pixelSize = GetPixelSize(foreImg.PixelFormat); 

       var byteLength = foreImg.Width * foreImg.Height * pixelSize; 
       var length = byteLength/sizeof(UInt64); 
       var reminder = byteLength % sizeof(UInt64); 


       System.Threading.Tasks.Parallel.For(0, length, j => 
       { 
        ulong* pxOne = (ulong*)((byte*)oneBits.Scan0 + j * sizeof(UInt64)); 
        ulong* pxRes = (ulong*)((byte*)thrBits.Scan0 + j * sizeof(UInt64)); 
        *pxRes = *pxOne; 
       }); 

       if (reminder > 0) 
       { 
        byte* pSrc = (byte*)oneBits.Scan0 + (pixelSize * length); 
        byte* pDst = (byte*)thrBits.Scan0 + (pixelSize * length); 
        for (int j = length; j < byteLength; j++) 
         *pDst++ = *pSrc++; 

       } 

       foreImg.UnlockBits(oneBits); 
       resImg.UnlockBits(thrBits); 
      } 

      resImg.Save(@"..\..\imgCopy.jpg"); 
     } 

     internal static int GetPixelSize(PixelFormat data) 
     { 
      switch (data) 
      { 
       case PixelFormat.Format8bppIndexed: 
        return 1; 
       case PixelFormat.Format16bppGrayScale: 
       case PixelFormat.Format16bppRgb555: 
       case PixelFormat.Format16bppRgb565: 
       case PixelFormat.Format16bppArgb1555: 
        return 2; 
       case PixelFormat.Format24bppRgb: 
        return 3; 
       case PixelFormat.Canonical: 
       case PixelFormat.Format32bppArgb: 
       case PixelFormat.Format32bppPArgb: 
       case PixelFormat.Format32bppRgb: 
        return 4; 
       case PixelFormat.Format48bppRgb: 
        return 6; 
       case PixelFormat.Format64bppArgb: 
       case PixelFormat.Format64bppPArgb: 
        return 8; 
      } 

      throw new FormatException("Unsupported image format: " + data); 
     } 
    } 
} 
+0

'byteLength'가 잘못되었습니다. 이미지는 _ 라인 _에 저장되며, 종종 그 라인들은 4 바이트의 다음 배수로 반올림됩니다. 이것이 올바른지 확인하려면'Width * pixelSize' 대신'Stride'를 사용해야하며, 보폭을 사용하여 라인 당 데이터를 복사해야합니다. 'Stride'는'BitmapData' 객체의 속성으로 사용할 수 있습니다. – Nyerguds

+0

@Nyerguds : '그 byte 길이가 틀립니다. 이미지는 한 줄에 저장되며, 종종 그 줄은 다음 4 바이트의 배수로 반올림됩니다. 얼마나 자주 ** ** System.Drawing.Bitmap 구현 형식과 관련이 있습니다. –

+0

어 ... 방금 쓴 것은 실제로 질문이 아니지만 32bpp 이미지를 사용하지 않으면 이미지 너비가 4 픽셀의 배수가 아닌 경우 문제가 발생합니다. – Nyerguds