[Qt]图像处理小软件——给证件照换背景

标签: 在线小工具  Qt  图像处理  opencv  qt5

之前看到码农大佬分享的文章,感觉是个小乐子,就自己动手做了个小软件,方便还没学会PS的小伙伴们临时换背景Hhhh~
具体的步骤实现,可以参看[VS2017]图像处理——给证件照换背景

软件操作如GIF图所示:
在这里插入图片描述

新建Qt的项目文件~
.h中:

#include <QWidget>
#include <QDebug>

#include <QFile>
#include <QFileDialog>

#include <iostream>
using namespace std;

#include <opencv.hpp>
using namespace cv;

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    Mat img,img_show,input_output;
    bool oldBG_Blue,oldBG_Red;
    bool newBG_Blue,newBG_Red,newBG_White;
    QImage QImg;
    Mat InputImg;

    QString file_path;
    string file;

    void DealPicture(Mat image);
    QImage cvMat2QImage(const cv::Mat& mat);
    cv::Mat QImage2cvMat(QImage image);



private slots:

    void on_radioButton_oldBG_Red_clicked();
    void on_radioButton_oldBG_Blue_clicked();
    void on_radioButton_newBG_White_clicked();
    void on_radioButton_newBG_Blue_clicked();
    void on_radioButton_newBG_Red_clicked();
    void on_pushButton_DealPicture_clicked();
void on_pushButton_SelectPicture_clicked();

.cpp中:

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    oldBG_Blue = true;
    oldBG_Red = false;

    newBG_Blue = false;
    newBG_Red = false;
    newBG_White = true;
    ui->radioButton_oldBG_Blue->click();
    ui->radioButton_newBG_White->click();
}

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

void Widget::DealPicture(Mat img)
{
    Mat img1,img2,img3,img4,img5,img6;

    img1 = img;
    //变换图片格式
    cvtColor(img1, img2, COLOR_BGR2HSV);
    //imshow("hsv image", img2);

    //检测背景
    if (oldBG_Blue)
    {
        inRange(img2, Scalar(90, 70, 70), Scalar(110, 255, 255), img3);//检测蓝色背景
    }
    else if (oldBG_Red)
    {
        inRange(img2, Scalar(0, 135, 135), Scalar(180, 245, 230), img3);//检测红色背景
    }
    //imshow("mask image", img3);

    //腐蚀
    Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
    erode(img3, img4, element);
    //imshow("erode image", img4);

    //膨胀
    dilate(img4, img5, element);
    //imshow("dilate image", img5);

    //遍历换颜色
    Mat ergodic_img = img5;
    int pointR, pointG, pointB;

    for (int i = 0; i < ergodic_img.rows; i++)
    {
        for (int j = 0; j < ergodic_img.cols ; j++)
        {
            if (ergodic_img.at<uchar>(i, j) == 255)
            {
                if (newBG_Blue)
                {
                    pointR = 67, pointG = 142, pointB = 219;//背景变为蓝色
                }
                else if (newBG_Red)
                {
                    pointR = 255, pointG = 0, pointB = 0; //背景变为红色
                }
                else if (newBG_White)
                {
                    pointR = 255, pointG = 255, pointB = 255;//背景变为白色
                }

                img1.at<cv::Vec3b>(i, j)[0] = pointB;
                img1.at<cv::Vec3b>(i, j)[1] = pointG;
                img1.at<cv::Vec3b>(i, j)[2] = pointR;
            }
        }
    }

    //imshow("result image", img);

    imwrite("../result.jpg", img1);
    img_show = img1;
    cv::resize(img_show, img_show, Point(221, 316));
    QImg = cvMat2QImage(img_show);
    ui->label_new->setPixmap(QPixmap::fromImage(QImg));

}


void Widget::on_radioButton_oldBG_Red_clicked()
{
    oldBG_Red = true;
    oldBG_Blue = false;
}

void Widget::on_radioButton_oldBG_Blue_clicked()
{
    oldBG_Blue = true;
    oldBG_Red = false;
}

void Widget::on_radioButton_newBG_White_clicked()
{
    newBG_White = true;
    newBG_Blue = false;
    newBG_Red = false;
}

void Widget::on_radioButton_newBG_Blue_clicked()
{
    newBG_Blue = true;
    newBG_White = false;
    newBG_Red = false;
}

void Widget::on_radioButton_newBG_Red_clicked()
{
    newBG_Red = true;
    newBG_White = false;
    newBG_Blue = false;
}

void Widget::on_pushButton_DealPicture_clicked()
{
    img = imread(file);
    //imshow("input image" , img);
    //qDebug()<<oldBG_Blue<<"\t"<<oldBG_Red<<"\t"<<newBG_Blue<<"\t"<<newBG_Red<<"\t"<<newBG_White;
    DealPicture(img);
}

