How to creat a 3-d matrix using Mat - c++

I want to use these code to create a 3-d matrix
int size[3] = { 100, 100,100};
cv::Mat mat3D(3, size, CV_8UC1, cv::Scalar(0));
but after I debug my code, I find
it seems that I don't get the right matrix, what's the problem?

Your code seems ok, maybe the debugger is misinterpreting.
This code displays well the 24 elements (I changed the dimensions to have a smaller matrix)
int size[3] = { 2, 3, 4};
cv::Mat mat3D(3, size, CV_8UC1, cv::Scalar(0));
std::cout << "Total size " << mat3D.size << std::endl;
int counter = 0;
for(cv::MatConstIterator_<uchar> it = mat3D.begin<uchar>(); it != mat3D.end<uchar>(); ++it){
std::cout << " " << (int) *it;
counter ++;
}
std::cout << std::endl;
std::cout << counter << " elts" << std::endl;

Your code is correct.
Concerning your debugger output, when dealing with multidimensional cv::Mat it is the expected behaviour. The OpenCV documentation for cv:Mat::rows reads: "the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions". Indeed, your debugger displays the values of channels x rows x columns (1 x -1 x -1).
You can try this to enumerate some cv::Mat related attributes:
std::cout
<< "dims : " << mat3D.rows
<< "\nchannels() : " << mat3D.channels()
<< "\nrows : " << mat3D.rows
<< "\ncols : " << mat3D.cols
<< "\nsize() : " << mat3D.size()
<< "\nsize : " << mat3D.size;
Your output should be:
dims : 3
channels() : 1
rows : -1
cols : -1
size() : [-1 x -1]
size : 1000 x 100 x 100

You can try this:
int DImensions3D[] = { 100,100 ,100 };
cv::Mat RTstruct3D(3,DImensions3D, CV_8U, Scalar(0));

One way is, you can use .reshape()
if you have one dimensional array
you can convert it to 3x3 array using below code
int x[] = {1,2,3,4,5,6,7,8,9};
int len_x = sizeof(x)/sizeof(x[0]);
cv::Mat mat3D(1,len_x, CV_32S,x);
mat3D = mat3D.reshape(3,3); //(dimension, height)

Related

Print multidimensional Mat in OpenCV (C++)

In the OpenCV Tutorial
http://docs.opencv.org/master/d6/d6d/tutorial_mat_the_basic_image_container.html
is the following example for creating a Mat.
int sz[3] = {2,2,2};
Mat L(3,sz, CV_8UC(1), Scalar::all(0));
This works fine, but when i try to print the Mat my programm crashes.
cout << "L = " << endl << " " << L << endl << endl;
Why doesn't this work ?
Is there a way to do this without loops or splitting the Mat L ?
To print n-dim matrix you could use Matrix slice. Since 2d matrices are stored row by row, 3d matrices plane by plane and so on, you could use code:
cv::Mat sliceMat(cv::Mat L,int dim,std::vector<int> _sz)
{
cv::Mat M(L.dims - 1, std::vector<int>(_sz.begin() + 1, _sz.end()).data(), CV_8UC1, L.data + L.step[0] * 0);
return M;
}
To perform mat slice.For more dimensions you should make more slices. Example shows 3 and 4 dimension matrices:
std::cout << "3 dimensions" << std::endl;
std::vector<int> sz = { 3,3,3 };
cv::Mat L;
L.create(3, sz.data(), CV_8UC1);
L = cv::Scalar(255);
std::cout<< sliceMat(L, 1, sz);
std::cout << std::endl;
std::cout <<"4 dimensions"<< std::endl;
sz = { 5,4,3,5 };
L.create(4, sz.data(), CV_8UC1);
L = cv::Scalar(255);
std::cout << sliceMat(sliceMat(L, 1, sz),2, std::vector<int>(sz.begin() + 1, sz.end()));
end result screen

Why are the matrices not initialized/printed correctly?

