I'm currently playing around with a 360° camera and want to use OpenCV's spherical warper for that. However, each time I try to run a simple program that makes use of the stitcher functionality, it fails to return a stitched image. I'm basically just taking the 360° picture, divide it into two separate pictures (front- and rear lens) and want to stitch them back together.
Here's the code:
Mat srcImage = imread("assets/360_0043.JPG");
Mat frontLensImage(srcImage, Rect(0, 0, srcImage.cols / 2, srcImage.rows));
Mat rearLensImage(srcImage, Rect(srcImage.rows, 0, srcImage.cols / 2, srcImage.rows));
vector<Mat> imagesToStitch;
imagesToStitch.push_back(frontLensImage);
imagesToStitch.push_back(rearLensImage);
Mat panorama;
Stitcher stitcher = Stitcher::createDefault();
if(!imagesToStitch.empty()){
stitcher.stitch(imagesToStitch, panorama);
imshow("test", panorama);
waitKey(0);
}
else{
cout << "ERROR: Image array empty" << endl;
}
return 0;
When trying to run, it returns this error:
OpenCV Error: Assertion failed (ssize.area() > 0) in resize, file /build/opencv-SviWsf/opencv-2.4.9.1+dfsg/modules/imgproc/src/imgwarp.cpp, line 1834
terminate called after throwing an instance of 'cv::Exception'
what(): /build/opencv-SviWsf/opencv-2.4.9.1+dfsg/modules/imgproc/src/imgwarp.cpp:1834: error: (-215) ssize.area() > 0 in function resize
When debugging, panorama is an empty object even though I pass it as the OutputArrayto stitcher.stitch. I searched the web thoroughly and couldn't find a solution, so any help would be greatly appreciated!
Kinda solved it. Apparently, OpenCVs memory management doesn't like you referencing the same address all the time. Since both of my images are dependant on srcImage I assume this is where the error was. I did a quick workaround which looks like this:
Mat unprocessedFrontLensImage(srcImage, Rect(0, 0, 3 * srcImage.cols / 4, srcImage.rows));
Mat unprocessedRearLensImage(srcImage, Rect(srcImage.cols / 4, 0, 3 * srcImage.cols / 4, srcImage.rows));
imwrite("left.jpg", unprocessedFrontLensImage);
imwrite("right.jpg", unprocessedRearLensImage);
Mat frontLensImage = imread("left.jpg");
Mat rearLensImage = imread("right.jpg");
Works like a charm. Don't teach me about redundancy, I know. I'm gonna clean up and refactor it, this is just my workaround for now.
Related
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;.
IMPORTANT: I fixed the problem. Solution at the end.
What do I try to achieve?
Display an image with OpenCV cv::imshow method. (imshow Documentation)
The image which is a 3x3 matrix is created like such:
Mat mask(3, 3, CV_32F, new float[9]{0, 1, 0, 1, -4, 1, 0, 1, 0});
To display the image I call imshow("mask", mask);
What is my problem?
Like I mentioned in the title there is an exception thrown while trying to display the image. Complete Error Message:
terminate called after throwing an instance of 'cv::Exception' what():
OpenCV(4.0.0-pre) /home/mrlab/Libraries/opencv_source/modules/highgui
/src/window_gtk.cpp:146: error: (-215:Assertion failed)
dst.data == widget->original_image->data.ptr in function 'cvImageWidgetSetImage'
Link to window_gtk.cpp
What did I already try?
Looking for the error on the internet. Maybe someone else already encountered the same problem. nope. nothing
Changed the matrix to only contain positive floating point values (0 to 1) in case it has problems with negative input. Initialization: Mat mask(3, 3, CV_32F, new float[9]{0, 1, 0, 1, 0, 1, 0, 1, 0}); same error
Calling the two methods in different locations in case there are changes made during my other code. same error
Writing small OpenCV program to just run these two lines. same error
Various combinations of the above mentioned ideas. same error
Displaying other images I read from memory instead of creating them myself. worked perfectly fine
Saving the image via imwrite("mask.png", mask) Looks like
this. Pretty small I know. I scaled the values to be in range of 0 to 255 since that what png needs. works perfectly fine
Complete code around my corrupted lines:
void high_pass(){
Mat src_f;
// Fourier transform src_bw
src_f = fourier(src_bw);
// Create Laplace High Pass Kernel
Mat mask(3, 3, CV_32F, new float[9]{0, 1, 0, 1, -4, 1, 0, 1, 0});
// In case of using fp values (0 to 1) initialize like this:
// Mat mask(3, 3, CV_32F, new float[9]{0, 1, 0, 1, 0, 1, 0, 1, 0});
imshow("mask", mask);
// Fourier transform kernel
Mat mask_f = fourier_kernel(mask, src_f.size());
Mat hp_filtered;
// Apply filter
mulSpectrums(src_f, mask_f, hp_filtered, DFT_ROWS);
// Transform it back
dst = fourier_inv(hp_filtered);
// Swap quadrants after applying filter
dst = swap_quadrants(dst);
// Show result
//imshow(WINDOW_NAME + "high pass", dst);
}
FYI: The last line threw the same exception which is why it is commented out. I ask the question with "mask" because it is easier.
After writing the question I had another idea.
Solution: I converted the CV_32F type matrix to a CV_8U matrix and scaled all values to be in range of 0 to 255. This solved the problem.
This is something I should have thought of first. For some reason it took me one hour to realize. Just in case someone else is encountering the same error or mental block I still post this here.
Solution: I converted the CV_32F type matrix to a CV_8U matrix and scaled all values to be in range of 0 to 255. This solved the problem.
Edit: As stated by Nikolaj Fogh it is also possible to revert to OpenCV Version 3.4.3. I did not test it myself.
For completeness, this is how to implement Philipp's solution (using his program's variables):
cv::Mat dist_8U; // to store the scaled image with appropriate type
double Min,Max;
cv::minMaxLoc(rgb,&Min,&Max);
dist -= Min;
dist.convertTo(dist_8U,CV_8U,255.0/(Max-Min));
Then dist_8U can be shown with imshow in opencv 4.0.0.
Tested on a raspberry pi.
Thought I'd try my hand at a little (auto)correlation/convolution today in openCV and make my own 2D filter kernel.
Following openCV's 2D Filter Tutorial I discovered that making your own kernels for openCV's Filter2D might not be that hard. However I'm getting unhandled exceptions when I try to use one.
Code with comments relating to the issue here:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc, char** argv) {
//Loading the source image
Mat src;
src = imread( "1.png" );
//Output image of the same size and the same number of channels as src.
Mat dst;
//Mat dst = src.clone(); //didn't help...
//desired depth of the destination image
//negative so dst will be the same as src.depth()
int ddepth = -1;
//the convolution kernel, a single-channel floating point matrix:
Mat kernel = imread( "kernel.png" );
kernel.convertTo(kernel, CV_32F); //<<not working
//normalize(kernel, kernel, 1.0, 0.0, 4, -1, noArray()); //doesn't help
//cout << kernel.size() << endl; // ... gives 11, 11
//however, the example from tutorial that does work:
//kernel = Mat::ones( 11, 11, CV_32F )/ (float)(11*11);
//default value (-1,-1) here means that the anchor is at the kernel center.
Point anchor = Point(-1,-1);
//value added to the filtered pixels before storing them in dst.
double delta = 0;
//alright, let's do this...
filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
imshow("Source", src); //<< unhandled exception here
imshow("Kernel", kernel);
imshow("Destination", dst);
waitKey(1000000);
return 0;
}
As you can see, using the tutorials kernel works fine, but my image will crash the program, I've tried changing the bit-depth, normalizing, checking size and lots of commenting out blocks to see where it fails, but haven't cracked it yet.
The image is, '1.png':
And the kernel I want 'kernel.png':
I'm trying to see if I can get a hotspot in dst at the point where the eye catchlight is (the kernel I've chosen is the catchlight). I know there are other ways to do this, but I'm interested to see how effective convolving the catchlight over itself is. (autocorrelation I think that's called?)
Direct questions:
why the crash?
is the crash indicating a fundamental conceptual mistake?
or (hopefully) is it just some (silly) fault in the code?
Thanks in advance for any help :)
The assertion error should be posted which would help someone to answer you other than questioning why is the crash. Anyways, I have posted below the possible errors and solution for convolution filter2D.
Error 1:
OpenCV Error: Assertion failed (src.channels() == 1 && func != 0) in cv::countNo
nZero, file C:\builds\2_4_PackSlave-win32-vc12-shared\opencv\modules\core\src\st
at.cpp, line 549
Solution : Your input Image and the kernel should be grayscales. You can use the flag 0 in imread. (ex. cv::imread("kernel.png",0) to read the image as grayscale.) If you want to apply different kernels to different channels, split the image into separate color planes using split() and process them individually.
I don't see anything other than the obove error that may crash. Kernel size should in odd numbers and your kernel image is 11X11 which is fine. If it stills crashes kindly provide more information in order to help you out.
I am using OpenCVwith Eclipse.
I need to detect the human skin, so I convert the image to HSV and the I use inRange function to obtain a Mat with the image with the skin in white.
The problem is that now,I need to detect in which components are the white color to modify this pixels in the original frame ( i am changing the skin color with the video camera), but I cant access to the Mat returned in InRange
cvtColor(frame,frame,CV_BGR2HSV);
Mat n;
inRange(frame, Scalar(0, 10, 60), Scalar(20, 150, 255), n);
for(int i=0;i<frame.rows;i++)
{
for(int j=0;j<frame.cols;j++)
{
n.at(&i);
//n(i,j);
}
}
That is the problematic code. When I get to the internal loop, the build fails giving a lot of error refering to the template.
Anyone knows how can I access to this matrix? Is there another way to achieve my objective? Maybe I am complicating the problem.
Thanks for your time.
nothing to do with inRange or such, it's just your Mat access code, that is broken.
Vec3b & hsvPixel = n.at<Vec3b>(i,j);
// hsvPixel[0] = h;
// hsvPixel[1] = s;
// hsvPixel[2] = v;
my question is very similar to this one... I'm trying to extract a sub matrix from a grayscale image wich is a polygon by 5 points , and convert it to a Mat.
This does not work:
std::vector<Point> vert(5);
vert.push_back(pt1);
vert.push_back(pt2);
vert.push_back(pt3);
vert.push_back(pt4);
vert.push_back(pt5);
Mat matROI = Mat(vert);
It shows me the following error message:
OpenCV Error: Bad number of channels (Source image must have 1, 3 or 4 channels) in cvConvertImage, file /home/user/opencv-2.4.6.1/modules/highgui/src/utils.cpp, line 611
terminate called after throwing an instance of 'cv::Exception'
what(): /home/user/opencv-2.4.6.1/modules/highgui/src/utils.cpp:611: error: (-15) Source image must have 1, 3 or 4 channels in function cvConvertImage
I'm using OpenCV 2.4.6.1 and C++.
Thank you
Edit:
I will rephrase my question: my objective is to obtain the right side of the image.
I thought I'd see the image as a polygon because I have the coordinates of the vertices, and then transform the vector that has the vertices in a matrix (cvMat).
My thought is correct or is there a simpler way to get this submatrix?
Your code has two problems:
First:
std::vector<Point> vert(5);
creates a vector initially with 5 points, so after you use push_back() 5 times you have a vector of 10 points, the first 5 of of which are (0, 0).
Second:
Mat matROI = Mat(vert);
creates a 10x1 Mat (from a vector of 10 points) with TWO channels. Check that with:
cout << "matROI.channels()=" << matROI.channels() << endl;
If you have a code like:
imshow("Window", matROI);
it will pass matROI through to cvConvertImage() which has the following code (and this causes the error you are seeing):
if( src_cn != 1 && src_cn != 3 && src_cn != 4 )
CV_ERROR( CV_BadNumChannels, "Source image must have 1, 3 or 4 channels" );
Since matROI is a list of points, it doesn't make sense to pass it to imshow().
Instead, try this:
Mat img(image.rows, image.cols, CV_8UC1);
polylines(img, vert, true, Scalar(255)); // or perhaps 0
imshow("Window", img);
int c = waitKey(0);