convert Eigen MatrixXd to QImage

• I want to convert matrixXd of Eigen to QImage(format, grayscale)。Here is my code, but the result is wrong. I am newer in QT and Eigen.

ObjWindow::ObjWindow(QWidget *parent) :
QWidget(parent),
ui(new Ui::ObjWindow)
{
ui->setupUi(this);
int height = 100;
int width = 100;

Eigen::MatrixXd doubleM(height, width);

for (int i = 0;i<height; i++)
{
for (int k = 0; k<width; k++)
{
if (i>=50) {
doubleM(i, k) = 200;
};

};
};
QImage xx = Eigen2QImage(doubleM);
ui->label->setPixmap(QPixmap::fromImage(xx));

}

QImage ObjWindow::Eigen2QImage(const MatrixXd &src)
{
double scale = 255.0;
double max_value = src.maxCoeff();
double min_value = src.minCoeff();
QImage dest(src.cols(), src.rows(), QImage::Format_Grayscale8);

for (int y = 0; y < src.rows(); ++y)
{
const double *src_row = src.row(y).data();
uchar * destrow = dest.scanLine(y);
for (int x = 0; x < src.cols() ; ++x)
{
uchar gray = (uchar)(src_row[x] / max_value * 255);
destrow[x] = gray;
}
}
return dest;
}

• but the result is wrong.

This is no valid error description.

Apart from this - row is x (horizontal) in Qt (and maybe also in eigen I would guess)

• The Image become: • Shouldn't you do modulo here:

uchar gray = (uchar)(src_row[x] / max_value % 255);

?

• @jsulm error: invalid operands to binary expression ('double' and 'double'). modulo is invalid for double type.

• @hei6775 Then fix it... c basics

What's the format of the eigen image? How must the gray value be interpreted / what's the range of it?

• @Christian-Ehrlicher double. Eigen::MatrixXd mean a matrix of dynamic size and double type.
The problem(@jsulm mentioned) is wrong direction.
I print the value of src_row[x], this is incorrect value.

// the first pixel in the loop
qDebug() << src_row[x];
// output:
// 1.05908e-319

• Eigen uses expression templates and lazy-evaluation. You're taking a pointer to data contained in an rvalue here src.row(y).data(). Anything can be there after the object goes out of scope.

• const double *src_row = src.row(y).data();

I think you should change this to:

const auto srcRow = src.row(y);
const double *src_row = srcRow.data();

To not loose temporary container

• I think you should change this to:

Yes, in principle, but you must not use auto with Eigen.

• const auto srcRow = src.row(y);
const double *src_row = srcRow.data();

This doesn't seem to work

• This doesn't seem to work

@kshegunov

Yes, in principle, but you must not use auto with Eigen.

• Yes, in principle, but you must not use auto with Eigen.

What is the problem with auto and Eigen?
Can you explain more, I don't know Eigen and always pleased to complete my knowledge about C++ :)

• What is the problem with auto and Eigen?

I'm going to spare you my personal opinion on auto, but this is it:

Eigen uses expression templates and lazy-evaluation.

And here's a reference if you want to read even more: https://eigen.tuxfamily.org/dox/TopicPitfalls.html
In a nutshell Eigen builds up a sort of a parse tree from its methods and delays evaluation to the last possible moment. It has the advantage that it's really efficient to pack up complex expressions in a single pass, but doesn't play well with auto, because auto captures a type which isn't a real type, but rather an "evaluation step" type.

• In a nutshell Eigen builds up a sort of a parse tree from its methods and delays evaluation to the last possible moment. It has the advantage that it's really efficient to pack up complex expressions in a single pass, but doesn't play well with auto, because auto captures a type which isn't a real type, or rather a "evaluation step" type.

Thanks for the link, so if I understand it right, there should be a call to eval() to ensure getting right type:
So this should then work?

const auto srcRow = src.row(y).eval();
const double *src_row = srcRow.data();

• Thanks for the link, so if I understand it right, there should be a call to eval() to ensure getting right type:

Not really. Instead of bending backwards to enforce compile-time type deduction, you just declare the type explicitly:

Eigen::VectorXd row = src.row(y);

• @kshegunov Thanks, for now I never used Eigen, but when I will have to use it I will try to remember this pitfall :)

• @KroMignon when i use eval(). It work. Thanks

• when i use eval(). It work. Thanks

Yes it works, but as @kshegunov has written and as you can read it in documentation (https://eigen.tuxfamily.org/dox/TopicPitfalls.html), this not be the best way to do with Eigen.
It would be better to not use auto but to specify right variable type like:

const Eigen::VectorXd row = src.row(y);
const double *src_row = srcRow.data();

• @KroMignon yes, you are right! Thanks.