1.QCameraViewfinder
QCamera的取景器,用于显示摄像头抓到的数据,前面所使用的就是这个。但是现在遇到一个需求,比如在一些场合中,需要在显示图像上打水印,OSD等信息,比如在人脸检测场景中一帮会要求识别画框,这里这里没有提供hook方式,不行,probe是并行的,并不会影响到显示这里。看有些博客上说继承一下QCameraViewfinder然后覆写paintevent
void QCameraViewfinderPri::paintEvent(QPaintEvent *e)
{ QCameraViewfinder::paintEvent (e);QPainter painter(this);painter.setPen(Qt::red);painter.drawRect(50, 50, 100, 100);
}
试了一下,并没有效果。最后发现说可以自己实现Viewfinder,在这样就可以控制显示了。
2.自定义viewfinder
继承的说明,网络上比较多,就不详细说明了。这里没有给显示策略,只是做了一次捕获操作。在继承过程中必须要实现纯虚函数present 和supportedPixelFormats。
class QSmartViewFinder : public QAbstractVideoSurface
{Q_OBJECT
public:QSmartViewFinder(QObject *parent = NULL);~QSmartViewFinder();
signals:void showFrame(QVideoFrame image);
protected:QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const override;bool present(const QVideoFrame &frame) override;
};
supportedPixelFormats用于表示可以支持的格式
QList<QVideoFrame::PixelFormat> QSmartViewFinder::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{QList<QVideoFrame::PixelFormat > pixelFormats;pixelFormats.append(QVideoFrame::Format_RGB32);pixelFormats.append(QVideoFrame::Format_YUV420P);return pixelFormats;
}
present 在每帧数据来的时候,都会进入一次,这里主要就是讲获取到的帧通过信号发送出去,QVideoFrame里面并没有存储真的数据,所以在传递时并不会带来什么开销。
bool QSmartViewFinder::present(const QVideoFrame &frame)
{if (frame.isValid()){QVideoFrame cloneFrame(frame);emit showFrame(cloneFrame);return true;}return false;
}
3.设置自定义的viewfinder
QSmartViewFinder *finder = new QSmartViewFinder(this);m_camera.reset(new QCamera(cameraInfo));//m_camera->setViewfinder(ui->widgetShowImage);m_camera->setViewfinder(finder);connect(finder,&QSmartViewFinder::showFrame,[this](QVideoFrame f){if(!f.isValid())return;f.map(QAbstractVideoBuffer::ReadOnly);cv::Mat img(f.height() * 3 / 2, f.width(), CV_8UC1, f.bits());cv::Mat mat;cvtColor(img, mat, cv::COLOR_YUV420p2BGR);QImage image(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);//这就可以绘图了QDateTime now = QDateTime::currentDateTime();ui->label->setPixmap(QPixmap::fromImage(create_image_text(image,now.toString(),40,QPoint(50,50))));f.unmap();});
这里就取消了之前设置的QCameraViewfinder,而是用了自定义的设置,由于设置输入的帧格式是YUV的,QImage并不支持YUV的转换,所以这里引入了一次opencv的转换,刚开始比较担心带来性能上的开销,后面发现并不会,显示十分流畅。这里采用自定义viewfinder之后,其实QVideoProbe就用不到了,毕竟自己就已经可以捕获每一帧数据了。
这里有个疑问,QImage明明设置是RGB888的,但是在mat转换的时候,需要设置为BGR,而不是RGB,不然显示色彩会有错。
4.文字绘制函数
QPen pen;QFont font;QImage tmp = base;pen.setStyle(Qt::DashDotLine);pen.setColor(Qt::white);pen.setCapStyle(Qt::RoundCap);pen.setJoinStyle(Qt::RoundJoin);font.setPixelSize(size);font.setBold(true);QPainter painter(&tmp);QFontMetrics fm = painter.fontMetrics();painter.setPen(pen);painter.setFont(font);painter.drawText(origin,text);painter.end();return tmp;