OpenCV ConvertTo CV_32SC1 from CV_8UC1 - opencv

Hello I am using opencv in version 3.4 and want to read an image (*.pgm) and then convert it to CV_32SC1. Therefore I use the following code (part):
img = imread(f, CV_LOAD_IMAGE_GRAYSCALE);
img.convertTo(imgConv, CV_32SC1);
The problem is the following, all pixels are converted to zero, and I don't understand why. I'm checking by (and imshow("Image", imgConv);)
cout << static_cast<int>(img.at<uchar>(200,100));
cout << static_cast<int32_t>(imgConv.at<int32_t>(200,100)) << endl;
In my example this results in
74
74
I tested several points of the image, all pixels are simply the same, but shouldn't them being converted automatically to the 32 bit range, or do I have to manage that manually?

You have to manage that manually. This is why cv::Mat::convertTo() has another parameter, a scale. For instance, if you want to convert from CV_8U to CV_32F you'd typically
img.convertTo(img2, CV_32F, 1.0/255.0);
to scale to the typical float-valued range. I'm not sure what your expected range for CV_32SC1 is, since you're going from unsigned to signed, but just add the scale factor you feel is right.

Related

Opencv Read Mat with double precision YAML

I am trying to read data from a YAML file using the tutorials available at the OpenCV website. I am using the ">>" operator as suggested.
cv::Mat R;
cv::FileStorage fs;
fs.open(filename, cv::FileStorage::READ);
R >> fs["matrix"];
It basically works but I want the matrix to be in double precision not in float precision. Typing the matrix R as a double matrix does not do the job. What would be the right way to achieve this.
To load the image as "double precision", aka of type CV_64F, the image need to be also stored as CV_64F.
If the image is saved as "single precision", aka of type CV_32F, you can however load it as CV_32F, and then convert to CV_64F with:
R.convertTo(R, CV_64F);
You can check the format of the saved matrix opening the yml file, and checking the field dt. For CV_32F formats it will have a f in it, for CV_64F formats it will have a d.

DataType<cv::detail::deriv_type>::depth what is it used for

I was wondering why this line is used for in the lucas kanade tracker in opencv:
DataType<cv::detail::deriv_type>::depth
can someone explain it to me?
In OpenCV, the depth of a Mat refers to the type of data contained in the Mat's data buffer. They are represented by integer values which correspond to a given data type. These integers are most commonly abstracted by an appropriate macro definition (e.g. uchar data is represented by the macro CV_8U).
cv::DataType is a type-traits class that provides a method to obtain the corresponding integer value without having to memorize which macro means which data type. There are very few cases where user code needs to use DataType::depth. Much more common is DataType::type.
A simple example shows one possible use of DataType::depth:
cv::Mat uchar_data = cv::Mat::ones(3, 3, CV_8UC1);
cv::Mat float_data;
uchar_data.convertTo(float_data, cv::DataType<float>::depth);
// ^^ This could equivalently be replaced
// by CV_32F macro
float_data.at<float>(0,1) += 0.5f;
std::cout << float_data << std::endl;

OpenCV FaceRecognizer wrong shapes for given matrices

I'm trying to make a FisherFaceRecognizer's predict() method work, but I keep getting an error
Bad argument (Wrong shapes for given matrices. Was size(src) =
(1,108000), size(W) = (36000,1).) in subspaceProject, file
/tmp/opencv-DCb7/OpenCV-2.4.3/modules/contrib/src/lda.cpp, line 187
This is similar to a question that was asked at Wrong shapes for given matrices in OPENCV
but in my case, both source and training images are the same data type, full color.
My code is adapted from the tutorial at http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html#fisherfaces
however, my test image is larger than the training images, so I needed to work on a region of interest (ROI) of the right size.
Here's how I read the images and converted sizes. I cloned the ROI matrix because an
earlier error message told me the target matrix must be contiguous:
vector<Mat> images;
images.push_back( cvLoadImage( trainingList[i].c_str()));
IplImage* img;
img = cvLoadImage( imgName.c_str() );
// take ROI and clone into a new Mat
Mat testSample1(img, Rect( xLoc, yLoc, images[0].cols, images[0].rows));
Mat testSample = testSample1.clone();
// Create a FisherFaceRecognizer in OpenCV
Ptr<FaceRecognizer> FFR = createFisherFaceRecognizer(0,DBL_MAX);
model->train(images, labels);
cout << " check of data type testSample is " << testSample.type() << " images is " << images[0].type() << endl;
int predictedLabel = model->predict(testSample);
//
I get an exception message at the predict statement.
The cout statement tells me both matrices have type 16, yet somehow it still doesn't believe the matrices are the same size and data type...
You should ensure the shapes, not types
Try
cout << testSample.rows << testSample.cols << images[0].rows << images[0].cols ;
Also
ensure that both ,training img & test img, are in the same color space
If not, Try
cvtColor(testSample, testSample_inSameSpaceOfTraining, CV_BGR2***); // default opencv colors "BGR"
I found out that the FisherFaceRecognizer requires grayscale images, so I should have loaded both training and test images like this:
trainingImages.push_back( imread( trainingList[i].c_str(), CV_LOAD_IMAGE_GRAYSCALE));
and
Mat img;
img = imread( imgName.c_str(), CV_LOAD_IMAGE_GRAYSCALE );
(also reconciled the type of img for consistency). The grayscale-only requirement is documented in the OpenCV reference manual (pdf available online) but apparently not in any of the online tutorials or other documents for FisherFaceRecognizer.

