【发布时间】:2018-03-27 09:14:07
【问题描述】:
我正在构建一个应用程序,它在一个线程中使用 OpenCV 从 IP 摄像机获取图像,然后在处理后将 Mat 转换为 QImage,然后将 QImage 发送到信号,然后是图像将由相应的槽在 GUI 线程中接收。
信号在处理图像线程类中声明:
void sendImage(const QImage &frame);
GUI线程类中的slot声明:
void onGetImage(const QImage &img);
但在那之后,当我在QLabel 上显示图像或将图像保存到磁盘时,程序崩溃了。
我对@987654327@有点陌生,那么QImage对象的传递引用有什么问题吗?如果是,那么在线程之间传递 Objects 而没有任何复制(重新分配内存)开销的正确方法是什么?因为我想在长时间运行的应用程序中防止哪怕是很小的开销。
更新:有时运行一段时间,然后崩溃,有时甚至在第一帧就崩溃。
谢谢!
代码:处理图像的代码
class ImageProcess
{
public:
ImageProcess(std::function<void(cv::Mat&)> imgCallback):imgCallback(imgCallback){}
public:
void start()
{
while(start) // loop till start become false
{
videpCapture.read(frame);
// .... some process on image
imgCallback(frame)
}
}
private:
cv::Mat frame;
std::function<void(cv::Mat&)> imgCallback;
};
代码:图像处理单元和 GUI 之间的通信
class WorkerThread: public QObject
{
Q_OBJECT
public:
WorkerThread()
{
imgProcess = new ImageProcess(std::bind(.....)); // bind the callback
}
public slots:
void onStart()
{
if(imProcessThread != nullptr)
{
imgProcess.start = false; // stop if running
imProcessThread->quit(); // quit the thread
imProcessThread->wait(); // wait to finish
delete imProcessThread; // delete the pointer
}
imProcessThread = new ImageProcessThread(imgProcess); // create
imProcessThread->start(); // start thread
}
signals:
void sendMessage(const QString& msg, const int& code);
private:
ImageProcess *imgProcess;
void frameCallback(const cv::Mat& frame); // frame callback
{
emit sendImage(matToQImage(frame)); // send the image to UI
}
// Mat to QImage converter
QImage matToQImage(const cv::Mat &mat)
{
cv::Mat rgbMat;
if(mat.channels() == 1) { // if grayscale image
return QImage((uchar*)mat.data, mat.cols, mat.rows, (int)mat.step,
QImage::Format_Indexed8);// declare and return a QImage
} else if(mat.channels() == 3) { // if 3 channel color image
cv::cvtColor(mat, rgbMat, CV_BGR2RGB); // invert BGR to RGB
return QImage((uchar*)rgbMat.data, mat.cols, mat.rows,
(int)mat.step, QImage::Format_RGB888);// declare and return a QImage
}
return QImage();
}
// image process thread
class ImageProcessThread : public QThread
{
public:
ImageProcessThread(ImageProcess *ip) : ip(ip){}
protected:
void run()
{
ip->start();
}
private:
ImageProcess *ip;
} *imProcessThread = nullptr;
};
代码:用户界面
class Camera : public QWidget
{
Q_OBJECT
public:
explicit Camera(QWidget *parent = 0)
{
wt = new WorkerThread;
thread = new QThread;
//conncet the signal-slots
connect(wt, &WorkerThread::sendImage, this, &Camera::onGetImage);
connect(ui->btStart, &QPushButton::clicked, wt, &WorkerThread::start);
}
private slots:
void onGetImage(const QImage &img)
{
// set the image to QLabel
}
private:
WorkerThread *wt;
QThread *thread;
};
wt.moveToThread(thread);
thread->start();
那么,什么是用于此目的的 goog 设计?
【问题讨论】:
-
我假设您正在根据运行代码时的崩溃方式返回对临时的引用,尽管如果没有看到您的代码就很难知道。你能提供更多的实现吗?
-
提供一个更完整的例子。您是否返回一个临时的或可能取消引用一个空指针?
-
你能提供一个最小的、可验证的、完整的例子吗?如果没有,您可以在调试模式下构建并发布 gdb 跟踪吗?
-
@AndrewKashpur 我不相信这实际上是真的...... QImage 实际上是 QImagePrivate 的引用计数包装器,使用 Qt 的 Q/D 指针。如果图像当前处于活动或锁定状态,它只会复制图像,否则只会增加 D 指针的引用。
-
不要以为它可能很慢。先让它工作,然后根据需要进行优化。