03_Windows10+OpenCV4.5.5打开本地图片进行图片处理 实时摄影并抓拍图片存入本机

目录

添加外部库

添加头文件和命名空间

设计ui界面

 1.打开本地图片

 2.图像处理--腐蚀

封装函数

3.点击保存图片

定时器

 4.打开摄像头

5.拍照

6.关闭摄像头

 完整代码

可添加写入视频功能

图像处理--思维导图

​编辑视频操作--思维导图


有关OpenCV的配置可参考此篇

https://blog.csdn.net/qq_52218412/article/details/130730387

Windows系统下 在qt中 对OpenCV下载配置并简单使用


添加外部库

INCLUDEPATH += $$PWD/../../../user/apps/software/OpenCV4.5/opencv/build/include

win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../user/apps/software/OpenCV4.5/opencv/build/x64/vc14/lib/ -lopencv_world455
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../user/apps/software/OpenCV4.5/opencv/build/x64/vc14/lib/ -lopencv_world455d

添加头文件和命名空间

#include <QWidget>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QDebug>
#include <QTimer>
#include <QDateTime>
#include <QFileDialog>

using namespace cv;

设计ui界面


 1.打开本地图片

打开本地文件夹选择图片、将图片放入label控件显示,以便后续操作(图像处理)

// 打开图片
void Widget::on_btn_open_clicked()
{
    // 打开文件 选择图片
    imagePath_ = QFileDialog::getOpenFileName(
                this,tr("选择图片"),
                "../../../user/picture/res",
                tr("Image files(*.jpg *.png *.webp);;All files(*.*)"));

    if(imagePath_.isEmpty()) {
        return;
    }

    // 读取图像 存储为cv::Mat类型对象  “QString *”转换为“const cv::String &”
    srcImage_ = imread(imagePath_.toStdString());


    //Mat转QImage 像素   oldlabel和newlabel放置图片
    // 将BGR颜色空间就转换为RGB空间
    cvtColor(srcImage_, srcImage_, COLOR_BGR2RGB);

    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disImage = QImage(srcImage_.data, srcImage_.cols, srcImage_.rows,
                             srcImage_.cols * srcImage_.channels(), QImage::Format_RGB888);

    // 对QImage对象进行缩放
    disImage = disImage.scaled(ui->old_label->width(), ui->old_label->height());
    // 在指定控件中放置图像
    ui->old_label->setPixmap(QPixmap::fromImage(disImage));
    ui->new_label->setPixmap(QPixmap::fromImage(disImage));
}

效果如下:

 2.图像处理--腐蚀

// 腐蚀
void Widget::on_btn_corrosion_clicked()
{
    Mat corImage;
    Mat srcImage = srcImage_;

    // 生成矩形操作,结构元素大小5*5,MORPH_RECT指定为矩形
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
    // 腐蚀操作  参数:输入Mat对象 输出Mat对象 腐蚀结构
    erode(srcImage, corImage, element);

  
    //Mat转QImage 像素   newlabel放置图像处理后图片
    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disimage2 = QImage(corImage.data, corImage.cols, corImage.rows, corImage.cols*corImage.channels(), QImage::Format_RGB888);

    disimage2 = disimage2.scaled(ui->new_label->width(), ui->new_label->height());
    ui->new_label->setPixmap(QPixmap::fromImage(disimage2));
}

左边原图 右边处理后(图片可以来源本地、也可来源摄像头)


封装函数

每次打开新的图片和打开摄像头时都需要转化为RGB空间,并放入两个QLabel控件

每次处理图片也需要转化格式,放入修改后的控件

将这两步封装成以下两个函数

