Boolean Not in OpenCV 3.1 - c++

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);
}
}

Related

Fitting 2d gauss function in C++ too slow

I'm trying to fit a 2d gauss function to an image (in cv::Mat format), and I'm using the NLopt library.
I put my object function like this:
for(i for each row)
for(j for each col)
{
//compute the gauss function value
double valuenow=x[0]*exp(-( x[3]*(j-x[1])*(j-x[1]) + 2*x[4]*(j-x[1])*(i-x[2]) + x[5]*(i-x[2])*(i-x[2]) ));
//add square residual to result
result+=(valuenow-fitdata.at<double>(i,j))*(valuenow-fitdata.at<double>(i,j));
}
return result;
My matrix is about 1000*1000 size, I'm using LN_COBYLA algorithm. When I ran this, it turned out to be extremely slow. I think there must be something wrong with the way I specify my object function, because I used to do the same thing in Matlab with lsqnonlinear, which returned in a second.
Can someone help me please? Thanks in advance.
The at<>() function is slow. If speed is of essence, it's not a good idea to use it inside loops. Take a pointer outside the loop and then just use that pointer inside the loop.
A related question:
OpenCV Mat array access, which way is the fastest for and why?

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);

OpenCV affectation

Why can't I do something like this:
cv::Mat img = imread("path/to/image1");
cv::Mat img2 = imread("path/to/image2");
img.ptr<uchar>(0,0) = img2.ptr<uchar>(0,0);
I get this message from VS : expression must be a modifiable lvalue
So instead I had to resort to doing something like this:
img.ptr<uchar>(0,0)[0] = img2.ptr<uchar>(0,0)[0];
And affect each channel, it doesn't bother me but I'd like to know why I can't do the other one.
The = operator would need to know what kind of image it was and would need complicated code for planar image types.
You can use the CV_IMAGE_ELEM macro

OpenCV - assign operator "not working"?

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.

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);