Why cv::cuda::remap wrong while cv::remap right? - opencv

I use cv::cuda::remap instead of cv::remap to take advantage of CUDA acceleration to speed up video undistortion. Both versions of the program can run normally, but, while the camera matrix, distortion coefficients, map1 and map2 which come from cv::initUndistortRectifyMap() are all the same, the undistorted result image of the CPU version cv::remap is correct as follow:
but the CUDA version cv::cuda::remap results in a problem:
The code snippet for the CPU version is as follows:
cv::cuda::GpuMat gpuMat(m_height, m_width, CV_8UC4, (void *)dpFrame);
cv::Mat mat;
gpuMat.download(mat);
cv::remap(mat, mat, m_map1, m_map2, cv::INTER_LINEAR);
gpuMat.upload(mat);
GPU version:
cv::cuda::GpuMat gpuMat(m_height, m_width, CV_8UC4, (void *)dpFrame);
cv::cuda::remap(gpuMat, gpuMat, m_gpuMap1, m_gpuMap2, cv::INTER_LINEAR);
Among them, dpFrame is of type CUdeviceptr, m_map1 and m_map2 are calculated by cv::initUndistortRectifyMap, m_gpuMap1 and m_gpuMap2 are of type cv::cuda::GpuMat obtained by uploading m_map1 and m_map2 to GPU.
cv::remap and cv::cuda::remap are the same algorithm, why are their results different? I tried both versions of OpenCV 455 and 460, and neither works.
I'm stuck here and don't know how to go forward. Any suggestions are really appreciated. Thanks.

Okey, I also tried your code and got the similar results. I ended up with getting a correct result after a few tests.
My code simply flips an image with remap. Here is your code result to my input:
Code
cv::cuda::GpuMat gpuMat(m_height, m_width, CV_8UC4, (void *)dpFrame);
cv::cuda::remap(gpuMat, gpuMat, m_gpuMap1, m_gpuMap2, cv::INTER_LINEAR);
Input
Output
Then I just add a new declaration of cv::cuda::GpuMat and put it to output of resize function. Here is the code.
cv::cuda::GpuMat gpuMat(m_height, m_width, CV_8UC4, (void *)dpFrame);
cv::cuda::GpuMat gpuMat2;
cv::cuda::remap(gpuMat, gpuMat2, m_gpuMap1, m_gpuMap2, cv::INTER_LINEAR);
gpuMat2.download(mat);
New Output
I dont have a clear answer to the question why. Since we deal with gpu, it seems better to define different types for input and output of resize

Related

OpenCV - copy CUDA device data into GPU Mat

Is there a way to directly copy previously allocated CUDA device data into an OpenCV GPU Mat? I would like to copy my data, previously initialized and filled by CUDA, into the OpenCV GPU mat. I would like to do so because I want solve a linear system of equations Ax = B by computing the inverse of the matrix A using OpenCV.
What I want to do is something like this:
float *dPtr;
gpuErrchk( cudaMalloc( (void**) &dPtr, sizeof(float) * height * width));
gpuErrchk( cudaMemset(dPtr, 0, sizeof(float) * height * width));
// modify dPtr in some way on the GPU
modify_dPtr();
// copy previously allocated and modified dPtr into OpenCV GPU mat?
// process GPU mat later - e.x. do a matrix inversion operation.
// extract raw pointer from GPU mat
EDIT:
The OpenCV documentation provides a GPU upload function.
Can the device pointer just be passed into that function as a parameter? If not, is there no other way to do such a data transfer? I don't want to copy data back and forth between the host and device memory, do my computation on a normal OpenCV Mat container, and copy back the results; my application is real-time. I am assuming that since there is no .at() function for a GPU Mat, as in the normal OpenCV Mat, there is no way to access the element at a particular location in the matrix? Also, does an explicit matrix inversion operation exist for the GPU Mat? The documentation does not provide a GPU Mat inv() function.
Just as talonmies posted in the comments, there is a constructor in the header of the GPU mat structure that allows the creation of a GPUMat header pointing to my previously allocated CUDA device data. This is what I had used:
cv::gpu::GpuMat dst(height, width, CV_32F, d_Ptr);
There is no need to figure out the step size because the constructor automatically evaluates it, given the width and height of the image.
Hopefully, when the support for OpenCV GPU functions becomes better, this post may be useful to someone.
EDIT
Another (probably) useful way is to utilize unified memory in CUDA. Pass the data into an OpenCV GPU and CPU mat, and continue operations from there.

Conversion between cv::Mat and arma::mat

I am using OpenCV and also want to add some of cool functions from mlpack, which is using Armadillo matrices.
Is there an easy way to convet between cv::Mat and arms::mat?
Thanks!
OpenCV's Mat has a pointer to its data. Armadillo has a constructor that is capable of reading from external data. It's easy to put them together. Remember that Armadillo stores in column-major order, whereas OpenCV uses row-major. I suppose you'll need to add another step for transformation, before or after.
cv::Mat opencv_mat; //opencv's mat, already transposed.
arma::mat arma_mat( reinterpret_cast<double*>opencv_mat.data, opencv_mat.rows, opencv_mat.cols )
The cv::Mat constructor has a form that accepts pointer to data, and arma::mat has a function for a double* pointer to its data called memptr().
So, if you'd like to convert from arma::mat to cv::Mat, this should work:
cv::Mat opencv_mat( rows, cols, CV_64FC1, arma_mat.memptr() )

Access multidimensional Mat range OpenCV