// 加载图片时
void Widget::setOriginalImage(Mat image)
{
    srcImage_ = image;

    // 将BGR颜色空间就转换为RGB空间
    cvtColor(srcImage_, srcImage_, COLOR_BGR2RGB);

    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disImage = QImage(srcImage_.data, srcImage_.cols, srcImage_.rows,
                             srcImage_.cols * srcImage_.channels(), QImage::Format_RGB888);

    // 对QImage对象进行缩放
    disImage = disImage.scaled(ui->old_label->width(), ui->old_label->height());
    // 在指定控件中放置图像
    ui->old_label->setPixmap(QPixmap::fromImage(disImage));
    ui->new_label->setPixmap(QPixmap::fromImage(disImage));
}


// 图像处理时
void Widget::setChangedImage(Mat image)
{
    changedImage_ = image;
    //Mat转QImage 像素   newlabel放置图像处理后图片
    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disimage2 = QImage(changedImage_.data, changedImage_.cols, changedImage_.rows, changedImage_.cols*changedImage_.channels(), QImage::Format_RGB888);
    disimage2 = disimage2.scaled(ui->new_label->width(), ui->new_label->height());
    ui->new_label->setPixmap(QPixmap::fromImage(disimage2));
}

3.点击保存图片

// 保存图片
void Widget::on_btn_save_clicked()
{
    QString saveImagePath = "../../../user/picture/opencv/";
    if(saveImagePath.isEmpty()) {
        return;
    }
    // 获取图片名称和后缀
    QString str = imagePath_.mid(20);
    QStringList imageName = str.split(".");


    // 保存修改后的图片到指定位置
    imwrite(QString("%1%2_save.%3").arg(saveImagePath).arg(imageName[0]).arg(imageName[1]).toStdString(), changedImage_);
}


定时器

摄像头取帧主要通过定时器QTimer来控制,在规定时间内反复取帧并放入界面QLabel

主要思想:在一定时间范围内不停捕捉视频帧,将视频帧Mat格式进行转化为QImage,呈现在屏幕上。

    构造函数中

    //超时就读取当前摄像头信息
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(getFrame()));


跳转槽生成的函数
// 从摄像头中抓取并返回每一帧
void Widget::getFrame(QPrivateSignal)
{
    // 视频帧保存到Mat,通过定时器刷新显示
    Mat frameImage;
    captrue_ >>frameImage;

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    setOriginalImage(frameImage);
}

 4.打开摄像头

// 打开摄像头
void Widget::on_btn_open_camera_clicked()
{
    // 打开摄像头 开始计时,超时则发出timeout()信号,200毫秒取一帧
    captrue_.open(0);
    timer->start(200);

    // 不可打开摄像 可关闭摄像 可拍照
    ui->btn_open_camera->setEnabled(false);
    ui->btn_close_camera->setEnabled(true);
    ui->btn_photograph->setEnabled(true);
}

5.拍照

// 拍照
void Widget::on_btn_photograph_clicked()
{
    // 视频帧保存到Mat,通过定时器刷新显示
    Mat frameImage;
    captrue_ >> frameImage;

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    setOriginalImage(frameImage);


    // 将捕获的图片存储到本机指定位置
    QString saveImagePath = "../../../user/picture/photograph/";
    if(saveImagePath.isEmpty()) {
        return;
    }
    // 以当前时间给图片命名
    QDateTime dateTime;
    dateTime = QDateTime::currentDateTime();
    QString name = dateTime.toString("yyyyMMdd_hhmmss");

    // 保存修改后的图片到指定位置
    imwrite(QString("%1%2.png").arg(saveImagePath).arg(name).toStdString(), frameImage);
}

6.关闭摄像头

// 关闭摄像头
void Widget::on_btn_close_camera_clicked()
{
    // 关闭摄像头 停止取帧
    captrue_.release();
    timer->stop();

    // 可打开摄像 不可关闭摄像 不可拍照
    ui->btn_open_camera->setEnabled(true);
    ui->btn_close_camera->setEnabled(false);
    ui->btn_photograph->setEnabled(false);
}

效果如下,当关闭摄像头时,可以对最后的视频帧做图像处理。


