Vector of Uchar to cv::Mat - c++

I have an image which I am putting into a vector of uchar which I am sending from processor to processor using open mpi, however I need to put the vector of uchar into a cv::Mat.
Is there an easy way to do this?
cv::Mat image_on_proc = newpopulation(cv::Rect(0, start, population.cols, rows_in_section));
std::vector<byte> img = matToBytes(image_on_proc);
std::vector<uchar> test;
for(int i=0; i<image_on_proc.rows; i++)
{
for(int j=0; j<image_on_proc.cols; j++)
{
test.push_back(image_on_proc.at<uchar>(i,j));
}
}
MPI_Barrier(MPI_COMM_WORLD);
MPI_Send(&test[0],test.size()*sizeof(uchar), MPI_BYTE, 0, 99, MPI_COMM_WORLD);
The above shows how I put the image into the vector and send it, there is a corresponding recv and it works, however I do not know how to turn it back into an image.

You can store a Mat into a vector<uchar> using:
Mat img = ...; // img must be CV_8UC1 in this example
vector<uchar> v(img.begin<uchar>(), img.end<uchar>());
and back into a Mat using:
Mat img2(img.rows, img.cols, img.type(), v.data());
Note that here you're not copying values, but just creating a Mat header for the data in v, so img2 will reflect any change done on v. If v goes out of scope, then img2 becomes invalid. You can simply use clone() to copy data, like:
Mat img3 = Mat(img.rows, img.cols, img.type(), v.data()).clone();

Related

Matrix assignement value error in opencv C++ with mat.at<uchar>(i,j)

I am learning image processing with OpenCV in C++. To implement a basic down-sampling algorithm I need to work on the pixel level -to remove rows and columns. However, when I assign values with mat.at<>(i,j) other values are assign - things like 1e-38.
Here is the code :
Mat src, dst;
src = imread("diw3.jpg", CV_32F);//src is a 479x359 grayscale image
//dst will contain src low-pass-filtered I checked by displaying it works fine
Mat kernel;
kernel = Mat::ones(3, 3, CV_32F) / (float)(9);
filter2D(src, dst, -1, kernel, Point(-1, -1), 0, BORDER_DEFAULT);
// Now I try to remove half the rows/columns result is stored in downsampled
Mat downsampled = Mat::zeros(240, 180, CV_32F);
for (int i =0; i<downsampled.rows; i ++){
for (int j=0; j<downsampled.cols; j ++){
downsampled.at<uchar>(i,j) = dst.at<uchar>(2*i,2*j);
}
}
Since I read here OpenCV outputing odd pixel values that for cout I needed to cast, I wrote downsampled.at<uchar>(i,j) = (int) before dst.at<uchar> but it does not work also.
The second argument to cv::imread is cv::ImreadModes, so the line:
src = imread("diw3.jpg", CV_32F);
is not correct; it should probably be:
cv::Mat src_8u = imread("diw3.jpg", cv::IMREAD_GRAYSCALE);
src_8u.convertTo(src, CV_32FC1);
which will read the image as 8-bit grayscale image, and will convert it to floating point values.
The loop should look something like this:
Mat downsampled = Mat::zeros(240, 180, CV_32FC1);
for (int i = 0; i < downsampled.rows; i++) {
for (int j = 0; j < downsampled.cols; j++) {
downsampled.at<float>(i,j) = dst.at<float>(2*i,2*j);
}
}
note that the argument to cv::Mat::zeros is CV_32FC1 (1 channel, with 32-bit floating values), so Mat::at<float> method should be used.

How do i store multiple images into multiple matrices

I have a file of 100+ images which i need to store each image into their individual matrices. Is there any way i can do this instead of hard-coding (as shown below)?
Mat src1 = imread("ts_04-11-21_16-27-00-mod", CV_8UC1);
Mat src2 = imread("ts_04-11-21_16-27-01-mod", CV_8UC1);
Mat src3 = imread("ts_04-11-21_16-27-02-mod", CV_8UC1);
Mat src4 = imread("ts_04-11-21_16-27-03-mod", CV_8UC1);
Mat src5 = imread("ts_04-11-21_16-27-04-mod", CV_8UC1);
I'm using Opencv and C++.
Maybe something like:
vector<Mat> images;
for(int i=0;i<n;i++)
{
Mat in = imread("ts_04-11-21_16-27-0"+i+"-mod", CV_8UC1);
images.push_back(in);
}
beware that reading a lot of images can be very memory consuming.

