PDA

View Full Version : ASSERT failure in QWidget: " Widgets must be created in GUI Thread"



rdockterjr
27th September 2012, 21:49
I realize other threads exist concerning this topic, but none of the responses apply to my situation.
I am using a QApplication and MainWindow instance to run my GUI from my main() function. I also run a windows API thread out of my main() to use various opencv functions in a separate thread. The strange part is when I remove the windows API thread calls, I don't have this problem, but I am 99% sure I don't call a QWidget in any of the runprog function. Any help would be awesome.

Here is my main.cpp



#include <Windows.h>
#include <WinCon.h>

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include "Alignment.h"
#include "mainwindow.h"
#include "globals.h"

#include <QtGui>
#include <QtCore/QCoreApplication>
#include <QApplication>
#include <QMainWindow>
#include <QHBoxLayout>
#include "conio.h"

#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sstream>

DWORD WINAPI runProg(LPVOID args);
HANDLE rThread;
HANDLE rEvent;

//Struct for passing data
struct PixelData {
int totalrpixels;
int totalgpixels;
int totalrpixelarea;
int totalgpixelarea;
cv::Point redcenter;
cv::Point greencenter;
};

cv::Point getCentroid(cv::Mat);
int runprog();
PixelData getColorSpotInfo(cv::Mat*, cv::Mat*, cv::Mat*);


int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow *mainwin = new MainWindow();
mainwin->show();
rEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
rThread = CreateThread(NULL,0,runProg,0,0,&runProgId);
return app.exec();
}

int runprog()
{
//Variables
cv::Mat depthimage, depthMap, bgrimage, dark, light, hsvim;
cv::Point gcoord;
cv::Point rcoord;

//Color Thresholds
int darkrmax = 230;
int darkrmin = 170;
int darkgmax = 220;
int darkgmin = 150;
int darkbmax = 200;
int darkbmin = 140;
int lightrmax = 150;
int lightrmin = 100;
int lightgmax = 80;
int lightgmin = 30;
int lightbmax = 90;
int lightbmin = 40;


//Adjust Console Location
HWND hwnds = GetConsoleWindow();
MoveWindow(hwnds,5,5,400,300,TRUE);

int rows, cols, centerx, centery;

cv::VideoCapture capture(CV_CAP_OPENNI);
capture.grab();

capture.retrieve(depthMap,CV_CAP_OPENNI_DEPTH_MAP) ;
capture.retrieve(bgrimage,CV_CAP_OPENNI_BGR_IMAGE) ;
cv::cvtColor(bgrimage,hsvim,CV_BGR2HSV);
inRange(hsvim, cv::Scalar(darkbmin, darkgmin, darkrmin), cv::Scalar(darkbmax, darkgmax, darkrmax), dark);
inRange(hsvim, cv::Scalar(lightbmin, lightgmin, lightrmin), cv::Scalar(lightbmax, lightgmax, lightrmax), light);

depthMap.convertTo(depthimage, CV_8UC1, 0.05f);
cv::cvtColor(bgrimage,hsvim,CV_BGR2HSV);
cv::imshow("CameraFeed",bgrimage);
cv::imshow("Dark",dark);
cv::imshow("Light",light);
cv::imshow("HSVFeed",hsvim);
cv::imshow("Depth",depthimage);

cvMoveWindow("CameraFeed", 5, 300);
cvMoveWindow("Dark", 800, 5);
cvMoveWindow("Light", 800, 300);
cvMoveWindow("HSVFeed", 300, 5);
cvMoveWindow("Depth", 1600, 5);

PixelData pixdatcap;

while(true){
capture.grab();
capture.retrieve(depthMap,CV_CAP_OPENNI_DEPTH_MAP) ;
capture.retrieve(bgrimage,CV_CAP_OPENNI_BGR_IMAGE) ;
depthMap.convertTo(depthimage, CV_8UC1, 0.05f);
cv::cvtColor(bgrimage,hsvim,CV_BGR2HSV);
inRange(hsvim, cv::Scalar(darkbmin, darkgmin, darkrmin), cv::Scalar(darkbmax, darkgmax, darkrmax), dark);
inRange(hsvim, cv::Scalar(lightbmin, lightgmin, lightrmin), cv::Scalar(lightbmax, lightgmax, lightrmax), light);
if(runnow == 1){
pixdatcap = getColorSpotInfo(&dark, &light, &depthMap);
runnow = 0;
}

cv::imshow("CameraFeed",bgrimage);
cv::imshow("Dark",dark);
cv::imshow("Light",light);
cv::imshow("HSVFeed",hsvim);
cv::imshow("Depth",depthimage);

cv::waitKey(1);

}
return 1;

}

