C# 将for循环转换为并行循环

C# 将for循环转换为并行循环,c#,for-loop,parallel-processing,C#,For Loop,Parallel Processing,我已经编写了一个代码来计算图像的焦点值。但这需要5秒钟以上的时间 public double GetFValue(Image image) { Bitmap source = new Bitmap(image); int count = 0; double total = 0; double totalVariance = 0; double FM = 0;

我已经编写了一个代码来计算图像的焦点值。但这需要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双GetFValue(Image)
{
位图源=新位图(图像);
整数计数=0;
双倍合计=0;
双总方差=0;
双FM=0;
位图bm=新位图(source.Width、source.Height);
矩形rect=新矩形(0,0,source.Width,source.Height);
位图targetRect=新位图(矩形宽度、矩形高度);
//转换为灰度
对于(int y=0;y
我正在尝试将此代码转换为并行计算。我最终被虫子缠住了,我的头无法绕过它们。有什么建议吗

  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);
    }
公共双计算值(图像)
{
位图myimage=新位图(图像);
整数计数=0;
int-total=0;
双总方差=0;
双FM=0;
Parallel.For(0,image.Height,y=>
{
对于(int x=0;x
这是因为您声明的变量超出了
Parallel.For
的范围。由于它们的访问(和写入)是不确定的,所以可能会用错误的数据(例如
FM
)覆盖值


我建议您让每个迭代产生关于其结果的信息,然后使用收集的数据以线程安全的方式在外部操纵变量。您也可以通过使用一些
lock
语句来避免这种情况,但我个人会避免这种情况。

要扩展我的评论,不要尝试并行运行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;
     }
public双GetFValue(Image)
{
位图源=新位图(图像);
整数计数=0;
双倍合计=0;
双总方差=0;
双FM=0;
位图bm=新位图(source.Width、source.Height);
矩形rect=新矩形(0,0,source.Width,source.Height);
//位图targetRect=新位图(矩形宽度、矩形高度);
//新的
///*
BitmapData bmd=source.LockBits(rect,ImageLockMode.ReadWrite,source.PixelFormat);
int[]pixelData=newint[(rect.Height*rect.Width)-1];
System.Runtime.InteropServices.Marshal.Copy(bmd.Scan0,pixelData,0,pixelData.Length);
对于(int i=0;i
在使用win7示例图片(jummery.jpg)中的1024 x 768 jpg的快速测试中:

锁位:241毫秒

getPixel:2208毫秒


注意:在转换代码时,我注意到一些奇怪的事情(如getpixel、setpixel、同一像素上的getpixel?),但我想你知道你想要实现什么,并且这段代码与你的代码完全相同

你看到的bug是什么?是的,你有大量的线程安全问题。但无论如何,getpixel非常慢,请查看锁位,而不是同时在不同线程上更新
count
total
FM
。您应该让每个循环迭代计算这些循环的局部值,然后在结束时将它们合并。谢谢,我将处理您的建议。将让您知道它是如何进行的。+1:还要确保在没有同步的情况下不要修改位图。当前代码以非线程安全方式使用
SetPixel
。(如前所述,如果性能有任何问题,则不应使用Get/Set pixel调用)。W