一、前言
本文主要在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<repetitions ;i++) { int ksize = 9; double sigmaColor = 11; double sigmaSpace = 5; bilateralFilter(smallImage ,tmp ,ksize,sigmaColor,sigmaSpace); bilateralFilter(tmp ,smallImage ,ksize,sigmaColor,sigmaSpace); } Mat bigImg; cv::resize(smallImage ,bigImg,sizeSrc ,0 ,0 ,INTER_LINEAR); dst.setTo(0); //全置为0 bigImg.copyTo(dst , mask);//掩码中黑色部分不会被复制,生成 素描掩码+ 彩色图画 = 卡通图画 }
五、实现效果
六、源代码与参考资料
源代码下载链接为: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:实用计算机视觉项目解析》