cv::Point getCentroid(cv::Mat img)
{
cv::Point Coord;
cv::Moments mm = cv::moments(img,false);
double moment10 = mm.m10;
double moment01 = mm.m01;
double moment00 = mm.m00;
Coord.x = int(moment10 / moment00);
Coord.y = int(moment01 / moment00);
return Coord;
}


PixelData getColorSpotInfo(cv::Mat *greenmat, cv::Mat *redmat, cv::Mat *depthdata){
cv::Mat green = *greenmat;
cv::Mat red = *redmat;
cv::Mat depdat = *depthdata;
int totalgpix = 0;
int totalrpix = 0;
int avgdepthg = 0;
int avgdepthr= 0;
int totaldepthr = 0;
int totaldepthg = 0;

PixelData pixdat;

pixdat.redcenter = getCentroid(red);
pixdat.greencenter = getCentroid(green);
for(int x = 0; x < green.rows; x++){
for(int y = 0; y < green.cols; y++){
if(((uchar*)(green.data + green.step*x))[y] != 0){
totalgpix++;
totaldepthg += ((uchar*)(depdat.data + depdat.step*x))[y];
}
if(((uchar*)(red.data + red.step*x))[y] != 0){
totalrpix++;
totaldepthr += ((uchar*)(depdat.data + depdat.step*x))[y];
}
}
}
avgdepthr = totaldepthr/totalrpix;
avgdepthg = totaldepthg/totalgpix;

pixdat.totalgpixels = totalgpix;
pixdat.totalrpixels = totalrpix;

pixdat.totalgpixelarea = (totalgpix*avgdepthg)/100;
pixdat.totalrpixelarea = (totalrpix*avgdepthr)/100;

return pixdat;

}

DWORD WINAPI runProg(LPVOID args) {
DWORD retint;
OutputDebugStringW(L"run thread started. ");
try {
retint = runprog();
}
catch( char * str ) {
std::cout << "Exception raised: " << str << '\n';
}
OutputDebugStringW(L"run thread leaving. ");
SetEvent(rEvent);
return retint;
}


And my mainwindow.cpp



#include "mainwindow.h"
#include "globals.h"
#include <Windows.h>
#include "ui_mainwindow.h"

#include <QtGui>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

void MainWindow::RunHandle()
{
runnow = 1;
system("cls");
}

void MainWindow::QuitHandle()
{
OutputDebugStringW(L"main window exit.");
quitnow = 1;
Sleep(100);
qApp->quit();
}

void MainWindow::OptionHandlePos(int buttonIdP)
{
if(buttonIdP == 1){
PosVar = 1;
}
else if(buttonIdP == 2){
PosVar = 2;
}
else if(buttonIdP == 3){
PosVar = 3;
}
else if(buttonIdP == 4){
PosVar = 4;
}
else{
PosVar = 1;
}
}

