我正在尝试计算从同一数码相机拍摄的两个加载图像的信噪比。这个想法是计算多个光照水平下的信噪比,以获得显示 CCD 镜头信噪比的图表。
我目前面临的问题是;当我缩放第二张图像(图像 B)以具有与第一张图像(图像 A)相同的平均像素强度时,所获得的值与第一张图像不同。我认为问题是图像转换的舍入误差的结果。
我用来计算信噪比的方法是:
- 将图像转换为灰度
- 将图像转换为 16 位签名
- 从 A 中减去图像 B
- 获取减法的平均像素强度
- 从 A 和 B 中减去平均值(以消除一些噪音)
- 转换回 8 位无符号
- 获取两个图像的平均像素值
- 获取这些平均值的比率
- 使用比率缩放图像 B(16 位无符号)以获得图像 A 的平均像素值 - 问题区域
- 转换回 8 位并计算平均像素强度
- 再次相互减去图像以消除最后的随机噪声
- 计算这个减法的标准偏差
- 将标准差转换为方差
我是 OpenCV 和一般编程的新手,因此对于特定问题的任何更好的方法和帮助将不胜感激。
int _tmain(int argc, _TCHAR* argv[])
{
float mean_A;
float mean_B1;
float var,mean_B;
float grey_B_mul;
float grey_sub2;
float o, standard, r;
IplImage *img = cvLoadImage("J:\\backup\\fotos\\IMG_0168.JPG", 3);//Define images
IplImage *img2 = cvLoadImage("J:\\backup\\fotos\\IMG_0164.JPG", 3);
IplImage *grayA = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
IplImage *grayB = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
IplImage *gray1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *gray1S = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *gray2S = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *gray2 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *sub1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *imgA = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
IplImage *imgA1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *imgA1U = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *imgB1U = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *imgB1 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *imgB = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
IplImage *imgB_mul = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *imgB_mull = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *imgB_scaled = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *imgBsc = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
IplImage *sub2 = cvCreateImage(cvGetSize(img),IPL_DEPTH_16S, 1);
IplImage *sub2U = cvCreateImage(cvGetSize(img),IPL_DEPTH_16U, 1);
IplImage *sub2_final = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U, 1);
if (img->nChannels ==3)
{
cvCvtColor(img, grayA, CV_BGR2GRAY); //convert to grayscale
cvCvtColor(img2, grayB, CV_BGR2GRAY);
}
else
{
cvCopyImage(img,grayA);
cvCopyImage(img2,grayB);
}
CvScalar m = cvAvg(grayA, 0); //Calculate average pixel intensity
double z = m.val[0];
CvScalar n = cvAvg(grayB, 0); //Calculate average pixel intensity
double y = n.val[0];
if (z > 128) //Convert to 16 bit signed
{
cvConvertScale(grayA, gray1, 256.0, -32768);
cvConvertScale(gray1, gray1S, 1.0);
}
else
cvConvertScale(grayA, gray1S, 256.0, -32768);
if (y> 128)
{
cvConvertScale(grayB, gray2, 256.0, -32768);
cvConvertScale(gray2, gray2S, 1.0);
}
else
cvConvertScale(grayB, gray2S, 256.0, -32768);
cvNamedWindow("CCD noise",1);
cvNamedWindow("Image A",1);
cvNamedWindow("Image B scaled",1);
cvSub(gray1S,gray2S, sub1); //Subtract images
cvSub(gray1S,sub1, imgA1);
cvSub(gray2S,sub1, imgB1);
cvConvertScale(imgA1, imgA1U, 1.0, +32768 );
cvConvertScale(imgB1, imgB1U, 1.0, +32768 );
cvConvertScale(imgA1U, imgA, 1.0/256);
cvConvertScale(imgB1U, imgB, 1.0/256);
CvScalar d = cvAvg(imgB, 0); //Calculate average pixel intensity
mean_B = d.val[0];
CvScalar e = cvAvg(imgA, 0); //Calculate average pixel intensity
mean_A = e.val[0];
printf("Image A pixel intensity = %f\n", mean_A);
printf("Image B pixel intensity = %f\n", mean_B);
r = mean_A/mean_B; // Ratio between average pixel intensities of image A and B
printf("r = %f\n", r);
for( int a = 0; a < imgB1U->height; a++ ) //Scale image B to achieve same average pixel intensity as image A
{
for( int b = 0; b < imgB1U->width; b++ )
{
CvScalar pixel = cvGet2D(imgB1U, a, b);
o = pixel.val[0]*r;
CvScalar p;
p.val[0] = o;
cvSet2D(imgB_mul, a, b, p);
}
}
cvConvertScale(imgB_mul, imgBsc, 1.0/256); //Convert back to 8 bit
CvScalar c = cvAvg(imgBsc, 0); //Calculate average pixel intensity
mean_B1 = c.val[0];
printf("Image B intensity after scaling = %f\n", mean_B1);
cvConvertScale(imgB_mul, imgB_scaled, 1.0, -32768);
cvSub(imgA1,imgB_scaled, sub2); //Final subtraction to calculte standard deviation
cvConvertScale(sub2, sub2U, 1.0, +32768 );
cvConvertScale(sub2U, sub2_final, 1.0/256);
CvScalar t,std;
cvAvgSdv(sub2_final, &t, &std); //Calculate std deviation
standard = std.val[0];
var = (standard*standard)/2; //Square std deviation and devide by 2 for variance
printf("Variance camera noise is = %f\n", var);
cvShowImage("Image A",imgA);
cvShowImage("Image B scaled",imgBsc);
cvShowImage("CCD noise",sub2);
cvWaitKey(0); //To terminate images
cvDestroyWindow("CCD gain");
cvDestroyWindow("Image A");
cvDestroyWindow("Image B scaled");
cvReleaseImage(&img);
cvReleaseImage(&img2);
cvReleaseImage(&gray1);
cvReleaseImage(&gray1S);
cvReleaseImage(&gray2S);
cvReleaseImage(&gray2);
cvReleaseImage(&sub1);
cvReleaseImage(&sub2);
cvReleaseImage(&imgA);
cvReleaseImage(&imgA1);
cvReleaseImage(&imgA1U);
cvReleaseImage(&imgB);
cvReleaseImage(&imgB1);
cvReleaseImage(&imgB1U);
cvReleaseImage(&imgB_mul);
cvReleaseImage(&imgB_mull);
cvReleaseImage(&imgBsc);
cvReleaseImage(&imgB_scaled);
cvReleaseImage(&sub2U);
cvReleaseImage(&sub2_final);
return 0;
}
这个程序的结果是:
图像 A 像素强度 = 138.292328
图像 B 像素强度 = 253.836456
比率 = 0.544809
缩放后的图像 B 强度 = 138.351196
CCD 噪声方差 = 8.016509
我在这里使用不同的图像进行演示,以强调应该发生的事情。在测试图像将更接近(比率将在 0.992 左右)。