I'm having trouble passing cv::mat data between forms on a qt gui application, for the moment I simply want to pass the Image chosen by the user on the main window and display it on the results page
void MainWindow::on_pushButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open Image"), ".", tr("Image Files (*.png *.jpg *.bmp)"));
Lateral= cv::imread(fileName.toAscii().data());
}
In the header file of the main window I definded:-
public:
cv::Mat get_Lateral(cv::Mat img);
cv::Mat get_Posteroanterior();
In the MainWindow.cpp file I have defined the folowing (i've tried a few variations of the method):-
cv::Mat MainWindow::get_Lateral(cv::Mat img ){
Lateral.copyTo(img);
return img;
}
cv::Mat MainWindow::get_Posteroanterior(){
return Posteroanterior;
}
Finally on the new form I have something like this:-
MainWindow Mw ;
cv::Mat op;
Mw.get_Lateral(op);
//(Mw.get_Posteroanterior()).copyTo(op);
cv::namedWindow("Lateral Image");
cv::imshow("Lateral Image",op);
When I run this I get a runtime error, so I added an if statment to check the contents of cv::mat op like this:-
MainWindow Mw ;
cv::Mat op;
Mw.get_Lateral(op);
//(Mw.get_Posteroanterior()).copyTo(op);
if (!op.data)
cv::namedWindow("dud Image");
else{
cv::namedWindow("Lateral Image");
cv::imshow("Lateral Image",op);
}
And I am given the dud image window implying that op is empty.
Any advice on how to do this process properly will be apppreciated, I am fairly new to opencv and c++ so I apologize for any blatant mistakes.
Cheers
Have a look at my answer involving integrating OpenCV with larger applications. I wouldn't recommend using the highgui imshow function inside of a Qt GUI application. It has done some weird things for me in the past.
Basically, you can convert the cv::Mat to a QImage and then either use QGLWidget, or just simply draw it onto a QPixmap if you don't particularly need high speed.
As for passing a Mat object between forms, you can either convert it to a QImage and then use signals/slots like my example shows, or if you need to manipulate the Mat object further, you can create a QMetaType. The QMetaType will allow you transmit it across forms just like you would any other native Qt object. Here is a Qt example to get you started.
Hope that is helpful!
The return value of get_Lateral is being discarded - you either need to modify it in place via a reference:
void MainWindow::get_Lateral(cv::Mat& img ){
Lateral.copyTo(img);
//return img;
}
or assign back to your local cv::Mat object in main:
MainWindow Mw ;
cv::Mat op;
op = Mw.get_Lateral(op);
//(Mw.get_Posteroanterior()).copyTo(op);
if (!op.data)
cv::namedWindow("dud Image");
else{
cv::namedWindow("Lateral Image");
cv::imshow("Lateral Image",op);
}
Related
I have a problem when resizing a cv::Mat and trying to use it for a pixmap in a Qlabel.
If I resize the mat and dont use it for the Qlabel, the program works fine, and if I do not resize the mat and use it for the pixmap with that size, it also works fine. The problem comes when I try to do both at the same time, for any reason I do not understand.
According to the debug, I recieve the SIGSEV here (from my mainWindow to the deepest error):
void MainWindow::print_img(const QImage &img)
{
ui->map->setPixmap(QPixmap::fromImage(img.rgbSwapped()));
}
---------
QImage rgbSwapped() const &
{ return rgbSwapped_helper(); }
---------
res = QImage(d->width, d->height, d->format);
---------
QImage::QImage(int width, int height, Format format)
: QImage(QSize(width, height), format)
---------
d = QImageData::create(size, format);
---------
d->data = (uchar *)malloc(d->nbytes);
Thanks in advance for the help.
I solved it by moving the map (where i got my image from) from the class variables to the run() function, so I do not have to resize the map.
I have a GUI composed of a QTableView with 18 columns and a QGraphicsView where I upload images using a button. I am able to draw a box on a region of interests (ROI) and as soon as I do that with a mouse right click I open up a small dialog. This dialog is composed of a TabWidget with two pages. The first page has a small QGraphicsView that carries the cropped image (say Image A) captured with the previous box drawn. The second page of the TabWidget has also another QGraphicsView that I use to upload a previously saved .jpg image (say Image B) that is on my Desktop. As soon as I hit ok the information on this dialog will be transferred to the first row of the QTableView. Image A will be stoted in one column (column 17 to be precise) and Image B in an additional column too (column 18 to be precise).
I was able to store the cropped Image A (which was the most difficult part because I had to work on understanding the conversion format between Qt and openCV and vice versa) in the QTableView but not Image B (which I handle as simple image that I saved on my Desktop).
I tried different options: option 1: I created a function with which I handle the image that I upload on the second page of the TabWidget (Image B), option 2: I tried to debug to narrow the problem and it seems that the compiler is not seeing the image I am trying to store.
I am attaching the most important part of the code that are carrying this bug:
In clipscene.h is how I declare the most important variables and functions I use:
class clipScene : public QDialog
{
Q_OBJECT
public:
explicit clipScene(QWidget *parent = 0);
~clipScene();
void setImage(QImage img);
void setClassifiedImage(QImage img);
SelectionData getData();
void setData(SelectionData newdata);
private:
SelectionData returnData;
Ui::clipScene *ui;
QImage simg;
QImage featureClassified;
};
In clipscene.cpp this is the function setClassifiedImage I use to handle Image B
void clipScene::setClassifiedImage(QImage img)
{
featureClassified = img;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(featureClassified));
workingImageScene->addItem(item);
}
In clipscene.cpp using setImage I successfully handle the Qt and openCV conversion of the cropped image
void clipScene::setImage(QImage img)
{
simg = img;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(simg));
scene->addItem(item);
ui->graphicsViewClipped->show();
cv::Mat input = cv::Mat(simg.height(), simg.width(), CV_16UC3, simg.bits(), simg.bytesPerLine());
// .....operations...
// .....operations...
}
In clipscene.cpp the following img1 represent the cropped Image A and the img2 represent Image B (that is currently nor stored neither passsed)
void clipScene::on_acceptBtn_clicked()
{
// .....operations...
// This will save the cropped Image A successfully
QPixmap img1;
img1.convertFromImage(simg);
QByteArray img1Array;
QBuffer buffer1(&img1Array);
buffer1.open(QIODevice::WriteOnly);
img1.save(&buffer1, "PNG");
returnData.mSave = img1Array;
// This will save a different Image B
// But here the compiler says that no arguments are being passed
QPixmap img2;
QByteArray img2Array;
QBuffer buffer2(&img2Array);
buffer2.open(QIODevice::WriteOnly);
img2.save(&buffer2, "PNG");
returnData.mClassImg = img2Array;
}
Finally when all information are passed and stored on the QTableView I am able to DoubleClick on one row of the QTableView and the same dialog I used before for manually storing the data will pop up with all information recorded and both images (Image A and Image B).
The part of the code that does this on MainWindow (and where the bug is connected) is below:
void MainWindow::onTableClick(const QModelIndex &index)
{
int row = index.row();
SelectionData currentData;
currentData.mName = index.sibling(row, 1).data().toString();
// ....additional data....
// ....additional data...
currentData.mSave = index.sibling(row, 17).data().toByteArray();
currentData.mClassImg = index.sibling(row, 18).data().toByteArray();
QPixmap iconPix;
if(!iconPix.loadFromData(index.sibling(row, 17).data().toByteArray())) {
}
QPixmap iconPix2;
if(!iconPix2.loadFromData(index.sibling(row, 18).data().toByteArray())) {
}
clipScene d(this);
d.setData(currentData);
d.setImage(iconPix.toImage());
d.setClassifiedImage(iconPix2.toImage());
// ....additional operations....
}
I have been struggling with this problem for some days now and anyone who can shed some light on this or provide a solution on how to solve this would be great.
I am not sure if this is still useful to you but since I had the same problem this might be helpful. I think you are never passing the image to the destination table. Are you ever loading the image? Are you ever doing something like this:
clipscene.h
private:
QList<QGraphicsPixmapItem*> leftClipPix;
clipscene.cpp
void clipScene::load_classifiedImageFromDb(QImage image)
{
clasImg = image;
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
leftClipPix.append(item);
workingImageScene->addItem(item);
ui->yourgraphicsView->show();
ui->yourgraphicsView->setSceneRect(QRectF(0, 0, image.width(), image.height()));
}
Also if, as you said, you are trying to upload an image from your Desktop or database, than it may be useful to do something like:
void clipScene::load_classifiedImage()
{
QString dir = QFileDialog::getOpenFileName(this, tr("Open image directory"), "", tr("Images (*.tif *.jpg *.png *.jpeg *.bmp *.gif *.tiff)"));
QImage image;
if(QString::compare(dir, QString()) != 0) {
image = QImage(dir);
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
leftClipPix.append(item);
workingImageScene->addItem(item);
}
ui->yourgraphicsView->show();
ui->yourgraphicsView->setSceneRect(QRectF(0, 0, image.width(), image.height()));
clasImg = image;
}
and pass load_classifiedImage() function to a QPushButton
It may be a very silly problem, but I am really got stack on this.
Here, I am trying to display a video frame by frame in QLabel. In the user interface, there is a QPushButton by clicking which user can select the video. Then QString of the video file is obtained, which is then converted to cv::String so that video can be loaded by using OpenCV libraries. After being loaded, every Mat3b type frame from the cv::video is being converted to the QImage, so that these frames can be displayed in a QLabel. But when I run this program, the QLabel is not displaying the video. And after few moments, it crushes showing Project.exe is not responding.
This may be a bit complex, but it has been thus done so that, some specific OpenCV methods can be applied on each frame if needed. Here is some code, which is responsible for this.
void MainWindow::on_Browse_clicked()
{
QFileDialog dialog(this);
dialog.setNameFilter(tr("Videos (*.avi)"));
dialog.setViewMode(QFileDialog::Detail);
QString videofileName = QFileDialog::getOpenFileName(this, tr("Open
File"), "C:/", tr("Videos (*.avi)"));
if(!videofileName.isEmpty())
{
String videopath;
videopath = videofileName.toLocal8Bit().constData();
bool playVideo = true;
VideoCapture cap(videopath);
if(!cap.isOpened())
{
QMessageBox::warning(this, tr("Warning"),tr("Error loadeing
video."));
exit(0);
}
Mat frame;
while(1)
{
if(playVideo)
cap >> frame;
Mat3b src=frame;
QImage dest= Mat3b2QImage(src); //To convert Mat3b to QImage
ui->label->setPixmap(QPixmap::fromImage(dest));
if(frame.empty())
{
QMessageBox::warning(this, tr("Warning"),tr("Video frame
cannot be openned."));
break;
}
}
}
}
But when I added the following few lines before the last three curly brace bracket, both the QLabel and cv::window are displaying the video.
imshow("Video",src);
char key = waitKey(10);
if(key == 'p')
playVideo = !playVideo;
if(key == 'q')
break;
But I don't want to display with cv::window. Can anyone help me fix it? I appreciate any help.
Thanks in advance.
The GUI thread is busy in the infinite while loop, so you never give Qt the chance to update the GUI.
You should add QApplication::processEvents inside the loop, which:
Processes all pending events for the calling thread [...].
You can call this function occasionally when your program is busy performing a long operation
I'm working on a homework for my Digital Image Processing class, and I'm using OpenCV with QT Framework.
I've created a class ImageDisplay, which is as sub class of the QWidget class.
I've using OpenCV to manipulate a grayscale image, and then creating a QImage object from the Mat object. After that I use the QWidget::drawImage() to draw the image. But sometimes it shows a distorted, angled image.
I was experimenting and discovered that it has something to do with the image dimensions.
For instance, this image with 320x391 pixels is rendered normally
But if change the dimension to 321x391 (using Gimp), it shows up like this:
This is the code for the paintEvent method:
void ImageDisplay::paintEvent(QPaintEvent *){
QPainter painter(this);
Mat tmp;
/* The mat in the next line is a Mat object that contains the image data */
cvtColor(mat, tmp, CV_GRAY2BGR);
QImage image(tmp.data, tmp.cols, tmp.rows, QImage::Format_RGB888);
painter.drawImage(rect(), image);
}
Does anyone has a clue what is the problem and how to fix it?
Thanks in advance!
I think you may need to specify the step of the image (number of bytes per line) when creating QImage in the fourth parameter:
QImage image((const uchar*) tmp.data, tmp.cols, tmp.rows, tmp.step, QImage::Format_RGB888);
So currently I open images created with openCV with something like
cvNamedWindow( "Original Image", CV_WINDOW_AUTOSIZE );
cvShowImage( "Original Image", original );
but my images are quite large and go off the screen like shown here
I want windows to be resizable or at least the size of the users screen but with scrolling.
How to do such thing?
A simple way to scroll large image is by usage of trackbar and a Rectangular for snipping.
.
.
.
namedWindow("winImage",WINDOW_AUTOSIZE);
namedWindow("controlWin",WINDOW_AUTOSIZE);
int winH=300;
int winW=600;
if(winH>=largeImage.rows)winH=largeImage.rows-1;
if(winW>=largeImage.cols)winW=largeImage.cols-1;
int scrolHight=0;
int scrolWidth=0;
cvCreateTrackbar("Hscroll", "controlWin", &scrolHight, (largeImage.rows -winH));
cvCreateTrackbar("Wscroll", "controlWin", &scrolWidth, (largeImage.cols -winW));
while(waitKey(0)!='q'){
Mat winImage= largeImage( Rect(scrolWidth,scrolHight,winW,winH) );
imshow("winImage",winImage);
}//while
.
.
EDIT
Short answer: you can't "enable" it, you have to implement it.
OpenCV does have trackbars -- have a look at the documentation, in particular the cvCreateTrackbar function. However, even if you use them, you still have to write the code behind it (for determining the new ROI and determining what to actually show).
If this sounds a bit too daunting, then you can wrap the displayed image using some GUI framework. Here is an example that uses OpenCV with wxWidgets. Of course, you can use any other GUI framework (for example, Qt).
This might help for one step: Just use CV_WINDOW_NORMAL instead of CV_WINDOW_AUTOSIZE.
cvNamedWindow(yourWindowName, CV_WINDOW_NORMAL);
cvShowImage("Original Image", original);
As far as I know (but I've only recently started looking at OpenCV) you need to build the OpenCV library with the Qt GUI library as GUI backend.
Then you get all the cute functions.
Well, OK, there's not very much, but the little that is there is documented as Qt only.
EDIT: PS, since possibly other answer might sow confusion, I'm not talking about using Qt to implement such functionality yourself. I'm talking about the functionality available in OpenCV's HighGUI module.
Cheers & hth.,
The best thing that I can do with pure opencv is by modifying the opencv trackbar method. I'm using ROI to update the display image according to the slider value. The weakness of this method is, opencv trackbar is displayed horizontally not vertically like the normal scrollbar, so in this case it is up to you whether you want to rotate your image horizontally or not.
int slider_max, slider, displayHeight;
int displayWidth = 1900;
Mat src1; // original big image
Mat dst;
cv::Rect roi;
static void on_trackbar(int, void*)
{
roi = cv::Rect(slider, 0, displayWidth, displayHeight); //Update ROI for display
dst = src1(roi);
imshow("Result", dst);
}
int main(void)
{
src1 = imread("BigImg.jpg"); // your big image
cv::rotate(src1, src1, cv::ROTATE_90_CLOCKWISE); //I rotate my image because opencv trackbar is displayed horizontally
cv::resize(src1, src1, cv::Size(src1.cols/2, src1.rows/2)); // resize the image if it's too big to display in 1 window
if (src1.empty()) { cout << "Error loading src1 \n"; return -1; }
slider_max = src1.cols - displayWidth;
slider = 0;
displayHeight = src1.rows;
namedWindow("Result", WINDOW_AUTOSIZE); // Create Window
char TrackbarName[50];
sprintf(TrackbarName, "Pixel Pos");
createTrackbar(TrackbarName, "Result", &slider, slider_max, on_trackbar);
on_trackbar(slider, 0);
waitKey(0);
return 0;
}
For changing the trackbar's orientation then you will need to use Qt or other GUI How to change the position of the trackbar in OpenCV applications?