C \ # 이미지 처 리 를 위 한 몇 가지 방법 (bitmap, bitmapData, IntPtr)

7765 단어
전환 하 다 http://blog.sina.com.cn/s/blog_628821950100wh9w.html
C \ # 이미지 처 리 를 위 한 몇 가지 방법
본 고 는 C \ # 이미지 처리 에서 Bitmap 류, BitmapData 류 와 unsafe 코드 의 사용 과 바이트 정렬 문 제 를 토론 했다.
비트 맵 클래스
네 임 스페이스: System. Drawing
GDI + 비트 맵 을 봉인 합 니 다. 이 비트 맵 은 그래 픽 이미지 와 속성의 픽 셀 데이터 로 구성 되 어 있 습 니 다.비트 맵 은 픽 셀 데이터 로 정 의 된 그림 을 처리 하 는 대상 입 니 다. 
    C \ # 클래스 를 이용 하여 이미지 처 리 를 하 는데 가장 편리 한 것 은 Bitmap 클래스 를 사용 하 는 것 입 니 다. 이러한 종류의 GetPixel () 과 SetPixel () 을 사용 하여 이미지 의 모든 픽 셀 점 에 접근 하 는 것 입 니 다.다음은 MSDN 의 예제 코드 입 니 다.
 
public void GetPixel_Example(PaintEventArgs e) 
{ 
    // Create a Bitmap object from an image file. 
    Bitmap myBitmap = new Bitmap("Grapes.jpg"); 
    // Get the color of a pixel within myBitmap. 
    Color pixelColor = myBitmap.GetPixel(50, 50); 
    // Fill a rectangle with pixelColor. 
    SolidBrush pixelBrush = new SolidBrush(pixelColor); 
    e.Graphics.FillRectangle(pixelBrush, 0, 0, 100, 100); 
}

