Qt使用OpenCV调用摄像头并裁剪
在Qt中调用摄像头并显示在界面中,有两种方式。第一种方式可以使用Qt自带的QCamera库,并在你的.pro文件中加入如下代码。
QT += multimedia
QT += multimediawidgets
这种方式虽然简单,但在嵌入式开发中配置环境很容易带来麻烦。而且这种方式无法使摄像头采集的图像完美适配各种自定义的分辨率(在网上找了很久也没找到,如果可以请指教)。
采用OpenCV则可以较好地实现这一要求,但使用前要先配好OpenCV的环境,环境配置具体不展开讲了。
配置好环境后,在头文件中include这几个包。
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace std;
然后在头文件定义如下内容。
private:
QLabel *nullFace;
VideoCapture cap;
Mat src_image;
QTimer *timer;
QImage *image;
QImage imag_null;
protected:
QImage MatImageToQt(const Mat &src);
由于需要不断地将摄像头采集到的画面刷新到QLabel上,因此定时器必不可少。在.cpp中加入下列内容。
timer = new QTimer(this);
image = new QImage();
cap.open(0);
timer->start(50);
connect(timer,SIGNAL(timeout()),this,SLOT(readFrame()));
start()括号里的数字控制画面刷新的帧率。
然后就是调摄像头了,其实只有一行代码cap.read(),剩下的都是适配画面代码调优。屏幕显示帧高度和宽度根据实际情况修改。
void readFrame()
{
Mat crop_frame;
Mat screen_frame; // 屏幕显示帧
int dst_h = 1280; // 屏幕显示帧高度(单位:像素)
int dst_w = 720; // 屏幕显示帧宽度(单位:像素)
cv::Size dsize(dst_w, dst_h);
float dst_w_h_ratio = (float)(dst_w)/(float (dst_h)) ; // crop_frame帧宽高比
cap.read(src_image);
frame_crop(src_image, dst_w_h_ratio, crop_frame); // 按指定宽高比截取frame
cv::resize(crop_frame, screen_frame, dsize, cv::INTER_AREA); //按屏幕实际宽高尺寸缩放crop_frame填充屏幕
//水平翻转
Mat img;
flip(screen_frame, img, ROTATE_180);
imag_null = QImage((const uchar*)img.data,img.cols,img.rows,QImage::Format_RGB888).rgbSwapped();
nullFace -> setPixmap(QPixmap::fromImage(imag_null));
}
裁剪摄像头画面的代码如下。
void frame_crop(cv::Mat raw_frame, float dst_w_h_ratio, cv::Mat &crop_frame)
{
/*
Mat raw_frame; // 输入帧
float dst_w_h_ratio; // 设置输出截取区域帧宽高比
Mat crop_frame; // 截取区域帧
*/
cv::Rect rect;
float raw_frame_w = raw_frame.cols;
float raw_frame_h = raw_frame.rows;
float new_frame_w, new_frame_h;
new_frame_w = raw_frame_h * dst_w_h_ratio;
if (new_frame_w > raw_frame_w)
{
new_frame_w = raw_frame_w;
new_frame_h = raw_frame_w / dst_w_h_ratio;
int det_h = raw_frame_h - new_frame_h;
int quotient = det_h / 2;
// int remainder = det_h % 2;
rect.x = 0;
rect.y = quotient;
rect.width = (int)new_frame_w;
rect.height = (int)new_frame_h;
raw_frame(rect).copyTo(crop_frame);
}
else
{
new_frame_h=raw_frame_h;
new_frame_w=new_frame_h*dst_w_h_ratio;
int det_w = raw_frame_w-new_frame_w;
int quotient = det_w/2;
// int remainder = det_w%2;
rect.x=quotient;
rect.y=0;
rect.height=(int)new_frame_h;
rect.width=(int)new_frame_w;
raw_frame(rect).copyTo(crop_frame);
}
}
打完收工~