c++ 在gtkmm中显示opencv cv::Mat图像

anauzrmj  于 2023-04-13  发布在  其他
关注(0)|答案(8)|浏览(233)

我想在gtkmm编写的GUI中显示一个cv::Mat。所以我做了一个测试。
我有一个小部件Gtk::Image image,我想用以下两种方法设置图像:

// first method, display from file
void displayImage1()
{
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_file("gtk.png");
    image.set(pixbuf);
}

// second method, display from cv::Mat
void displayImage2()
{
    cv::Mat outImage = cv::imread("gtk.png");
    cv::cvtColor(outImage, outImage, CV_BGR2RGB);
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(outImage.data, Gdk::COLORSPACE_RGB,false, 8, outImage.cols, outImage.rows, outImage.step);
    image.set(pixbuf);
}

第一种方法效果很好。

然而,第二种方法不太好用,我在屏幕上得到了一个被破坏的图像,如图所示。

如果我将has_alpha参数设置为true,结果也很奇怪(见下图)。
使用Gtk::DrawingArea进行了类似的测试。使用了不同的IDE(但所有的g++编译器都在linux下)。所有结果都相同。
更新:
我测试了很多图像。有时图像坏了,有时程序崩溃了
程序意外结束。

0s7z1bwu

0s7z1bwu1#

对于Gtkmm-2.4和OpenCv 4.6,检查https://onthim.blogspot.com/2015/10/using-opencv-in-gtk-applications.htmlhttps://developer-old.gnome.org/gtkmm-tutorial/2.24/sec-draw-images.html.es

Mat frame;
    frame = imread("gtk.png");    
    cv::cvtColor (frame, frame, COLOR_BGR2RGB);//COLOR_BGR2GRAY
    Glib::RefPtr<Gdk::Pixbuf> image = Gdk::Pixbuf::create_from_data(frame.data,Gdk::COLORSPACE_RGB, false, 8, frame.cols, frame.rows, frame.step);
    image->render_to_drawable(get_window(), get_style()->get_black_gc(),0, 0, 0, 0, image->get_width(), image->get_height(), // draw the whole image (from 0,0 to the full width,height) at 100,80 in the window
Gdk::RGB_DITHER_NONE, 0, 0);
ycggw6v2

ycggw6v22#

通常,这种“破碎”的形象会在我的脑海中触发一个警告:“wrong rawstride!"。Gdk::Pixbuf中的rawstride在一行数据的字节长度中。这是因为您可能有一些字节对齐约束,因此在一行的末尾可能有一些填充。
我检查了这个step参数是什么,是的,这在OpenCV中与Gdk::Pixbuf中的rawstride相同。直到我意识到outImage.step是一个cv:MatStep对象,而Gdk::Pixbuf::create_from_data需要一个int。我认为你应该使用outImage.step[0]
请阅读https://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat

bkkx9g8r

bkkx9g8r3#

我们开始吧:

auto lenna = imread("Lenna.png");
Image image;

cvtColor(lenna, lenna, COLOR_BGR2RGB);
auto size = lenna.size();
auto img = Gdk::Pixbuf::create_from_data(lenna.data, Gdk::COLORSPACE_RGB, lenna.channels() == 4, 8, size.width, size.height, (int) lenna.step);

image.set(img);
guykilcj

guykilcj4#

这就是我所做的,它显示了良好的效果图像显示

cvtColor(resize_image, resize_image, COLOR_BGR2RGB);
Pixbuf = Gdk::Pixbuf::create_from_data(resize_image.data, Gdk::COLORSPACE_RGB, false, 8, resize_image.cols, resize_image.rows, resize_image.step);
2jcobegt

2jcobegt5#

所以我测试了这个(add scale_simple),结果很成功:
From:http://orobotp.blogspot.com/2014/01/opencv-with-gtkmm3.html
版本:Gtkmm 3.22.2-2,OpenCV 4.4.0-开发版本,g++ 7.5.0

void displayImage2()
{
    cv::Mat outImage;
    outImage = cv::imread("gtk.png");
    cv::cvtColor(outImage, outImage, cv::COLOR_RGB2BGR);
    Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(outImage.data, Gdk::COLORSPACE_RGB,false, 8, outImage.cols, outImage.rows, outImage.step)->scale_simple( outImage.cols, outImage.rows, Gdk::INTERP_BILINEAR );
    image.set(pixbuf);
}
rbpvctlc

rbpvctlc6#

IMO,正如@三木在评论中所建议的那样,这只是一个终身问题。
我遇到了同样的问题,类似的代码:

{
    cv::Mat rgb;
    cv::cvtColor(src, rgb, cv::COLOR_GRAY2RGB);
    pixbuf = gdk_pixbuf_new_from_data(rgb.data,
                                      GDK_COLORSPACE_RGB, FALSE, 8,
                                      rgb.cols, rgb.rows, rgb.step,
                                      NULL, NULL);
}

上面的代码段根本不起作用(或者间歇性地起作用),因为引用gdk_pixbuf_new_from_data documentation,“数据由函数的调用者拥有”。
问题是在渲染图像的时候,rgb已经被破坏了。在pixbuf赋值之前添加一个rgb.addref()可以解决这个问题,尽管会引入内存泄漏。
一种解决方案是利用destroy回调取消引用Mat对象,例如:

static void
unref_mat(guchar *data, gpointer user_data)
{
    ((cv::Mat *) user_data)->release();
}

{
    cv::Mat rgb;
    cv::cvtColor(src, rgb, cv::COLOR_GRAY2RGB);
    rgb.addref()
    pixbuf = gdk_pixbuf_new_from_data(rgb.data,
                                      GDK_COLORSPACE_RGB, FALSE, 8,
                                      rgb.cols, rgb.rows, rgb.step,
                                      unref_mat, &rgb);
}
oewdyzsn

oewdyzsn7#

尝试添加对outimage的引用,如outimage.addref()。我所有的问题都与此有关。在gdk_pixbuf_new_from_data有机会Map它之前,源图像被取消引用。导致segfaults,corruption等。请确保稍后释放它,或使用gdk_pixbuf_new_from_data提供的回调

3j86kqsm

3j86kqsm8#

cv::MatoutImage会在执行超出函数displayImage2()的作用域时被破坏,因此您应该在您的自定义类中声明变量outImage,该自定义类派生自Gtk::Window。下面是一个使用gtkmm4和opencv4的示例:

#include <opencv2/opencv.hpp>
#include <gtkmm.h>

class Buttons : public Gtk::Window
{
public:
  Buttons();
  virtual ~Buttons();

protected:
  cv::Mat outImage;
  Gtk::Image image;
};

Buttons::Buttons()
{
  outImage = cv::imread("gtk.jpg");
  cv::cvtColor(outImage, outImage, cv::COLOR_BGR2RGB);
  Glib::RefPtr<Gdk::Pixbuf> pixbuf = Gdk::Pixbuf::create_from_data(outImage.data,
                                                                   Gdk::Colorspace::RGB,
                                                                   false, 
                                                                   8, 
                                                                   outImage.cols, 
                                                                   outImage.rows, 
                                                                   outImage.step);
  image.set(pixbuf);
  set_child(image);
}

Buttons::~Buttons()
{
}

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app->make_window_and_run<Buttons>(argc, argv);
}

相关问题