OpenCV - assign operator "not working"? - c++

I have one function to compute convolution (to test whether we are using correct settings for filter2D), I think the function body is not important, so here's just header and the end:
template<typename T>
cv::Mat conv(const cv::Mat &input, const cv::Mat &kernel) {
cv::Mat output(input); // or should I rather use output( input.rows, input.cols, input.depth())?
...
return output;
}
cv::Mat result = conv( input, kernel);
At this point, I have completely useless results in result (those aren't even random data, they have some strange pattern which got repeated every time I run the function).
When I rewrite function to:
template<typename T>
void conv(const cv::Mat &input, cv::Mat &output, const cv::Mat &kernel) {
...
}
cv::Mat result(input);
conv( input, result, kernel);
Everything works just fine and result matrix contains exactly what it should.
So my question is: What's wrong on first approach? Am I doing something wrong? Why isn't assign operator/return from function working?
*Note: OpenCv version: extra/opencv 2.3.1_a-3 (archlinux package)*
Something similar happened to me when I was loading external data from opencv storage and data got lost until I used data( loaded.clone())

Well, it seems that filter2d, or whatever you do, does not work 'in-place', that is, when input and output are the same. With your first line in the function,
cv::Mat output(input); // or should I rather use output( input.rows, input.cols, input.depth())?
you make output point to the same data as input! It is not a clone, it is another reference!
What you want to do is written in your comment. Another option may be (depending on your code) to let output completely uninitialized, as typically C++ OpenCV functions will initialize their output matrices for you, if they are empty.
Note that your conv(), even when giving a proper results, would always destroy your input matrix on the way. OpenCV does not respect const in its internal data reference meachanism. Yes, it is bad design.

Related

How to make getting a pixel value independent of the cv::Mat type?

I am writing a method that uses OpenCV (C++).
For example
void foo(const cv::Mat &image);
Inside, I need to take the pixel value of the cv::Mat by row and column.
If the type of image the method works with is CV_32FC3, I need to use
image.at<cv::Vec3f>(row, col);
If the type is CV_32SC2, I need to use
image.at<cv::Vec2i>(row, col);
If the type is CV_8UC1, I need to use
image.at<uchar>(row, col);
etc.
I would like the method to be universal, that is, it works with an image with any number of channels and depth. Can anything be done to fulfill this requirement (any template logic)? Perhaps the solution is quite obvious, but I did not find it.
Thank you!
Drop the use of cv::Mat - where you have to call type() method (at runtime) to get the type of values stored by mat, and instead that just start using templated version of mat class: it is cv::Mat_<Type> and write more generic code.
Then you could write only one function template to read mat pixels:
template<class T>
T access(cv::Mat_<T> const& img, int r, int c) {
return img(r,c);
}
More about cv::Mat_ here.

Boolean Not in OpenCV 3.1

I would like to know if there's a simple way of doing a boolean "not" operation on a cv::Mat. This does not work:
cv::Mat mat = cv::Mat::ones(3,3, CV_8U);
cv::Mat mat_not = !mat;
As such, is there an effective or simple way to do this? Should I resort to using something like this:
cv::Mat mat_not = mat < cv::Mat::ones(3,3,CV_8U);
Thanks a lot!
EDIT: I confused the "not" operator between MATLAB and C++ (since I'm translating the first one to the other). This works fine:
cv::Mat map2 = ~map1;
Edit: 12:30pm 7/20/2016
I see the op wants a regular NOT and I'm used to that being different for things like IDL and MatLab etc..
As #cxyzs7, #Cedric, and #Miki mentioned the operator in c++ is ~ so ...
mat = ~mat;
However if you ever want to do something else element wise (for example a bitwise) most of the time there's already a whole function for that. IE...
bitwise_not
cv::Mat src;
src = stuff;
cv::Mat dst;
//then call it
bitwise_not(src,dst);
If the function you want to do element by element is non-existent in the library or isn't an overloaded operator you can always do it the brute force way...
for(...) {
for (...) {
dst.at<int>(i,j) = ! src.at<int>(i,j);
}
}

how can set a pointer to the content of a Mat variable in OpenCV

A Mat can be CV_8UC3, CV_8UC1, CV_32FC3 and etc. For example, for a Mat which is CV_8UC3, I can set a pointer: Vec3b *p to the Mat. However, If I only know the Mat's datatype which can be obtained using Mat.type(), How can I set a proper pointer?
The sad answer is: you can't. The type of data should be set in compilation time. But in your example actual type will be decided only during run time. You will have to put switch somewhere in your code. i.e. you will need to have different implementations of your algorithm for all possible types. Note however that you can prevent code duplication by using templates.
If you do know type of data, and the only thing you don't know is number of channels, then the problem is a bit simpler. For example if your image contains unsigned char you can write
uchar* p = img.ptr<uchar>();
And it doesn't matter whether your image have one channel or three. Of course when it comes to actually working with the pixels you do need this information.
Use a void pointer. Void pointers can point to any data type.
http://www.learncpp.com/cpp-tutorial/613-void-pointers/
If you know a type, you can set a pointer to the first element of the first row of cv::Mat using ptr (documentation)
cv::Mat matrix = cv::Mat::zeros(3, 3, CV_32F);
float* firstElement = matrix.ptr<float>(0);

Compressing images on opencv (imwrite). How to explicitly set the compression factor?

I was wondering if there is a way to easily specify the compression factor when compressing images on opencv without having to declare a dummy vector. If I declare a vector p (similar to this discussion), but containing only 2 items, which is what imwrite takes, I can make the call:
vector<int> p(2);
p[0] = CV_IMWRITE_JPEG_QUALITY;
p[1] = 50; // compression factor
imwrite("compressed.jpg", img, p);
The above works fine. However, I want to compress the same image with several compression factors in a loop. Is there a way to explicitly pass the parameter to imwrite? Something like:
imwrite("compressed.jpg", img, {CV_IMWRITE_JPEG_QUALITY, factor}); // this doesn't work
Just as a side note, the function header is:
bool imwrite(const string& filename, const Mat& img, const vector<int>& params=vector<int>());
Thanks!
Update:
After activating C++0x, I can pass a vector explicitly defined inline to the function.
As suggested, activating C++0x allows me to pass a vector explicitly defined inline to the function. This solved the issue.
vector<int> compression_params;
compression_params.push_back(IMWRITE_JPEG_QUALITY);
compression_params.push_back(30);
compression_params.push_back(IMWRITE_JPEG_PROGRESSIVE);
compression_params.push_back(1);
compression_params.push_back(IMWRITE_JPEG_OPTIMIZE);
compression_params.push_back(1);
compression_params.push_back(IMWRITE_JPEG_LUMA_QUALITY);
compression_params.push_back(30);
imwrite('sample.jpg', img, compression_params);

Need to keep track of types of opencv Mats

So I'm using the class Mat from opencv in a program I'm writing. Mat looks something like this:
class Mat {
public:
Mat(int width, int height, int type);
template <typename T> T getElt(int x, int y);
int depth();
...
}
The type in the constructor specifies whether elements in the Mat are floats, ints, etc as well as the number of channels in the image. depth() returns the data type used to store image elements.
Unfortunately I have to call getElt() in my code. Whenever I do that I use a switch statement to check the depth of the Mat so I can call getElt() with the appropriate template parameter. Doing it that way is pretty verbose, so I was wondering if there was a better way to do it. Could I create a container for a Mat and use template magic create a method that returns a type as opposed to a value? Or could I use macros to make things more efficient and logical?
I'd rather not have to subclass Mat since there are several methods besides getElt() for which I have this same issue.
Edit: made the description more accurate.
You're probably looking for Mat_<T> instead. An black&white image really isn't the same as a greyscale image, and neither is equal to a color image. Those should be separate at compile time.
IIRC the 'type' in openCV MAT corresponds to the image type (ie number of channels) not the data type float/int/char etc.
If you want a templated image class that can transparently work with char/int/bool/double etc - take a look at CImg