opencv - image multiplication

后端 未结 2 953
伪装坚强ぢ
伪装坚强ぢ 2021-01-13 12:29

hi, i\'m trying to play a little bit with Mat class. I want to do a product element wise between two images, the c++/opencv port of MATLAB immultiply.

This is my cod

相关标签:
2条回答
  • 2021-01-13 13:14

    Thanks to Wajih comment i have done some basic test, and some basic debug, and i got i work perfectly. I think this could become a mini tutorial on alpha blending and image multiply, but for now is only a few lines of commented code.

    note that the 2 images must be of the same size.. and for sure some error checking should be done for a solid code..

    Hope it helps someone! And, of course, if you have some hints to make this code more readable or more compact (one-liner guys are very appreciate!) or efficient.. just comment, thank you a lot!

    #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;
    }
    
    0 讨论(0)
  • 2021-01-13 13:25

    You are right, you should convert your matrices imgA, imgB to say CV32FC1 type. Since the max values in this matrices is 255, the maximum possible value is 65025. However, the maximum at imgA and imgB may not be in the same location, so 64009 is quite possible.

    0 讨论(0)
提交回复
热议问题