2009-02-01 70 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)找到顶部和底部的限制。这种方式应该非常快。