PSNRおよびSSIMまたはCでの画像の操作方法

画像 この記事では、画像の操作方法の基本原則について触れます。 このため、 OpenCVライブラリーを選択しました。 無料で配布されるため、ダウンロードは簡単です。

2つの写真の違い、特に元の写真から変更された写真の品質を評価するために2つのメトリックを作成する勉強をするタスクを与えられたとき、もちろん少し混乱しました。 プログラミングの知識は、控えめに言っても、それほど大きなものではなく、結局のところ、最初の1年だけでした。 幸いなことに、彼らは事前にどのライブラリを選択するかを言ったので、困難はありませんでした。 しかし、それをどのように使用するかはすでに桁違いに難しく、主にインターネットで掘ることができるのは英語でしたが、私はそれらを読むことができるレベルで知っています。 図書館自体の広大さのために、文学はうまく適合しませんでした。 可能だったこと、どんな機能、どのように使用できるかが素晴らしいことです。その後、先生に説明しました。 そして、画像自体、特に画像の個々のピクセルにアクセスする方法を理解することだけが必要でした。 興味のある方、猫へようこそ。



PSNR / SSIM


まず、 PSNRSSIMとは何ですか? ウィキペディアが私たちに伝えているように。 PSNR-ピーク信号対雑音比。画像圧縮の歪みレベルを測定するために最もよく使用されます。 そして、私たちはそのような彼女を見つけるでしょう。 この場合、すべてが画像のビット数に依存します。



画像



MSE標準偏差はどこにありますか?



画像



SSIMはより複雑であると考えられており、いわば2つの画像の違いをより正確に判断するために作成されました。 特徴は、常に-1から1の範囲にあり、その値が1であるということは、2つの同一の画像があることを意味します。 一般式の形式は



画像



ここに 画像 (x)最初の画像の平均値、 画像 (y)これは2番目のものです。 画像 (x)最初の画像の標準偏差、およびそれに応じて 画像 (y)2番目の場合、 画像 (x、y)これはすでに共分散です。 彼女に思い出させる 画像 (x、y)= 画像 (x、y)- 画像 (x)* 画像 (y)。 分母が小さいために必要な補正係数であるC1とC2を続けます。 さらに、それらは、画像の所定のビット数に対応する色の数に等しい数の2乗に等しく、それぞれ0.01と0.03を乗算します。



コード


私のプログラミングスタイルはおそらくあまり良くないことを告白しますが、私を厳しく判断しないでください。私は多くの経験がなく、常に改善することを約束します。 この記事では、SSIMメトリックのみの解析に限定しています。 まず、Visual Studioを手元に用意する必要があります。 その後、最初に選択したライブラリをプロジェクトに追加する方法を非常に理解できました。 ヘッダーファイルと、ファイル自体を新しく作成したプロジェクトに追加する必要があります。 これについては、 ここで詳しく説明します

私が書いたコードを説明するために、私は途中で彼女がコメントすることに賭けます。 コードは長すぎず、理解できるようになっています。 さあ、始めましょう。



私たちがそうする写真へのポインター。
IplImage* img1 = cvvLoadImage("before.bmp"); IplImage* img2 = cvvLoadImage("after.bmp");
      
      





ビットネスを決定できます
 img->depth
      
      



それは非常に簡単です。



目的の数量を見つけるために、関数をいくつか作成しました。 見つけるために 画像 (x)、つまり平均値 。 実際、2次元配列の場合と同様に画像を使用します。 ここでも、取得した値を画像のサイズで割る必要があります。次のようになります。



 (img->width)*(img->height)
      
      







 double avg(IplImage* img){ unsigned char* ptr; int x,y,b=0,g=0,r=0,col=0; for(x=0;x<=img->width;x++){ for(y=0;y<=img->height;y++){ ptr=(uchar*)(img->imageData+y*img->widthStep); //       b=ptr[3*x]; g=ptr[3*x+1]; //           r=ptr[3*x+2]; // b - blue, r - red, g - green col+=b+g+r; }} return col/3.00; }
      
      







標準偏差はそうです。ここでは、とりわけ、以前に取得した平均値を送信する必要があります。



 double var(IplImage* img, double mu){ //variance unsigned char* ptr; int x,y,b=0,g=0,r=0; double col=0; for(x=0;x<=img->width;x++){ for(y=0;y<=img->height;y++){ ptr=(uchar*)(img->imageData+y*img->widthStep); b=ptr[3*x]; col+=(abs(1.0*b-mu))*(abs(1.0*b-mu)); g=ptr[3*x+1]; col+=(abs(1.0*g-mu))*(abs(1.0*g-mu)); r=ptr[3*x+2]; col+=(abs(1.0*r-mu))*(abs(1.0*r-mu)); }} return col; }
      
      







そして、このような共分散



 double cov(IplImage* img1,IplImage* img2,double mu1,double mu2){ //covariance unsigned char* ptr; int x,y,b1=0,g1=0,r1=0,b2=0,g2=0,r2=0; double col=0; for(x=0;x<=img1->width;x++){ for(y=0;y<=img1->height;y++){ ptr=(uchar*)(img1->imageData+y*img1->widthStep); b1=ptr[3*x]; g1=ptr[3*x+1]; r1=ptr[3*x+2]; ptr=(uchar*)(img2->imageData+y*img2->widthStep); b2=ptr[3*x]; g2=ptr[3*x+1]; r2=ptr[3*x+2]; col+=(b1-mu1)*(b2-mu2)+(g1-mu1)*(g2-mu2)+(r1-mu2)*(r2-mu2); }} return col; }
      
      







実際、上記の定式で得られた値を置き換えるだけです。 また、メモリを解放することを忘れないでください。



  cvReleaseImage(&img1); cvReleaseImage(&img2);
      
      







PS
ここからライブラリ自体をダウンロードできます。 ここで OpenCVについての興味深いことがたくさんありますZlodeiBaalに感謝します )。 また、将来的にはこれと似た記事を書きたいと思いますが、すでにビデオの操作と他のライブラリの使用について書いています。



誰が質問をしたり、エラーに気づいたり、または単に著者を称賛したい、書いて、私は間違いなく答えます。



All Articles