2013-05-25 24 views
1

나는 엣지 검출 알고리즘을 구현 한 프로그램을 만든다. 하지만 프로세스에 시간이 오래 걸립니다. getpixel 및 setpixel 대신 lockbits 및 안전하지 않은 상태 사용에 대해 읽었지만 여전히 사용 방법을 알고 있습니다.Lockbit를 사용한 엣지 검출 C#

이 내 예제 코드입니다 : 내가 fastbitmap 클래스를 사용하고, 나는 이런 식으로 구현

private Bitmap SobelEdgeDetect(Bitmap original) 
     { 
      Bitmap b = original; 
      Bitmap bb = original; 
      int width = b.Width; 
      int height = b.Height; 
      int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; 
      int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }; 

      int[,] allPixR = new int[width, height]; 
      int[,] allPixG = new int[width, height]; 
      int[,] allPixB = new int[width, height]; 

      int limit = 128 * 128; 

      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        allPixR[i, j] = b.GetPixel(i, j).R; 
        allPixG[i, j] = b.GetPixel(i, j).G; 
        allPixB[i, j] = b.GetPixel(i, j).B; 
       } 
      } 

      int new_rx = 0, new_ry = 0; 
      int new_gx = 0, new_gy = 0; 
      int new_bx = 0, new_by = 0; 
      int rc, gc, bc; 
      for (int i = 1; i < b.Width - 1; i++) 
      { 
       for (int j = 1; j < b.Height - 1; j++) 
       { 

        new_rx = 0; 
        new_ry = 0; 
        new_gx = 0; 
        new_gy = 0; 
        new_bx = 0; 
        new_by = 0; 
        rc = 0; 
        gc = 0; 
        bc = 0; 

        for (int wi = -1; wi < 2; wi++) 
        { 
         for (int hw = -1; hw < 2; hw++) 
         { 
          rc = allPixR[i + hw, j + wi]; 
          new_rx += gx[wi + 1, hw + 1] * rc; 
          new_ry += gy[wi + 1, hw + 1] * rc; 

          gc = allPixG[i + hw, j + wi]; 
          new_gx += gx[wi + 1, hw + 1] * gc; 
          new_gy += gy[wi + 1, hw + 1] * gc; 

          bc = allPixB[i + hw, j + wi]; 
          new_bx += gx[wi + 1, hw + 1] * bc; 
          new_by += gy[wi + 1, hw + 1] * bc; 
         } 
        } 
        if (new_rx * new_rx + new_ry * new_ry > limit || new_gx * new_gx + new_gy * new_gy > limit || new_bx * new_bx + new_by * new_by > limit) 
         bb.SetPixel(i, j, Color.Black); 


        else 
         bb.SetPixel(i, j, Color.Transparent); 
       } 
      } 
      return bb; 
     } 

:

private Bitmap SobelEdgeDetectTwo(Bitmap original) 
     { 
      int width = original.Width; 
      int height = original.Height; 
      Bitmap result = new Bitmap(width,height); 
      FastBitmap b = new FastBitmap(original); 
      FastBitmap bb = new FastBitmap(result); 

      b.LockBitmap(); 
      bb.LockBitmap(); 

      int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; 
      int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }; 

      int[,] allPixR = new int[width, height]; 
      int[,] allPixG = new int[width, height]; 
      int[,] allPixB = new int[width, height]; 

      int limit = 128 * 128; 

      for (int i = 0; i < width; i++) 
      { 
       for (int j = 0; j < height; j++) 
       { 
        var pixel = b.GetPixel(i,j); 
        allPixR[i, j] = pixel.Red; 
        allPixG[i, j] = pixel.Green; 
        allPixB[i, j] = pixel.Blue; 

       } 
      } 

      int new_rx = 0, new_ry = 0; 
      int new_gx = 0, new_gy = 0; 
      int new_bx = 0, new_by = 0; 
      int rc, gc, bc; 
      for (int i = 1; i < width - 1; i++) 
      { 
       for (int j = 1; j < height - 1; j++) 
       { 

        new_rx = 0; 
        new_ry = 0; 
        new_gx = 0; 
        new_gy = 0; 
        new_bx = 0; 
        new_by = 0; 
        rc = 0; 
        gc = 0; 
        bc = 0; 

        for (int wi = -1; wi < 2; wi++) 
        { 
         for (int hw = -1; hw < 2; hw++) 
         { 
          rc = allPixR[i + hw, j + wi]; 
          new_rx += gx[wi + 1, hw + 1] * rc; 
          new_ry += gy[wi + 1, hw + 1] * rc; 

          gc = allPixG[i + hw, j + wi]; 
          new_gx += gx[wi + 1, hw + 1] * gc; 
          new_gy += gy[wi + 1, hw + 1] * gc; 

          bc = allPixB[i + hw, j + wi]; 
          new_bx += gx[wi + 1, hw + 1] * bc; 
          new_by += gy[wi + 1, hw + 1] * bc; 
         } 
        } 

        if (new_rx * new_rx + new_ry * new_ry > limit || new_gx * new_gx + new_gy * new_gy > limit || new_bx * new_bx + new_by * new_by > limit) 
        { 
         PixelData p = new PixelData(Color.Black); 
         bb.SetPixel(i, j, p); 

        } 
        else 
        { 
         PixelData p = new PixelData(Color.Transparent); 
         bb.SetPixel(i, j, p); 

        } 

       } 
      } 


      b.UnlockBitmap(); 
      bb.UnlockBitmap(); 

      return result; 
     } 