I have a 3x3x1000 OpenCV Mat matrix created using
int sz[] = {3,3,1000};
Mat bigCube(3, sz, CV_8U);
I want to do matrix operations on the 1000 separate 3x3 sub-matrices. But I can not find a way to do this.
The most obvious would be in a for-loop using Range, something like;
bigCube(Range(0,3),Range(0,3),Range(i,i+1));
//Do some operations...
But this won't compile. Is there a way to do this?

What's the full name of `IplImage` and `CvMat` in OpenCV?

There is a IplImage and CvMat in OpenCV. What are the full names of them?
IPL in IplImage stands for Intel Processing Library, which is a remnant of when OpenCV was maintained by Intel.
CV in cvMat stands for Computer Vision Matrix, which is a data structure commonly used in graphics.
IplImage is an old structure, which I believe is internally converted into cv::Mat, or just Mat if you're in the cv namespace already. Likewise, cvMat is converted into Mat as well.
http://opencv.willowgarage.com/documentation/cpp/basic_structures.html?highlight=iplimage

Extracting HoG Features using OpenCV

I am trying to extract features using OpenCV's HoG API, however I can't seem to find the API that allow me to do that.
What I am trying to do is to extract features using HoG from all my dataset (a set number of positive and negative images), then train my own SVM.
I peeked into HoG.cpp under OpenCV, and it didn't help. All the codes are buried within complexities and the need to cater for different hardwares (e.g. Intel's IPP)
My question is:
Is there any API from OpenCV that I can use to extract all those features / descriptors to be fed into a SVM ? If there's how can I use it to train my own SVM ?
If there isn't, are there any existing libraries out there, which could accomplish the same thing ?
So far, I am actually porting an existing library (http://hogprocessing.altervista.org/) from Processing (Java) to C++, but it's still very slow, with detection taking around at least 16 seconds
Has anyone else successfully to extract HoG features, how did you go around it ? And do you have any open source codes which I could use ?
Thanks in advance
You can use hog class in opencv as follows
HOGDescriptor hog;
vector<float> ders;
vector<Point> locs;
This function computes the hog features for you
hog.compute(grayImg, ders, Size(32, 32), Size(0, 0), locs);
The HOG features computed for grayImg are stored in ders vector to make it into a matrix, which can be used later for training.
Mat Hogfeat(ders.size(), 1, CV_32FC1);
for(int i=0;i<ders.size();i++)
Hogfeat.at<float>(i,0)=ders.at(i);
Now your HOG features are stored in Hogfeat matrix.
You can also set the window size, cell size and block size by using object hog as follows:
hog.blockSize = 16;
hog.cellSize = 4;
hog.blockStride = 8;
// This is for comparing the HOG features of two images without using any SVM
// (It is not an efficient way but useful when you want to compare only few or two images)
// Simple distance
// Consider you have two HOG feature vectors for two images Hogfeat1 and Hogfeat2 and those are same size.
double distance = 0;
for(int i = 0; i < Hogfeat.rows; i++)
distance += abs(Hogfeat.at<float>(i, 0) - Hogfeat.at<float>(i, 0));
if (distance < Threshold)
cout<<"Two images are of same class"<<endl;
else
cout<<"Two images are of different class"<<endl;
Hope it is useful :)
I also wrote the program of 2 hog feature comparing with the help of the above article.
And I apply this method to check ROI region changing or not.
Please refer to the page here.
source code and simple introduction
Here is GPU version as well.
cv::Mat temp;
gpu::GpuMat gpu_img, descriptors;
cv::gpu::HOGDescriptor gpu_hog(win_size, Size(16, 16), Size(8, 8), Size(8, 8), 9,
cv::gpu::HOGDescriptor::DEFAULT_WIN_SIGMA, 0.2, gamma_corr,
cv::gpu::HOGDescriptor::DEFAULT_NLEVELS);
gpu_img.upload(img);
gpu_hog.getDescriptors(gpu_img, win_stride, descriptors, cv::gpu::HOGDescriptor::DESCR_FORMAT_ROW_BY_ROW);
descriptors.download(temp);
OpenCV 3 provides some changes to the way GPU algorithms (i.e. CUDA) can be used by the user, see the Transition Guide - CUDA.
To update the answer from user3398689 to OpenCV 3, here is a snipped code:
#include <opencv2/core/cuda.hpp>
#include <opencv2/cudaimgproc.hpp>
[...]
/* Suppose you load an image in a cv::Mat variable called 'src' */
int img_width = 320;
int img_height = 240;
int block_size = 16;
int bin_number = 9;
cv::Ptr<cv::cuda::HOG> cuda_hog = cuda::HOG::create(Size(img_width, img_height),
Size(block_size, block_size),
Size(block_size/2, block_size/2),
Size(block_size/2, block_size/2),
bin_number);
/* The following commands are optional: default values applies */
cuda_hog->setDescriptorFormat(cuda::HOG::DESCR_FORMAT_COL_BY_COL);
cuda_hog->setGammaCorrection(true);
cuda_hog->setWinStride(Size(img_width_, img_height_));
cv::cuda::GpuMat image;
cv::cuda::GpuMat descriptor;
image.upload(src);
/* May not apply to you */
/* CUDA HOG works with intensity (1 channel) or BGRA (4 channels) images */
/* The next function call convert a standard BGR image to BGRA using the GPU */
cv::cuda::GpuMat image_alpha;
cuda::cvtColor(image, image_alpha, COLOR_BGR2BGRA, 4);
cuda_hog->compute(image_alpha, descriptor);
cv::Mat dst;
image_alpha.download(dst);
You can then use the descriptors in 'dst' variable as you prefer like, e.g., as suggested by G453.

Resources