[Qt]图像处理小软件——给证件照换背景
之前看到码农大佬分享的文章,感觉是个小乐子,就自己动手做了个小软件,方便还没学会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中:
结果展示:
原图:
改为白色背景:
改为证件蓝色背景:
改为证件红色背景:
喜欢的小伙伴记得点赞哦~!
智能推荐
Rtthread学习笔记(十三)RT-Thread Studio开启硬件看门狗Watchdog
一、开启硬件看门狗Watchdog 1、配置RT-Thread Settings 2、开启stm32f1xx_hal_conf.h中的宏定义 3.使用RT接口函数初始化硬件看门狗...
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...
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专为性能优化而开发,性能是其最重要的考量,实现上非常注重效率,能经受...