用OpenCV将摄像头采集到的图片转换成动画风格,加上了QT界面。这个小实验并不复杂,后面直接贴代码。
在QT creator中建的工程,只上部分比较重要的代码了,其他都是一样的。
mainWindow.h
:定义了一些槽函数以及中间变量。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
QImage cvMat2QImage(const cv::Mat & mat);
void cartoonize(cv::Mat & src, cv::Mat & dst);
void cartoonize_v2(cv::Mat & src, cv::Mat & dst);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void readFrame();
private:
Ui::MainWindow *ui;
bool cartoonize_flag;
QImage dst_image;
QTimer *timer;
cv::VideoCapture camera;
cv::Mat frame;
cv::Mat cartoon_image;
};
#endif // MAINWINDOW_H
mainWindow.cpp
:具体定义了那些函数。
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->timer = new QTimer(this);
this->cartoonize_flag = false;
this->connect(this->timer, SIGNAL(timeout()), this, SLOT(readFrame()));
}
MainWindow::~MainWindow()
{
delete ui;
}
//从摄像头读取一帧图像
void MainWindow::readFrame()
{
this->camera >> this->frame;
if(frame.empty())
{
std::cerr<<"ERROR: Couldn't grab a camera frame."<< std::endl;
exit(1);
}
if(this->cartoonize_flag)
{
//this->frame.copyTo(this->cartoon_image);
cartoonize(this->frame, this->cartoon_image);
cv::cvtColor(this->cartoon_image, this->cartoon_image, cv::COLOR_BGR2RGB);
}
else
{
cv::cvtColor(this->frame, this->cartoon_image, cv::COLOR_BGR2RGB);
//this->frame.copyTo(this->cartoon_image);
}
// the image must be converted into RGB, but not the default BGR in OpenCV
this->dst_image = cvMat2QImage(this->cartoon_image);
//在GraphicView中显示图像
QGraphicsScene *scene = new QGraphicsScene;
scene->addPixmap(QPixmap::fromImage(this->dst_image));
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
}
//打开摄像头,映射到按键1的槽函数
void MainWindow::on_pushButton_clicked()
{
//Open Camera
this->camera.open(0);
if(!this->camera.isOpened())
{
std::cerr << "Could not access the camera or video!" << std::endl;
exit(1);
}
this->camera.set(cv::CAP_PROP_FRAME_WIDTH, 640);
this->camera.set(cv::CAP_PROP_FRAME_HEIGHT, 480);
this->timer->start(33);
}
//是否进行卡通化转换标志,映射到按键2的槽函数
void MainWindow::on_pushButton_2_clicked()
{
//Cartoonizing
this->cartoonize_flag = !this->cartoonize_flag;
}
//关闭摄像头,映射到按键3的槽函数
void MainWindow::on_pushButton_3_clicked()
{
//Close Camera
this->timer->stop();
this->camera.release();
exit(1);
}
//OpenCV中Mat类型转换为Qt中的QImage类型
QImage MainWindow::cvMat2QImage(const cv::Mat & mat)
{
//if(!mat.empty())
//{
//bgr->rgb
//cv::cvtColor(mat, mat, cv::COLOR_BGR2RGB);
//}
switch(mat.type())
{
case CV_8UC1:
{
QImage img(mat.cols, mat.rows, QImage::Format_Indexed8);
img.setColorCount(255);
for(int i=0;i<256;i++)
{
img.setColor(i, qRgb(i,i,i));
}
uchar * pSrc = mat.data;
for(int row=0;rowmemcpy(pDest, pSrc, mat.cols);
pSrc += mat.step;
}
return img;
}
case CV_8UC3:
{
const uchar * pSrc = (const uchar *)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
return image.copy();
}
case CV_8UC4:
{
const uchar * pSrc = (const uchar *)mat.data;
QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
return image.copy();
}
default:
{
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
}
}
}
//卡通化处理
void MainWindow::cartoonize(cv::Mat & src, cv::Mat & dst)
{
cv::Mat gray;
cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY);//转成灰度图
const int MEDIAN_BLUR_FILTER_SIZE = 7;
cv::medianBlur(gray, gray, MEDIAN_BLUR_FILTER_SIZE);//中值滤波
cv::Mat edges;
const int LAPLACIAN_FILTER_SIZE = 5;
cv::Laplacian(gray, edges, CV_8U, LAPLACIAN_FILTER_SIZE);//边缘检测,也可用canny检测或是其他算法
cv::Mat mask;
const int EDGES_THRESHOLD = 65;
cv::threshold(edges, mask, EDGES_THRESHOLD, 255, cv::THRESH_BINARY_INV);//二值化,生成边缘掩码,注意是cv::THRESH_BINARY_INV
mask.copyTo(dst);
//为了保证处理速度,将图像大小压缩一倍
cv::Size srcSize = src.size();
cv::Size newSize;
newSize.width = srcSize.width / 2;
newSize.height = srcSize.height / 2;
cv::Mat newImg = cv::Mat(newSize, CV_8UC3);
cv::resize(src, newImg, newSize, 0, 0, cv::INTER_LINEAR);
//做两次双边滤波
cv::Mat tmp = cv::Mat(newSize, CV_8UC3);
int repetitions = 3;
for(int i=0;iint ksize = 9;
double sigmaColor = 11;
double sigmaSpace = 5;
cv::bilateralFilter(newImg, tmp, ksize, sigmaColor, sigmaSpace);
cv::bilateralFilter(tmp, newImg, ksize, sigmaColor, sigmaSpace);
}
cv::Mat resImg;
cv::resize(newImg, resImg, srcSize, 0, 0, cv::INTER_LINEAR);//调整回原来的大小
dst.setTo(0);
resImg.copyTo(dst, mask);
}
参考链接:
https://zhuanlan.zhihu.com/p/24416498
http://blog.csdn.net/liyuanbhu/article/details/46662115
http://blog.csdn.net/AP1005834/article/details/51263012