이 를 통 해 알 수 있 듯 이 Bitmap 류 는 우아 한 방식 으로 이미 지 를 조작 하지만 가 져 온 성능 의 감 소 는 무시 할 수 없다.예 를 들 어 800 * 600 의 컬러 이미지 에 대한 그 레이스 케 일 화 는 그 소모 시간 을 초 단위 로 계산 해 야 한다.실제 프로젝트 에서 이미지 처 리 를 하 는 속 도 는 결코 참 을 수 없다.
 
 
BitmapData 클래스
네 임 스페이스: System. Drawing. Imaging
비트 맵 이미지 의 속성 을 지정 합 니 다.BitmapData 클래스 는 Bitmap 클래스 의 LockBits 와 UnlockBits 방법 으로 사 용 됩 니 다.물 려 받 을 수 없다.
    다행히 우 리 는 BitmapData 클래스 가 있 습 니 다. BitmapData BitmapData LockBits () 를 통 해 Bitmap 를 시스템 메모리 에 잠 글 수 있 습 니 다.이러한 종류의 공공 속성 은:
  • Width           Bitmap 대상 의 픽 셀 폭 을 가 져 오 거나 설정 합 니 다.이것 도 스 캔 줄 의 픽 셀 수로 볼 수 있다
  • Height          Bitmap 대상 의 픽 셀 높이 를 가 져 오 거나 설정 합 니 다.때로는 스캐닝 줄 수 라 고도 부른다
  • PixelFormat  이 BitmapData 대상 을 되 돌려 주 는 Bitmap 대상 의 픽 셀 정 보 를 가 져 오 거나 설정 합 니 다
  • Scan0            비트 맵 의 첫 번 째 픽 셀 데 이 터 를 가 져 오 거나 설정 합 니 다.그것 도 비트 맵 의 첫 번 째 스 캔 줄 로 볼 수 있다
  • Stride            Bitmap 대상 의 간격 폭 을 가 져 오 거나 설정 합 니 다

  •     아래 MSDN 의 예제 코드 는 PixelFormat, Height, Width 와 Scan 0 속성 을 어떻게 사용 하 는 지 보 여 줍 니 다.LockBits 와 UnlockBits 방법;그리고 ImageLockMode 매 거 진.
    private void LockUnlockBitsExample(PaintEventArgs e) 
    {
        // Create a new bitmap. 
        Bitmap bmp = new Bitmap("c:\\fakePhoto.jpg");
        // Lock the bitmap's bits.  
        Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); 
        System.Drawing.Imaging.BitmapData bmpData = 
            bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, 
            bmp.PixelFormat); 
        // Get the address of the first line. 
       IntPtr ptr = bmpData.Scan0;
        // Declare an array to hold the bytes of the bitmap. 
        int bytes  = bmpData.Stride * bmp.Height; 
        byte[] rgbValues = new byte[bytes];
        // Copy the RGB values into the array. 
        System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
        // Set every red value to 255.  
        for (int counter = 0; counter < rgbValues.Length; counter+=3) 
            rgbValues[counter] = 255; 
        // Copy the RGB values back to the bitmap 
        System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
        // Unlock the bits. 
        bmp.UnlockBits(bmpData);
        // Draw the modified image. 
        e.Graphics.DrawImage(bmp, 0, 150);
    }

    위의 코드 는 낮은 효 과 를 사용 하지 않 고 배열 방식 으로 그림 에 접근 하 는 방법 을 보 여 주 었 다.
    GetPixel () 과 SetPixel ().
     
    unsafe 코드
        그러나 실제 에서 위의 방법 은 우리 의 요 구 를 만족 시 키 지 못 한다. 이미지 처 리 는 연 산 량 이 비교적 많은 조작 으로 우리 가 쓴 일반적인 응용 프로그램 과 다르다.우리 에 게 필요 한 것 은 C + + 프로그램 에 필적 할 수 있 는 이미지 처리 프로그램 이다.C + + 는 어떻게 효율 을 높 입 니까? 라 고 대답 했다. 지침.다행히도. Net 도 비 안전 코드 블록 에서 만 지침 을 사용 할 수 있 도록 해 주 었 습 니 다.무엇 을 비 안전 코드 라 고 합 니까?
        형식 안전 을 유지 하기 위해 기본적으로 C \ # 포인터 연산 은 지원 되 지 않 습 니 다.단, unsafe 키 워드 를 사용 하면 지침 을 사용 할 수 있 는 불안 전한 컨 텍스트 를 정의 할 수 있 습 니 다.공용 어 라 이브 러 리 (CLR) 에서 보안 하지 않 은 코드 는 검증 할 수 없 는 코드 를 말한다.C \ # 의 안전 하지 않 은 코드 가 반드시 위험 하 지 는 않 습 니 다. 다만 안전성 이 CLR 에 의 해 검증 되 지 않 는 코드 입 니 다.따라서 CLR 은 완전히 신뢰 받 는 프로그램 에 집 중 된 불안 전한 코드 에 만 작 동 합 니 다.안전 하지 않 은 코드 를 사용 하면 코드 가 안전 위험 이나 지침 오 류 를 일 으 키 지 않도록 책임 집 니 다.안전 하지 않 은 코드 는 다음 속성 을 가지 고 있 습 니 다:
    4. 567917. 방법, 유형 과 안전 하지 않 은 코드 블록 으로 정의 할 수 있 습 니 다
    4. 567917. 특정한 상황 에서 배열 의 경 계 를 제거 하고 검 사 를 통 해 안전 하지 않 은 코드 는 응용 프로그램의 성능 을 향상 시 킬 수 있다
    4. 567917. 포인터 가 필요 한 이 컴퓨터 함 수 를 호출 할 때 안전 하지 않 은 코드 를 사용 해 야 합 니 다
    4. 567917. 안전 하지 않 은 코드 를 사용 하면 안전 위험 과 안정성 위험 을 초래 할 것 이다
    4. 567917. C \ # 에서 안전 하지 않 은 코드 를 컴 파일 하기 위해 서 는 / unsafe 로 프로그램 을 컴 파일 해 야 합 니 다
        에서 말 한 것 처럼 개발 자 든 사용자 의 측면 에서 볼 때 안전 하지 않 은 코드 는 사실상 '안전' 기능 이다.안전 하지 않 은 코드 는 수정자 unsafe 로 명확 하 게 표시 해 야 합 니 다. 그러면 개발 자 들 은 안전 하지 않 은 기능 을 잘못 사용 하지 않 고 실행 엔진 은 신뢰 하지 않 는 환경 에서 안전 하지 않 은 코드 를 실행 하지 않도록 확보 할 것 입 니 다.
        다음 코드 는 BitmapData 류 를 통 해 그림 을 포인터 로 옮 겨 다 니 는 방법 을 보 여 줍 니 다. 여기 있 는 unsafe 코드 블록 에 있 는 코드 는 비 안전 코드 입 니 다.
    //     
    Bitmap image =  new Bitmap( "c:\\images\\image.gif" ); 
    //     BitmapData   
    BitmapData data = image.LockBits( new Rectangle( 0 , 0 , image.Width , image.Height ) , ImageLockMode.ReadWrite  , PixelFormat.Format24bppRgb  );  
    //     
    unsafe 
    {  
           byte* ptr = ( byte* )( data.Scan0 );  
           for( int i = 0 ; i < data.Height ; i ++ ) 
           { 
              for( int j = 0 ;  j < data.Width ;  j ++ ) 
               { 
                 // write the logic implementation here 
                 ptr += 3;   
               } 
             ptr += data.Stride - data.Width * 3; 
           } 
    }

    의심 할 여지없이 이런 방식 을 사용 하 는 것 이 가장 빠 르 기 때문에 실제 공정에 서 는 모두 포인터 방식 으로 이미지 픽 셀 에 접근한다.
     
    질문      상례 에서 ptr + = data. Stride - data. Width * 3 은 쓸모없는 영역 을 뛰 어 넘 었 음 을 나타 낸다. 그 이 유 는 이미지 데이터 가 메모리 에 저 장 될 때 4 바이트 로 정렬 되 었 기 때문이다. 구체 적 으로 설명 하면 다음 과 같다.
        그림 의 폭 이 6 이 라 고 가정 하고 Format24bppRgb 형식 이 라 고 가정 합 니 다 (픽 셀 당 3 바이트, 다음 토론 에서 특별히 설명 하지 않 으 면 Bitmap 는 24 비트 RGB 로 여 겨 집 니 다).한 줄 에 6 * 3 = 18 개의 바이트 저장 이 필요 한 것 은 분명 하 다.비트 맵 에 대해 서 는 그렇습니다.그러나 BitmapData 에 대해 data. Width 는 image. Width 와 같 지만 디 스 플레이 성능 을 고려 하여 각 줄 의 실제 바이트 수 는 가장 가 까 운 4 의 전체 배수 보다 클 것 입 니 다. 이때 의 실제 바이트 수 는 Stride 입 니 다.이 경우 18 은 4 의 전체 배수 가 아니 라 18 보다 큰 18 의 가장 가 까 운 4 의 배수 가 20 이기 때문에 이 data. Stride = 20 이다.분명히 너비 자체 가 4 의 배수 일 때 data. Stride = image. Width * 3.
        그림 을 그 리 는 것 이 더 이해 할 수 있 을 것 이다.R, G, B 는 각각 원색 분량 바이트 3 개 를 나타 내 고 BGR 은 하나의 픽 셀 을 나타 낸다.편 해 보이 기 위해 서 나 는 픽 셀 마다 빈 칸 을 꽂 았 지만 사실은 없 었 다.X 는 4 의 배 수 를 채 워 자동 으로 삽 입 된 바이트 입 니 다.인간 의 읽 기 습관 에 맞 게 나 는 줄 을 나 누 었 다. 사실은 컴퓨터 메모리 에서 연속 적 인 단락 으로 봐 야 한다.
    |-------Stride-----------|  |-------Width---------| |  Scan0:  BGR BGR BGR BGR BGR BGR XX  BGR BGR BGR BGR BGR BGR XX  BGR BGR BGR BGR BGR BGR XX  .  .  .
        먼저 data. scan 0 으로 0 번 째 픽 셀 의 0 번 째 분량 의 주 소 를 찾 습 니 다. 이 주 소 는 byte 형식 을 가리 키 기 때문에 byte * ptr 로 정의 되 었 습 니 다.스 캔 을 할 때 현재 포인터 위치 (현재 픽 셀 의 0 번 째 색 분량 으로 보 셔 도 좋 습 니 다) 에서 3 개의 값 (3 개의 원색 분량) 을 연속 으로 꺼 냅 니 다. 주의 하 세 요. 0.12 대표 순 서 는 B G R 입 니 다. 포인터 가 가리 키 는 값 을 취 할 때 p [n] 과 p + = n 재 취 p [0] 은 등가 인 것 같 습 니 다. 그리고 3 개의 위치 (ptr + = 3, 다음 픽 셀 의 0 번 째 색 분량 으로 보 입 니 다) 를 내 립 니 다.Bitmap. Width 를 한 번 조작 한 후에 Bitmap. Width * 3 의 위치 에 도 착 했 습 니 다. 그림 에 X 로 표 시 된 바이트 (모두 Stride - Width * 3 바이트) 를 건 너 뛰 어야 합 니 다. 코드 에 ptr + = dataIn. Stride - dataIn. Width * 3 이 있 습 니 다.
        본 고 를 읽 으 면서 C \ # 를 사용 하여 이미지 처 리 를 하 는 데 사용 할 수 있 는 몇 가지 방법 에 대해 알 게 되 었 다 고 믿 습 니 다.어떤 방식 을 채택 하 느 냐 는 너의 성능 요구 에 달 려 있다.그 중에서 첫 번 째 방식 이 가장 우아 하 다.세 번 째 방식 이 가장 빠 르 지만 안전 코드 가 아 닙 니 다.두 번 째 방식 은 절충 을 해서 안전 코드 임 을 보증 하 는 동시에 효율 도 높 였 다.C / C + + 프로 그래 밍 을 잘 아 는 사람 은 세 번 째 방식 에 치 우 칠 수 있 습 니 다. 저도 개인 적 으로 세 번 째 방식 을 좋아 합 니 다.

    좋은 웹페이지 즐겨찾기