完整代码

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <QDebug>
#include <QTimer>
#include <QDateTime>
#include <QFileDialog>

using namespace cv;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private:
    void setChangedImage(Mat image);

    void setOriginalImage(Mat image);

private slots:
    void getFrame(QPrivateSignal);

    void on_btn_snowflake_clicked();                // 雪花屏

    void on_btn_gaussian_clicked();                 // 高斯模糊

    void on_btn_median_filtering_clicked();         // 中值滤波

    void on_btn_grayscale_clicked();                // 灰度化

    void on_btn_xy_vague_clicked();                 // xy方向模糊

    void on_btn_bilateral_vague_clicked();          // 双边模糊

    void on_btn_corrosion_clicked();                // 腐蚀

    // 打开保存图片
    void on_btn_open_clicked();
    void on_btn_save_clicked();

    // 打开关闭摄像头,拍照
    void on_btn_open_camera_clicked();
    void on_btn_close_camera_clicked();
    void on_btn_photograph_clicked();

private:
    Ui::Widget *ui;

    // 原图
    Mat srcImage_;
    // 修改后的图
    Mat changedImage_;
    //  图片路径
    QString imagePath_;

    QTimer *timer;
    VideoCapture captrue_;

};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    setWindowTitle("opencv");


    // 不能关闭摄像头 不可拍照
    ui->btn_photograph->setEnabled(false);
    ui->btn_close_camera->setEnabled(false);

    //超时就读取当前摄像头信息
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(getFrame()));
}

Widget::~Widget()
{
    delete ui;
}

void Widget::setChangedImage(Mat image)
{
    changedImage_ = image;
    //Mat转QImage 像素   newlabel放置图像处理后图片
    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disimage2 = QImage(changedImage_.data, changedImage_.cols, changedImage_.rows, changedImage_.cols*changedImage_.channels(), QImage::Format_RGB888);
    disimage2 = disimage2.scaled(ui->new_label->width(), ui->new_label->height());
    ui->new_label->setPixmap(QPixmap::fromImage(disimage2));
}

void Widget::setOriginalImage(Mat image)
{
    srcImage_ = image;

    // 将BGR颜色空间就转换为RGB空间
    cvtColor(srcImage_, srcImage_, COLOR_BGR2RGB);

    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    QImage disImage = QImage(srcImage_.data, srcImage_.cols, srcImage_.rows,
                             srcImage_.cols * srcImage_.channels(), QImage::Format_RGB888);

    // 对QImage对象进行缩放
    disImage = disImage.scaled(ui->old_label->width(), ui->old_label->height());
    // 在指定控件中放置图像
    ui->old_label->setPixmap(QPixmap::fromImage(disImage));
    ui->new_label->setPixmap(QPixmap::fromImage(disImage));
}

// 从摄像头中抓取并返回每一帧
void Widget::getFrame(QPrivateSignal)
{
    // 视频帧保存到Mat,通过定时器刷新显示
    Mat frameImage;
    captrue_ >>frameImage;

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    setOriginalImage(frameImage);
}


// 雪花屏
void Widget::on_btn_snowflake_clicked()
{
    Mat srcImage = srcImage_;
    //像素二维矩阵函数
    int rows = srcImage.rows;
    //像素二维矩阵列数
    int cols = srcImage.cols * srcImage.channels();
    for(int i=0;i<rows;i++)
    {
        // 获取Mat对象的第i行像素的指针
        uchar * data = srcImage.ptr<uchar>(i);
        for(int j=0; j<cols; j++)
        {
            //雪花屏特效
            int q = rand()%cols;
            data[q]=155;            //某些通道随机改成155
        }
        // 在Mat对象中采用二维矩阵的形式存储,而在QImage对象中则将所有像素数据序列化为一个一维数组,因此可以通过指针来访问和修改图像数据。
    }

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(srcImage);
}


