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;