スパース行列(SparseMat)の使い方2:超解像

22 7月 2010 Under: opencv2.x-samples

SparseMatをつかった超解像処理を行います.このデモンストレーションは下記論文の実装になっています.詳細は以下論文やビデオをご覧ください.また,このサンプルコードはOpenMPを有効化するとコアを有効に使います.メモリは1Gほど使うため実行時には注意してください.

Farsiu, S.,Robinson, D., Elad, M., Milanfar, P.”Fast and robust multiframe super resolution,” IEEETrans.ImageProcessing 13 (2004)1327?1344.


C++


(1)劣化画像と劣化行列(疎行列)を生成します.

画像の劣化は,動き,ぼけ,ダウンサンプルなどに分解され,それぞれの影響を受けて観測されます.理想的な信号をX,観測信号をYとして,動きを表す行列をF,ぼけ(レンズやモーションブラー,サンプリングによるぼけなど)を表す行列をH,ダウンサンプルを行う行列をDとすると

Y=DHFX

で表すことができます.行列DHFををまとめて書けば,

Y=AX

となります.最後にガウシアンノイズとスパイクノイズを劣化画像に追加します.これを図に示すと以下のようになります.

(2) 劣化の逆変換を最急降下法で行うことで超解像処理を行います.

ぼけ除去のサンプルに加えて,Bilateral Total Variation(BTV)による正則化が追加されており,ノイズにロバストになっています.ここでは,この式の計算を繰り返し処理により行います.(L1ノルム最小化の場合

Xn+1Xn – β{Σk=1NAkTsign(AkXn-Y)+λΣl=-ppΣm=pp[I-Sx-lSy-m]sign(Xn-SxlSymXn)}

βは収束のステップを,λは画像の滑らかさの拘束の強さを,αはBTVの距離関する減衰のパラメータとなっています.また,SR_DATA_L2,SR_DATA_L1で最小化するノルムを選択可能になっています.数式中,SxlSymは画像をx,y方向にl,mピクセル平行移動する行列を表しており,Iは何もしない単位行列となっています.また関数signは符号関数で,正の場合1を負の場合-1を返します.

(3)まずはじめに初期値として,リサイズ(線形補間)した画像を入力します.

ここから超解像処理の詳細に入ります.ここでは,初期画像のPSNR(画質の評価関数)も測定しています.

(4)画像をベクトルに変換します.

行列で処理しやすいように図のようなベクトルの形式に画像を変換します.

(5)最急降下法により,少しずつ近づけていきます.

1.まず,BTVによるペナルティを計算します.このペナルティは画像が急激に変化するところで大きくなります.

2.複数の入力画像と劣化行列をかけた現推定画像と比較(L1かL2ノルムで)し,残差を記憶します.

3.それらを足した後,正解画像との比較を行ってどれくらいの精度が出ているか確認します.実際の使用時には,正解画像はないため,ここではただ評価のためだけに正解画像を使用しています.

結果

16枚の解像度128×128の入力画像から,線形補間で拡大した画像と超解像処理を行ったものを以下に示します.線形補間では失われている高周波情報が復元されていることや,スパイクノイズ,ガウシアンノイズが超解像後には消えているのがわかります.

16枚の低解像度画像からの超解像処理結果

入力画像(16枚のうちの1つ)

リサイズ(線形補間)

超解像結果

“スパース行列(SparseMat)の使い方2:超解像” への17件のコメント

  1. Wang Yongwen より:

    Thank you for your sharing! I try to run your code on VS2010 and Open CV but there are some errors existing such as”Unhandled exception at 0x7603c6e3 in SuperResolution.exe: Microsoft C++ exception: cv::Exception at memory location 0x001be79c..”, which I don’t know how to debug it.Could you give me some suggestions about how to run this code successfully to achieve super_resolution?
    Thank you very much!

  2. Nguyen Le より:

    Hi Norishige FUKUSHIMA,

    If I already had my own sample images which were shifted a little in comparison with the first image, how can I modify your code to achieve the matrix A as well as the final super resolution image?
    I already tried to use the function “calcOpticalFlowPyrLK” to calculate the displacement between the first image and the others based on the iterative Lucas-Kanade method with pyramids. Then, I returned the result of that function to the array move[i].x and move[i].y in order to calculate the matrix A. However, my solution did not seem to work correctly at all!!
    Please let me know if you have any suggestion!!
    Thanks in advance!!

    • fukushima より:

      Please modify the loop of (1) and the function of “createDegradedImageandSparseMat32″. This loop generates randomly shifted-multiple images from single image. If you want to use pre-captured image, please modify this part.
      BRs,

  3. Le Nguyen より:

    Hi Norishige FUKUSHIMA,

    If I already had my own sample images which were shifted a little in comparison with the first image, how can I modify your code to achieve the matrix A as well as the final super resolution image?
    I already tried to use the function “calcOpticalFlowPyrLK” to calculate the displacement between the first image and the others based on the iterative Lucas-Kanade method with pyramids. Then, I returned the result of that function to the array move[i].x and move[i].y in order to calculate the matrix A. However, my solution did not seem to work correctly at all!!
    Please let me know if you have any suggestion!!
    Thanks in advance!!

  4. I have a problem with this code.
    What is the allowed maximum size of the input image?

    • fukushima より:

      I cannot know that because the size depends on OpenCV core function’s version deeply. In my computer, I cannot set large image size (256×256, 512×512).

  5. iOn_azuma より:

    haartrainingを使用しています。-nstages 21にて機械学習を行っていると処理に時間が掛かっているstage(だいたい17か18)の途中でtraing_data.xmlが作成されます。
    CPU負荷と計算中の%表示から一見計算は続いている様に見えますが、この現象は各パラメータの設定が不適切で機械学習が最後まで実施できていない際の処理と考えています。
    この場合の処置として正しいのは、
    1.処理を途中で打ち切って再度パラメータを変更して作業を行う。
    できたxmlは使えない。
    2.まだ計算中なので継続して処理を行う。
    最終的に xmlが上書きされる。
    作業としてどちらが正解か、ご存知の方いないでしょうか?
    あれこれ試しておりますが、顔認識用サンプルのxmlのようにファイルができません。
    よろしくお願いいたします。

  6. Utkarsh より:

    Awesome – thanks for the code. Do you know if any newer, better techniques have come up?

  7. David より:

    Dear Fukushima:

    Sorry if this is not the appropiate place for a question, let me know
    where to post if not here.

    I tried to use your code in a set of images not generated by the progam itself.
    These images are aligned; so no movement is taken in account. They are noisy already.
    I can’t figure how to calculate the A matrix as createDegradedImageandSparseMat32F( ) does;
    because createDownsampledMotionandBlurCCDSparseMat32f( ) expects a source of the same size as the output.
    I tried resizing the input images to destination size (rfactor times), and using move parameter 0,0.
    The noise was removed but no superresolution achieved.
    Can you explain how to work with preloaded images or how to calculate the A matrix in the situation
    of aligned pictures ?

    Best regards, David

    • fukushima より:

      Dear David

      Please use following function for computing sparse A matrix.
      createDownsampledMotionandBlurCCDSparseMat32f(src,amp,move);
      src: image which has desired (super resesoluved)resolution, which has not contain image data, bacause only image size is required.
      amp:(high resolution)/(low resolution)
      move:global motion per image.

      >>The noise was removed but no superresolution achieved.
      This implementation is based on multi-frame super resolution[1].
      Thus, this method has weak capability for single image SR.

      [1]Farsiu, S.,Robinson, D., Elad, M., Milanfar, P.”Fast and robust multiframe super resolution,” IEEETrans.ImageProcessing 13 (2004)1327-1344.

      Regards,

      Norishige FUKUSHIMA
      in the main function (at line 74-76)
      A[i]=createDegradedImageandSparseMat32F(image, imtemp,move[i],rfactor);
      addgaussnoise(imtemp,degimage[i],10.0);//add gaussian noise
      addspikenoise(degimage[i],degimage[i],500);//add spike noise

  8. 長澤亨 より:

    すみません、お教え下さい。
    プログラム中のimages1が未定義なのではありませんか?
    コンパイルエラーがでますが、、、

    void addgaussnoise(Mat& src, Mat& dest, double sigma) {

    images1.convertTo(src_f,CV_32FC1); // <– images1が未定義?

    }

    • fukushima より:

      コードをアップするときにソースが特殊文字扱いになってしまいimages1…と表示されている部分ですが,本来はimage[ c ] という文字列が入っています.
      コードにこの文字化け?変更が行われないようにアップし直しましたので確認してみてください.

  9. PVDHP より:

    All it’s cool! But where is dowload link and how to compile it?

  10. fukushima より:

    福嶋です.
    このコードでは,スパース行列の入力部分の例外処理(294行目)で負の値が入った場合にうまく機能しないようになってしまっています。ここを修正すればプログラムが落ちることはなくなると思います.

    しかし,行列を作る部分(300~303行目)では,第一象限(x,yともに正)の場合のみうまく行くように線形補間での行列アクセスを設計しています.

    例えば平行移動が,x,y = (1.4,1.8)の場合,この画素のこの線形補間は,
    0.6*0.2*[1,1] + 0.4*0.2*[2,1] + 0.6*0.8*[1,2]+ 0.4*0.8*[2,2]
    で表されます.ここで,[m,n]は(m,n)pixelの画素の値です.
    しかしここにマイナスが入って来た場合x,y = (-1.4,-1.8)
    このプログラムでは,
    [-1,-1],[-1,0],[0,-1],[0,0]
    の4ペアを使って線形補間しようとします.
    正しい最近傍は
    [-2,-2],[-2,-1],[-1,-2],[-1,-1]
    のペアとなるため,プログラムを修正する必要があると思います.

    対策として,もっとも小さな(負の方向に絶対値が大きい)ものを基準画像に設定してしまうかこのプログラムを修正してみてください.

    • r_takuma より:

      何度もご親切なアドバイスありがとうございました.
      福嶋さんのおかげで無事,負の値をとる場合でも超解像処理を行うことができました.

      今回だけでなく,無知な私に優しく親切なアドバイスをしていただき,本当にありがとうございました.
      私は,学生なのですが,福嶋さんのおかげで研究(といっても,それほど大したものでもありませんが...)を進めることができます.

      お忙しいところ,本当にありがとうございました.

  11. r_takuma より:

    はじめまして.こちら(http://oshiete.goo.ne.jp/qa/6345132.html)でも何度か質問させていただいた者です.

    今,こちらのプログラムを参考にさせていただいて,複数の低解像度画像から高解像度画像を生成するプログラムを作っています.
    そこで,どうしても分からないところがあり,こちらに質問させていただきました.
    コメント欄にこのような質問を投稿してしまう無礼をお許しください.

    実行しようとしていることの概要としましては,
    1,複数の低解像度画像からの高解像度画像生成
    2,複数の低解像度画像は,平行移動のみと仮定(アフィン変換等はしていない)
    3,別のプログラムで,移動量は推定済み
    4,その他,ブラーカーネル等のパラメータはも推定済み

    このような条件のもと,プログラムしたところ,移動量が正の値をとる場合の超解像処理は無事行うことができました.
    しかし,移動量が負の値をとる場合,処理が最後まで実行できないバグが発生してしまいました.
    訂正すべき箇所は,260-310行目のcreateDownsampledMotionandBlurCCDSparseMat32f内であることは理解できたのですが,この関数がどのような処理を行っているかが理解しかねているため,どのような訂正を行えば良いかが分かりません.

    よろしければ,アドバイス等いただけたらと思います.
    長文失礼しました.

PVDHP への返信