Poisson Blending

09 9月 2011 Under: opencv2.x-samples

このサンプルは,OpenCVの機能とはあまり関係なく,差分やデータの保持にcv::Mat形式を利用している程度です.このサンプルでは,ある画像の一部を別の画像にコピーする際に,それらを滑らかにブレンディングします.
コピー後の画素値は,Dirichlet条件の下でPoisson方程式を解くことで求められます.つまり,コピー元画像の画像勾配をなるべく保ったまま,コピー境界の画素値をコピー先の画素値と合うように,コピー結果画素値を決定します.
詳しくは,SIGGRAPH2003の論文 Poisson Image Editting (PDF) を参照してください.

Souce Image, Target Image, Mask Image, Blending Result

また,Gradient Mixtureを行うことで,コピー元とコピー先の画像のうち,より強い勾配を保存することができます.
下図に,紙に書かれた文字(左)を,手のひらの合成するデモ結果を示します.
Gradient Mixtureを行わない通常のブレンディングの場合(中央),コピー元画像の背景である紙部分が上書きされ,手のシワが消えてのっぺりした画像になっています.
ここで Gradient Mixture を行うと(右),シワなどの強い勾配が保存されたブレンディング結果になります.

 

以下は,サンプル用のソースコードですが,実行には,OpenCV-2.2以降,Eigen2/3,UmfPack が必要です.Ubuntu 11.04 上でのみ動作を確認しています.
また,OpenCV自身の Blender クラスとはまったくの無関係です.
疎な連立方程式の解法部分は,UmfPackのソルバに丸投げですが,Gauss-Seidel 法,Mutigrid 法などで解いても良いでしょう.
モナリザの画像(375×505[pixel])を例に挙げると,Core i7 2.67[GHz] の VM 上 Linux で,約950[msec] ほどの処理時間が必要です.

C++

poisson_blending.hpp


main.cpp


“Poisson Blending” への15件のコメント

  1. panovr より:

    uchar tlrb = 15; // 0b1111
    if(mask1.at(y-1,x)==0) {
    *drv -= target1.at(y-1,x);
    tlrb &= 7; //0b0111
    }

    May you interpret these magic number (15, 7, etc.) more?
    Thanks!

  2. miros より:

    d:\eigen\unsupported\eigen\umfpacksupport(9): fatal error C1083: 无法打开包括文件:“umfpack.h”: No such file or directory

    Could u please help me about that ? thank!

    Environment:win7+MSVC2010

  3. student より:

    プログラムの提供ありがとうございます。

    実装してみたところ二つのエラーが発生しました。
    一つは他の人も言っているように、“UmfPackSupport”がないこと。(Eigen3.1.3を使用)
    もう一つは、265行目で”ch”に値が格納されていないので、宣言時にエラーが発生してしまいます。

    どうすれば解決するか教えてください。
    返信お持ちしてます。

    • teacher より:

      説明にもある通り、疎な連立方程式を解くにあたってUMFPACKを使う必要は必ずしもありません。試してみたところ、Eigenでスパース行列をコレスキー分解して普通に解いても全然大丈夫でしたよ。
      もう1つの問題ですが、265行目で”ch”に値が格納されていないためにエラーを吐いているというわけではなく、たぶん、配列の要素数を変数で宣言していることが問題なのでは? 試しに、動的に確保してみたら大丈夫でした。

  4. Nadin より:

    Dear sir,

    I have been trying to use the package in my android project, I use Native Development Kit (NDK) with OpneCV 2.4.1 library under windows.

    My question is how to use the packages: Eigen & UMFPack in my project, given that U said it’s build only under Ubunto.

    Thanks in advance,

    • Nadin より:

      Dear Sir,

      Kindly reply to my message below as it’s an urgent project for me.

      Thanks in advance,
      ——————————
      “Nadin より:
      2013/01/04 00:18

      Dear sir,

      I have been trying to use the package in my android project, I use Native Development Kit (NDK) with OpneCV 2.4.1 library under windows.

      My question is how to use the packages: Eigen & UMFPack in my project, given that U said it’s build only under Ubunto.

      Thanks in advance,”

  5. dai より:

    I have met with the same problem,then I found the solution.Maybe it’s your eigen pack is too old,download the newest editon will help solve the problem.Since I look in to the website below thttp://reference.mrpt.org/svn/_umf_pack_support_source.html#l00026,found out the statement”struct UmfPack {};”was what missing in my umfpacksupport.

  6. Chris より:

    Hi, thanks for the code. Works great! I propose two small improvements:
    1. the output image is 2 pixel too wide and two pixel to tall
    2. you aren’t be able to use a mask that goes up until the border of the input image, it has to be at least 4pixels away from the image border.

    To account for this, just change lines 224 to 242 to this:

    cv::Rect mask_roi2(tl, br+cv::Point(4,4));
    cv::Mat _srcUp, _targetUp, _maskUp, _dstUp;
    cv::copyMakeBorder(_src, _srcUp, 2,2,2,2, cv::BORDER_REPLICATE);
    cv::copyMakeBorder(_target, _targetUp, 2,2,2,2, cv::BORDER_REPLICATE);
    cv::copyMakeBorder(_mask, _maskUp, 1,1,1,1, cv::BORDER_CONSTANT);

    // allocate destination image
    _dstUp = _targetUp.clone();
    _dst = cv::Mat(_dstUp, cv::Rect(2,2,_dstUp.cols-4, _dstUp.rows-4));

    mask_roi1 = cv::Rect(tl, br+cv::Point(2,2));
    mask1 = cv::Mat(_maskUp, mask_roi1);
    target1 = cv::Mat(_targetUp, mask_roi2+offset);
    dst1 = cv::Mat(_dstUp, mask_roi2+offset);

    cv::Mat src(_srcUp, mask_roi2);
    cv::Mat target(_targetUp, mask_roi2+offset);
    cv::Mat dst(_dstUp, mask_roi2+offset);

    How the output image is the right size and the mask can be anywhere in the image.

    Cheers,
    Chris

    • dai より:

      Hi,can you help me solve the complie problem?All error occurs in the statement:
      cv::Mat pdx_src[ch], pdy_src[ch], pdx_target[ch], pdy_target[ch];
      I found out that the variable ch has not been assigned with a value.

      How you deal with this?please replay.thanks in advance.

      • dai より:

        I’ve ask a really stupid question.It is all because my complier does not support using a variable as the array dimentions.
        But I also want to know the mask image is generated by what method.

  7. mercadee より:

    You will need to composite two (or more) images to make a panorama. It is your choice on whether to incrementally warp one image to another or warp all the images to one image. It is also your choice on how to composite. You can simply do over, averaging, feathering, GraphCut seams, Poisson image blending or any other technique you feel like. You will not be penalized for doing simple composite techniques, but your results may not look as good.

  8. Gil Megidish より:

    Awesome work! What is the license for this code?

  9. lu より:

    oh to add on to the previous comment, in poisson_blending.hpp i changed a line
    in the beginning from

    #include
    to
    #include

    Because in the new version of Eigen package, there is change of directory where the file “UmfPackSupport” is located.

    Please kindly help.

    Thanks again.

  10. lu より:

    in the header file, this line

    // solve sparse linear system
    solve(A, b, u);

    caused a compile problem
    poisson_blending.hpp(297): error C2039: ‘UmfPack’ : is not a member of ‘Eigen’

    Could you help please. thanks!

dai への返信