Qt中基于QCamera的摄像头流红圈绘制问题求助
嘿,作为Qt新手能搞定摄像头流已经超棒了!我给你梳理几个关键步骤,帮你实现圆圈标记的效果,一步步来:
1. 先捕获摄像头的每一帧图像
你之前用QCamera+QCameraViewfinder只是显示流,但要做识别和标记,得先拿到每一帧的图像数据。Qt的QVideoProbe是干这个的绝佳工具:
先创建一个
QVideoProbe实例,绑定到你的摄像头对象上,监听帧数据:QVideoProbe *frameProbe = new QVideoProbe(this); if (frameProbe->setSource(yourCameraInstance)) { // 绑定帧捕获的槽函数 connect(frameProbe, &QVideoProbe::videoFrameProbed, this, &YourMainWindow::onNewVideoFrame); }在槽函数里,把
QVideoFrame转换成QImage(方便后续处理和绘制):void YourMainWindow::onNewVideoFrame(const QVideoFrame &frame) { QVideoFrame readableFrame = frame; // 先映射帧到内存,才能读取数据 if (!readableFrame.map(QAbstractVideoBuffer::ReadOnly)) { return; } // 转换成QImage,注意格式匹配 QImage frameImage(readableFrame.bits(), readableFrame.width(), readableFrame.height(), QVideoFrame::imageFormatFromPixelFormat(readableFrame.pixelFormat())); readableFrame.unmap(); // 拿到图像后,就可以去识别圆圈并标记了 markDetectedCircles(frameImage); }
2. 识别图像中的圆圈(用OpenCV最省心)
Qt本身没有内置的圆圈识别算法,最成熟的方案是配合OpenCV的霍夫圆变换,新手友好且效果稳定:
- 先把
QImage转换成OpenCV的cv::Mat,做预处理(降噪、转灰度),然后调用霍夫圆检测:#include <opencv2/opencv.hpp> void YourMainWindow::markDetectedCircles(QImage &inputImage) { // QImage转OpenCV Mat(注意QImage是RGB,OpenCV默认是BGR) cv::Mat cvImage(cv::Size(inputImage.width(), inputImage.height()), CV_8UC3, inputImage.bits(), inputImage.bytesPerLine()); cv::cvtColor(cvImage, cvImage, cv::COLOR_RGB2BGR); // 预处理:转灰度+高斯模糊,减少噪声干扰 cv::Mat grayImage; cv::cvtColor(cvImage, grayImage, cv::COLOR_BGR2GRAY); cv::GaussianBlur(grayImage, grayImage, cv::Size(9, 9), 2, 2); // 霍夫圆检测,参数可以根据你的场景调整 std::vector<cv::Vec3f> detectedCircles; cv::HoughCircles(grayImage, detectedCircles, cv::HOUGH_GRADIENT, 1, // 累加器分辨率 grayImage.rows / 8, // 圆心之间的最小距离 200, // Canny边缘检测的高阈值 100, // 累加器阈值(越小识别越多) 0, 0); // 最小/最大半径 // 给识别到的圆圈画红色标记 for (size_t i = 0; i < detectedCircles.size(); ++i) { cv::Point circleCenter(cvRound(detectedCircles[i][0]), cvRound(detectedCircles[i][1])); int circleRadius = cvRound(detectedCircles[i][2]); // 画红色圆心(实心) cv::circle(cvImage, circleCenter, 3, cv::Scalar(0, 0, 255), -1); // 画红色圆轮廓(粗线) cv::circle(cvImage, circleCenter, circleRadius, cv::Scalar(0, 0, 255), 3); } // 把标记后的Mat转回QImage cv::cvtColor(cvImage, cvImage, cv::COLOR_BGR2RGB); QImage markedImage(cvImage.data, cvImage.cols, cvImage.rows, cvImage.step, QImage::Format_RGB888); // 拷贝一份避免内存指针失效 inputImage = markedImage.copy(); // 最后把标记后的图像显示出来 updateDisplay(inputImage); }
3. 显示带标记的图像
你之前用QCameraViewfinder显示原始流,现在换成QLabel或者自定义QWidget来显示处理后的图像就好:
void YourMainWindow::updateDisplay(const QImage &image) { // 把图像缩放到标签尺寸,保持比例 ui->displayLabel->setPixmap(QPixmap::fromImage(image.scaled(ui->displayLabel->size(), Qt::KeepAspectRatio))); }
4. 一些新手注意点
- 如果用OpenCV,记得在Qt项目的
.pro文件里配置链接:INCLUDEPATH += /你的OpenCV路径/include LIBS += -L/你的OpenCV路径/lib -lopencv_core -lopencv_imgproc -lopencv_highgui - 帧处理可能会卡顿,要是识别速度跟不上帧率,把识别+绘制的逻辑放到子线程里,别阻塞UI线程。
QVideoFrame的格式可能有差异,如果转换QImage失败,可以试试强制用QImage::Format_ARGB32格式手动转换。
内容的提问来源于stack exchange,提问作者Nghia Bui
相关产品推荐
相关产品推荐

