How can I make a matrix same as MNIST image dataset. - c++

I'm trying to make a vector matrix, which is the same as MNIST image dataset.
Each image from the webcam is captured and store into the vector. However the matrix i created is different from the MNIST dataset. So the main code doesn't work for matrix I created.
I was thinking that maybe its because the pixel type is different.
What I noticed is, when I looked up a single matrix from MNIST data it had 15 decimal points. However I was not able to set 15 decimal points. When I set the image to be CV_FC64. It shows following error message.
"Assertion failed in cv::cvtColor, file C:\file path. "
The main code works for MNIST dataset.. I'm not sure what to do..
please advice. me.
while (1)
{
cap >> src;
src.convertTo(src, CV_64FC1);
src = src / 256;
cvtColor(src, src_gray, CV_RGB2GRAY);
resize(src_gray, src_N, size);
testX.push_back(src_N);
}

cvtColor only allows 8U, 16U and 32F bit-depths. So after you convertTo(..., CV_64FC1), the bit-depth is 64F and the assertion fails: https://github.com/opencv/opencv/blob/84699e0e1860a3485e3dfc12230fbded955dba13/modules/imgproc/src/color.cpp#L8676:
CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_32F );
If you really need 64F, it'd make sense to first cvtColor and then increase bit-depth to 64F using convertTo.

Related

error: (-215:Assertion failed) m.dims <= 2 in function 'FormattedImpl' in cv::dnn

I am loading a pre-trained TensorFlow model in the opencv dnn module using the following code -
cv::dnn::Net net = cv::dnn::readNetFromTensorflow("frozen_inference_graph.pb",
"graph.pbtxt");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA); //Run model on GPU
net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);
Mat image = imread("img.jpeg");
Mat resized;
cv::resize(image, resized, cv::Size(300, 300));
cout<<resized.size()<<endl;
cout<<"Resized"<<endl;
auto input_image = dnn::blobFromImage(image, 1.0, cv::Size(300, 300),
cv::Scalar(127.5, 127.5, 127.5),
false, false, CV_32F);
cout<<"Now setting Input";
net.setInput(input_image);
auto detections = net.forward();
cout<<detections;
return 0;
However the I get the following error as mentioned in the question -
what(): OpenCV(4.4.0) /home/atharva/opencv-4.4.0/modules/core/src/out.cpp:87: error: (-215:Assertion failed) m.dims <= 2 in function 'FormattedImpl'
Could someone please point out what the mistake is?. I believe there is some problem in BlobFromImage as nothing after it is getting printed.
TIA
This error occurs because you are trying to print a cv::Mat to standard output that has more than 2 dimensions. With cv::dnn, the output after using net.forward() is 4-dimensional. However I have no idea what model you are using because the output structure of the blob is different depending on what task you are trying to do. If I had to guess you are doing some sort of object detection given your choice of variable names. In that case, usually the first dimension is the batch size and since you are using only one image, the batch size is 1. The second dimension is the number of channels in the output. As you're doing object detection on the image, this will also be size 1. The third and fourth dimensions are the number of rows and columns for the final output layer.
Going on faith, you can extract a 2D version of this cv::Mat to print out to standard output by doing:
cv::Mat output(detections.size[2], detections.size[3], CV_32F, detection.ptr<float>());
Now that this is a 2D matrix, you can print out this instead by doing std::cout << output << std::endl;.

How to get a depth image from sparse depth data?

I am currently working on a problem where I have created an uint16 image of type CV_16UC1 based on Velodyne data where lets say 98% of the pixels are black (value 0) and the remaining pixels have the metric depth information (distance to that point). These pixels correspond to the velodyne points from the cloud.
cv::Mat depthMat = cv::Mat::zeros(frame.size(), CV_16UC1);
depthMat = ... //here the matrice is filled
If I try to display this image I get this:
On the image you can see that the brightest(white) pixels correspond to the pixels with biggest depth.From this I need to get a denser depth image or smth that would resemble a proper depth image like in the example shown on this video:
https://www.youtube.com/watch?v=4yZ4JGgLE0I
This would require proper interpolation and extrapolation of those points (the pixels of the 2D image) and it is here is where I am stuck. I am a beginner when it comes to interpolation techniques. Does anyone know how this can be done or at least can point me to a working solution or example algorithm for creating a depth map from sparse data?
I tried the following from the Kinect examples but it did not change the output:
depthMat.convertTo(depthf, CV_8UC1, 255.0/65535);
const unsigned char noDepth = 255;
cv::Mat small_depthf, temp, temp2;
cv::resize(depthf, small_depthf, cv::Size(), 0.01, 0.01);
cv::inpaint(small_depthf, (small_depthf == noDepth), temp, 5.0, cv::INPAINT_TELEA);
cv::resize(temp, temp2, depthf.size());
temp2.copyTo(depthf, (depthf == noDepth));
cv::imshow("window",depthf);
cv::waitKey(3);
I managed to get the desired output(something that resembles a depth image) by simply using dilation on the sparse depth image:
cv::Mat result;
dilate(depthMat, result, cv::Mat(), cv::Point(-1, -1), 10, 1, 1);

How can I get the mean image of several images in OpenCV(using C++)?

