同じデジタル カメラから取得した 2 つの読み込み済み画像の信号対雑音比を計算しようとしています。アイデアは、CCD レンズの信号対雑音比を示すグラフを実現するために、多数の光レベルで信号対雑音を計算することです。
私が現在直面している問題は次のとおりです。最初の画像 (画像 A) と同じ平均ピクセル強度を持つように 2 番目の画像 (画像 B) をスケーリングすると、得られる値は最初の画像と正確な値ではありません。問題は、画像変換による丸め誤差の結果だと思います。
SNR の計算に使用する方法は次のとおりです。
- 画像をグレースケールに変換
- 画像を 16 ビット符号付きに変換する
- A から画像 B を減算
- 減算の平均ピクセル強度を取得します
- その平均値を A と B から引きます (ノイズを除去するため)。
- 符号なし 8 ビットに戻す
- 両方の画像の平均ピクセル値を取得する
- それらの平均値の比率を取得します
- 画像 A の平均ピクセル値を取得する比率で画像 B (符号なし 16 ビット) をスケーリングします - 問題領域
- 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 になります)。