2009-02-01 11 views
7

Sto cercando una soluzione per che rileva lo spigolo del bordo di C# bitmap, dalla libreria GDI + gestita in C#.C# GDI Algoritmo di rilevamento degli spazi bianchi GDI

Le immagini sarebbe o trasparente o bianco, la maggior parte delle immagini 400x sono 8000x8000px con circa 2000px spazi intorno ai bordi.

Quale sarebbe il modo più efficace per scoprire i bordi, x, y, coordinate di altezza e larghezza? Ho provato ad andare pixel per pixel, ma lo trovavo molto lento.

Update per soluzione --Added sinistra/destra/alto/limiti inferiori

Problemi con fotografie dettaglio immagini centro, ora coltivazioni qualsiasi trasparente (0%) o bianco pixel (#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); 
} 

risposta

9

Una grande risorsa GDI + è Bob Powells GDI+ FAQ!

Non hai detto come hai avuto accesso ai pixel nell'immagine, quindi presumo che tu abbia usato i metodi lenti di GetPixel. È possibile utilizzare puntatori e LockBits per accedere pixel in un modo più veloce: see Bob Powells explanation of LockBits - Ciò richiederà un blocco di codice non sicuro - se non si vuole questo o non si dispone di FullTrust è possibile utilizzare il trucco spiegato qui: Pointerless Image Processing in .NET by J. Dunlap

Il codice seguente utilizza l'approccio LockBits (per PixelFormat.Format32bppArgb) e riempirà i punti iniziale e finale con il valore in cui vengono scoperti il ​​primo e l'ultimo pixel di un'immagine che non hanno il colore descritto nel colore dell'argomento. Il metodo ignora anche i pixel completamente trasparenti che è utile se vuoi rilevare l'area di un'immagine in cui inizia il "contenuto" visibile.

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

Prima assicurarmi di utilizzare il metodo LockBits descritto da Patrick. Secondo, controllerei i pixel sulle linee centrali per determinare rapidamente i bordi. Con le linee di mezzo intendo, se si dice ad esempio un'immagine 2000x1000, si guarderebbe prima lungo la linea orizzontale numero 500 (su 1000) per trovare i limiti sinistro e destro, quindi lungo la linea verticale numero 1000 (fuori 2000) per trovare i limiti superiore e inferiore. Dovrebbe essere molto veloce in questo modo.

Problemi correlati