Should I initialize a cv::Mat

I have this code:
mapx.create(image.size(), CV_32FC1);
mapy.create(image.size(), CV_32FC1);
what is the values in the mapx and mapy after this? Are all data is zero?
what about this type of initialization:
cv::Mat mapx(image.size(), CV_32FC1);
Do I need explicitly set the value of each element to zero?
How can I set the value of each element to say -1?
Data after create should be undefined. In fact, your are just allocating memory.
cv::Mat mapx(image.size(), CV_32FC1);
is exactly as
cv::Mat1f mapx(image.size());
and
cv::Mat mapy;
mapy.create(image.size(), CV_32FC1);
You can assign an initial value (e.g. -1) like this:
cv::Mat1f(images.size(), -1.f);
Regarding you main question Should I initialize a cv::Mat, the answer is that in general you don't need to. From OpenCV doc:
Instead of writing:
Mat color;
...
Mat gray(color.rows, color.cols, color.depth());
cvtColor(color, gray, CV_BGR2GRAY);
you can simply write:
Mat color;
...
Mat gray;
cvtColor(color, gray, CV_BGR2GRAY);
You can see the opencv documentation :
Mat::zeros
Mat::ones
Mat A = Mat::ones(100, 100, CV_8U)*3; // make 100x100 matrix filled with 3.
http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-zeros
How can I set the value of each element to say -1?
I think something like that :
Mat A = Mat::ones(100, 100, CV_8U)*-1; // make 100x100 matrix filled with -1.

OpenCV cv::Mat to short* (avoiding memcpy)

I have a C++ function that is to be called from someone else's C# application. As input my function is given an array of signed short integers, the dimensions of the image it represents, and memory allocated for the returning data, namely another array of signed short integers. This would represent my function's header:
my_function (short* input, int height, int width, short* output)
Inside my function I create a cv::Mat from input, like this:
cv::Mat mat_in = cv::Mat (height, width, CV_16S, input);
This mat_in is then converted to CV_32F and processed by OpenCV's cv::bilateralFilter. After it returns cv::Mat mat_out, I convert the data back to CV_16S (bilateralFilter only accepts CV_8U and CV_32F). Now I need to convert this cv::Mat mat_out back to an array of short integers so that it may be returned to the calling function. This is my code:
my_function (short* input, int height, int width, short* output)
{
Mat mat_in_16S = Mat (height, width, CV_16S, input);
Mat mat_in_32F = Mat (height, width, CV_32F);
Mat mat_out_CV_32F = Mat (height, width, CV_32F);
mat_in_16S.convertTo (mat_in_32F, CV_32F);
bilateralFilter (mat_in_32F, mat_out_32F, 5, 160, 2);
Mat mat_out_16S = Mat (mat_in_16S.size(), mat_in_16S.type());
mat_out_32F.convertTo (mat_out_16S, CV_16S);
return 0;
}
Obviously, somewhere there at the end I need to get the data that is in mat_out_16S into output. My first try was to return a reference:
output = &mat_out_16S.at<short>(0,0);
but of course I realised that this was a silly idea, as mat_out_16S goes out of scope as soon as the function returns, leaving output pointing at emptiness. Currently my best attempt is as follows (from this question):
memcpy ((short*)output, (short*)mat_out_16S.data, height*width*sizeof(short));
Now I would like to know, is there a better way? It feels kind of inefficient to copy all this data, but I don't see what else I can do. I can't return a cv::Mat unfortunately. If there is no better way, is my current memcpy method safe at least? My data are all 2-byte signed short integers, so I don't think there should be issues with padding, but I don't want to run into any unpleasant surprises.
You can use this constructor for your mat_out_16S:
Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
So your function will be:
my_function (short* input, int height, int width, short* output)
{
Mat mat_in_16S = Mat (height, width, CV_16S, input);
Mat mat_in_32F = Mat (height, width, CV_32F);
Mat mat_out_CV_32F = Mat (height, width, CV_32F);
mat_in_16S.convertTo (mat_in_32F, CV_32F);
bilateralFilter (mat_in_32F, mat_out_32F, 5, 160, 2);
Mat mat_out_16S = Mat (mat_in_16S.size(), mat_in_16S.type(), output);
mat_out_32F.convertTo (mat_out_16S, CV_16S);
return 0;
}

