2009-02-01 96 views
7

我正在尋找一個解決方案從c#管理的GDI +庫檢測c#位圖的邊緣空白c#GDI邊緣空白檢測算法

的圖像將是要麼透明白色,大部分400X的圖片是與8000x8000px周圍的邊緣大約2000像素的空格。

什麼是尋找邊緣的最有效方式,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 - 這將需要一個不安全的代碼塊 - 如果你不希望這樣,或者你沒有FullTrust可以使用的伎倆解釋這裏: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)找到頂部和底部的限制。這種方式應該非常快。