// 高斯模糊
void Widget::on_btn_gaussian_clicked()
{
    Mat gauImage;
    Mat srcImage = srcImage_;

    // 高斯模糊   参数:输入Mat对象 输出Mat对象 高斯核大小(矩阵) 计算标准差
    GaussianBlur(srcImage, gauImage, Size(5, 5), 0, 0);

    // 数据源为data指针,图像的宽度、高度、字节数、像素格式
    setChangedImage(gauImage);
}

// 中值滤波
void Widget::on_btn_median_filtering_clicked()
{
    Mat medImage;
    Mat srcImage = srcImage_;

    //中值滤波  参数:输入Mat对象 输出Mat对象 卷积核大小(正方形边长)
    medianBlur(srcImage, medImage, 5);

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(medImage);

}


// 灰度化
void Widget::on_btn_grayscale_clicked()
{
    Mat graImage;
    Mat srcImage = srcImage_;

    // 彩色图像转化为灰度图像  灰度图像再转为彩色图像
    cvtColor(srcImage, graImage, COLOR_BGR2GRAY);
    cvtColor(graImage, graImage, COLOR_GRAY2BGR);

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(graImage);
}

// xy方向模糊
void Widget::on_btn_xy_vague_clicked()
{
    Mat xyImage;
    Mat srcImage = srcImage_;

    // xy轴模糊 均值滤波  参数:输入Mat对象 输出Mat对象 均值滤波卷积核大小(矩阵)
    blur(srcImage, xyImage, Size(10, 10));

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(xyImage);
}

// 双边模糊
void Widget::on_btn_bilateral_vague_clicked()
{
    Mat bilImage;
    Mat srcImage = srcImage_;

    // 双边模糊  参数:输入Mat对象 输出Mat对象 卷积核大小 灰度空间中的标准差值  坐标空间中标准差
    // 插值方式(为负,INTER_LINEAR;为零,INTER_NEAREST;为正,INTER_AREA、INTER_CUBIC)
    bilateralFilter(srcImage, bilImage, 15, 120, 10, 4);

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(bilImage);
}

// 腐蚀
void Widget::on_btn_corrosion_clicked()
{
    Mat corImage;
    Mat srcImage = srcImage_;

    // 生成矩形操作,结构元素大小5*5,MORPH_RECT指定为矩形
    Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
    // 腐蚀操作  参数:输入Mat对象 输出Mat对象 腐蚀结构
    erode(srcImage, corImage, element);

    //Mat转QImage 像素   newlabel放置图像处理后图片
    setChangedImage(corImage);
}


// 打开图片
void Widget::on_btn_open_clicked()
{
    // 打开文件 选择图片
    imagePath_ = QFileDialog::getOpenFileName(
                this,tr("选择图片"),
                "../../../user/picture/res",
                tr("Image files(*.jpg *.png *.webp);;All files(*.*)"));

    if(imagePath_.isEmpty()) {
        return;
    }

    // 读取图像 存储为cv::Mat类型对象  “QString *”转换为“const cv::String &”
    srcImage_ = imread(imagePath_.toStdString());

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    setOriginalImage(srcImage_);
}

// 保存图片
void Widget::on_btn_save_clicked()
{
    QString saveImagePath = "../../../user/picture/opencv/";
    if(saveImagePath.isEmpty()) {
        return;
    }
    // 获取图片名称和后缀
    QString str = imagePath_.mid(20);
    QStringList imageName = str.split(".");


    // 保存修改后的图片到指定位置
    imwrite(QString("%1%2_save.%3").arg(saveImagePath).arg(imageName[0]).arg(imageName[1]).toStdString(), changedImage_);
}



// 打开摄像头
void Widget::on_btn_open_camera_clicked()
{
    // 打开摄像头 开始计时,超时则发出timeout()信号,200毫秒取一帧
    captrue_.open(0);
    timer->start(200);

    // 不可打开摄像 可关闭摄像 可拍照
    ui->btn_open_camera->setEnabled(false);
    ui->btn_close_camera->setEnabled(true);
    ui->btn_photograph->setEnabled(true);
}

