图像乘法

opencv - image multiplication

本文关键字:图像      更新时间:2023-10-16

嗨,我试着和Mat类玩一点。我想在两个图像之间做一个乘积元素明智的,c++/opencv端口的MATLAB immultiply。

这是我的代码:

#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(我不理解的数字)

感谢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;
}

你是对的,你应该转换你的矩阵imgA, imgB说CV32FC1类型。因为这个矩阵的最大值是255,所以可能的最大值是65025。但是,imgA和imgB的最大值可能不在同一位置,所以很可能是64009。