opencv简单图像处理工具(持续更新)

资料

其它实现

页面切换

  • 利用`ui->stackedWidget->setCurrentIndex(0);``实现 欢迎与操作页面转换。
  • 利用stackedWidgetsetCurrentWidget()实现最右侧算法执行栏切换

图片导入与保存

导入
void MainWindow::on_act_insert_pic_triggered()
{
    //打开图片文件,选择图片
    QString filename=QFileDialog::getOpenFileName(this,tr("Open Image"),QDir::homePath(),tr("(*.jpg)\n(*.bmp)\n(*.png)"));
    emit SignImagePath(filename);
}
  • work界面
void Work::SlotImagePath(QString path)
{
    if(path.isEmpty()){
            qDebug()<<"图片打开失败";
        return;
    }
    _path = path;
    QPixmap image(_path);
    // 利用opencv打开图片
    _mat = cv::imread(Lib::QStringToString(_path));
    //保存图片的内容用来保存  MatToQImage  mat与QImage转换。
    _exportImage = Lib::MatToQImage(_mat);
    // 显示图片
    ui->label_image->setPixmap(image);

}
图片的保存
void MainWindow::on_act_Export_pic_triggered()
{
    QString currentPath = QCoreApplication::applicationDirPath();
    QString path = QFileDialog::getSaveFileName(nullptr, QStringLiteral("保存文件"), currentPath, QStringLiteral("(*.jpg)\n(*.bmp)\n(*.png)"));
    emit this->SignSaveImagePath(path);
}

void Work::SlotSaveImagePath(QString path)
{
    _exportImage.save(path);
}

cv::Mat与QImage转换

cv::Mat Lib::QImageTocvMat(const QImage& image)
{
    switch(image.format())
    {
    // 8-bit, 4 channel
    case QImage::Format_ARGB32:
        break;
    case QImage::Format_ARGB32_Premultiplied:
    {
        cv::Mat mat(image.height(), image.width(),
                    CV_8UC4,
                    (void*)image.constBits(),
                    image.bytesPerLine());
        return mat.clone();
    }

    // 8-bit, 3 channel
    case QImage::Format_RGB32:
    {
        cv::Mat mat(image.height(),image.width(),
                    CV_8UC4,
                    (void*)image.constBits(),
                    image.bytesPerLine());

        // drop the all-white alpha channel
        cv::cvtColor(mat, mat, cv::COLOR_BGRA2BGR);
        return mat.clone();
    }
    case QImage::Format_RGB888:
    {
        QImage swapped = image.rgbSwapped();
        cv::Mat mat(swapped.height(), swapped.width(),
                    CV_8UC3,
                    (void*)image.constBits(),
                    image.bytesPerLine());
        return mat.clone();
    }

    // 8-bit, 1 channel
    case QImage::Format_Indexed8:
    {
        cv::Mat mat(image.height(),image.width(),
                    CV_8UC1,
                    (void*)image.constBits(),
                    image.bytesPerLine());
        return mat.clone();
    }

    // wrong
    default:
        qDebug() << "ERROR: QImage could not be converted to Mat.";
        break;
    }
    return cv::Mat();
}

QImage Lib::MatToQImage(const cv::Mat& mat)
{
    switch (mat.type())
    {
    // 8-bit, 4 channel
    case CV_8UC4:
    {
        QImage image(mat.data,
                     mat.cols, mat.rows,
                     static_cast<int>(mat.step),
                     QImage::Format_ARGB32);

        return image;
    }

        // 8-bit, 3 channel
    case CV_8UC3:
    {
        QImage image(mat.data,
                     mat.cols, mat.rows,
                     static_cast<int>(mat.step),
                     QImage::Format_RGB888);

        return image.rgbSwapped();
    }

        // 8-bit, 1 channel
    case CV_8UC1:
    {
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
        QImage image(mat.data,
                     mat.cols, mat.rows,
                     static_cast<int>(mat.step),
                     QImage::Format_Grayscale8);
#else
        static QVector<QRgb>  sColorTable;

        // only create our color table the first time
        if (sColorTable.isEmpty())
        {
            sColorTable.resize( 256 );

            for ( int i = 0; i < 256; ++i )
            {
                sColorTable[i] = qRgb( i, i, i );
            }
        }

        QImage image(mat.data,
                     mat.cols, mat.rows,
                     static_cast<int>(mat.step),
                     QImage::Format_Indexed8 );

        image.setColorTable(sColorTable);
#endif

        return image;
    }

    // wrong
    default:
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        break;
    }
    return QImage();
}

对于基础类的使用

图像变换即图像色彩空间修改

在这里插入图片描述

void Work::on_btn_transform_clicked()
{
    cv::Mat result;
    if(_mat.empty()){
        emit SignImageIsNull();
        return;
    }
    if(ui->RGB2HSV->isChecked()){
        cvtColor(_mat,result,cv::COLOR_RGB2HSV);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("转换为HSV图像");
    }
    if(ui->BGR2GRAY->isChecked()){
        cvtColor(_mat, result, cv::COLOR_BGR2GRAY);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("转换为灰度图像");

    }
    QImage image = Lib::MatToQImage(result);
    _exportImage = image;
    ui->label_image->setPixmap(QPixmap::fromImage(image));
}

图像平滑

在这里插入图片描述

	if(_mat.empty()){
        emit SignImageIsNull();
        return;
    }
    cv::Mat dst = cv::Mat(_mat.size(),_mat.type());
    cv::Size size = cv::Size(5,5);
    //选择滤波核
    if(ui->radio_size1->isChecked()){
        size = cv::Size(3,3);
    }
    if(ui->radio_size2->isChecked()){
        size = cv::Size(5,5);
    }
    //选择平滑算法
    //方框
    if(ui->radio_pane->isChecked()){
        cv::boxFilter(_mat,dst , -1, size, cv::Point(-1, -1), 1);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("方框算法");
    }
    //均值
    if(ui->radio_mean->isChecked()){
        cv::blur(_mat, dst, size, cv::Point(-1, -1));
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("均值算法");
    }
    // 高斯
    if(ui->radio_gauss->isChecked()){
        cv::GaussianBlur(_mat, dst, size, 0);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("高斯算法");
    }

    QImage image = Lib::MatToQImage(dst);
    _exportImage = image;
    ui->label_image->setPixmap(QPixmap::fromImage(image));

边缘检测

在这里插入图片描述

void Work::on_btn_edge_clicked()
{
    if(_mat.empty()){
        emit SignImageIsNull();
        return;
    }
    //创建与src同类型和同大小的矩阵
    cv::Mat dst = cv::Mat(_mat.size(),_mat.type());
    //边缘检测
    if(ui->radio_Canny->isChecked()){
        cv::Mat edge, grayImage;
        //将原始图转化为灰度图
        cv::cvtColor(_mat, grayImage, cv::COLOR_BGR2GRAY);
        //先使用3*3内核来降噪
        cv::blur(grayImage, edge, cv::Size(3, 3));
        //运行canny算子
        cv::Canny(edge, dst, 3, 9, 3);
        // Canny(edge, edge, 3, 9, 3);
        // imshow("边缘提取效果", edge);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("Canny");
    }
    if(ui->radio_Sobel->isChecked()){
        cv::Mat grad_x, grad_y;
        cv::Mat abs_grad_x, abs_grad_y;

        //求x方向梯度
        cv::Sobel(_mat, grad_x, CV_16S, 1, 0, 3, 1, 1,cv::BORDER_DEFAULT);
        cv::convertScaleAbs(grad_x, abs_grad_x);
        // imshow("x方向soble", abs_grad_x);

        //求y方向梯度
        cv::Sobel(_mat, grad_y,CV_16S,0, 1,3, 1, 1, cv::BORDER_DEFAULT);
        cv::convertScaleAbs(grad_y,abs_grad_y);
        // imshow("y向soble", abs_grad_y);

        //合并梯度
        cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
        // imshow("整体方向soble", dst);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("Sobel");
    }
    if(ui->radio_Laplacian->isChecked()){
        cv::Mat gray, abs_dst;
        //高斯滤波消除噪声
        cv::GaussianBlur(_mat, dst, cv::Size(3, 3), 0, 0, cv::BORDER_DEFAULT);
        //转换为灰度图
        cv::cvtColor(dst, gray, cv::COLOR_RGB2GRAY);
        //使用Laplace函数
        //第三个参数:目标图像深度;第四个参数:滤波器孔径尺寸;第五个参数:比例因子;第六个参数:表示结果存入目标图
        cv::Laplacian(gray, dst, CV_16S, 3, 1, 0, cv::BORDER_DEFAULT);
        //计算绝对值,并将结果转为8位
        cv::convertScaleAbs(dst, abs_dst);
        dst = abs_dst.clone();
        // imshow("laplace效果图", abs_dst);
        ui->edit_algorithm->clear();
        ui->edit_algorithm->insertPlainText("Laplacian");

    }
    QImage image = Lib::MatToQImage(dst);
    _exportImage = image;
    ui->label_image->setPixmap(QPixmap::fromImage(image));
}

图像滤镜

点击滤镜按钮

void Work::on_pic_filter_clicked()
{
    ui->stackedWidget->setCurrentWidget(ui->page_filter);
    ui->edit_algorithm->clear();
    ui->edit_algorithm->insertPlainText("滤镜");
    QStringList strList;
    strList<<"原图"<<"浮雕"<<"素描"<<"怀旧"<<"轮廓"<<"模糊"<<"锐化"<<"美颜"<<"水彩";
    ui->filter_comboBox->addItems(strList);
}

点击执行算法

算法选择
void Work::on_btn_filter_clicked()
{
    if(_mat.empty()){
        emit SignImageIsNull();
        return;
    }
    QString algorithm_description = "滤镜";
    Mat dst(_mat.size(),_mat.type());
    int filter_data = ui->filter_comboBox->currentIndex();
    ImageFilter filter;
    // "原图", "浮雕", "素描", "怀旧", "轮廓", "模糊", "锐化", "美颜", "水彩";
    switch (filter_data) {
    // case FilterConfig::OriginalImage:
    //     qDebug()<<a;
    //     break;原图 设置为default
    case FilterConfig::ReliefImage:
        //浮雕
        dst = filter.relief(_mat,150);
        algorithm_description = "滤镜为:浮雕";
        break;
    case FilterConfig::SketchImage:
        //素描
        dst = filter.sketch(_mat);
        algorithm_description = "滤镜为:素描";
        break;
    case FilterConfig::NostalgiaImage:
        //怀旧
        dst = filter.nostalgia(_mat);
        algorithm_description = "滤镜为:怀旧";
        break;
    case FilterConfig::ContourImage:
        // 轮廓
        dst = filter.edge(_mat);
        algorithm_description = "滤镜为:轮廓";
        break;
    case FilterConfig::ObscureImage:
        // 模糊
        dst = filter.blur(_mat);
        algorithm_description = "滤镜为:模糊";
        break;
    case FilterConfig::SharpeningImage:
        // 锐化
        dst = filter.sharp(_mat);
        algorithm_description = "滤镜为:锐化";
        break;
    case FilterConfig::BeautyImage:
        // 美颜
        dst = filter.bifilter(_mat);
        algorithm_description = "滤镜为:美颜";
        break;
    case FilterConfig::WatercolorImage:
        // 水彩
        dst = filter.stylization(_mat);
        algorithm_description = "滤镜为:水彩";
        break;
    default://原图FilterConfig::OriginalImage
        dst = _mat.clone();
        algorithm_description = "设置为:原图";
        break;
    }
    ui->edit_algorithm->clear();
    ui->edit_algorithm->insertPlainText(algorithm_description);
    QImage image = Lib::MatToQImage(dst);
    _exportImage = image;
    ui->label_image->setPixmap(QPixmap::fromImage(image));
}

枚举
// "原图""浮雕", "素描", "怀旧", "轮廓", "模糊", "锐化", "美颜", "水彩";
enum FilterConfig{
    OriginalImage,
    ReliefImage,
    SketchImage,
    NostalgiaImage,
    ContourImage,
    ObscureImage,
    SharpeningImage,
    BeautyImage,
    WatercolorImage
};
算法内容
#ifndef IMAGEFILTER_H
#define IMAGEFILTER_H
// #include <QImage>
// #include <opencv2/core/core.hpp>
// #include <opencv2/highgui/highgui.hpp>
// #include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/opencv.hpp"
using namespace cv;
class ImageFilter
{
public:
    ImageFilter();
public:
    //图像轮廓检测
    Mat edge(Mat image);
    //图像模糊处理
    Mat blur(Mat image);
    //图像锐化
    Mat sharp(Mat image);
    //图像双边滤波处理(美颜)
    Mat bifilter(Mat image);
    //图像浮雕处理
    Mat relief(Mat image,int Degree);
    //素描
    Mat sketch(Mat image);
    //怀旧
    Mat nostalgia(Mat image);
    //水彩
    Mat stylization(Mat image);
};

#endif // IMAGEFILTER_H

实现
#include "imagefilter.h"
ImageFilter::ImageFilter() {}

Mat ImageFilter::edge(Mat image)
{
    Mat dst(image.size(),image.type());
    cv::cvtColor(image,dst,cv::COLOR_BGR2GRAY);
    GaussianBlur(dst,dst,Size(5,5),0);
    Canny(dst,dst,100,200);
    // cv::cvtColor(image,dst,cv::COLOR_HSV2RGB);
    return dst;
}

Mat ImageFilter::blur(Mat image)
{
    Mat dst;
    cv::blur(image,dst,Size(15,15));
    return dst;
}

Mat ImageFilter::sharp(Mat image)
{
    Mat dst;
    // 定义卷积核
    Mat kernel = (Mat_<float>(3,3) << 0, -1, 0,
                  -1, 5, -1,
                  0, -1, 0);
    cv::filter2D(image,dst,-1,kernel);
    return dst;
}

Mat ImageFilter::bifilter(Mat image)
{
    Mat dst;
    cv::bilateralFilter(image,dst,0,30,15);
    return dst;
}

Mat ImageFilter::relief(Mat image, int Degree)
{
    Mat dst;
    cvtColor(image,dst,COLOR_BGR2GRAY);
    int w = dst.cols;
    int h = dst.rows;

    Mat img1 = Mat::zeros(dst.size(),dst.type());
    for(int i = 0;i<h;i++){
        for(int j=0;j<w-1;j++){
            // 前一个像素值
            int a = static_cast<int>(dst.at<uchar>(i, j));
            // 后一个像素值
            int b = static_cast<int>(dst.at<uchar>(i, j + 1));
            // 计算新的像素值,并确保在 0 到 255 之间
            int newValue = min(max(a - b + Degree, 0), 255);
            // 更新输出图像
            img1.at<uchar>(i, j) = static_cast<uchar>(newValue);
        }
    }
    return img1;
}

Mat ImageFilter::sketch(Mat image)
{
    Mat dst(image.size(),image.type());
    cv::cvtColor(image,dst,cv::COLOR_BGR2GRAY);
    GaussianBlur(dst,dst,Size(3,3),0);
    Canny(dst,dst,50,140);
    cv::threshold(dst,dst,90,255,THRESH_BINARY_INV);
    return dst;
}

Mat ImageFilter::nostalgia(Mat image)
{
    // 获取图像属性
    int h = image.rows;
    int w = image.cols;

    // 定义空白图像,存放怀旧处理后的图像
    Mat dst(h, w, CV_8UC3);

    // 遍历图像像素进行怀旧处理
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            float B = 0.131 * image.at<Vec3b>(i, j)[0] + 0.534 * image.at<Vec3b>(i, j)[1] + 0.272 * image.at<Vec3b>(i, j)[2];
            float G = 0.168 * image.at<Vec3b>(i, j)[0] + 0.686 * image.at<Vec3b>(i, j)[1] + 0.349 * image.at<Vec3b>(i, j)[2];
            float R = 0.189 * image.at<Vec3b>(i, j)[0] + 0.769 * image.at<Vec3b>(i, j)[1] + 0.393 * image.at<Vec3b>(i, j)[2];

            // 防止图像溢出
            if (B > 255) B = 255;
            if (G > 255) G = 255;
            if (R > 255) R = 255;

            // 设置怀旧后的像素值
            dst.at<Vec3b>(i, j)[0] = static_cast<uchar>(B);
            dst.at<Vec3b>(i, j)[1] = static_cast<uchar>(G);
            dst.at<Vec3b>(i, j)[2] = static_cast<uchar>(R);
        }
    }

    return dst;
}

Mat ImageFilter::stylization(Mat image)
{
    Mat dst(image.size(),image.type());
    cv::stylization(image,dst,60,0.6);
    return dst;
}

```
  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值