Can not convert with cvMerge,DFT

I am trying to make the dft of one single channeled image, and as cvDft is expecting complex values, I was adviced to merge the original image with another image with all 0's so this last one will be considered as imaginary part.
My problem comes when using cvmerge function,
Mat tmp = imread(filename,0);
if( tmp.empty() )
{cout << "Usage: dft <image_name>" << endl;
return -1;}
Mat Result(tmp.rows,tmp.cols,CV_64F,2);
Mat tmp1(tmp.rows,tmp.cols,CV_64F, 0);
Mat image(tmp.rows,tmp.cols,CV_64F,2);
cvMerge(tmp,tmp1,image);`
It gives me the next error: can not convert cvMAt to cvArr
Anyone could help me? thanks!
1) it seems like you're mixing up 2 different styles of opencv code
cv::Mat (- Mat) is a c++ class from the new version of opencv, cvMerge is a c function from the old version of opencv.
instead of using cvmerge use merge
2) you're trying to merge a matrix (tmp) of type CV_8U (probably) with a CV_64F
use convertTo to get tmp as CV_64F
3) why is your Result & image mats (the destination mat) are initializes to cv::Scalar(2)? i think you're misusing the constractor parameters. see here for more info.
4) you're image mat is a single channel mat and you wanted it as a 2 channel mat (as mentioned in the question), change the declaration to
Mat image(tmp.rows,tmp.cols,CV_64FC2);

counting bright pixels and summing them. Medical Image C++

Currently, I'm working on a project in medical engineering. I have a big image with several sub-images of the cell, so my first task is to divide the image.
I thought about the next thing:
Convert the image into binary
doing a projection of the brightness pixels into the x-axis so I can see where there are gaps between brightnesses values and then divide the image.
The problem comes when I try to reach the second part. My idea is using a vector as the projection and sum all the brightnesses values all along one column, so the position number 0 of the vector is the sum of all the brightnesses values that are in the first column of the image, the same until I reach the last column, so at the end I have the projection.
This is how I have tried:
void calculo(cv::Mat &result,cv::Mat &binary){ //result=the sum,binary the imag.
int i,j;
for (i=0;i<=binary.rows;i++){
for(j=0;j<=binary.cols;j++){
cv::Scalar intensity= binaria.at<uchar>(j,i);
result.at<uchar>(i,i)=result.at<uchar>(i,i)+intensity.val[0];
}
cv::Scalar intensity2= result.at<uchar>(i,i);
cout<< "content" "\n"<< intensity2.val[0] << endl;
}
}
When executing this code, I have a violation error. Another problem is that I cannot create a matrix with one unique row, so...I don't know what could I do.
Any ideas?! Thanks!
At the end, it does not work, I need to sum all the pixels in one COLUMN. I did:
cv::Mat suma(cv::Mat& matrix){
int i;
cv::Mat output(1,matrix.cols,CV_64F);
for (i=0;i<=matrix.cols;i++){
output.at<double>(0,i)=norm(matrix.col(i),1);
}
return output;
}
but It gave me a mistake:
Assertion failed (0 <= colRange.start && colRange.start <= colRange.end && colRange.end <= m.cols) in Mat, file /home/usuario/OpenCV-2.2.0/modules/core/src/matrix.cpp, line 276
I dont know, any idea would be helpful, anyway many thanks mevatron, you really left me in the way.
If you just want the sum of the binary image, you could simply take the L1-norm. Like so:
Mat binaryVectorSum(const Mat& binary)
{
Mat output(1, binary.rows, CV_64F);
for(int i = 0; i < binary.rows; i++)
{
output.at<double>(0, i) = norm(binary.row(i), NORM_L1);
}
return output;
}
I'm at work, so I can't test it out, but that should get you close.
EDIT : Got home. Tested it. It works. :) One caveat...this function works if your binary matrix is truly binary (i.e., 0's and 1's). You may need to scale the norm output with the maximum value if the binary matrix is say 0's and 255's.
EDIT : If you don't have using namespace cv; in your .cpp file, then you'll need to declare the namespace to use NORM_L1 like this cv::NORM_L1.
Have you considered transposing the matrix before you call the function? Like this:
sumCols = binaryVectorSum(binary.t());
vs.
sumRows = binaryVectorSum(binary);
EDIT : A bug with my code :)
I changed:
Mat output(1, binary.cols, CV_64F);
to
Mat output(1, binary.rows, CV_64F);
My test case was a square matrix, so that bug didn't get found...
Hope that is helpful!

Resources