What does cv::Mat's UMatData being 0x0(nullptr) mean? - c++

In my code I'm encountering a situation where it is running for few hours but crashing at random points after that(SIGSEGV, Segmentation fault). Whenever crash happens, the cv::Mat involved(often different) will have the u parameter as a nullptr. (Link to what u is: https://docs.opencv.org/3.4/d3/d63/classcv_1_1Mat.html#a2742469fe595e1b9036f60d752d08461)
So I'm wondering what this u being a nullptr actually means and if this is the cause for crashing? This is confusing because u is 0x0 or nullptr at other points during execution as well and not just when it crashes.
An example code of how I'm using the mats and causing the u to become 0x0:
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat main_data = cv::Mat::zeros(10, 10, CV_8UC3);
cv::Mat buffer = cv::Mat::zeros(100, 100, CV_8UC3);
cv::Mat valid_data = buffer;
std::cout << "before: " << valid_data.u << std::endl;
memcpy(buffer.data, main_data.data, main_data.rows*main_data.step);
valid_data = cv::Mat(main_data.rows, main_data.cols, main_data.type(), buffer.data, main_data.step[0]);
std::cout << "after: " << valid_data.u << std::endl;
return 0;
}
I have multiple threads and I'm using the above along with locks for sharing data between them.

Related

Consecutive lines printing same pointer with "std::cout" produce completely different output

I apologize for the vague title of my question. I don't know a better way to phrase it. I've never asked a Stack Overflow question before but this one has me completely stumped.
A method in class Chunk uses the Eigen linear algebra library to produce a vector3f, which is then mapped to a C-style array with the following.
ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);
float *fit = x.data();
return fit;
This array is returned and accessed in the main function. However, whenever I attempt to print out a value from the pointer, I get completely different results. A sample is below.
Chunk test = Chunk(CHUNK_SIZE, 0, 0, 1, poBand);
float* fit = test.vector; // Should have size 3
std::cout << fit[0] << std::endl; // Outputs 3.05 (correct)
std::cout << fit[0] << std::endl; // Outputs 5.395e-43
std::cout << fit[0] << std::endl; // Outputs 3.81993e+08
What makes this issue even more perplexing is that the incorrect values change when I end the lines with "\n" or ", ". The first value is always the expected value, no matter whether I print index 0, 1, or 2.
I have tried dynamically allocating memory for the fit variable, as well as implementing the code on this answer, but none of it changes this functionality.
Thank you in advance for any guidance on this issue.
Minimally Reproducible Example:
float* getVector() {
Eigen::Vector3f x;
x << 3, 5, 9;
float* fit = x.data();
return fit;
}
int main(void) {
float* fit = getVector();
std::cout << fit[0] << std::endl;
std::cout << fit[0] << std::endl;
std::cout << fit[0] << std::endl;
}
You create the vector x in the function on the stack. It is destroyed after the function exited. Hence your pointer is invalid.
Here an example with shared_ptr
ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);
shared_ptr<float> fit(new float[3],std::default_delete<float[]>());
memcpy(fit,x.data(),sizeof(float)*3);
return fit;
Another possible way is
ColPivHouseholderQR<MatrixXf> dec(f);
Vector3f x = dec.solve(b);
return x;

Using std::async with a method receiving a cv::OutputArray in order to assign it doesn't work

I have the following function:
void MyClass::myFunc(cv::OutputArray dst) const {
cv::Mat result;
...
dst.assign(result);
}
If I run it like this:
cv::Mat result;
myFunc(result);
otherFunc(result);
It works fine and otherFunc recieves result modified by myFunc.
But if I use std::async like this:
cv::Mat result;
auto resultFuture = std::async(&MyClass::myFunc, this, result);
resultFuture.wait();
otherFunc(result);
otherFunc receives empty result. What am I doing wrong?
The root cause is that passing arguments by reference (&) to a function to run via std::async is problematic. You can read about it here: Passing arguments to std::async by reference fails (in your case there is no a compilation error, but the link explains the issue in general).
And in your case you use cv::OutputArray which is defined in opencv as a refernce type:
typedef const _OutputArray& OutputArray;
I assume you wanted the reference semantics, since you expected your result object to be updated by myFunc.
The solution is to use std::ref.
But since the result object you pass is a cv::Mat, it preferable and more straightforward that myFunc will receive a cv::Mat&.
I also managed to produce a solution using a cv::OutputArray, but it requires an ugly cast (in addition to the std::ref). It works fine on MSVC, but I am not sure it is will be generally valid.
Below is the code demostrating these 2 options. I recomend to use the 1st approach if you can. You can call otherFunc(result); at the point where I print the dimensions of result after it is initialized.
#include <opencv2/core/core.hpp>
#include <future>
#include <iostream>
// Test using a cv::Mat &:
class MyClass1
{
void myFunc(cv::Mat & dst) const
{
cv::Mat result(4, 3, CV_8UC1);
result = 1; // ... initialize some values
dst = result; // instead of using cv::OutputArray::assign
}
public:
void test()
{
cv::Mat result;
std::cout << "MyClass1: before: " << result.cols << " x " << result.rows << std::endl;
auto resultFuture = std::async(&MyClass1::myFunc, this, std::ref(result));
resultFuture.wait();
// Here result will be properly set.
std::cout << "MyClass1: after: " << result.cols << " x " << result.rows << std::endl;
}
};
// Test using a cv::OutputArray:
class MyClass2
{
void myFunc(cv::OutputArray dst) const
{
cv::Mat result(4, 3, CV_8UC1);
result = 1; // ... initialize some values
dst.assign(result);
}
public:
void test()
{
cv::Mat result;
std::cout << "MyClass2: before: " << result.cols << " x " << result.rows << std::endl;
auto resultFuture = std::async(&MyClass2::myFunc, this, std::ref(static_cast<cv::OutputArray>(result)));
resultFuture.wait();
// Here result will be properly set.
std::cout << "MyClass2: after: " << result.cols << " x " << result.rows << std::endl;
}
};
int main()
{
// Test receiving a cv::Mat&:
MyClass1 m1;
m1.test();
// Test receiving a cv::OutputArray:
MyClass2 m2;
m2.test();
return 0;
}

