0

我正在尝试计算从同一数码相机拍摄的两个加载图像的信噪比。这个想法是计算多个光照水平下的信噪比,以获得显示 CCD 镜头信噪比的图表。

我目前面临的问题是;当我缩放第二张图像(图像 B)以具有与第一张图像(图像 A)相同的平均像素强度时,所获得的值与第一张图像不同。我认为问题是图像转换的舍入误差的结果。

我用来计算信噪比的方法是:

  1. 将图像转换为灰度
  2. 将图像转换为 16 位签名
  3. 从 A 中减去图像 B
  4. 获取减法的平均像素强度
  5. 从 A 和 B 中减去平均值(以消除一些噪音)
  6. 转换回 8 位无符号
  7. 获取两个图像的平均像素值
  8. 获取这些平均值的比率
  9. 使用比率缩放图像 B(16 位无符号)以获得图像 A 的平均像素值 - 问题区域
  10. 转换回 8 位并计算平均像素强度
  11. 再次相互减去图像以消除最后的随机噪声
  12. 计算这个减法的标准偏差
  13. 将标准差转换为方差

我是 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 左右)。

4

0 回答 0