1

I've been trying to use OpenCV to capture a camera feed, and show it in Qt as a QLabel. Following a guide I found, this works to a certain degree. However, the application just outright crashes if I try to resize the Mat before making a QImage and setting the Pixmap. The crash is of the type "CameraSoftware.exe has stopped working", so it's hard to debug much other than finding out where it crashes.

Environment is 64 bit windows with QtCreator 3.6.0 (Qt 5.5.1) and OpenCV 3.10.

Here's the important bits of codes:

void VideoStreamOpenCVWorker::receiveGrabFrame()
{
    if(!toggleStream) return;

    (*cap) >> frameOriginal;
    if(frameOriginal.empty()) return;

    process();

    qDebug() << frameProcessed.cols << "x" << frameProcessed.rows;

    QImage output((const unsigned char *) frameProcessed.data, frameProcessed.cols, frameProcessed.rows, QImage::Format_RGBA8888);

    emit sendFrame(output);
}


void VideoStreamOpenCVWorker::process()
{
    cv::cvtColor(frameOriginal, frameProcessed, cv::COLOR_BGR2RGBA);
    cv::Size size(641,481);
    cv::resize(frameProcessed, frameProcessed, size);
}

This is sent back to a QLabel widget:

void VideoStreamWidget::receiveFrame(QImage frame){
    this->setPixmap(QPixmap::fromImage(frame));
}

This is where it crashes specifically, on the "setpixmap" line.

The Qlabel is added to a QMainWindow with simply:

QVBoxLayout *pictureLayout = new QVBoxLayout;
VideoStreamWidget *video = new VideoStreamWidget();
pictureLayout->addWidget(video);

The original cap picture is 640x480 for whatever reason, the camera I'm using is a full HD camera. Any idea what's causing this? The Qt window size doesn't seem to matter, as I can add a large picture directly if I want to. I just can't resize anything without crashing.

If I haven't provided enough information, ask away.

EDIT: I updated my debugger and got this error message upon executing the setPixmap line:

The inferior stopped because it triggered an exception.
Stopped in thread 0 by: Exception at 0x7ffe38fdadbb, code: 0xc0000005:
read access violation at: 0x0, flags=0x0 (first chance).
Ilya
  • 4,583
  • 4
  • 26
  • 51
Excludos
  • 1,380
  • 1
  • 12
  • 24
  • 1
    Why it's hard to debug? Run your application under debugger. – Dmitry Sazonov Aug 26 '16 at 09:09
  • I know where it crashes, I just don't know how, why or what to do about it. The reason it's hard to debug is because I don't get an error message I can read out. The application just hardlocks, and one of those windows "thisapplication.exe has stopped working" instead of the usual error message you're suppose to have. – Excludos Aug 26 '16 at 09:17
  • @Excludos make sure that frameProcessed has enough memory to store image. – Nikita Aug 26 '16 at 10:40
  • @nikitoz I would be very surprised if opencv wasn't capable of allocating enough space for a Mat after its resize automatically. Especially since that's not where it crashes, but rather when trying to put the image onto the label. It does resize down (to a certain degree) without crashing though, so it's not impossible. But any attempt at allocating memory before resizing ends up exactly the same. – Excludos Aug 26 '16 at 11:08
  • @Excludos then just debug your slot, check if you receive correct QImage(try to save it to file and check if that file contains correct image). – Nikita Aug 26 '16 at 11:17
  • @nikitoz Trying to save the QImage to file results in a crash similar to earlier. However the QImage itself has data. The height and width (the resized one, not the original) is also correct – Excludos Aug 26 '16 at 12:31
  • @Excludos that means your QImage is broken, check if you can save it to file right after construction. – Nikita Aug 26 '16 at 12:48
  • @nikitoz Saving to file right before sending works, saving to file right after receiving crashes. So you are entirely correct in that something is happening between the signal and slot in Qt. Here's a picture of the QImage variable right before and after sending it: http://oi65.tinypic.com/4vp7j5.jpg – Excludos Aug 26 '16 at 13:14
  • 1
    @Excludos try to create QImage with operator new (allocate on heap)and send pointer to slot. – Nikita Aug 26 '16 at 13:22
  • 2
    Or try an explicit copy: `emit sendFrame(output.copy());` – Mailerdaimon Aug 26 '16 at 13:25
  • @nikitoz That doesn't work. I might have implemented it wrong tho, so don't take my word for it. – Excludos Aug 26 '16 at 14:49
  • @Mailerdaimon This, on the other hand, worked! Any idea what exactly happened here and why this works? Or is this a legit bug? – Excludos Aug 26 '16 at 14:49
  • This is no bug. You define the image localy and it gets destroyed when it goes out of scope. Copying the image by reference just copies the header but not the image data. For the data to be copied you need to use `copy()` – Mailerdaimon Aug 26 '16 at 14:51
  • @Excludos you create QImage on the stack so it is destructed after going out of scope. – Nikita Aug 26 '16 at 14:51
  • @Mailerdaimon that seems well and good, but doesn't make sense when you consider that it works without resizing it. You can do pretty much anything to the picture, and it still works, except the resize function. – Excludos Aug 26 '16 at 14:55
  • `QImage` obeys the rules of [implicit sharing](http://doc.qt.io/qt-5/implicit-sharing.html). There are multiple articles on the Internet where the exact same thing is done. Also @Excludos is right - it is really strange that when no resizing is done everything works otherwise it doesn't. I'll try to test some code these couple of days if time permits it to dig deeper into the issue because I'm also very interested why this is happening. – rbaleksandar Aug 26 '16 at 16:27
  • First question would be: Is the position of the frameProcessed data member the same before and after resizing? I would gues that resizing changes the position in memory and therefore the code crashes... – Mailerdaimon Aug 29 '16 at 06:15

1 Answers1

2

Thanks to Mailerdaimon for providing the answer. Emitting the output as a copy

emit sendFrame(output.copy());

does the trick. I am still unsure why exactly this is happening in the first place and why this fixes the problem.

Excludos
  • 1,380
  • 1
  • 12
  • 24