Debugging OpenCV images into a Qt Application

Selection_001Getting right to the point: Qt has his own event loop control. So, if you want to use the OpenCV functions to show images you will discover that they do not change. The solution is to do the debugging inside the Qt loop. How?, creating a dialog and drawing the images inside. Lets see how to do it

CVDebugSystem

This class will take control of all debug windows (yes, we want to have more than one debugging window). When we want to debug the image we are processing, we only need to call to one method of this class passing the window name (like in OpenCV imshow function) and the image we want to show.

Probably, we want to debug images from different parts of our code, and create a debug object each time we want to debug could be a problem (after debug, maybe we forget to delete this objects and the code keeps “dirty”). To solve this, we will declare CVDebugSystem as a Singleton. Now, we do not need to create CVDebugSystem objects, the class take care of all the windows and debug a image is as simple as call the method:

CVDebugSystem::getInstance().showimg("Title of debug window", image_to_debug);

The different windows are stored into a QHash list, using the window title as key.

cvdebugsystem.h

#ifndef CVDEBUGSYSTEM_H
#define CVDEBUGSYSTEM_H

#include <QHash>
#include "cvdebugwindow.h"

class CVDebugSystem
{
public:
    static CVDebugSystem &getInstance()
    {
        if(pInstance_ == NULL)
        {
            pInstance_ = new CVDebugSystem();
            atexit(&DestroySingleton);    // At exit, destroy the singleton
        }
        return *pInstance_;
    }
    ~CVDebugSystem();

private:
    // Singleton
    static CVDebugSystem* pInstance_;

    // Delete the singleton instance
    static void DestroySingleton(){
        if(pInstance_ != NULL) delete pInstance_;
    }

    // Private to ensure single instance
    CVDebugSystem();
    QHash<QString, CVDebugWindow* > mWindows;

public:
    void showimg(QString window, cv::Mat *img);
    void showimg(QString window, cv::Mat img);
};

#endif // CVDEBUGSYSTEM_H

cvdebugsystem.cpp

#include "cvdebugsystem.h"
#include <QImage>

CVDebugSystem* CVDebugSystem::pInstance_ = NULL;

CVDebugSystem::CVDebugSystem()
{
    mWindows.clear();
}

CVDebugSystem::~CVDebugSystem()
{
    QHash<QString, CVDebugWindow* >::const_iterator i = mWindows.constBegin();
     while (i != mWindows.constEnd()) {
         delete i.value();
         ++i;
     }
}

void CVDebugSystem::showimg(QString window, cv::Mat *img)
{
    if (!mWindows.contains(window))
    {
        CVDebugWindow *win = new CVDebugWindow();
        mWindows.insert(window, win);
    }
    mWindows[window]->setImage(img);
    mWindows[window]->setWindowTitle(window);
    mWindows[window]->show();
}

void CVDebugSystem::showimg(QString window, cv::Mat img)
{
    this->showimg(window, &img);
}

CVDebugWindow

This is the class that inherits from QDialog. It only has a QLabel where we draw the image. In the code attached I have included some more widgets to help me, like a “Fit the image to the window” or scale the OpenCV image to make it more clear. Usually I use the UI files, if you prefer to code the widgets it is also possible

cvdebugwindow.h

#ifndef CVDEBUGWINDOW_H
#define CVDEBUGWINDOW_H

#include <QDialog>
#include <opencv2/core/core.hpp>

namespace Ui {
class CVDebugWindow;
}

class CVDebugWindow : public QDialog
{
Q_OBJECT

public:
explicit CVDebugWindow(QWidget *parent = 0);
void setImage(cv::Mat *image);
~CVDebugWindow();

private Q_SLOTS:
void on_fitButton_toggled(bool checked);

private:
Ui::CVDebugWindow *ui;
};

#endif // CVDEBUGWINDOW_H

cvdebugwindow.cpp

#include "cvdebugwindow.h"
#include "ui_cvdebugwindow.h"

CVDebugWindow::CVDebugWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::CVDebugWindow)
{
ui->setupUi(this);
ui->label->setAlignment(Qt::AlignCenter | Qt::AlignHCenter);
}

CVDebugWindow::~CVDebugWindow()
{
delete ui;
}

void CVDebugWindow::setImage(cv::Mat *image)
{
QImage::Format format;
if (image->channels() == 1) format = QImage::Format_Mono;
else                        format = QImage::Format_RGB888;

QImage  img = QImage((const unsigned char*)(image->data),
image->cols,
image->rows,
image->step,
format).rgbSwapped();

QImage aux;
if (ui->fitButton->isChecked())
{
aux = img.scaled(ui->label->size());
}
else
{
if (ui->scaleFactor->value() != 1)
{
aux = img.scaled(img.size()*ui->scaleFactor->value());
}
else
aux = img;
}

ui->label->setPixmap(QPixmap::fromImage(aux));
}

void CVDebugWindow::on_fitButton_toggled(bool checked)
{
if (checked) ui->scaleFactor->setEnabled(false);
else ui->scaleFactor->setEnabled(true);
}

In GitHub you can find the repository with the code. Improvements are welcome.

Leave a Reply

Your email address will not be published. Required fields are marked *