OpenCV 2マラソン4周目——画像ミックス

5544 ワード

ふところに収める
  • リニアブレンド
  • について
  • addWeightedを使用して任意に混合する
  • ひまわりの宝典
    Computer Vision:Algorithm and Application(以降CVAAと略称する)の3.1.3に記載されています.
    C=(1−α)B+αF. 
    Bは背景色、Fは前景色、これは万能の公式です(実は万能の公式ほど使いにくいので、この公式は何も言わないようです)
    CVAAのこの小さい節はほじくりと合成を話して、ほじくりの難易度は比較的に大きいです
    初識API
    次にSampleフォルダの下のImgProcサブディレクトリに入り、まずAddingImages.cppを検討します.次はソースコードです.
    #include "opencv2/highgui/highgui.hpp"
    #include <iostream>
    
    using namespace cv;
    
    int main( void )
    {
    
       double alpha = 0.5; double beta; double input;
    
       Mat src1, src2, dst;
    
       /// Ask the user enter alpha
       std::cout<<" Simple Linear Blender "<<std::endl;
       std::cout<<"-----------------------"<<std::endl;
       std::cout<<"* Enter alpha [0-1]: ";
       std::cin>>input;
    
       // We use the alpha provided by the user iff it is between 0 and 1
       if( alpha >= 0 && alpha <= 1 )
         { alpha = input; }
    
       /// Read image ( same size, same type )
       src1 = imread("../images/LinuxLogo.jpg");
       src2 = imread("../images/WindowsLogo.jpg");
    
       if( !src1.data ) { std::cout<< "Error loading src1"<<std::endl; return -1; }
       if( !src2.data ) { std::cout<< "Error loading src2"<<std::endl; return -1; }
    
       /// Create Windows
       namedWindow("Linear Blend", 1);
    
       beta = ( 1.0 - alpha );
       addWeighted( src1, alpha, src2, beta, 0.0, dst);
    
       imshow( "Linear Blend", dst );
    
    
       waitKey(0);
       return 0;
    }

    コードは簡単で、1枚目の画像が占める割合はalphaで、2枚目は1-alphaです.
    dst = src1[I]*alpha+ src2[I]*beta + gamma;
    次にaddWeightedのソースコードを見てarithm.cppで
    void cv::addWeighted( InputArray src1, double alpha, InputArray src2,
                          double beta, double gamma, OutputArray dst, int dtype )
    {
        double scalars[] = {alpha, beta, gamma};
        arithm_op(src1, src2, dst, noArray(), dtype, getAddWeightedTab(), true, scalars);
    }
  • 最初のパラメータ、InputArrayタイプのsrc 1は、重み付けが必要な最初の配列を表し、常にMatを記入します.
  • 第2パラメータ、alpha、第1配列の重み
  • を表す
  • 第3のパラメータ、src 2は、第2の配列を表し、第1の配列と同じサイズとチャネル数を持つ必要がある.
  • 第4パラメータ、beta、第2配列の重み値を表す.
  • の5番目のパラメータ、dst、出力の配列、それは入力の2つの配列と同じサイズとチャネル数を持っています.
  • 6番目のパラメータ、gamma、重みの合計に加算されたスカラー値です.次の式を見ると自然に理解できます.
  • の7番目のパラメータ、dtype、出力アレイのオプションの深さ、デフォルト値-1があります.2つの入力配列が同じ深さを持つ場合、このパラメータは-1(デフォルト値)、すなわちsrc 1.depth()に等しい-1(デフォルト値)に設定されます.
  • 次にarithm_opという関数をよく見てみましょう
    static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
                   InputArray _mask, int dtype, BinaryFunc* tab, bool muldiv=false, void* usrdata=0)

    私たちはaddWeightedの中で1つのnoArray()が伝わっていることを発見しました.マスクがなくて、tabパラメータがあります.これは何ですか.名前を見ると関数のポインタのようですか.上を見ると、私は発見しました.
    static BinaryFunc* getAddWeightedTab()
    {
        static BinaryFunc addWeightedTab[] =
        {
            (BinaryFunc)GET_OPTIMIZED(addWeighted8u), (BinaryFunc)GET_OPTIMIZED(addWeighted8s), (BinaryFunc)GET_OPTIMIZED(addWeighted16u),
            (BinaryFunc)GET_OPTIMIZED(addWeighted16s), (BinaryFunc)GET_OPTIMIZED(addWeighted32s), (BinaryFunc)addWeighted32f,
            (BinaryFunc)addWeighted64f, 0
        };
    
        return addWeightedTab;
    }
    これらの事関数ポインタの配列を見て、GET_OPTIMIZEDはまた何ですか
    #define GET_OPTIMIZED(func) (func)
    多くの定義は詳しく見るには及ばないが、次回はさらに詳しく検討する必要がある.これらのaddWeighted 8 uなどの関数は同じcppの下で定義されている.私たちのtabは一連の関数ポインタである.arithm_opには1行の関数がある.
    BinaryFunc func = tab[CV_MAT_DEPTH(wtype)];
    データ型に応じて対応する重み付け関数を取得
    arithm_opの関数の多くはデータ型であり,マスクのこの判断は,主な操作がこのfuncで行われ,中にはaddWeighted_というテンプレート関数が呼び出される.
    template<typename T, typename WT> static void
    addWeighted_( const T* src1, size_t step1, const T* src2, size_t step2,
                  T* dst, size_t step, Size size, void* _scalars )
    {
        const double* scalars = (const double*)_scalars;
        WT alpha = (WT)scalars[0], beta = (WT)scalars[1], gamma = (WT)scalars[2];
        step1 /= sizeof(src1[0]);
        step2 /= sizeof(src2[0]);
        step /= sizeof(dst[0]);
    
        for( ; size.height--; src1 += step1, src2 += step2, dst += step )
        {
            int x = 0;
            #if CV_ENABLE_UNROLLED
            for( ; x <= size.width - 4; x += 4 )
            {
                T t0 = saturate_cast<T>(src1[x]*alpha + src2[x]*beta + gamma);
                T t1 = saturate_cast<T>(src1[x+1]*alpha + src2[x+1]*beta + gamma);
                dst[x] = t0; dst[x+1] = t1;
    
                t0 = saturate_cast<T>(src1[x+2]*alpha + src2[x+2]*beta + gamma);
                t1 = saturate_cast<T>(src1[x+3]*alpha + src2[x+3]*beta + gamma);
                dst[x+2] = t0; dst[x+3] = t1;
            }
            #endif
            for( ; x < size.width; x++ )
                dst[x] = saturate_cast<T>(src1[x]*alpha + src2[x]*beta + gamma);
        }
    }
    
    この関数は私たちのアルゴリズムです.はっきり見えます.
    dst = src1[I]*alpha+ src2[I]*beta + gamma;
    一反三を挙げる
    addWeighted関数は、2つのマトリクスのサイズが同じでなければならないことを要求しています.もし私が違うとしたらどうしますか?
    実はとても简単で、OpenCV 2の中で、cloneとcopytoの2つの関数だけがデータをコピーすることを知っていて、その他はすべて新しいMatのHeader(行列などの情报を含む)だけで、データはやはり元の地方を指して、ref countは1回増加しました.
    だから、行列の一部を取って混合すればいいのではないでしょうか.
    src 1が1000*1000で、srcが100*100の小人頭であると仮定し、小人頭とsrc 1の(500,500)座標を混合したい
    方法1:blendimg=src 1(Range(500,500+src 2.rows),Range(500,500+src 2.cols); 
    方法2:blendimg=src 1(Rect(500,500,src 2.cols,src 2.rows);
    addWeighted関数を使用すればよい
    コンピュータビジュアルディスカッショングループ162501053
    転載は以下のことを明記してください.http://blog.csdn.net/abcd1992719g