I am computing the mean image of two images and don't know the correct method to use the function mean() in OpenCV.
Mat img1,img2,img3;
img1=imread("picture1.jpg");
img2=imread("picture2.jpg");
img3=mean(img1,img2);
However it says
R6010
-abort() has been recalled
How can I get the average of img1 & img2?
Thanks.
You could use cv::accumulate :
Mat img3 = Mat::zeros(img1.size(), CV_32F); //larger depth to avoid saturation
cv::accumulate(img1, img3);
cv::accumulate(img2, img3);
img3 = img3/2;
According to opencv documentation :
"The function mean calculates the mean value M of array elements, independently for each channel, and return it:"
This mean it should return you a scalar for each layer of you image, and the second parameter is a mask of pixels to where to perform computation
have you simply tried to do something like this ?
img3 = (img1+img2) * 0.5;
[EDIT] to avoid some losses if values are > 255, you probably should convert your images to CV_32F, before performing computations, then cast the result of you operation into CV_8U using the cv::convertTo opencv documentation on ConvertTo

Issues multiplying Mat matrices

I am trying to project an image to eigenface convariance matrix that EigenFacesRecognizer of opencv returns. I use the following code to load eigenfaces parameters loading an image and trying to project the sample image to pca subspace.
Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
model->load("eigenfaces.yml"); // Load eigenfaces parameters
Mat eigenvalues = model->getMat("eigenvalues"); // Eigen values of PCA
Mat convMat = model->getMat("eigenvectors"); //Convariance matrix
Mat mean = model->getMat("mean"); // Mean value
string path = fileName;
Mat sample ,pca_ed_sample;
sample = imread(path, CV_LOAD_IMAGE_GRAYSCALE); //size 60x60
Mat nu = sample.reshape(1,3600 ).t(); //1x3600
pca_ed_sample = (nu - mean)*(convMat);
I am keeping 5 eigenvectors, so the size of eigenvalues 5x1, convMat3600x5 mean 1x3600. When I am trying to calculate pca_ed_sample it returns me:
cv::Exception at memory location 0x0011d300.Dimensionality reduction using default opencv eigenfaces...
OpenCV Error: Assertion failed (type == B.type() && (type == CV_32FC1 || type ==
CV_64FC1 || type == CV_32FC2 || type == CV_64FC2)) in unknown function, file .\
src\matmul.cpp, line 711`
The problem stands in nu Mat since when I trying to calculate nu*.nu.t();(1x3600* 3600x1) it returns the same issue. Am I having troubles due to reshape function?? I am trying to transform my sample mat to a vector, it seems to work but I cant understand why I cant even multiply nu with nu_transposed.
Matrix multiplication is only possible with floating point data, which is what the assertion error is trying to tell you.
Your image is loaded as type CV_8U, and you must first rescale that to float using the convertTo member.
sample = imread(path, CV_LOAD_IMAGE_GRAYSCALE); //size 60x60
cv::Mat sample_float;
sample.convertTo(sample_float, CV_32F); // <-- Convert to CV_32F for matrix mult
Mat nu = sample_float.reshape(1,3600 ).t(); //1x3600
pca_ed_sample = (nu - mean)*(convMat);

Access pixel value in a cvMat image in OpenCV

I have used Canny edge detector to successfully identify the edges of a given image. I'm struggling with finding specific points on this detected edge line.
My approach:
I used the cv::canny function in opencv and the output is stored in cv::Mat format. I want to iterate through the all values of the matrix and identify all those pixels where the edge is present so that I can detect the specific points on the detected edge line.
Function used:
cv::Canny(frame_gray,contours,50,150);
The output is stored in contours and it is of type CV_8UC3
To access the pixel value, have tried
contours.at<int>(i,j) != 0
and also
contours.at<uchar>(i,j) != 0
Will greatly appreciate help in the above. If the approach is correct and am missing something or else if i should try another approach
Thanks
Edit:
for(int i=0;i<img_width;i++)
{
if((int)contours.at<uchar>(i,neckcenter.y) > 0 )
{
Point multipoints(i,neckcenter.y);
circle( contours, multipoints, neckpoint, Scalar( 255, 0, 0 ),4, 8, 0 );
cout << (int)contours.at<uchar>(i,neckcenter.y) << endl;
}
}
I am using the above code which forms a small circle of radius 1 (defined by neckpoint) where it detects a point on and edge. The neckcenter.y is a constant value derived from an earlier calculation. What am i doing wrong here ?
Output of the code -
you probably want a grayscale pass before applying Canny:
Mat gray;
cvtColor(bgr,gray,CV_BGR2GRAY); // now gray is a 8bit, uchar Mat
Mat contours;
cv::Canny(gray,contours,50,150);
// now you're safe to use:
uchar value = contours.at<uchar>(i,j);
The syntax:
contours.at<uchar>(i,j)
Is correct for your case in terms of data type (i.e. a grayscale image). The problem is possibly hinted at by this line:
for(int i=0;i<img_width;i++)
When you access OpenCV pixels using at, you must specify the pixel position as (row, col), so your indexing is the wrong way round. Try this in all places where you access pixels:
contours.at<uchar>(j,i)
From the OpenCV documentation:
You have a 3 channel image of the type unsigned char. To access it you should use the cv::Vec3b type. Here is how to do it:
int channel = 0;//or 1 or 2
contours.at<cv::Vec3b>(i,j)[channel]
To check if all elements are 0:
contours.at<cv::Vec3b>(i,j)[0]==0 && contours.at<cv::Vec3b>(i,j)[1]==0 && contours.at<cv::Vec3b>(i,j)[2]==0
But where do you have the information that the image type of contours is CV_8UC3 ?