I am playing around with cv::Mat and think my code really behaves weird, although I follow the syntax described in here.
Code:
std::cout << "parameter for matrices: " << "x = " << X << " y = " << Y << " psi = " << Psi << std::endl;
double dataRot[] = { cos(Psi), -sin(Psi), sin(Psi), cos(Psi) };
double dataTrans[] = { X, Y };
cv::Mat matRot(2, 2, CV_32FC1, dataRot);
cv::Mat matTrans(2, 1, CV_32FC1, dataTrans);
std::cout << "matRot = " << matRot.at<double>(0,0) << "," << matRot.at<double>(0,1) << ";" << matRot.at<double>(1,0) << "," << matRot.at<double>(1,1) << std::endl;
std::cout << "matRot = " << matRot << std::endl;
std::cout << "matTrans = " << matTrans.at<double>(0,0) << "," << matTrans.at<double>(0,1) << std::endl;
std::cout << "matTrans = " << matTrans << std::endl;
matOut = matRot*matIn + matTrans*cv::Mat::ones(1, matIn.cols, CV_32FC1);
Output:
parameter for matrices: x = 20.5 y = 20 psi = 0
matRot = 1,-0;-0,0
matRot = [0, 1.875;
0, -0]
matTrans = 20.5,20
matTrans = [0; 2.8203125]
Why is the identity matrix not initalized correctly?
And why does the second way of printing a matrix deliver wrong results?
Any help is appreciated.
Since you're working with double, the OpenCV matrix type should be CV_64FC1:
cv::Mat matRot(2, 2, CV_64FC1, dataRot);
cv::Mat matTrans(2, 1, CV_64FC1, dataTrans);
For simplicity, you can also use:
cv::Matx22d matRot(cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Matx21d matTrans(X, Y);
or:
cv::Mat1d matRot = (cv::Mat1d(2,2) << cos(Psi), -sin(Psi), sin(Psi), cos(Psi));
cv::Mat1d matTrans = (cv::Mat1d(2,1) << X, Y);
and access values like:
std::cout << matRot(row, col);

How to access 3D Histogram values in C++ using OpenCV?

I am trying to access an 3D histogram of a RGB image. But the histogram matrix returns the number of rows and columns equal to -1. I want to iterate through the histogram and check the individual values in the 3D matrix. But, when I check the number of rows and columns in the matrix, I get -1 as shown below.
CODE
int main( int argc, const char** argv ) {
Mat image = imread("fl.png");
int histSize[3] = {8, 8, 8};
float range[2] = {0, 256};
const float * ranges[3] = {range, range, range};
int channels[3] = {0, 1, 2};
Mat hist;
calcHist(&image, 1, channels, Mat(), hist, 3, histSize, ranges);
cout << "Hist.rows = "<< hist.rows << endl;
cout << "Hist.cols = "<< hist.cols << endl;
return 0;
}
OUTPUT
Hist.rows = -1
Hist.cols = -1
What mistake am I making? How can I access the individual matrix values.
From the documentation of Mat:
//! the number of rows and columns or (-1, -1) when the array has more than 2 dimensions
But you have 3 dimensions.
You can access individual values of your histogram using hist.at<T>(i,j,k).
Or you can use iterators as described in the documentation here.
Code
// Build with gcc main.cpp -lopencv_highgui -lopencv_core -lopencv_imgproc
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
using std::cout;
using std::endl;
using namespace cv; # Please, don't include whole namespaces!
int main( int argc, const char** argv ) {
Mat image = imread("good.jpg");
int histSize[3] = {8, 8, 8};
float range[2] = {0, 256};
const float * ranges[3] = {range, range, range};
int channels[3] = {0, 1, 2};
Mat hist;
calcHist(&image, 1, channels, Mat(), hist, 3, histSize, ranges);
cout << "Hist.dims = " << hist.dims << endl;
cout << "Value: " << hist.at<double>(0,0, 0) << endl;
cout << "Hist.rows = "<< hist.rows << endl;
cout << "Hist.cols = "<< hist.cols << endl;
return 0;
}
Iterate through every value:
for (MatConstIterator_<double> it = hist.begin<double>(); it != hist.end<double>(); it++) {
cout << "Value: " << *it << "\n";
}
cout << std::flush;
Iterate through every value using indices:
for (int i=0; i<histSize[0]; i++) {
for (int j=0; j<histSize[1]; j++) {
for (int k=0; k<histSize[2]; k++) {
cout << "Value(" << i << ", " << j << ", " << k <<"): " << hist.at<double>(i, j, k) << "\n";
}
}
}
cout << std::flush;

opencv - image multiplication

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 code:
#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;
}
here is the result:
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
I think that max value in the product has to be greater than 255, but is truncated to 255 because the type of the two matrixes is 16.
I have tried to convert the matrixes to CV_32F but the maxVal in the product is 64009 (a number that i don't understand)
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;
}
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.

Getting pixel color with Magick++?

I've already asked this question, but that was about FreeImage. Now I'm trying to do the same thing with ImageMagick (to be more correct, with Magick++).
All I need is to get the RGB value of pixels in an image with the ability to print it out onto the screen. I asked this in the ImageMagick forum, but it seems there is nobody there. :-( Can anybody help, please?
Version 6 API
Given an "Image" object, you have to request a "pixel cache", then work with it. Documentation is here and here:
// load an image
Magick::Image image("test.jpg");
int w = image.columns();
int h = image.rows();
// get a "pixel cache" for the entire image
Magick::PixelPacket *pixels = image.getPixels(0, 0, w, h);
// now you can access single pixels like a vector
int row = 0;
int column = 0;
Magick::Color color = pixels[w * row + column];
// if you make changes, don't forget to save them to the underlying image
pixels[0] = Magick::Color(255, 0, 0);
image.syncPixels();
// ...and maybe write the image to file.
image.write("test_modified.jpg");
Version 7 API
Access to pixels has changed in version 7 (see: porting), but low-level access is still present:
MagickCore::Quantum *pixels = image.getPixels(0, 0, w, h);
int row = 0;
int column = 0;
unsigned offset = image.channels() * (w * row + column);
pixels[offset + 0] = 255; // red
pixels[offset + 1] = 0; // green
pixels[offset + 2] = 0; // blue
#Sga's answer didn't work for me, I'm using the ImageMagick-7.0.7-Q8 (8 bit depth) library.
Here's how I did it, to scan an image pixel by pixel and output each one's RGB value:
// "InitializeMagick" called beforehand!
void processImage()
{
std::ifstream fin;
std::stringstream fs;
fs << "/img.png";
std::cout << "Opening image \"" << fs.str() << "\".." << std::endl;
try
{
Image img;
img.read( fs.str() );
int imgWidth = img.columns();
int imgHeight = img.rows();
std::cout << "Image width: " << imgWidth << std::endl;
std::cout << "Image height: " << imgHeight << std::endl;
std::cout << "Image channels: " << img.channels() << std::endl;
img.modifyImage();
for ( int row = 0; row <= imgHeight; row++ )
{
for ( int column = 0; column <= imgWidth; column++ )
{
ColorRGB px = img.pixelColor( column, row );
std::cout << "Pixel " << column << "," << row << " R: " << px.red() << " G: " << px.green() <<
" B: " << px.blue() << std::endl;
}
}
}
catch ( Magick::Exception & error )
{
std::cerr << "Caught Magick++ exception: " << error.what() << std::endl;
}
fin.close(); // Close the file
}