을하지만, 이미지가 전혀 변경되지 않습니다. 내 코드의 어느 부분이 실수인지 조언 해 주시겠습니까?

답변

3

FastBitmap과 같은 클래스를 사용하는 것이 가장 쉽습니다. FastBitmap을 추가하고 비트 맵 대신 GetPixel()을 사용하면 나머지는 동일 할 수 있습니다. 이 같은

뭔가 :

Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat); 
FastBitmap fastBitmap = new FastBitmap(dstBmp); 
fastBitmap.LockBitmap(); 
//... 
var pixel = fastBitmap.GetPixel(x,y); 
//... 
fastBitmap.UnlockBitmap(); 
+0

+1. FastBitmap 주셔서 감사합니다. Bitmap.GetPixel의 끔찍한 감속을 발견 한 후 항상 수동으로 LockBits를 사용했습니다. – Samuel

+0

나는 도형을 오래 전에 그리는 프로그램을 만들었습니다. 예, Set 및 GetPixel은 매우 느립니다. 그러나 FastBitmap과 같은 클래스를 사용하면 쉽게 해결할 수 있습니다. 포인터 로직을 숨 깁니다. – Carra

+0

오류에 대한 내 문제가 해결되었습니다. 위의 함수에 FastBitmap 클래스를 구현할 수 있지만 이미지가 전혀 변경되지 않습니다. – christ2702

3

좋아, 이제 우리가 무엇을 할 수 있는지 보자 - 빠른 구글은 단순히이

private Bitmap SobelEdgeDetect(Bitmap original) 
{ 
    int width = original.Width; 
    int height = original.Height; 

    int BitsPerPixel = Image.GetPixelFormatSize(original.PixelFormat); 
    int OneColorBits = BitsPerPixel/8; 

    BitmapData bmpData = original.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, original.PixelFormat); 
    int position; 
    int[,] gx = new int[,] { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } }; 
    int[,] gy = new int[,] { { 1, 2, 1 }, { 0, 0, 0 }, { -1, -2, -1 } }; 
    byte Threshold = 128; 

    Bitmap dstBmp = new Bitmap(width, height, original.PixelFormat); 
    BitmapData dstData = dstBmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, dstBmp.PixelFormat); 

    unsafe 
    { 
     byte* ptr = (byte*)bmpData.Scan0.ToPointer(); 
     byte* dst = (byte*)dstData.Scan0.ToPointer(); 

     for (int i = 1; i < height - 1; i++) 
     { 
      for (int j = 1; j < width - 1; j++) 
      { 
       int NewX = 0, NewY = 0; 

       for (int ii = 0; ii < 3; ii++) 
       { 
        for (int jj = 0; jj < 3; jj++) 
        { 
         int I = i + ii - 1; 
         int J = j + jj - 1; 
         byte Current = *(ptr + (I * width + J) * OneColorBits); 
         NewX += gx[ii, jj] * Current; 
         NewY += gy[ii, jj] * Current; 
        } 
       } 
       position = ((i * width + j) * OneColorBits); 
       if (NewX * NewX + NewY * NewY > Threshold * Threshold) 
        dst[position] = dst[position + 1] = dst[position + 2] = 255; 
       else 
        dst[position] = dst[position + 1] = dst[position + 2] = 0; 
      } 
     } 
    } 
    original.UnlockBits(bmpData); 
    dstBmp.UnlockBits(dstData); 

    return dstBmp; 
} 

그것은이 완료되지 복사/붙여 넣기 솔루션입니다하지만 당신은 할 수 있어야처럼 기능 무언가에 적용 할 수 있습니다 this를 발견 LockBits을 사용하여 원래 작성자가 픽셀 데이터에 액세스하는 방법을 확인하십시오. 나머지는 당신에게 달려 있습니다 ;-)

이전 질문에 my answer으로 설명했듯이 프로젝트 속성에 unsafe 옵션을 설정해야합니다.

+0

좋아, 나는 그것을 시도 할 것이다. 덕분에 – christ2702

+0

마침내 구현할 수 있습니다. 하지만 '투명'대신 항상 '흰색'색상이 표시됩니다. 이 문제를 해결하는 방법을 알려주십시오. 이미지 결과에 ColorTransparent를 사용하고 싶습니다. – christ2702