c\#에서 이미지 그 레이스 케 일 기술 에 대한 상세 한 설명 실현

작년 에 디지털 이미지 처리 알고리즘 을 샀 는데 계속 보지 않 았 습 니 다.몇 주 전에 일 하 느 라 바 빴 습 니 다.이 단 계 를 틈 타 여 유 롭 게 사진 처 리 를 하 는 것 도 재 미 있 었 습 니 다.
예전 에 저희 가 웹 에 있 는 사용자 등록 을 할 때 보통 인증 코드 를 만 들 었 습 니 다.모두 가 폭력 등록 을 방지 하 는 데 사용 되 는 것 을 알 고 있 습 니 다.물론 인증 코드 를 언급 하면 모두 가 C\#안에 비트 맵 류 가 그림 을 처리 하 는 데 사용 되 는 것 을 알 고 있 습 니 다.좋 습 니 다.이 편 은 가장 간단 한'그림 그 레이스 케 일'부터 시작 하 겠 습 니 다.
그림 그 레이스 케 일
우 리 는 모두 비트 맵 이 하나의 픽 셀 점 으로 구성 되 어 있다 는 것 을 알 고 있다.픽 셀 점 은 빨간색,오렌지색,분홍색 등 일 수 있다.이런 색 들 은 우리 가 모두 RGB 로 표시 한 것 을 안다.
각 색상 의 분량 은 하나의 바이트(0-255)이기 때문에 일반적인 상황 에서 그림 의 픽 셀 점 은 24 자리 입 니 다.물론 32 자리,64 자리 도 있 습 니 다.RGB 가 0-255 사이 의 다른 값 일 때 이 픽 셀 점 은'알록달록'을 나타 내 고 RGB 가 같은 값 일 때 는 소점 처럼'회색'을 나타 내 며 CSS 를 해 보 셨 다 면...한 글자 에 주 는 color 는 보통\#9999999,\#666666,\#3333333 등 깊이 가 다른 회색 이라는 것 을 잘 알 고 있 을 것 이다.
1.계산 공식
다음은 합 리 적 인 그 레이스 케 일 값 을 어떻게 설정 해 야 합 니까?물론 현재 의 RGB 를 모델 로 하고 RGB 에 합 리 적 인 가중치 를 곱 하면 ok 입 니 다.

   Gary(i,j)=0.299*R(i,j)+0.587*G(i,j)+0.114*B(i,j);
2.프로 그래 밍
공식 이 있 으 면 실현 하 는 것 은 문제 가 되 지 않 는 다.Bitmap 클래스 에는 GetPixel/SetPixel 이 있 습 니 다.현재 픽 셀 점 을 가 져 오고 설정 할 수 있 습 니 다.

static void Main(string[] args)
{
  Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");
 
  for (int i = 0; i < bitmap.Width; i++)
  {
    for (int j = 0; j < bitmap.Height; j++)
    {
      //         
      var color = bitmap.GetPixel(i, j);
 
      var gray = (int)(color.R * 0.299 + color.G * 0.587 + color.B * 0.114);
 
      //          
      bitmap.SetPixel(i, j, Color.FromArgb(gray, gray, gray));
    }
  }
 
  bitmap.Save(Environment.CurrentDirectory + "//2.jpg");
}

3.개선
위의 방법 은 매우 간단 합 니 다.Get/Set 은 Ok 입 니 다.물론 이것 은 우리 가 화소 점 이라는 각도 에서 문 제 를 고려 하 는 것 입 니 다.O(N2)의 시간 만 있 으 면 KO 문 제 를 해결 할 수 있 을 것 같 습 니 다.그러나 Get/Set 은 O(1)가 아 닙 니 다.성능 을 고려 하면 우 리 는 더 좋 은 방법 이 있 을 수 있 습 니까?이때 우 리 는 바이트 라 는 각도 에서 생각 할 수 있 습 니 다.그러나 여기 서 우리 가 주의해 야 할 문 제 는 그림 의 width=21px 이다.하나의 픽 셀 점 은 3 개의 바이트 를 차지 하지만 21 개의 픽 셀 점 이 반드시 63 개의 바이트 를 차지 하 는 것 은 아니다.이것 은 시스템 이 성능 을 고려 하여 각 줄 에'사용 되 지 않 는 구역'을 저장 하여 그림 각 줄 의 byte 수가 4 의 배수 임 을 확보 하기 때문이다.그러면 어떻게 한 줄 의 바이트 수 를 읽 을 수 있 습 니까?
C\#안에 Stride 속성 이 하나 있 으 면 얻 을 수 있 습 니 다.간단 하 죠?

static void Main(string[] args)
    {
      Bitmap bitmap = new Bitmap(Environment.CurrentDirectory + "//1.jpg");
 
      //    bitmap rect       
      Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
 
      //      
      var bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, bitmap.PixelFormat);
 
      //      
      var ptr = bitmapData.Scan0;
 
      //stride:   
      int len = bitmapData.Stride * bitmap.Height;
 
      var bytes = new byte[len];
 
      //        copy byte   
      Marshal.Copy(ptr, bytes, 0, len);
 
      for (int i = 0; i < bitmap.Height; i++)
      {
        for (int j = 0; j < bitmap.Width * 3; j = j + 3)
        {
          var color = bytes[i * bitmapData.Stride + j + 2] * 0.299
                + bytes[i * bitmapData.Stride + j + 1] * 0.597
                + bytes[i * bitmapData.Stride + j] * 0.114;
 
          bytes[i * bitmapData.Stride + j]
               = bytes[i * bitmapData.Stride + j + 1]
               = bytes[i * bitmapData.Stride + j + 2] = (byte)color;
        }
      }
 
      //copy   
      Marshal.Copy(bytes, 0, ptr, len);
 
      //  
      bitmap.UnlockBits(bitmapData);
 
      bitmap.Save(Environment.CurrentDirectory + "//3.jpg");
    }

좋은 웹페이지 즐겨찾기