我编写了一个计算图像焦点值的代码。但这需要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);
}
答案 0 :(得分:7)
这是因为您在Parallel.For
范围之外声明的变量。由于它们的访问(和写入)是非确定性的,您可能会使用错误的数据(例如FM
)覆盖值。
我建议你让每次迭代产生有关其结果的信息,然后使用收集的数据以线程安全的方式操纵你的变量。您也可以使用一些lock
语句来逃避它,但我个人会避免这种情况。
答案 1 :(得分:1)
要扩展我的评论,请不要尝试并行运行GetPixel,而是使用lockBits。
使用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示例图片中的1024 x 768 jpg快速测试(Chrysanthemum.jpg):
lockbits:241毫秒
getPixel:2208毫秒
注意转换代码时我注意到一些奇怪的东西(比如getpixel,setpixel,getpixel在同一个像素上?)但是我想你知道你想要实现什么,而且这段代码完全相当于你的代码