I am trying to make a feature matching algorithm with OpenCV on CUDA.
I am using the ORB features.
The main problem I have is that I am able to well compute the ORB keypoints but the descriptors are always empty. I tried all the ways but without success. I tried with the last version of opencv (3.4.0) and the 3.2.0 version.
This is the simplified version of my code:
cv::Ptr<cv::cuda::ORB> orb_gpu = cv::cuda::ORB::create(5000);
std::vector<cv::KeyPoint> keypoints;
cv::cuda::GpuMat descriptors;
cv::cuda::GpuMat img_gpu(curr_frame);
orb_gpu->detect(img_gpu, keypoints);
orb_gpu->compute(img_gpu, keypoints, descriptors);
cv::Mat desc_cpu;
descriptors.upload(desc_cpu);
The problem is with the direction of memory copy. You are calling upload instead of download function to copy descriptors from device to host. The following line is the culprit:
descriptors.upload(desc_cpu);
Replace it with:
descriptors.download(desc_cpu);
upload copies from host to device whereas download copies from device to host.
I have tested and verified the example with OpenCV 3.4 compiled with CUDA 8 on Ubuntu 14.04.
I am trying to read an 8BPP PNG image using imread() in OpenCV and copy it into a larger matrix. This is the code:
Mat subimage = imread((directory + file).toStdString(), IMREAD_COLOR);
subimage.copyTo(whole(Rect(rect.left(), rect.top(),
rect.width(), rect.height())));
I have tried other flags like IMREAD_ANYCOLOR, IMREAD_ANYDEPTH, IMREAD_GRAYSCALE and IMREAD_UNCHANGED. None of them seem to work (subimage remains empty).
I am getting the folowing error:
OpenCV Error: Assertion failed (!fixedSize()) in cv::_OutputArray::release, file ..\..\..\sources\modules\core\src\matrix.cpp, line 1619
I finally figured out the error. However, it has nothing to do with imread. I am downloading the images and was trying to read them before the download is complete.
I am simply trying to save a Mat as a ppm image. I am able to read the ppm and load it into a Mat. The part of code that is causing the error is:
// Display Image
namedWindow("Comparison", CV_WINDOW_NORMAL);
imshow("Comparison", comparisonMat);
waitKey();
vector<int> compression_params;
compression_params.push_back(CV_IMWRITE_PXM_BINARY);
compression_params.push_back(1);
imwrite("Comparison.ppm",comparisonMat,compression_params);
It builds successfully but when it comes to writing the file, I get the following error:
"Unhandled exception at 0x76b2c41f in HW.exe: Microsoft C++ exception: std::bad_alloc at memory location 0x0018f280.."
Any idea how to fix this?
Edit:
I made it work by doing the following:
IplImage* writeImage=cvCloneImage(&(IplImage)comparisonMat);
cvSaveImage("Comparison.ppm", writeImage);
Has anyone managed to get the Brox dense optical flow algorithm in OpenCV working?
Here is some code:
{
// Load images
cv::Mat PreviousFrameGrayFloat; // Has an image in format CV_32FC1
cv::Mat CurrentFrameGrayFloat; // Has an image in format CV_32FC1
// Upload images to GPU
cv::gpu::GpuMat PreviousFrameGPU(PreviousFrameGrayFloat);
cv::gpu::GpuMat CurrentFrameGPU(CurrentFrameGrayFloat);
// Prepare receiving variables
cv::gpu::GpuMat FlowXGPU;
cv::gpu::GpuMat FlowYGPU;
// Create optical flow object
cv::gpu::BroxOpticalFlow OpticalFlowGPU = cv::gpu::BroxOpticalFlow(0.197f, 0.8f, 50.0f, 10, 77, 10);
// Perform optical flow
OpticalFlowGPU(PreviousFrameGPU, CurrentFrameGPU, FlowXGPU, FlowYGPU); // EXCEPTION
// Exception in opencv_core244d!cv::GlBuffer::unbind
// Download flow from GPU
cv::Mat FlowX;
cv::Mat FlowY;
FlowXGPU.download(FlowX);
FlowYGPU.download(FlowY);
}
I get an exception, as commented above, when I try and use the cv::gpu::BroxOpticalFlow object, I have the same problem with cv::gpu::PyrLKOpticalFlow but only the dense version not the sparse one, and cv::gpu::FarnebackOpticalFlow works fine...
Weird.
Entire exception is:
Exception at 0x7c812fd3, code: 0xe06d7363: C++ exception, flags=0x1 (execution cannot be continued) in opencv_core244d!cv::GlBuffer::unbind
I'm using a debug build with debug libraries, using OpenCV 2.4.4 however the code also raises an exception in OpenCV 2.4.3.
When I use OpenCV 2.4.3 I get this exception:
Exception at 0x7c812fd3, code: 0xe06d7363: C++ exception, flags=0x1 (execution cannot be continued) in opencv_core243d!cv::SparseMat::erase
OpenGL is required, but there may also be a problem with your scale parameter (50.0f). It seems too large. As I understand, this should be less than 1. If it is a large number, the algorithm fills up GPU memory quickly. Plus, it may not make sense to use an expanding (upside-down?) image pyramid. Not perfectly sure though.
After experimenting with other versions of OpenCV and following the information contained here: http://stuartjames.info/Journal/opencv-brox-optical-flow-sample-possible-fix.aspx
It looks like I need to recompile OpenCV with OpenGL.
It seems that you can test whether your install of OpenCV has OpenGL by running the command: cv::gpu::setGlDevice(0); if this fails with a weird exception like the one above then you need to recompile.
OpenGL is required as the newer optical flow algorithms in OpenCV map data to OpenGL textures to (I assume) speed up operations, or maybe to just make the code simpler.
So, after all this, the solution is to recompile OpenCV with OpenGL. This can be achieved by ticking the WITH_OPENGL box when using CMake to configure the build.
If you want to use the GPU version of the video reader make sure you also tick WITH_NVCUVID this is included with CUDA but not included unless you request it...
-- EDIT --
After the comments from paul I've corrected the scale factor in my code from the question.
Here is the complete code I'm testing, for nkint:
{
// Load images
cv::Mat PreviousFrameGray = cv::imread("Input1.png", 0);
cv::Mat CurrentFrameGray = cv::imread("Input2.png", 0);
cv::Mat PreviousFrameGrayFloat; // Has an image in format CV_32FC1
cv::Mat CurrentFrameGrayFloat; // Has an image in format CV_32FC1
PreviousFrameGray.convertTo(PreviousFrameGrayFloat, CV_32FC1, 1.0/255.0);
CurrentFrameGray.convertTo(CurrentFrameGrayFloat, CV_32FC1, 1.0/255.0);
// Upload images to GPU
cv::gpu::GpuMat PreviousFrameGPU(PreviousFrameGrayFloat);
cv::gpu::GpuMat CurrentFrameGPU(CurrentFrameGrayFloat);
// Prepare receiving variables
cv::gpu::GpuMat FlowXGPU;
cv::gpu::GpuMat FlowYGPU;
// Create optical flow object
cv::gpu::BroxOpticalFlow OpticalFlowGPU = cv::gpu::BroxOpticalFlow(0.197f, 50.0f, 0.8f, 10, 77, 10);
// Perform optical flow
OpticalFlowGPU(PreviousFrameGPU, CurrentFrameGPU, FlowXGPU, FlowYGPU);
// Download flow from GPU
cv::Mat FlowX;
cv::Mat FlowY;
FlowXGPU.download(FlowX);
FlowYGPU.download(FlowY);
// Use FlowX and FlowY in further processing
//...
}
In OpenCV to create an image Mat I'd usually do something along the lines of: cv::Mat myImage however when I use this method cv::gpu::GpuMat myImage to create a GpuMat I get undefined reference errors. I have noticed that a lot of people simply declare GpuMat myImage however using namespace cv::gpu leads to the same errors.
In short, how do I create a GpuMat in OpenCV properly?
Note: I'm still learning C/C++, so it's likely I'm missing something obvious (or not accessing the method correctly).
The problem occurred as I had not included the opencv_gpu231 lib, thanks for the help!