4

画像のフォーカス値を計算するコードを書きました。ただし、完了までに 5 秒以上かかります。

 public double GetFValue(Image image)
        {
            Bitmap source = new Bitmap(image);
            int count = 0;
            double total = 0;
            double totalVariance = 0;
            double FM = 0;
             Bitmap bm = new Bitmap(source.Width, source.Height);
             Rectangle rect = new Rectangle(0,0,source.Width,source.Height);
              Bitmap targetRect = new Bitmap(rect.Width, rect.Height);

            // converting to grayscale
            for (int y = 0; y < source.Height; y++)
            {
                for (int x = 0; x < source.Width; x++)
                {
                    count++;
                    Color c = source.GetPixel(x, y);
                    int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
                    source.SetPixel(x, y, Color.FromArgb(luma, luma, luma)); // the image is now gray scaled 
                    var pixelval = source.GetPixel(x, y);
                  //  targetRect.Save(@"C:\Users\payam\Desktop\frame-42-rectangle.png", System.Drawing.Imaging.ImageFormat.Png);
                    int pixelValue = pixelval.G;
                    total += pixelValue;
                    double avg = total / count;
                    totalVariance += Math.Pow(pixelValue - avg, 2);
                    double stDV = Math.Sqrt(totalVariance / count); // the standard deviation, which is also the focus value
                    FM = Math.Round(stDV, 2);
                }
            }
            return FM;
        }

このコードを並列計算に変換しようとしています。頭が追いつかないバグに行き着きます。なにか提案を?

  public double CalculateFvalue (Image image)
    {
        Bitmap myimage = new Bitmap(image);
        int count = 0;
        int total = 0;
        double totalVariance = 0;
        double FM = 0;
        Parallel.For(0, image.Height, y =>
            {

            for (int x = 0; x < myimage.Width; x++)
                   {
                           count++;
                           Color c = myimage.GetPixel(x, y);
                           int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
                           myimage.SetPixel(x, y, Color.FromArgb(luma, luma, luma)); // the image is now gray scaled 
                           var pixelval = myimage.GetPixel(x, y);
                           int pixelValue = pixelval.G;
                           total += pixelValue;
                           double avg = total / count;
                           totalVariance += Math.Pow(pixelValue - avg, 2);
                           double stDV = Math.Sqrt(totalVariance / count); // the standard deviation, which is also the focus value
                           FM = Math.Round(stDV, 2);
                   }


    });

        return Math.Round(FM,2);
    }
4

2 に答える 2

7

これは、 のスコープ外で宣言した変数が原因で発生しますParallel.For。それらのアクセス (および書き込み) は非決定論的であるため、値が間違ったデータ ( などFM) で上書きされる可能性があります。

すべての反復でその結果に関する情報が得られるようにし、収集したデータを使用して外部の変数をスレッドセーフな方法で操作することをお勧めします。lockいくつかのステートメントを使用して回避することもできますが、個人的にはそれを避けます。

于 2012-12-21T18:46:39.850 に答える
2

私のコメントを拡張するには、GetPixel を並行して実行しないでください。代わりに lockBits を使用してください。

ロックビットを使用したコード:

    public double GetFValue(Image image)
    {
        Bitmap source = new Bitmap(image);
        int count = 0;
        double total = 0;
        double totalVariance = 0;
        double FM = 0;
        Bitmap bm = new Bitmap(source.Width, source.Height);
        Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
        //Bitmap targetRect = new Bitmap(rect.Width, rect.Height);

        //new
        ///*
        BitmapData bmd = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
        int[] pixelData = new int[(rect.Height * rect.Width) -1];
        System.Runtime.InteropServices.Marshal.Copy(bmd.Scan0, pixelData, 0, pixelData.Length);

        for (int i = 0; i < pixelData.Length; i++)
        {
            count++;
            Color c = Color.FromArgb(pixelData[i]);
            int luma = (int)(c.R * 0.3 + c.G * 0.59 + c.B * 0.11);
            //Probably a formula for this
            pixelData[i] = Color.FromArgb(luma, luma, luma).ToArgb(); 
            total += luma;
            double avg = total / count;
            totalVariance += Math.Pow(luma - avg, 2);
            double stDV = Math.Sqrt(totalVariance / count);
            FM = Math.Round(stDV, 2);
        }
        source.UnlockBits(bmd);
        return FM;
     }

win7 のサンプル画像 (Chrysanthemum.jpg) からの 1024 x 768 jpg を使用した簡単なテスト:

ロックビット: 241 ミリ秒

getPixel: 2208 ミリ秒

コードを変換するときに、いくつかの奇妙なことに気付きました (同じピクセルの getpixel、setpixel、getpixel など)。

于 2012-12-21T21:11:17.337 に答える