4

嗨,我想玩一点 Mat 课。我想在两个图像之间明智地做一个产品元素,MATLAB immultiply的 c++/opencv 端口。

这是我的代码:

#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,但被截断为 255,因为两个矩阵的类型是 16。我试图将矩阵转换为 CV_32F 但产品中的 maxVal 是 64009(一个数字我不明白)

4

2 回答 2

5

感谢Wajih 的 评论,我做了一些基本的测试和一些基本的调试,我得到了完美的工作。我认为这可以成为关于 alpha 混合和图像乘法的迷你教程,但现在只有几行注释代码。

请注意,这两个图像必须具有相同的大小..并且肯定应该对可靠的代码进行一些错误检查..

希望它可以帮助某人!而且,当然,如果您有一些提示可以使此代码更具可读性或更紧凑(单行人员非常感谢!)或高效.. 只需发表评论,非常感谢!

#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 回答