void MainWindow::OptionHandleFull(int buttonIdF)
{
if(buttonIdF == 1){
FullVar = 1;
}
else if(buttonIdF == 2){
FullVar = 2;
}
else{
FullVar = 1;
}
}

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{

//Position Menu
QGroupBox *PosGroup = new QGroupBox("Position Menu");
QRadioButton *Pos1 = new QRadioButton("Top Right");
QRadioButton *Pos2 = new QRadioButton("Top Left (default)");
QRadioButton *Pos3 = new QRadioButton("Bottom Right");
QRadioButton *Pos4 = new QRadioButton("Bottom Left");
Pos2->setChecked(true);
QVBoxLayout *PosBox = new QVBoxLayout;
PosBox->addWidget(Pos1);
PosBox->addWidget(Pos2);
PosBox->addWidget(Pos3);
PosBox->addWidget(Pos4);
PosBox->addStretch(1);
PosGroup->setLayout(PosBox);
//mapping radio buttons
QSignalMapper* SigMapPos = new QSignalMapper(this);
connect(SigMapPos, SIGNAL(mapped(int)), this, SLOT(OptionHandlePos(int)));
SigMapPos->setMapping(Pos1, 1);
SigMapPos->setMapping(Pos2, 2);
SigMapPos->setMapping(Pos3, 3);
SigMapPos->setMapping(Pos4, 4);
connect(Pos1, SIGNAL(clicked()), SigMapPos, SLOT(map()));
connect(Pos2, SIGNAL(clicked()), SigMapPos, SLOT(map()));
connect(Pos3, SIGNAL(clicked()), SigMapPos, SLOT(map()));
connect(Pos4, SIGNAL(clicked()), SigMapPos, SLOT(map()));

//Make Full Screen Menu
QGroupBox *FullGroup = new QGroupBox("Toggle Full Screen");
QRadioButton *Full1 = new QRadioButton("Normal (default)");
QRadioButton *Full2 = new QRadioButton("Full");
Full1->setChecked(true);
QVBoxLayout *FullBox = new QVBoxLayout;
FullBox->addWidget(Full1);
FullBox->addWidget(Full2);
FullBox->addStretch(1);
FullGroup->setLayout(FullBox);
//mapping radio buttons
QSignalMapper* SigMapFull = new QSignalMapper(this);
connect(SigMapFull, SIGNAL(mapped(int)), this, SLOT(OptionHandleFull(int)));
SigMapFull->setMapping(Full1, 1);
SigMapFull->setMapping(Full2, 2);
connect(Full1, SIGNAL(clicked()), SigMapFull, SLOT(map()));
connect(Full2, SIGNAL(clicked()), SigMapFull, SLOT(map()));


//Reset/Close Application buttons
QGroupBox *RCGroup = new QGroupBox("Actions");
QPushButton* ButtonRun= new QPushButton("Run");
QPushButton* ButtonQuit = new QPushButton("Close");
QHBoxLayout *RCBox = new QHBoxLayout;
RCBox->addWidget(ButtonRun);
RCBox->addWidget(ButtonQuit);
RCBox->addStretch(1);
RCGroup->setLayout(RCBox);
connect(ButtonQuit, SIGNAL(clicked()), this, SLOT(QuitHandle()) );
connect(ButtonRun, SIGNAL(clicked()), this, SLOT(RunHandle()) );

//Combine all menu options
QVBoxLayout *MenuBox = new QVBoxLayout;
MenuBox->addWidget(PosGroup);
MenuBox->addWidget(FullGroup);
MenuBox->addWidget(RCGroup);
QWidget *widget = new QWidget(this);
widget->setLayout(MenuBox);
setCentralWidget(widget);

}




And globals.h/cpp is a basic global variables thing but I doubt the global stuff has anything to do with it though.

I like to think I know QT fairly well but for the life of me I cannot figure out what is going on. Any help, even as much as copying the code and running it to see if its just my system would be appreciated greatly.

Thanks,
Rod

amleto
27th September 2012, 23:33
a call stack would be useful.

fyi, the following headers are not standard:
#include "conio.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

ChrisW67
28th September 2012, 02:13
If you remove the lines getting and moving the console does the problem go away? Is the console window the one provided by Qt?

rdockterjr
28th September 2012, 21:23
Thanks for the quick replies.

The call trace didn't really lead anywhere so I just threw in a slew of print statements and found out it was the cv::imshow() call. It seems like when you build opencv with qt, the opencv imshow windows use qt code and so the other qt thread believes the imshow window is also making a widget? Have you heard of this before?

Anyways, I believe thats the issue so I'm trying some work-arounds. Also what do you mean those headers are not standard, I thought stdio and stdlib were?

And ChrisW67, no the console-move command is moving win32 application console.

amleto
29th September 2012, 20:17
correct header names are cstdlib, cstdio and ctime

wysota
29th September 2012, 20:30
What's actually the reason for trying to move the OpenCV window from within a worker thread?