Opencv C++ to C interface function conversion

void doCorrectIntensityVariation(Mat& image)
{
Mat kernel = getStructuringElement(MORPH_ELLIPSE, Size(19,19));
Mat closed;
morphologyEx(image, closed, MORPH_CLOSE, kernel);
image.convertTo(image, CV_32F); // divide requires floating-point
divide(image, closed, image, 1, CV_32F);
normalize(image, image, 0, 255, NORM_MINMAX);
image.convertTo(image, CV_8UC1); // convert back to unsigned int
}
inline void correctIntensityVariation(IplImage *img)
{
//Mat imgMat(img); copy the img
Mat imgMat;
imgMat = img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
imshow("gamma corrected",imgMat); cvWaitKey(0);
}
When I call
cvShowImage ("normal", n_im); cvWaitKey (0);
correctIntensityVariation(n_im);//here n_im is IplImage*
cvShowImage ("After processed", n_im); cvWaitKey (0);
// here I require n_im for further processing
I wanted "After processed" to be same as that of "gamma corrected" but what I found "After processed" was not the same as that of "gamma corrected" but same as that of "normal" . Why?? What is going wrong??
A very simple wrapper should do the job
Cheetsheet of openCV
I rarely use the old api, because Mat are much more easier to deal with, and
they do not have performance penalty when compare with the old c api.Like the openCV
tutorial page say The main downside of the C++ interface is that many embedded development systems at the moment support only C. Therefore, unless you are targeting embedded platforms, there’s no point to using the old methods (unless you’re a masochist programmer and you’re asking for trouble).
openCV tutorial
cv::Mat to Ipl
Ipl to cv::Mat and Mat to Ipl
IplImage* pImg = cvLoadImage(“lena.jpg”);
cv::Mat img(pImg,0); //transform Ipl to Mat, 0 means do not copy
IplImage qImg; //not pointer, it is impossible to overload the operator of raw pointer
qImg = IplImage(img); //transform Mat to Ipl
Edit : I did a mistake earlier, if the Mat would be reallocated in the function, you need
to copy or try to steal the resource(I don't know how to do it yet) from the Mat.
Copy the data
void doCorrectIntensityVariation(cv::Mat& image)
{
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(19,19));
cv::Mat closed;
cv::morphologyEx(image, closed, cv::MORPH_CLOSE, kernel);
image.convertTo(image, CV_32F); // divide requires floating-point
cv::divide(image, closed, image, 1, CV_32F);
cv::normalize(image, image, 0, 255, cv::NORM_MINMAX);
image.convertTo(image, CV_8UC1); // convert back to unsigned int
}
//don't need to change the name of the function, the compiler treat
//these as different function in c++
void doCorrectIntensityVariation(IplImage **img)
{
cv::Mat imgMat;
imgMat = *img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
IplImage* old = *img;
IplImage src = imgMat;
*img = cvCloneImage(&src);
cvReleaseImage(&old);
}
int main()
{
std::string const name = "onebit_31.png";
cv::Mat mat = cv::imread(name);
if(mat.data){
doCorrectIntensityVariation(mat);
cv::imshow("gamma corrected mat",mat);
cv::waitKey();
}
IplImage* templat = cvLoadImage(name.c_str(), 1);
if(templat){
doCorrectIntensityVariation(&templat);
cvShowImage("mainWin", templat);
// wait for a key
cvWaitKey(0);
cvReleaseImage(&templat);
}
return 0;
}
you could write a small function to alleviate the chores
void copy_mat_Ipl(cv::Mat const &src, IplImage **dst)
{
IplImage* old = *dst;
IplImage temp_src = src;
*dst = cvCloneImage(&temp_src);
cvReleaseImage(&old);
}
and call it in the function
void doCorrectIntensityVariation(IplImage **img)
{
cv::Mat imgMat;
imgMat = *img; //no copy is done, imgMat is a header of img
doCorrectIntensityVariation(imgMat);
copy_mat_to_Ipl(imgMat, img);
}
I will post how to "steal" the resource from Mat rather than copy after
I figure out a solid solution.Anyone know how to do it?