2013-05-25 7 views
1

Je crée un programme qui implémente un algorithme de détection de contour. mais cela prend beaucoup de temps pour le processus. J'ai lu à propos des verrous d'utilisation et de l'état non sécurisé au lieu de getpixel et setpixel, mais je comprends toujours comment l'utiliser.Détection de contours avec Lockbits C#

c'est mon exemple de code:

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; 
     } 

je suis en utilisant la classe fastbitmap, et je mets en œuvre comme ceci:

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; 
     } 

mais l'image ne change pas du tout. pourriez-vous me donner un conseil sur la partie de mon code qui était une erreur?

Répondre

3

Il est plus facile d'utiliser une classe comme FastBitmap. Ajoutez simplement un FastBitmap et utilisez GetPixel() sur cette classe plutôt que sur votre Bitmap, le reste peut être le même.

Quelque chose comme ceci:

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. Merci pour FastBitmap. Toujours utilisé LockBits manuellement après avoir découvert le ralentissement terrible de Bitmap.GetPixel – Samuel

+0

J'ai fait un programme qui dessine des fractales tout à l'heure et a découvert que oui, Set et GetPixel sont incroyablement lent. Mais il est facile de le contourner avec une classe comme FastBitmap, et il cache la logique du pointeur :) – Carra

+0

J'ai résolu mon problème à propos de l'erreur. Je peux implémenter la classe FastBitmap à ma fonction ci-dessus, mais l'image ne change pas du tout. – christ2702

3

Ok, nous allons voir ce que nous pouvons faire - un rapide sur Google trouvé this, qui peut être simplement adaptée à votre fonction quelque chose comme ça

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; 
} 

Ce n'est pas la solution copier/coller complète mais vous devriez être en mesure de voir comment l'auteur d'origine accède aux données de pixel en utilisant LockBits exactement comme vous le souhaitez. Le reste dépend de vous ;-)

Vous devrez définir l'option unsafe dans les propriétés de votre projet comme expliqué dans my answer à votre question précédente.

+0

D'accord, je vais essayer. merci – christ2702

+0

enfin, je peux l'implémenter. mais, j'ai toujours la couleur «blanche» au lieu de «transparent». pouvez-vous m'aider à résoudre ce problème? Je veux utiliser Color.Transparent dans le résultat de l'image – christ2702

Questions connexes