4

こんにちは、Mat クラスで少し遊んでみます。MATLAB immultiplyの c++/opencv ポートである 2 つのイメージ間で製品要素を賢明に処理したいと考えています。

これは私のコードです:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

Mat imgA, imgB;
Mat imgAB;
Mat product;

void printMinMax(Mat m, string s) {
    double minVal; 
    double maxVal; 
    Point minLoc; 
    Point maxLoc;

    minMaxLoc( m, &minVal, &maxVal, &minLoc, &maxLoc );
    cout << "min val in " << s << ": " << minVal << endl;
    cout << "max val in " << s << ": " << maxVal << endl;
}

int main(int /*argc*/, char** /*argv*/) {

    cout << "OpenCV version: " << CV_MAJOR_VERSION << " " << CV_MINOR_VERSION << endl;

    imgA = imread("test1.jpg"); 
    cout << "original image size: " << imgA.rows << " " << imgA.cols << endl;
    cout << "original type: " << imgA.type() << endl;
    cvtColor(imgA, imgA, CV_BGR2GRAY);
    printMinMax(imgA, "imgA");

    imgB = imread("test2.jpg"); 
    cout << "original image size: " << imgB.rows << " " << imgB.cols << endl;
    cout << "original type: " << imgB.type() << endl;
    cvtColor(imgB, imgB, CV_BGR2GRAY);
    printMinMax(imgB, "imgB");

    namedWindow("originals", CV_WINDOW_AUTOSIZE);
    namedWindow("product", CV_WINDOW_AUTOSIZE);

    imgAB = Mat( max(imgA.rows,imgB.rows), imgA.cols+imgB.cols, imgA.type());
    imgA.copyTo(imgAB(Rect(0, 0, imgA.cols, imgA.rows)));
    imgB.copyTo(imgAB(Rect(imgA.cols, 0, imgB.cols, imgB.rows)));

    product = imgA.mul(imgB);
    printMinMax(product, "product");

    while( true )
    {
        char c = (char)waitKey(10);

        if( c == 27 )
            { break; }

        imshow( "originals", imgAB );
        imshow( "product", product );
    }

    return 0;
}

結果は次のとおりです。

OpenCV version: 2 4
original image size: 500 500
original type: 16
min val in imgA: 99
max val in imgA: 255
original image size: 500 500
original type: 16
min val in imgB: 0
max val in imgB: 255
init done 
opengl support available 
min val in product: 0
max val in product: 255

製品の最大値は 255 より大きい必要があると思いますが、2 つのマトリックスのタイプが 16 であるため、255 に切り捨てられます。マトリックスを CV_32F に変換しようとしましたが、製品の maxVal は 64009 (数値) です。わからないこと)

4

2 に答える 2

5

Wajih の コメントのおかげで、いくつかの基本的なテストといくつかの基本的なデバッグを行い、完全に動作するようになりました。これは、アルファ ブレンディングと画像の乗算に関するミニ チュートリアルになると思いますが、今のところ、コメント付きのコードは数行だけです。

2つの画像は同じサイズでなければならないことに注意してください..そして、確実なコードのためにいくつかのエラーチェックを行う必要があります..

それが誰かを助けることを願っています! そして、もちろん、このコードをより読みやすく、よりコンパクトにするためのヒントがあれば (ワンライナーの人は非常に感謝しています!)、または効率的です.. コメントしてください、どうもありがとう!

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "opencv2/imgproc/imgproc.hpp"

#include <iostream>

using namespace cv;
using namespace std;

void printMinMax(Mat m, string name) {
    double minVal; 
    double maxVal; 
    Point minLoc; 
    Point maxLoc;

    if(m.channels() >1) {
        cout << "ERROR: matrix "<<name<<" must have 1 channel for calling minMaxLoc" << endl;
    }

    minMaxLoc( m, &minVal, &maxVal, &minLoc, &maxLoc );
    cout << "min val in " << name << ": " << minVal << " in loc: " << minLoc << endl;
    cout << "max val in " << name << ": " << maxVal << " in loc: " << maxLoc << endl;
}

