一、前言
本文主要在Qt中使用opencv进行编程,实现了简易的摄像头播放及其卡通化处理功能,编程环境为Qt5.5.1+opencv2.4.6,实现的关键是将Mat变量转换为QImage变量,并使用QLabel进行显示。
二、环境配置
首先需要安装Qt creator 5.5.1和下载解压opencv2.4.6,为了能够在Qt中调用opencv中的函数,必须用cmake对openc2.4.6进行编译,如何编译就不详解了,编译之后得到的库我将其放在E:\software\OpenCV-2.4.6.0\opencv。三、新建工程
打开Qt creator,使用版本为5.5.1,新建Qt Widgets Application,选择如下在pro文件中添加编译之后的opencv路径
INCLUDEPATH+=E:\software\OpenCV-2.4.6.0\opencv\build\include\opencv\
E:\software\OpenCV-2.4.6.0\opencv\build\include\opencv2\
E:\software\OpenCV-2.4.6.0\opencv\build\include
LIBS +=E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_core246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_highgui246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_imgproc246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_calib3d246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_contrib246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_features2d246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_flann246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_gpu246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_legacy246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_ml246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_objdetect246.dll.a\
E:\software\OpenCV-2.4.6.0\opencv\MinGW\lib\libopencv_video246.dll.a
打开widget.ui,按照下图拖入3个按钮与一个Label标签,编程的目的是点击打开摄像头按钮可将视频显示于label中,当然稍微改动也可以打开其他已存在的视频片段。点击视频卡通化按钮即可将视频卡通化处理,点击关闭摄像头按钮则关闭摄像头。
四、代码简介
在widget.h中定义如下槽函数与数据成员
private slots:
void openCamera();
void readFrame();
void closeCamera();
QImage cvMat2QImage(const cv::Mat& mat); //将Mat数据结构转换为QImage
void cartoonifyImage( Mat & , Mat & ); //视频卡通化处理
void startCaroonify(); //令flag为true
private:
Ui::Widget *ui;
QTimer *timer;
QImage img;
VideoCapture camera;
Mat frame,dstImage;
bool flag ;
在widget.cpp中,各主要函数定义如下所示:
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
timer = new QTimer(this);
flag = false;
connect(timer, SIGNAL(timeout()), this, SLOT(readFrame()));
connect(ui->pushButton_1, SIGNAL(clicked()), this, SLOT(openCamera()));
connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(startCaroonify()));
connect(ui->pushButton_3, SIGNAL(clicked()), this, SLOT(closeCamera()));
}
Widget::~Widget()
{
delete ui;
}
void Widget::openCamera()
{
camera.open(0);
if (!camera.isOpened())
{
std::cerr <<"Could not access the camera or video!"<<
std::endl;
exit(1);
}
camera.set(CV_CAP_PROP_FRAME_WIDTH ,640);
camera.set(CV_CAP_PROP_FRAME_HEIGHT , 480); //设置分辨率
timer->start(33); //显示时间控制
}
void Widget::readFrame()
{
camera >>frame;
if (frame.empty())
{
std::cerr<<"ERROR: Couldn't grab a camera frame."<<
std::endl;
exit(1);
}
if (flag)
cartoonifyImage(frame , dstImage);
else
frame.copyTo(dstImage);
img = cvMat2QImage(dstImage);
ui->label->resize(frame.cols,frame.rows);
ui->label->setPixmap(QPixmap::fromImage(img));
}
void Widget::closeCamera()
{
timer->stop();
camera.release();
exit(1); //结束退出
}
void Widget::startCaroonify()
{
flag = !flag;
}
QImage Widget::cvMat2QImage(const cv::Mat& mat)
{
// 8-bits unsigned, NO. OF CHANNELS = 1
if(mat.type() == CV_8UC1)
{
QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
// Set the color table (used to translate color indexes to qRgb values)
image.setColorCount(256);
for(int i = 0; i < 256; i++)
{
image.setColor(i, qRgb(i, i, i));
}
// Copy input Mat
uchar *pSrc = mat.data;
for(int row = 0; row < mat.rows; row ++)
{
uchar *pDest = image.scanLine(row);
memcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return image;
}
// 8-bits unsigned, NO. OF CHANNELS = 3
else if(mat.type() == CV_8UC3)
{
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.rgbSwapped();
}
else if(mat.type() == CV_8UC4)
{
qDebug() << "CV_8UC4";
// Copy input Mat
const uchar *pSrc = (const uchar*)mat.data;
// Create QImage with same dimensions as input Mat
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
else
{
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
void Widget::cartoonifyImage( Mat &srcColor , Mat &dst)
{
Mat gray;
cvtColor(srcColor , gray ,CV_BGR2GRAY); //默认彩色格式是BGR
const int MEDIAN_BLUR_FILTER_SIZE = 7;
medianBlur(gray ,gray ,MEDIAN_BLUR_FILTER_SIZE); //中值滤波器去噪
Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
Laplacian(gray ,edges , CV_8U ,LAPLACIAN_FILTER_SIZE);
Mat mask;
const int EDGES_THRESHOLD = 65;
threshold(edges , mask ,EDGES_THRESHOLD,255 ,THRESH_BINARY_INV); //生成边缘掩码mask
mask.copyTo(dst);
Size sizeSrc = srcColor.size(); //算法较为复制,为提高效率,将原图像长宽缩减一半进行双边滤波处理
Size smallSize;
smallSize.width = sizeSrc.width/2;
smallSize.height = sizeSrc.height/2;
Mat smallImage = Mat(smallSize ,CV_8UC3);
cv::resize(srcColor ,smallImage ,smallSize ,0,0,INTER_LINEAR);
Mat tmp = Mat(smallSize ,CV_8UC3);
int repetitions = 3;
for(int i = 0; i
五、实现效果
六、源代码与参考资料
源代码下载链接为:http://download.csdn.net/detail/ap1005834/9504595
参考资料为:
http://blog.chinaunix.net/uid-23381466-id-3826748.html
Mat类转换为QImage参考自http://blog.csdn.net/liyuanbhu/article/details/46662115
卡通化处理代码参考自书本《深入理解OpenCV:实用计算机视觉项目解析》