Segmentation Fault in creating a cv::Mat from unsigned char array

I cannot understand why the following minimal code outputs segmentation fault and cv::Mat values are not printed correctly:
#include <opencv2/opencv.hpp>
int main()
{
unsigned char out[1280*720*3/2] = {100};
cv::Mat dummy_query = cv::Mat(1, 1280*720*3/2*sizeof(unsigned char), CV_8UC1, (void *)out);
cv::Size s = dummy_query.size();
std::cout << s << "\r\n";
for(int i = 0; i < 1280*720*3/2; i++)
{
std::cout << i << "ss" << int(out[i]) << ":";
std::cout << dummy_query.at<int>(0,i) << " ";
}
}
You have defined uchar datatype in cv::Mat but accessing at this line
as int std::cout << dummy_query.at<int>(0,i) << " ";
so your program will likely get crash at end of the loop
e.g.
// create a 100x100 8-bit matrix
Mat M(100,100,CV_8U);
// this will be compiled fine. no any data conversion will be done.
Mat_<float>& M1 = (Mat_<float>&)M;
// the program is likely to crash at the statement below
M1(99,99) = 1.f;
check this open cv reference

weird behavior of boost function

My following code runs into error if I comment out the first line in the constructor. The return error is:
libc++abi.dylib: terminating with uncaught exception of type boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<std::overflow_error> >: Error in function boost::math::cyl_bessel_k<double>(double,double): numeric overflow
Abort trap: 6
However, it is weird that if I output something (e.g., uncomment the first line) in the constructor, then my program works fine.
GP::GP(const Training_set& _sample, Eigen::VectorXd& param,
const std::string& which_kernel) : sample(_sample)
{
// std::cout << "WORKS" << std::endl;
if (which_kernel == "Matern") {
std::cout << "Matern kernel is used!" << std::endl;
Kernel_Matern matern(param, param.size());
kernel = &matern;
} else if (which_kernel == "Square_Exponential") {
std::cout << "Square Exponential kernel is used!" << std::endl;
Kernel_SE se(param, param.size());
kernel = &se;
} else {
std::cout << "Cannot identify the kernel" << std::endl;
exit(1);
}
input_dim = sample.dim;
input_size = sample.size;
L_chol.resize(sample.size, sample.size);
Eigen::MatrixXd cov_matrix = Eigen::MatrixXd::Zero(sample.size, sample.size);
get_cov_matrix(sample.X, input_size, sample.X, input_size, cov_matrix);
get_chol(cov_matrix);
}
You are storing an address of a temporary that goes out of scope. Using *kernel after what it points to goes out of scope is undefined behavior.
kernel should be of type std::unique_ptr<X> instead of type X*.
Replace assignment with:
kernel = std::make_unique<Kernel_Matern>(param, param.size());
or:
kernel = std::make_unique<Kernel_SE>(param, param.size());
at the two lines in question.
If you have code where you pass kernel to a function, instead pass kernel.get().
Note that is blocks copying instances of GP but not moving them, as unique ptr is move-only. If you have a type that stores both values and pointers into its own values, copying it is probably a bug anyhow.

TIFF files garbled by ArrayFire (C++)

I notice that this simple ArrayFire program is causing loaded TIFF images to be heavily distorted:
#include <iostream>
#include <arrayfire.h>
int main( int argc, char** argv ) {
af::array img = af::loadImage( argv[1] );
double mn, mx;
unsigned idxn, idxx;
af::min( &mn, &idxn, img );
af::max( &mx, &idxx, img );
std::cout << "Image size = " << img.dims()[0] << ", " << img.dims()[1] << '\n';
std::cout << "Data type = " << img.type() << '\n';
std::cout << "Min = " << mn << " (at " << idxn << ")\n";
std::cout << "Max = " << mx << " (at " << idxx << ")\n";
af::saveImage( argv[2], img );
return 0;
}
I then compile and run on a simple (monochrome) image:
./a.out orig.tif out.tif
with the following output:
Image size = 256, 256
Data type = 0
Min = 0 (at 65535)
Max = 81.5025 (at 31356)
When I visualize these images I get the following result:
which of course is not what ArrayFire is expected to do; I would expect it to dump the exact same image out since I didn't make any changes to it. Unfortunately I don't know enough about the TIFF image format or the graphics backend of ArrayFire to understand what is going on. Am I doing something wrong while loading the image? (I followed the ArrayFire documentation for loadImage and saveImage).
I also tried using loadImageNative and saveImageNative alternatively, but the latter returns a 4-layer TIFF image while the original image is only a 1-layer TIFF.
Any help at all from ArrayFire experts would be great.
Thanks!