int main(int /*argc*/, char** /*argv*/) {

    cout << "OpenCV version: " << CV_MAJOR_VERSION << " " << CV_MINOR_VERSION << endl; // 2 4

    Mat imgA, imgB;
    Mat imgAB;
    Mat product;

    // fast matrix creation, comma-separated initializer
    // example1: create a matrix with value from 0 to 255
    imgA = Mat(3, 3, CV_8UC1);
    imgA = (Mat_<uchar>(3,3) << 0,1,2,3,4,5,6,7,255);
    cout << "test Mat 3x3" << endl << imgA << endl;

    // not that if a value exceed 255 it is truncated at value%256 
    imgA = (Mat_<uchar>(3,3) << 0,1, 258 ,3,4,5,6,7,255);
    cout << "test Mat 3x3 with last element truncated to 258%256=2" << endl << imgA << endl;

    // create a second matrix
    imgB = Mat(3, 3, CV_8UC1);
    imgB = (Mat_<uchar>(3,3) << 0,1,2,3,4,5,6,7,8);

    // now the matrix product. we are multiplying a value that can goes from 0-255 with another 0-255 value..
    // the edge cases are "min * min" and "max * max", 
    // that means: our product is a function that return a value in the domain 0*0-255*255 ; 0-65025
    // ah, ah! this number exceed the Mat U8C1 domain!, we need different data types. 
    // we need a bigger one.. let's say 32FC1 

    Mat imgA_32FC1 = imgA.clone();
    imgA_32FC1.convertTo(imgA_32FC1, CV_32FC1);
    Mat imgB_32FC1 = imgB.clone();
    imgB_32FC1.convertTo(imgB_32FC1, CV_32FC1);

    // after conversion.. value are scaled?
    cout << "imgA after conversion:" << endl << imgA_32FC1 << endl;
    cout << "imgB after conversion:" << endl << imgB_32FC1 << endl;

    product = imgA_32FC1.mul( imgB_32FC1 );
    // note: the product values are in the range 0-65025
    cout << "the product:" << endl << product << endl;

    // now, this does not have much sense, because we started from a 0-255 range Mat and now we have a 0-65025 that is nothing..
    // it is not uchar range and it is not float range (that is a lot bigger than that)
    // so, we can normalize back to 0-255
    // what do i mean with 'normalize' now?
    // i mean: scale all values for a constant that maps 0 to 0 and 65025 to 255..
    product.convertTo(product, CV_32FC1, 1.0f/65025.0f * 255);
    // but it is still a 32FC1.. not as the start matix..
    cout << "the product, normalized back to 0-255, still in 32FC1:" << endl << product << endl;
    product.convertTo(product, CV_8UC1);
    cout << "the product, normalized back to 0-255, now int 8UC1:" << endl << product << endl;

    cout << "-----------------------------------------------------------" << endl;

    // real stuffs now.
    imgA = imread("test1.jpg"); 
    cvtColor(imgA, imgA, CV_BGR2GRAY);

    imgB = imread("test2.jpg"); 
    cvtColor(imgB, imgB, CV_BGR2GRAY);

    imgA_32FC1 = imgA.clone();
    imgA_32FC1.convertTo(imgA_32FC1, CV_32FC1);
    imgB_32FC1 = imgB.clone();
    imgB_32FC1.convertTo(imgB_32FC1, CV_32FC1);

    product = imgA_32FC1.mul( imgB_32FC1 );
    printMinMax(product, "product");
    product.convertTo(product, CV_32FC1, 1.0f/65025.0f * 255);
    product.convertTo(product, CV_8UC1);

    // concat two images in one big image
    imgAB = Mat( max(imgA.rows,imgB.rows), imgA.cols+imgB.cols, imgA.type());
    imgA.copyTo(imgAB(Rect(0, 0, imgA.cols, imgA.rows)));
    imgB.copyTo(imgAB(Rect(imgA.cols, 0, imgB.cols, imgB.rows)));

    namedWindow("originals", CV_WINDOW_AUTOSIZE);
    namedWindow("product", CV_WINDOW_AUTOSIZE);

    while( true )
    {
        char c = (char)waitKey(10);

        if( c == 27 )
            { break; }

        imshow( "originals", imgAB );
        imshow( "product", product );
    }

    return 0;
}
于 2013-01-06T01:15:11.743 に答える
1

そうです、マトリックス imgA、imgB を CV32FC1 タイプに変換する必要があります。このマトリックスの最大値は 255 であるため、可能な最大値は 65025 です。ただし、imgA と imgB の最大値は同じ場所にない可能性があるため、64009 はかなり可能性があります。

于 2013-01-05T21:05:30.687 に答える