In OpenCV, if I have a Mat img that contains uchar data, how do I convert the data into float? Is there a function available? Thank you.
If you meant c++ then you have
#include<opencv2/opencv.hpp>
using namespace cv;
Mat img;
img.create(2,2,CV_8UC1);
Mat img2;
img.convertTo(img2, CV_32FC1); // or CV_32F works (too)
details in opencv2refman.pdf.
UPDATE:
CV_32FC1 is for 1-channel (C1, i.e. grey image) float valued (32F) pixels
CV_8UC1 is for 1-channel (C1, i.e. grey image) unsigned char (8UC) valued ones.
UPDATE 2:
According to Arthur Tacca, only CV_32F is correct (or presumably CV_8U), since convertTo should not change the number of channels. It sounds logical right? Nevertheless, when I have checked opencv reference manual, I could not find any info about this, but I agree with him.
Use cvConvert function. In Python:
import cv
m = cv.CreateMat(2, 2, cv.CV_8UC1)
m1 = cv.CreateMat(2, 2, cv.CV_32FC1)
cv.Convert(m, m1)
Related
While reading the image with IMREAD_COLOR, 'dft' function throws the error:
DFT function works just fine when reading an image with IMREAD_GRAYSCALE. But I want to read the image with IMREAD_COLOR.
main function
const char* filename = "face.jpg";
Mat I = imread(filename, IMREAD_COLOR);
if(I.empty()) return 0;
Mat padded;
I.convertTo(padded, CV_32F);
Mat fft;
Mat planes[2];
dft(padded, fft, DFT_SCALE|DFT_COMPLEX_OUTPUT);
Mat fftBlur = fft.clone();
fftBlur *= 0.5;
split(fftBlur, planes);
Mat ph, mag;
mag.zeros(planes[0].rows, planes[0].cols, CV_32F);
ph.zeros(planes[0].rows, planes[0].cols, CV_32F);
cartToPolar(planes[0], planes[1], mag, ph);
merge(planes, 2, fftBlur);
//inverse
Mat invfft;
dft(fftBlur, invfft, DFT_INVERSE|DFT_REAL_OUTPUT);
Mat result;
invfft.convertTo(result, CV_8U);
Mat image;
cvtColor(result, image, COLOR_GRAY2RGB);
imshow("Output", result);
imshow("Image", image);
waitKey();
The message you receive is an assertion it tells you DFT function only takes single precision floating point image with one or two channels (CV_32FC1, CV_32FC2, the letter C at the end of the flag mean channel) or double precision floating point images with one or two channels (CV_64FC1, CV_64FC2).
The two channel case is actually the representation of complex image in OpenCV data storage.
If you want you can split you image to std::vector<cv::Mat> where each element does represent one channel, using cv::split apply the DFT on each channels do the processing you want on it and recreate an multichannel image thanks to cv::merge.
From Learning OpenCV (about dft function):
The input array must be of floating-point type and may be single- or double-channel. In the single-channel case, the entries are assumed to be real numbers, and the output will be packed in a special space-saving format called complex conjugate symmetrical.
The same question is mentioned here in terms of matlab image processing.
You can check out cv::split function if you want to separate channels of your initial image.
I'm trying to implement color conversion from RGB-LMS and LMS-RGB back and using reshape for multiplication matrix, following answer from this question : Fastest way to apply color matrix to RGB image using OpenCV 3.0?
My ori Mat object is from an image with 3 channel (RGB), and I need to multiply them with matrix of 1 channel (lms), it seems like I have an issue with the matrix type. I've read reshape docs and questions related to this issue, like Issues multiplying Mat matrices, and I believe I have followed the instructions.
Here's my code : [UPDATED : Convert into flat image]
void test(const Mat &forreshape, Mat &output, Mat &pic, int rows, int cols)
{
Mat lms(3, 3, CV_32FC3);
Mat rgb(3, 3, CV_32FC3);
Mat intolms(rows, cols, CV_32F);
lms = (Mat_<float>(3, 3) << 1.4671, 0.1843, 0.0030,
3.8671, 27.1554, 3.4557,
4.1194, 45.5161 , 17.884 );
/* switch the order of the matrix according to the BGR order of color on OpenCV */
Mat transpose = (3, 3, CV_32F, lms).t(); // this will do transpose from matrix lms
pic = forreshape.reshape(1, rows*cols);
Mat flatFloatImage;
pic.convertTo(flatFloatImage, CV_32F);
rgb = flatFloatImag*transpose;
output = rgb.reshape(3, cols);
}
I define my Mat object, and I have converted it into float using convertTo
Mat ori = imread("ori.png", CV_LOAD_IMAGE_COLOR);
int rows = ori.rows;
int cols = ori.cols;
Mat forreshape;
ori.convertTo(forreshape, CV_32F);
Mat pic(rows, cols, CV_32FC3);
Mat output(rows, cols, CV_32FC3);
Error is :
OpenCV Error: Assertion failed (type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2)) ,
so it's the type issue.
I tried to change all type into either 32FC3 of 32FC1, but doesn't seem to work. Any suggestion ?
I believe what you need is to convert your input to a flat image and than multiply them
float lms [] = {1.4671, 0.1843, 0.0030,
3.8671, 27.1554, 3.4557,
4.1194, 45.5161 , 17.884};
Mat lmsMat(3, 3, CV_32F, lms );
Mat flatImage = ori.reshape(1, ori.rows * ori.cols);
Mat flatFloatImage;
flatImage.convertTo(flatFloatImage, CV_32F);
Mat mixedImage = flatFloatImage * lmsMat;
Mat output = mixedImage.reshape(3, imData.rows);
I might have messed up with lms matrix there, but I guess you will catch up from here.
Also see 3D matrix multiplication in opencv for RGB color mixing
EDIT:
Problem with distortion is that you got overflow after float to 8U conversion. This would do the trick:
rgb = flatFloatImage*transpose;
rgb.convertTo(pic, CV_32S);
output = pic.reshape(3, rows)
Output:
;
Also I'm not sure but quick google search gives me different matrix for LMS see here. Also note that opencv stores colors in B-G-R format instead of RGB so change your mix mtraixes recordingly.
Here is my problem, I have 8 mat grayscale images with 100*100,
I would like to combine them together into a 3d matrix like 100*100*8;
Here is my code: (8 mat are named from img1 to img8 with same size 100*100 and pixel value is double)
int sz[3] = {img1.rows,img1.cols,8};
Mat m(3,sz, CV_8UC1, Scalar::all(0));
m.at<double>(m.rows,m.cols,1)=img1;
I think this code can put img1 into the 1st plane of 3d matrix 100*100*8, but then I got a error:
The type cannot convert from MAT to double.
How could I fix this problem?
You have to convert the double type matirces into uchar matrices first, which can be done as follows:
cv::Mat img1u;
img1.convertTo(img1u);
m.at<double>(m.rows,m.cols,1)=img1u;
the problem is to fourie transform ( cv::dft ) a signal with fourie descriptors. So the mat should be complex numbers :(
But my problem is how can make a mat with complex numbers ?
Please help me to find an example or any other that show me how to store a complex number(RE + IM) to a mat ?
Is there a way to use merge ?
merge()
I found an answer saying:
I think you can use merge() function here, See the Documentation
It says : Composes a multi-channel array from several single-channel arrays.
Reference: How to store complex numbers in OpenCV matrix?
look at the nice dft sample in the opencv repo, also at the dft tutorial
so, if you have a Mat real, and a Mat imag (both of type CV_32FC1):
Mat planes[] = {real,imag};
Mat complexImg;
merge(planes, 2, complexImg); // complexImg is of type CV_32FC2 now
dft(complexImg, complexImg);
split(complexImg, planes);
// real=planes[0], imag=planes[1];
I want to compare the values of a Mat with RBG image (i.e. Mat with 3 channels) with a threshold Mat th = [0.2,0.2,0.2] where each value in Mat th corresponds to threshold for each channel i.e. th=[th for Red,th for blue,th for Green].
When I declare th as Mat th(3,1,CV_32F,Scalar(0.2,0.2,0.2));
The output of cout<<th; shows th=[0,0,0]. What mistake am I doing in declaring the datatype?
And for 3 channels, do I need to declare it as Mat th(1,1,CV_32UC3,Scalar(0.2,0.2,0.2))?
Which data type helps to capture the logic for 3 channels and non-integer numbers ?
I believe you are looking for CV_32FC3. Another option would be to use Vec3f if you only want a single pixel.
Mat th(1,1,CV_32FC3,Scalar(0.2,0.2,0.2));
or
Vec3f th(0.2, 0.2, 0.2);
Use type CV_32FC3 or CV_64FC3 for float in 3-channel Mat.
Mat th(3,1,CV_32FC3,Scalar(0.2,0.2,0.2));
or
Mat th(3,1,CV_64FC3,Scalar(0.2,0.2,0.2));