优化图像处理中均值和方差计算
一、均值和方差的普通优化
图像处理中,有时候会需要计算图像某区域的均值和方差。在我之前的博客中《图像比较之模板匹配》,对计算方差有做简化计算的介绍。详细介绍可以参考我之前的博文。在此,我简单的介绍下计算方差的简化方法:
按照上述方式计算均值和方差,很多应用场景下都比较合适。但是有两个缺陷:
- 如果均值远大于标准差,意味着方差计算中相减的两个数非常接近,将引入过度舍入的问题;
- 对于新增加一个统计变量重新计算其均值和方差的时候,需要对所有统计变量再重新计算,做了大量的重复工作,效率不高;
经过如下方法简化计算之后,如果新增一个变量计算全体统计变量均值和方差的时候,并不需要重新再对所有变量进行统计计算。只需要保存三个变量即可:当前统计变量数量;当前统计变量和;当前统计变量和平方和:
其BASIC语言实现方式为:
二、利用直方图信息优化均值和方差的计算
图像处理中,也常常会涉及到直方图。假若我们已知了某幅图像的直方图信息,那么我们还有更加简便有效的方式计算图像的均值和方差。我们知道图像直方图中每个bin中所代表的值是具有相同灰度值像素的数量,相当于把图像像素进行了分组统计。这就方便在计算均值和方差也可进行分组计算累加。因此,我们可以依据直方图的信息按照如下公式进行均值和方差的计算:
其BASIC语言实现为:
三、在OpenCV的简单应用
int main()
{
int dims = 1;
int sizes[] = {256};
int type = CV_HIST_ARRAY;
float range[] = {0,255};
float *ranges[] = {range};
CvHistogram *hist = NULL;
IplImage *src_img;
CvScalar Avg,Std;
int i,count;
double Avg_Hist = 0,Std_Hist = 0;
src_img = cvLoadImage("8Bit_lena.bmp",-1);
if(src_img == NULL)
{
printf("wrong input pic\n");
return -1;
}
hist = cvCreateHist(dims,sizes,type,ranges,1);
cvCalcHist(&src_img,hist,0,NULL);
count = src_img->width*src_img->height;
for(i = 0;i < 256;i++)
Avg_Hist += i*cvQueryHistValue_1D(hist,i);
Avg_Hist = Avg_Hist/count;
printf("Avg from hist:%f\n",Avg_Hist);
for(i = 0;i < 256;i++)
Std_Hist += pow((i-Avg_Hist),2)*cvQueryHistValue_1D(hist,i);
Std_Hist = sqrt(Std_Hist/(count));
printf("Std from hist:%f\n",Std_Hist);
cvAvgSdv(src_img,&Avg,&Std,0);
puts("\n");
printf("平均值 \n");
printf("Avg in channel1:%f\n",Avg.val[0]);
printf("Avg in channel2:%f\n",Avg.val[1]);
printf("Avg in channel3:%f\n",Avg.val[2]);
printf("Avg in channel4:%f\n",Avg.val[3]);
printf("方差\n");
printf("Std in channel1:%f\n",Std.val[0]);
printf("Std in channel2:%f\n",Std.val[1]);
printf("Std in channel3:%f\n",Std.val[2]);
printf("Std in channel4:%f\n",Std.val[3]);
printf("\ndiff Avg and Std from hist and function:%f %f\n",fabs(Avg.val[0]-Avg_Hist),fabs(Std.val[0]-Std_Hist));
cvNamedWindow("Show original image",0);
cvShowImage("Show original image",src_img);
cvWaitKey(0);
cvDestroyWindow("Show original image");
printf("done\n");
cvReleaseImage(&src_img);
return 0;
}
测试图像数据:
测试结果和Opencv函数计算结果一致: