2009-02-01 3 views
7

의 C# 관리되는 GDI + 라이브러리에서 C# 비트 맵의 ​​가장자리 공백을 감지하는 솔루션을 찾고 있습니다.C# GDI 가장자리 공백 검출 알고리즘

이미지 중 하나를 투명 또는 흰색이의 400 배 사진의 대부분의 가장자리 주위에 대한 2000px 공백으로 8000x8000px입니다 것입니다.

가장자리를 찾는 가장 효율적인 방법은 무엇입니까 x, y, 높이 및 너비 좌표는입니까? 나는 픽셀 단위로 픽셀을 시도했지만 매우 느린 것을 발견했다. 용액

업데이트 --Added 좌/우/상/하 경계 이미지 세부 센터 이미지

문제 지금 투명한 (0 %) 작물 또는 백색 (#FFFFFF) 픽셀.

var top = bitmap.Height; 
var left = bitmap.Width; 
var right = 0; 
var bottom = 0; 

...

var pData = pData0 + (y * data.Stride) + (x * 4); 
var xyAlpha = pData[3]; 
var xyBlue = pData[0]; 
var xyGreen = pData[1]; 
var xyRed = pData[2]; 
if ((xyAlpha > 0) || (xyRed != 255 && xyGreen != 255 && xyBlue != 255)) { 
    if (y < top) 
     top = y; 
    if (y > bottom) 
     bottom = y; 
    if (x < left) 
     left = x; 
    if (x > right) 
     right = x; 
} 

...

var cropWidth = right - left; 
var cropHeight = bottom - top; 
var cropX = top; 
var cropY = left; 

var cacheBitmap = new Bitmap(cropWidth, cropHeight, PixelFormat.Format32bppArgb); 
using (var cacheGraphics = Graphics.FromImage(cacheBitmap)) { 
    cacheGraphics.DrawImage(context.Image, new Rectangle(0, 0, cropWidth, cropHeight), cropX, cropY, cropWidth, cropHeight, GraphicsUnit.Pixel); 
} 

답변

9

큰 GDI + 자원 Bob Powells GDI+ FAQ입니다!

이미지의 픽셀에 어떻게 접근했는지 말하지 않았으므로 느린 GetPixel 메서드를 사용했다고 가정합니다. 당신은 빠른 방법으로 픽셀에 액세스하는 포인터와 LockBits를 사용할 수 있습니다 see Bob Powells explanation of LockBits - 이것은 안전하지 않은 코드 블록이 필요합니다 - 당신이 원하지 않는 경우 또는 사용할 수있는 완전 신뢰 당신이 트릭은 여기에서 설명하지 않아도 : Pointerless Image Processing in .NET by J. Dunlap

아래 코드는 LockBits 접근 방식 (PixelFormat.Format32bppArgb)을 사용하고 인수 색상으로 설명 된 색상이없는 이미지의 첫 번째 및 마지막 픽셀이 발견 된 값으로 시작 및 끝점을 채 웁니다. 또한이 메소드는 완전히 투명한 픽셀을 무시하므로 보이는 '내용'이 시작되는 이미지의 영역을 감지하려는 경우 유용합니다.

Point start = Point.Empty; 
    Point end = Point.Empty; 

    int bitmapWidth = bmp.Width; 
    int bitmapHeight = bmp.Height; 

    #region find start and end point 
    BitmapData data = bmp.LockBits(new Rectangle(0, 0, bitmapWidth, bitmapHeight), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); 
    try 
    { 
     unsafe 
     { 
      byte* pData0 = (byte*)data.Scan0; 
      for (int y = 0; y < bitmapHeight; y++) 
      { 
       for (int x = 0; x < bitmapWidth; x++) 
       { 
        byte* pData = pData0 + (y * data.Stride) + (x * 4); 

        byte xyBlue = pData[0]; 
        byte xyGreen = pData[1]; 
        byte xyRed = pData[2]; 
        byte xyAlpha = pData[3]; 


        if (color.A != xyAlpha 
          || color.B != xyBlue 
          || color.R != xyRed 
          || color.G != xyGreen) 
        { 
         //ignore transparent pixels 
         if (xyAlpha == 0) 
          continue; 
         if (start.IsEmpty) 
         { 
          start = new Point(x, y); 
         } 
         else if (start.Y > y) 
         { 
          start.Y = y; 
         } 
         if (end.IsEmpty) 
         { 
          end = new Point(x, y); 
         } 
         else if (end.X < x) 
         { 
          end.X = x; 
         } 
         else if (end.Y < y) 
         { 
          end.Y = y; 
         } 
        } 
       } 
      } 
     } 
    } 
    finally 
    { 
     bmp.UnlockBits(data); 
    } 
    #endregion 
2

패트릭 (Patrick)이 설명한 LockBits 메서드를 사용해야합니다. 둘째, 가운데 선의 픽셀을 확인하여 가장자리를 빠르게 결정합니다. 중간 선으로 말하면 2000x1000 이미지를 예로 들면 수평 라인 번호 500 (1000 개 중 하나)을보고 왼쪽 및 오른쪽 제한을 ​​찾은 다음 세로 라인 번호 1000 (2000 개 중)을 찾습니다. 상단 및 하단 제한을 찾을 수 있습니다. 이 방법은 매우 빠릅니다.