2012-06-28 1 views
3

Я хочу сравнить альфа-канал с одного изображения на ~ 1000 других изображений. Мой сравнивать метод выглядит следующим образом:Можно ли распараллелить обработку изображений с помощью PLINQ?

public static unsafe double Similiarity (Bitmap a, Bitmap b) 
{ 
    BitmapData aData = a.LockBits (
     new Rectangle (0, 0, a.Width, a.Height), 
     System.Drawing.Imaging.ImageLockMode.ReadOnly, a.PixelFormat); 
    BitmapData bData = b.LockBits (
     new Rectangle (0, 0, b.Width, b.Height), 
     System.Drawing.Imaging.ImageLockMode.ReadOnly, b.PixelFormat); 
    int PixelSize = 4; 

    double sum = 0; 
    for (int y=0; y<aData.Height; y++) { 
     byte* aRow = (byte *)aData.Scan0 + (y * aData.Stride); 
     byte* bRow = (byte *)bData.Scan0 + (y * bData.Stride); 
     for (int x=0; x<aData.Width; x++) { 
      byte aWeight = aRow [x * PixelSize + 3]; 
      byte bWeight = bRow [x * PixelSize + 3]; 
      sum += Math.Abs (aWeight - bWeight); 
     } 
    } 
    a.UnlockBits (aData); 
    b.UnlockBits (bData); 

    return 1 - ((sum/255)/(a.Width * a.Height)); 
} 

Я думал, что самый простой способ ускорить вычисление будет с помощью PLINQ:

var list = from Bitmap img in imageList.AsParallel where (Similiarity (referenceImage, img) > 0.5) select img; 

Но об исполнении есть исключение в gdiplus:

System.InvalidOperationException: The operation is invalid [GDI+ status: Win32Error] 
    at System.Drawing.GDIPlus.CheckStatus (Status status) [0x00000] in <filename unknown>:0 
    at System.Drawing.Bitmap.LockBits (Rectangle rect, ImageLockMode flags, PixelFormat format, System.Drawing.Imaging.BitmapData bitmapData) [0x00000] in <filename unknown>:0 

Я понимаю, что gdiplus должен выполняться в разных процессах, но я думал, что PLINQ делает это. Что не так с моими предположениями?

+0

PLINQ, конечно, не используя различные способы исполнения. Он использует потоки. – svick

ответ

3

Я хотел бы предложить, чтобы отделить вычисление веса из сравнения сходства, как это:

public static unsafe byte[,] GetWeight(Bitmap a) 
{ 
    BitmapData aData = a.LockBits(new Rectangle(0, 0, a.Width, a.Height), ImageLockMode.ReadOnly, a.PixelFormat); 
    const int pixelSize = 4; 

    byte[,] weight = new byte[aData.Width, aData.Height]; 
    for (int y = 0; y < aData.Height; y++) 
    { 
     byte* aRow = (byte*)aData.Scan0 + (y * aData.Stride); 
     for (int x = 0; x < aData.Width; x++) 
     { 
      byte aWeight = aRow[x * pixelSize + 3]; 
      weight[x, y] = aWeight; 
     } 
    } 
    a.UnlockBits(aData); 
    return weight; 
} 

public static double GetSimilarity(byte[,] weightsA, byte[,] weightsB) 
{ 
    double sum = 0; 
    int height = weightsA.GetLength(1); 
    int width = weightsA.GetLength(0); 
    for (int y = 0; y < height; y++) 
    { 
     for (int x = 0; x < width; x++) 
     { 
      byte aWeight = weightsA[x,y]; 
      byte bWeight = weightsB[x, y]; 
      sum += Math.Abs(aWeight - bWeight); 
     } 
    } 

    return 1 - ((sum/255)/(width * height)); 
} 

сам вызов будет выглядеть следующим образом:

var referenceWeigth = GetWeight(referenceImage);  
var list = 
     imageList 
      .AsParallel() 
      .Select(image => new {@Image = image, @Weight = GetWeight(image)}) 
      .Where(imageAndWeight => GetSimilarity(imageAndWeight.Weight, referenceWeigth) > 0.5) 
      .Select(imageAndWeight => imageAndWeight.Image); 
+1

Спасибо за предлагаемый код. Он работает так, как ожидалось, а также улучшил мое понимание LINQ. – Rodja

1

Я думаю, проблема может заключаться в том, что вы пытаетесь одновременно заблокировать одни и те же биты в разных потоках. Возможное решение (как вы только читаете) должно состоять в том, чтобы сначала извлечь биты из каждого растрового изображения и использовать эти массивы только для параллельного сравнения.

1

Проблема, которую я вижу в этом вопросе, заключается в том, что в то время как img взято из списка, referenceImage - тот же самый экземпляр, используемый в нескольких потоках, каждый из которых пытается его заблокировать.

Рассмотрите возможность блокировки эталонного изображения снаружи и передачи BitmapData.

 Смежные вопросы

  • Нет связанных вопросов^_^