// 关闭摄像头
void Widget::on_btn_close_camera_clicked()
{
    // 关闭摄像头 停止取帧
    captrue_.release();
    timer->stop();

    // 可打开摄像 不可关闭摄像 不可拍照
    ui->btn_open_camera->setEnabled(true);
    ui->btn_close_camera->setEnabled(false);
    ui->btn_photograph->setEnabled(false);
}

// 拍照
void Widget::on_btn_photograph_clicked()
{
    // 视频帧保存到Mat,通过定时器刷新显示
    Mat frameImage;
    captrue_ >> frameImage;

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    setOriginalImage(frameImage);


    // 将捕获的图片存储到本机指定位置
    QString saveImagePath = "../../../user/picture/photograph/";
    if(saveImagePath.isEmpty()) {
        return;
    }
    // 以当前时间给图片命名
    QDateTime dateTime;
    dateTime = QDateTime::currentDateTime();
    QString name = dateTime.toString("yyyyMMdd_hhmmss");

    // 保存修改后的图片到指定位置
    imwrite(QString("%1%2.png").arg(saveImagePath).arg(name).toStdString(), frameImage);
}

可添加写入视频功能

在打开摄像头时,将捕获到的视频帧存入容器(全局变量QList<Mat> lstFrame_);关闭摄像头时, 将容器中的视频帧通过VideoWrite对象写入视频文件avi。

具体操作为,定时器触发timeout信号时,调用getFrame槽函数(将视频帧保存到容器lstFrame_)。关闭摄影时,调用SaveVideo函数,并将容器清空clear(方便下次录制)。

// 在关闭摄像头这一瞬间 将之前的视频帧写入视频文件avi
void Widget::SaveVideo()
{
    // 创建VideoWriter对象
    VideoWriter writer;
    double fps = 25;
    Size frameSize(640, 480);

    // 存储到本机指定位置
    QString savePath = "../../mp34/video/";
    QDateTime dateTime = QDateTime::currentDateTime();
    QString name = dateTime.toString("yyyyMMdd_hhmmss");
    QString fileName = QString("%1%2.avi").arg(savePath).arg(name);

    // open()打开视频文件   文件名 编解码类型 帧率 帧大小 彩色true
    writer.open(fileName.toStdString(), VideoWriter::fourcc('M', 'J', 'P', 'G'), fps, frameSize, true);

    if(!writer.isOpened()) {
        return;
    }

    // 将视频帧写入文件write()
    for(int i=0; i<lstFrame_.length(); i++) {
        if(lstFrame_[i].empty()) {
            continue;
        }
        // 将BGR颜色空间就转换为RGB空间
        cvtColor(lstFrame_[i], lstFrame_[i], COLOR_BGR2RGB);
        writer.write(lstFrame_[i]);
    }

    // 写入完成 关闭视频文件
    writer.release();

}


// 从摄像头中抓取并返回每一帧
void Widget::getFrame(QPrivateSignal)
{
    // 视频帧保存到Mat,通过定时器刷新显示
    Mat frameImage;
    captrue_ >> frameImage;

    //Mat转QImage 像素   oldlabel和newlabel放置图片
    SetOriginalImage(frameImage);

    // 视频帧保存到临时容器
    lstFrame_.append(frameImage);
}




// 关闭摄像头
void Widget::on_btn_close_camera_clicked()
{
    // 关闭摄像头 停止取帧
    captrue_.release();
    timer->stop();

    // 关闭摄像头时 写入视频文件 并存储所有视频帧的容器清空
    SaveVideo();
    lstFrame_.clear();

    // 可打开摄像 不可关闭摄像 不可拍照
    ui->btn_open_camera->setEnabled(true);
    ui->btn_close_camera->setEnabled(false);
    ui->btn_photograph->setEnabled(false);
}

图像处理--思维导图


视频操作--思维导图

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值