2010-06-10 16 views
2

Je modifie les valeurs de couleur de chaque pixel d'une image en fonction d'un calcul. Le problème est que cela prend plus de 5 secondes sur ma machine avec une image 1000x1333 et je cherche un moyen de l'optimiser pour être beaucoup plus rapide.Comment utiliser les valeurs chromatiques calculées avec ColorMatrix?

Je pense que ColorMatrix peut être une option, mais j'ai du mal à comprendre comment j'obtiendrais un ensemble de valeurs RVB de pixels, utilisez-le pour calculer et ensuite définir la nouvelle valeur de pixel. Je peux voir comment cela peut être fait si je modifiais (en multipliant, soustrayant, etc.) la valeur d'origine avec ColorMatrix, mais maintenant comment je peux utiliser la valeur retournée par les pixels pour l'utiliser et calculer une nouvelle valeur.

Par exemple:

Sub DarkenPicture() 
    Dim clrTestFolderPath = "C:\Users\Me\Desktop\ColorTest\" 
    Dim originalPicture = "original.jpg" 
    Dim Luminance As Single 
    Dim bitmapOriginal As Bitmap = Image.FromFile(clrTestFolderPath + originalPicture) 
    Dim Clr As Color 
    Dim newR As Byte 
    Dim newG As Byte 
    Dim newB As Byte 
    For x = 0 To bitmapOriginal.Width - 1 
     For y = 0 To bitmapOriginal.Height - 1 
      Clr = bitmapOriginal.GetPixel(x, y) 
      Luminance = ((0.21 * (Clr.R) + (0.72 * (Clr.G)) + (0.07 * (Clr.B))/ 255 
      newR = Clr.R * Luminance 
      newG = Clr.G * Luminance 
      newB = Clr.B * Luminance 
      bitmapOriginal.SetPixel(x, y, Color.FromArgb(newR, newG, newB)) 
     Next 
    Next 
    bitmapOriginal.Save(clrTestFolderPath + "colorized.jpg", ImageFormat.Jpeg) 
End Sub 

La valeur Luminance est celle calculée. Je sais que je peux mettre ColorMatrix de M00, M11, M22 à 0, 0, 0 respectivement, puis mettre une nouvelle valeur dans M40, M41, M42, mais cette nouvelle valeur est calculée sur la base d'une multiplication de valeur et l'addition des composants de ce pixel (((0.21 * (Clr.R) + (0.72 * (Clr.G)) + (0.07 * (Clr.B)) et le résultat de cela - Luminance - est multiplié par le composant de couleur).

Est-ce encore possible avec ColorMatrix?

Répondre

3

Non. Il n'est pas possible de multiplier l'un des composants couleur avec lui-même ou avec un autre composant avec une ColorMatrix. Vous pouvez seulement multiplier les composants avec des constantes et ensuite ajouter les parties ensemble.

Mais ce que peut est d'écrire ceci en C# et d'utiliser .LockBits au lieu de GetPixel/SetPixel. Ce serait encore plus rapide que ce que vous pourriez réaliser avec un ColorMatrix.

MISE À JOUR: un exemple de code:

private static void myVerySpecialSepia(
     IntPtr source, 
     IntPtr destination, 
     int height, 
     int width, 
     int sourceStride, 
     int destinationStride, 
     int sourceBytesPerPixel, 
     int destinationBytesPerPixel) 
    { 
     unsafe 
     { 
      for (int y = 0 ; y < height ; y++) 
      { 
       byte* pOrig = (byte*)source.ToPointer() + sourceStride * y; 
       byte* pDest = (byte*)destination.ToPointer() + destinationStride * y; 
       for (int x = width ; x > 0 ; x--) 
       { 
        float b = pOrig[0]; 
        float g = pOrig[1]; 
        float r = pOrig[2]; 
        float b2 = b * b; 
        float g2 = g * g; 
        float r2 = r * r; 
        pDest[0] = (byte)(
         b * 0.400367618f + b2 * 0.00011502471f + 
         g * (-0.0337239578f) + g2 * 0.00056673412f + 
         r * 0.221445322f + r2 * 0.0008506606f + 
         6.2766808485f); 
        pDest[1] = (byte)(
         b * 0.493460029f + b2 * (-0.00023297003f) + 
         g * (-0.008577178f) + g2 * 0.00031247039f + 
         r * 0.5043012 + r2 * (-0.00006892065f) + 
         0.2746957206f); 
        pDest[2] = (byte)(
         b * 0.617727f + b2 * (-0.00070876251f) + 
         g * 0.00271902746f + g2 * 0.00007401942f + 
         r * 0.6954346f + r2 * (-0.00065937551f) + 
         0.116103285f); 
        pOrig += sourceBytesPerPixel; 
        pDest += destinationBytesPerPixel; 
       } 
      } 
     } 
    } 
+0

merci, je vais vérifier cela. J'utilise VB.NET, donc je comprends que le marshalling n'est pas aussi rapide en VB que le lock/unlockbits en C#. Je vais essayer de faire fonctionner cela. –

+1

Vous pouvez ajouter un projet C# à votre solution VB.Net et ajouter simplement cette méthode critique unique à l'appel de votre code VB. Je suppose que vous obtiendriez quelque part une amélioration de la vitesse de 30 fois. –