QT+OpenCV照片动画风格转换

前言

用OpenCV将摄像头采集到的图片转换成动画风格,加上了QT界面。这个小实验并不复杂,后面直接贴代码。

代码

在QT creator中建的工程,只上部分比较重要的代码了,其他都是一样的。
mainWindow.h:定义了一些槽函数以及中间变量。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QDebug>
#include <opencv2/opencv.hpp>
#include <iostream>

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;row<mat.rows;row++)
        {
            uchar *pDest = img.scanLine(row);
            memcpy(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;i<repetitions;i++)
    {
        int 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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值