Question

I am using Qt add in for Visual Studio C++ for my GUI.

And on my GUI, I have a button called the plotButton which will draw an histogram of the image when clicked. My plotting option is via the usage of QWT.

However, it does not seem to be plotting anything and closes almost immediately. Tried sleep(), but it doesn't seem to work either. Could the problem be with my code? Here is my code for reference:

void qt5test1 ::on_plotButton_clicked()
{
    //Convert to grayscale
    cv::cvtColor(image, image, CV_BGR2GRAY);


    int histSize[1] = {256}; // number of bins
    float hranges[2] = {0.0, 255.0}; // min andax pixel value
    const float* ranges[1] = {hranges};
    int channels[1] = {0}; // only 1 channel used

    cv::MatND hist;
    // Compute histogram
    calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);

    double minVal, maxVal;
    cv::minMaxLoc(hist, &minVal, &maxVal);//Locate max and min values

    QwtPlot plot; //Create plot widget
    plot.setTitle( "Plot Demo" ); //Name the plot
    plot.setCanvasBackground( Qt::black ); //Set the Background colour
    plot.setAxisScale( QwtPlot::yLeft, minVal, maxVal ); //Scale the y-axis
    plot.setAxisScale(QwtPlot::xBottom,0,255); //Scale the x-axis
    plot.insertLegend(new QwtLegend()); //Insert a legend

    QwtPlotCurve *curve = new QwtPlotCurve(); // Create a curve
    curve->setTitle("Count"); //Name the curve
    curve->setPen( Qt::white, 2);//Set colour and thickness for drawing the curve 
    //Use Antialiasing to improve plot render quality
    curve->setRenderHint( QwtPlotItem::RenderAntialiased, true );
    /*Insert the points that should be plotted on the graph in a 
    Vector of QPoints or a QPolgonF */
    QPolygonF points;
    for( int h = 0; h < histSize[0]; ++h) {
        float bin_value = hist.at<float>(h);
        points << QPointF((float)h, bin_value);
    }

    curve->setSamples( points ); //pass points to be drawn on the curve
    curve->attach( &plot ); // Attach curve to the plot 
    plot.resize( 600, 400 ); //Resize the plot
    plot.replot();
    plot.show(); //Show plot
    Sleep(100);
}

Upon clicking this button after loading the image, a window appear and disappear immediately. Under the output window, the lines can be found.

First-chance exception at 0x75d54b32 (KernelBase.dll) in qt5test1.exe: Microsoft C++ exception: cv::Exception at memory location 0x0044939c..
Unhandled exception at 0x75d54b32 (KernelBase.dll) in qt5test1.exe: Microsoft C++ exception: cv::Exception at memory location 0x0044939c..

Does anybody have any idea what could be wrong with my code? Thanks. Please note once again that the program is build, and written within Microsoft Visual Studio C++. Thanks.

Was it helpful?

Solution

The problem is that you are constructing a stack object here:

QwtPlot plot; //Create plot widget

That is true that you are trying to show the plot at the end of the method, but the show() method is not blocking with an event loop like the QDialog classes when you use the exec() call on them.

It would be processed, but you are leaving the scope right after the call either way.

There are several ways of addressing this issue, but I would strive for the Qt parent/child hierarchy where the deletion will come automatically when using pointers.

1) Qt parent/child relation

QwtPlot *plot = new QwtPlot(this);
                            ^^^^

2) Make "plot" a class member

plot.show();

and construct it in the class constructor.

3) Use a smart pointer

QSharedPointer<QwtPlot> plot = QSharedPointer<QwtPlot>(new QwtPlot());

It depends on your further context of the class which way to pick up, so try to understand these approaches, and take your peek.

OTHER TIPS

plot should be created using new. Now you create it on stack, so it will be deleted immediately when on_plotButton_clicked function finished. Sleep should not be used here, you won't get any good from it.

QwtPlot* plot = new QwtPlot();
plot->setTitle( "Plot Demo" ); //Name the plot
//...
plot->show(); //Show plot

The problem might be that your QwtPlot is just a local variable and even because the sleep is also in the main thread you won't be able to draw it in time before the function returns. Then when it finish sleeping it destroys your local QwtPlot object and returns, so you are luck enough if you get a blink of the window like that.

To make it work you will have to call it like this:

QwtPlot* plot = new QwtPlot(this);

where this is the parent window that will host your plot (if any). That way your widget will remain alive until you close it or its parent destroy it at the end of the program execution.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top