嗨,我正在尝试玩一些 Mat 类(class)。 我想在两个图像之间明智地做一个产品元素,MATLAB 的 c++/opencv 端口 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,但由于两个矩阵的类型为 16 而被截断为 255。 我试图将矩阵转换为 CV_32F,但乘积中的 maxVal 是 64009(我不理解的数字)
最佳答案
感谢Wajih comment我已经完成了一些基本测试和一些基本调试,并且我的工作非常完美。我认为这可以成为有关 alpha 混合和图像乘法的迷你教程,但目前只有几行注释代码。
请注意,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;
}
关于c++ - opencv - 图像乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14175114/