如何正确使用cv::Mat和Eigen::Matrix? (OpenCV + 本征)
How to use cv::Mat and Eigen::Matrix correctly? (OpenCV + Eigen)
我能够将 OpenCV mat 对象转换为 Eigen 对象,然后再转换回来。但是,当我尝试在屏幕上显示 Eigen->Mat 时,我得到一个空白 window,我不知道为什么。我可以将图像保存到一个文件中,这样我就知道它的转换是否正确。
关于如何让转换后的图像显示在屏幕上有什么建议吗?
这是我当前的代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
if ( argc != 2 )
{
printf("usage: DisplayImage.out <Image_Path>\n");
return -1;
}
cv::Mat image;
image = cv::imread( argv[1], cv::ImreadModes::IMREAD_GRAYSCALE);
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::namedWindow("Display Image", cv::WINDOW_AUTOSIZE );
cv::imshow("Display Image", image);
cv::waitKey(0);
Eigen::MatrixXd eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
// std::cout << eigen_matrix << std::endl;
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
// This is blank
cv::namedWindow("Display Image2", cv::WINDOW_AUTOSIZE );
cv::imshow("Display Image2", test_image);
cv::waitKey(0);
cv::imwrite("test.png", test_image);
return 0;
}
从Eigen document,我们可以找到这个:
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
也就是说,你把灰度图转成double
。当 OpenCV 在 [0, 1.0]
范围内显示 float/double 时,在 [0, 255.0]
.
范围内保存 float/double
两种解决方法:
imshow CV_32F|CV_64F
乘以 (1.0/255)
cv::imshow("doube image ", test_image*(1.0/255));
将特征矩阵元素类型更改为 unsigned char
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc;
MatrixXuc eigen_matrix;
这是我的结果:
代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
cv::Mat image = cv::imread( "Knight.jpg", cv::ImreadModes::IMREAD_GRAYSCALE);
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::imshow("Source", image);
// (1) display multiplied by (1.0/255)
{
Eigen::MatrixXd eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
cv::imshow("doube image ", test_image*(1.0/255));
cv::imwrite("dst_double.png", test_image);
}
// (2) change Eigen Matrix type
{
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc;
MatrixXuc eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
cv::imshow("uchar image", test_image);
cv::imwrite("dst_uchar.png", test_image);
}
cv::waitKey(0);
return 0;
}
通知:
帮助 cv2.imshow
imshow(...)
imshow(winname, mat) -> None
. @brief Displays an image in the specified window.
.
. The function imshow displays an image in the specified window. If the window was created with the
. cv::WINDOW_AUTOSIZE flag, the image is shown with its original size, however it is still limited by $
. Otherwise, the image is scaled to fit the window. The function may scale the image, depending on its$
.
. - If the image is 8-bit unsigned, it is displayed as is.
. - If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the
. value range [0,255\*256] is mapped to [0,255].
. - If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is$
. value range [0,1] is mapped to [0,255].
帮助 cv2.imwrite
imwrite(...)
imwrite(filename, img[, params]) -> retval
. @brief Saves an image to a specified file.
.
. The function imwrite saves the image to the specified file. The image format is chosen based on the
. filename extension (see cv::imread for the list of extensions). Only 8-bit (or 16-bit unsigned (CV_1$
. in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images
. can be saved using this function. If the format, depth or channel order is different, use
. Mat::convertTo , and cv::cvtColor to convert it before saving. Or, use the universal FileStorage I/O
. functions to save the image to XML or YAML format.
上一个答案只适用于 GrayScale
,这个适用于 Color
。
关键是reshape
cv::Mat.
cv::Mat::reshape(int new_channel, int new_rows);
结果:
代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
cv::Mat image = cv::imread( "Knight.jpg");
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::imshow("Source", image);
int chs = image.channels();
// (1) display multiplied by (1.0/255)
{
cv::Mat img = image.reshape(1, 0);
std::cout << img.size() << ", " << img.channels() << std::endl;
typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MatrixXd;
MatrixXd mat;
cv::cv2eigen(img, mat);
cv::Mat img2;
cv::eigen2cv(mat, img2);
img2 = img2.reshape(chs, 0);
cv::imshow("doube color image ", img2*(1.0/255));
cv::imwrite("dst_double.png", img2);
}
// (2) change Eigen Matrix type
{
cv::Mat img = image.reshape(1, 0);
std::cout << img.size() << ", " << img.channels() << std::endl;
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc;
MatrixXuc mat;
cv::cv2eigen(img, mat);
cv::Mat img2;
cv::eigen2cv(mat, img2);
img2 = img2.reshape(chs, 0);
std::cout << img2.size() << ", " << img2.channels() << std::endl;
cv::imshow("uchar color image", img2);
cv::imwrite("dst_uchar.png", img2);
}
cv::waitKey(0);
return 0;
}
我能够将 OpenCV mat 对象转换为 Eigen 对象,然后再转换回来。但是,当我尝试在屏幕上显示 Eigen->Mat 时,我得到一个空白 window,我不知道为什么。我可以将图像保存到一个文件中,这样我就知道它的转换是否正确。
关于如何让转换后的图像显示在屏幕上有什么建议吗?
这是我当前的代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
if ( argc != 2 )
{
printf("usage: DisplayImage.out <Image_Path>\n");
return -1;
}
cv::Mat image;
image = cv::imread( argv[1], cv::ImreadModes::IMREAD_GRAYSCALE);
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::namedWindow("Display Image", cv::WINDOW_AUTOSIZE );
cv::imshow("Display Image", image);
cv::waitKey(0);
Eigen::MatrixXd eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
// std::cout << eigen_matrix << std::endl;
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
// This is blank
cv::namedWindow("Display Image2", cv::WINDOW_AUTOSIZE );
cv::imshow("Display Image2", test_image);
cv::waitKey(0);
cv::imwrite("test.png", test_image);
return 0;
}
从Eigen document,我们可以找到这个:
typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
也就是说,你把灰度图转成double
。当 OpenCV 在 [0, 1.0]
范围内显示 float/double 时,在 [0, 255.0]
.
两种解决方法:
imshow
CV_32F|CV_64F
乘以(1.0/255)
cv::imshow("doube image ", test_image*(1.0/255));
将特征矩阵元素类型更改为
unsigned char
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc; MatrixXuc eigen_matrix;
这是我的结果:
代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
cv::Mat image = cv::imread( "Knight.jpg", cv::ImreadModes::IMREAD_GRAYSCALE);
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::imshow("Source", image);
// (1) display multiplied by (1.0/255)
{
Eigen::MatrixXd eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
cv::imshow("doube image ", test_image*(1.0/255));
cv::imwrite("dst_double.png", test_image);
}
// (2) change Eigen Matrix type
{
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc;
MatrixXuc eigen_matrix;
cv::cv2eigen(image, eigen_matrix);
cv::Mat test_image;
cv::eigen2cv(eigen_matrix, test_image);
cv::imshow("uchar image", test_image);
cv::imwrite("dst_uchar.png", test_image);
}
cv::waitKey(0);
return 0;
}
通知:
帮助 cv2.imshow
imshow(...)
imshow(winname, mat) -> None
. @brief Displays an image in the specified window.
.
. The function imshow displays an image in the specified window. If the window was created with the
. cv::WINDOW_AUTOSIZE flag, the image is shown with its original size, however it is still limited by $
. Otherwise, the image is scaled to fit the window. The function may scale the image, depending on its$
.
. - If the image is 8-bit unsigned, it is displayed as is.
. - If the image is 16-bit unsigned or 32-bit integer, the pixels are divided by 256. That is, the
. value range [0,255\*256] is mapped to [0,255].
. - If the image is 32-bit or 64-bit floating-point, the pixel values are multiplied by 255. That is$
. value range [0,1] is mapped to [0,255].
帮助 cv2.imwrite
imwrite(...)
imwrite(filename, img[, params]) -> retval
. @brief Saves an image to a specified file.
.
. The function imwrite saves the image to the specified file. The image format is chosen based on the
. filename extension (see cv::imread for the list of extensions). Only 8-bit (or 16-bit unsigned (CV_1$
. in case of PNG, JPEG 2000, and TIFF) single-channel or 3-channel (with 'BGR' channel order) images
. can be saved using this function. If the format, depth or channel order is different, use
. Mat::convertTo , and cv::cvtColor to convert it before saving. Or, use the universal FileStorage I/O
. functions to save the image to XML or YAML format.
上一个答案只适用于 GrayScale
,这个适用于 Color
。
关键是reshape
cv::Mat.
cv::Mat::reshape(int new_channel, int new_rows);
结果:
代码:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>
int main(int argc, char **argv) {
cv::Mat image = cv::imread( "Knight.jpg");
if ( !image.data )
{
printf("No image data \n");
return -1;
}
cv::imshow("Source", image);
int chs = image.channels();
// (1) display multiplied by (1.0/255)
{
cv::Mat img = image.reshape(1, 0);
std::cout << img.size() << ", " << img.channels() << std::endl;
typedef Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> MatrixXd;
MatrixXd mat;
cv::cv2eigen(img, mat);
cv::Mat img2;
cv::eigen2cv(mat, img2);
img2 = img2.reshape(chs, 0);
cv::imshow("doube color image ", img2*(1.0/255));
cv::imwrite("dst_double.png", img2);
}
// (2) change Eigen Matrix type
{
cv::Mat img = image.reshape(1, 0);
std::cout << img.size() << ", " << img.channels() << std::endl;
typedef Eigen::Matrix<unsigned char, Eigen::Dynamic, Eigen::Dynamic> MatrixXuc;
MatrixXuc mat;
cv::cv2eigen(img, mat);
cv::Mat img2;
cv::eigen2cv(mat, img2);
img2 = img2.reshape(chs, 0);
std::cout << img2.size() << ", " << img2.channels() << std::endl;
cv::imshow("uchar color image", img2);
cv::imwrite("dst_uchar.png", img2);
}
cv::waitKey(0);
return 0;
}