视频监控系统做到后面,逐渐需要搭配人工智能算法,将算法计算后的信息以OSD标签以及方框各种图形的信息显示到视频中,这种当然和OSD一样也是有两种方式,一种是源头就贴好了,一种是将结果发给软件这边解析绘制,于是才需要这种通用的图形绘制需求,有了之前OSD标签信息的经验,这个在最初设计的时候就考虑了很多可能的要素,比如图形的边框大小、边框颜色、背景颜色,区域为了兼容更多的内容,除了矩形,还支持QPainterPath路径集合,多边形区域QList点坐标集合,尤其是QPainterPath路径集合涵盖了所有可能的情况,只是对程序员使用者要求高很多,需要自己填充这个路径集合然后传入进来。
一般都是矩形区域居多,比如人脸框,人体区域、物体区域等,都是一个矩形区域,图形信息和OSD标签信息一样,都可以选择三种绘制方式,一种是绘制到覆盖窗体中,一种是绘制到图片中,一种是源头数据绘制好,如果源头支持的尽量源头就绘制好,比如ffmpeg的滤镜就专干这事的,而且干的非常漂亮,亲测几千个文字使用和几千个矩形框同时绘制在源头数据中,效果非常好,性能还是非常高的,就是数量越多占用CPU越高。
//图形信息(人脸框和多边形区域等)
struct GraphInfo {QString name; //名字唯一标识符(方便删除或更新)int borderWidth; //边框大小QColor borderColor; //边框颜色QColor bgColor; //背景颜色QRect rect; //矩形区域QPainterPath path; //路径集合QList points; //点坐标集合GraphInfo() {name = "graph";borderWidth = 2;borderColor = "#FF0000";bgColor = Qt::transparent;}
};
void WidgetHelper::drawRect(QPainter *painter, const QRect &rect, int borderWidth, QColor borderColor, bool angle)
{painter->setPen(QPen(borderColor, borderWidth));//背景颜色borderColor.setAlpha(50);//painter->setBrush(QBrush(borderColor));int x = rect.x();int y = rect.y();int width = rect.width();int height = rect.height();if (!angle) {painter->drawRect(x, y, width, height);} else {//绘制四个角int offset = 10;painter->drawLine(x, y, x + offset, y);painter->drawLine(x, y, x, y + offset);painter->drawLine(x + width - offset, y, x + width, y);painter->drawLine(x + width, y, x + width, y + offset);painter->drawLine(x, y + height - offset, x, y + height);painter->drawLine(x, y + height, x + offset, y + height);painter->drawLine(x + width - offset, y + height, x + width, y + height);painter->drawLine(x + width, y + height - offset, x + width, y + height);}
}void WidgetHelper::drawPoints(QPainter *painter, const QList &pts, int borderWidth, QColor borderColor)
{//至少要两个点if (pts.count() < 2) {return;}painter->setPen(QPen(borderColor, borderWidth));//背景颜色borderColor.setAlpha(50);//painter->setBrush(QBrush(borderColor));//绘制多边形QPainterPath path;//先移动到起始点path.moveTo(pts.first());//逐个连接线条int count = pts.count();for (int i = 1; i < count; ++i) {path.lineTo(pts.at(i));}//闭合图形path.closeSubpath();painter->drawPath(path);
}void WidgetHelper::drawPath(QPainter *painter, QPainterPath path, int borderWidth, QColor borderColor)
{painter->setPen(QPen(borderColor, borderWidth));painter->drawPath(path);
}void AbstractVideoWidget::drawInfo(QPainter *painter)
{//只有音频和句柄模式不用绘制OSDif (videoWidth == 0 || onlyAudio || widgetPara.videoMode == VideoMode_Hwnd) {return;}//标签位置尽量偏移多一点避免遮挡QRect rect = image.isNull() ? coverWidget->rect() : image.rect();int borderWidth = widgetPara.borderWidth + 5;rect = QRect(rect.x() + borderWidth, rect.y() + borderWidth, rect.width() - (borderWidth * 2), rect.height() - (borderWidth * 2));//将标签信息绘制到遮罩层if (widgetPara.osdDrawMode == DrawMode_Cover) {foreach (OsdInfo osd, listOsd) {if (osd.visible) {painter->save();WidgetHelper::drawOsd(painter, osd, rect);painter->restore();}}}//将图形信息绘制到遮罩层if (widgetPara.graphDrawMode == DrawMode_Cover) {foreach (GraphInfo graph, listGraph) {painter->save();if (!graph.rect.isEmpty()) {WidgetHelper::drawRect(painter, graph.rect, graph.borderWidth, graph.borderColor);}if (!graph.path.isEmpty()) {WidgetHelper::drawPath(painter, graph.path, graph.borderWidth, graph.borderColor);}if (graph.points.count() > 0) {WidgetHelper::drawPoints(painter, graph.points, graph.borderWidth, graph.borderColor);}painter->restore();}}
}void AbstractVideoWidget::drawImage(QPainter *painter)
{if (image.isNull()) {return;}//标签位置尽量偏移多一点避免遮挡QRect rect = image.isNull() ? coverWidget->rect() : image.rect();int borderWidth = widgetPara.borderWidth + 5;rect = QRect(rect.x() + borderWidth, rect.y() + borderWidth, rect.width() - (borderWidth * 2), rect.height() - (borderWidth * 2));//将标签信息绘制到图片上if (widgetPara.osdDrawMode == DrawMode_Image) {foreach (OsdInfo osd, listOsd) {if (osd.visible) {QPainter painter;painter.begin(&image);//painter.setRenderHints(QPainter::Antialiasing);WidgetHelper::drawOsd(&painter, osd, rect);painter.end();}}}//将图形信息绘制到图片上if (widgetPara.graphDrawMode == DrawMode_Image) {foreach (GraphInfo graph, listGraph) {QPainter painter;painter.begin(&image);//painter.setRenderHints(QPainter::Antialiasing);if (!graph.rect.isEmpty()) {WidgetHelper::drawRect(&painter, graph.rect, graph.borderWidth, graph.borderColor);}if (!graph.path.isEmpty()) {WidgetHelper::drawPath(&painter, graph.path, graph.borderWidth, graph.borderColor);}if (graph.points.count() > 0) {WidgetHelper::drawPoints(&painter, graph.points, graph.borderWidth, graph.borderColor);}painter.end();}}//绘制图片painter->save();painter->drawImage(imageRect, image);painter->restore();
}