void Widget::on_pushButton_SelectPicture_clicked()
{
    file_path = QFileDialog::getOpenFileName(this,"open","../");
    if (file_path.isEmpty() ==false)
    {
        file = file_path.toStdString();

        img = imread(file);
        img_show = img;
        cv::resize(img_show, img_show, Point(221, 316));
        QImg = cvMat2QImage(img_show);
        ui->label_old->setPixmap(QPixmap::fromImage(QImg));
    }
}


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 colour 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();
    }
}
/*
cv::Mat Widget::QImage2cvMat(QImage image)
{
    cv::Mat mat;
    qDebug() << image.format();
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}
*/

.ui中:

在这里插入图片描述
结果展示:
原图:
在这里插入图片描述

改为白色背景:
在这里插入图片描述

改为证件蓝色背景:
在这里插入图片描述
改为证件红色背景:
在这里插入图片描述
喜欢的小伙伴记得点赞哦~!

版权声明:本文为weixin_43487953原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_43487953/article/details/108408352

智能推荐

Rtthread学习笔记(十三)RT-Thread Studio开启硬件看门狗Watchdog

一、开启硬件看门狗Watchdog 1、配置RT-Thread Settings 2、开启stm32f1xx_hal_conf.h中的宏定义 3.使用RT接口函数初始化硬件看门狗...

TYVJ 4864 天天去哪吃 || 清北学堂金秋杯大奖赛

题目描述: 记录一下i这个值上次出现的位置在哪里,就是pre...

java反编译

jvm 把Boolean类型的值flag当做int类型处理。​​​ Foo.java: 由 class 文件生成 jasm 文件:java -jar asmtools.jar jdis Foo.class > Foo.jasm  修改jasm文件: 执行反编译: java -jar jd-gui-1.6.6.jar File 打开Foo.class文件:b修改为2 重新执行java...

【学习笔记】03-v-html的学习和示例

v-html的认识和使用 示例: 显示结果: 注意:v-html是有复制的...

Java实现在线考试系统(系统介绍)

1.和现在有的考试系统有以下几种优势: a.和现在有的系统比较起来,本系统有科目、章节、老师、学生、班级等信息的管理,还有批阅试卷查看已批阅试卷等。传统的考试系统划分并不细,业务功能简单。 b.和学校的考试系统还有外面的考试系统比较起来,本系统是B/S结构,学校的考试系统一般为C/S结构,性能方面不如B/S结构,并且C/S接口需要安装客户端,客户端压力很大,我的系统只需要电脑具有浏览器,在同一局域...

猜你喜欢

计算机视觉--多视几何初步尝试

基础矩阵的原理 K和K’分别是两个相机的参数矩阵。p和p’是X在平面π的坐标表示。所以可以得出 具体计算过程 代码: #!/usr/bin/env python coding: utf-8 from PIL import Image from numpy import * from pylab import * import numpy as np from imp ...

java初学者怎么学习才可以快速入门

java初学者怎么学习才可以快速入门 一、了解JAVA 我们要知道:Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言。 Java之父:詹姆斯·高斯林 1.1 java的三个体系 Java SE(Java Platform Standard Edition)。Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境...

字段属性之主键&增删改查&自增长&唯一键约束

字段属性之主键&自增长&唯一键约束 主键 主键:primary key 主要的键 一张表中只有一个字段可以使用对应的键,用来唯一的约束该字段里面的数据,不能重复,这种称之为主键 一张表只能最多一个主键 增加主键 SQL操作中有多种方式增加主键大体分为三种 1.在创建表的时候直接在字段之后跟primary key关键字(主键本身不允许为空) 优点:非常直接:缺点:只能使用一个字段作为...

linux下 基于libmad的socket多用户mp3音频在线播放服务器

在众多大神的帮助下,这个在线播放流媒体服务器终于完成啦。。。。 这个mp3流媒体服务器设计的思路是,服务器程序server用多线程实现和多个客户端的通信(这是必然的),然后发送给客户端当前的音频列表公客户端选择,之后根据k客户端的选择给多个客户端传输相应mp3文件的数据,同时,客户端进行实时地音频解码并播放。 关于libmad开源mp3音频解码库的使用,见上一篇博客吧。。。。 在服务器程序这一端,...

Nginx

Nginx Nginx简介: Nginx是一个高性能的http和反向代理服务器,特点是有内存少,并发能力强,事实上Nginx的并发能力确实在同类型网页服务器中表现较好, Nginx用作web服务器:Nginx可以作为静态页面的web服务器,同时还支持CGI语言,但不支持java,java程序只能通过Tomcat配合完成。Nginx专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率,能经受...