通过QT和OpenCV设计一款简易的美图软件,了解其中对于图片操作的方法
1.新建QT项目,在.pro文件中添加OpenCV通过cmake编译后的文件
2.在mainwindow.h中输入以下代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include //opencv的头文件
#include //QT有关图片的头文件
#include //标签控件里面的图片格式头文件
using namespace cv;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
QImage MatToImage(Mat &m); //将Mat格式转化成QImage类型
void whiteFace(Mat &m); //改变Mat中所有像素点的对比度或者亮度
private slots:
void openActionSlot(); //打开图像文件的槽函数
void on_constrastSlider_valueChanged(int value); //对比度条的槽函数
void on_brightSlider_valueChanged(int value); //亮度条的槽函数
void on_originalButton_pressed(); //原图按钮按下时的槽函数
void on_originalButton_released(); //原图按钮松开时的槽函数
void on_beautyButton_clicked(); //磨皮按钮的槽函数
void on_matButton_clicked(); //抠图按钮的槽函数
private:
Ui::MainWindow *ui;
QImage src; //图片
QString fileName; //文件名
float m_contrast; //图片对比度
int m_bringtnees; //图片亮度
Mat m_mat; //原始Mat数据
Mat rest; //调整后的Mat数据
};
#endif // MAINWINDOW_H
2.在mainwindow.cpp中输入以下代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include //打开文件的头文件
#include //QT标准输出
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//点击打开,释放信号,执行打开文件的槽函数
connect(ui->openAction, &QAction::triggered, this, &MainWindow::openActionSlot);
//初始化对比度和亮度
m_contrast = 1;
m_bringtnees = 0;
//初始化对比度slider,设置最大最小值,每个刻度值,标志
ui->constrastSlider->setMinimum(-10);
ui->constrastSlider->setMaximum(10);
ui->constrastSlider->setSingleStep(1);
ui->constrastSlider->setTickPosition(QSlider::TicksAbove);
//初始化亮度slider, 设置最大最小和刻度
ui->brightSlider->setMinimum(-50);
ui->brightSlider->setMaximum(50);
ui->brightSlider->setSingleStep(10);
}
MainWindow::~MainWindow()
{
delete ui;
}
QImage MainWindow::MatToImage(Mat &m) //Mat格式转化QImage类型
{
switch (m.type()) { //判断Mat的类型,从而返回不同类型的img
case CV_8UC1:{
// 通过QImage::QImage(uchar *data, int width, int height, int bytesPerLine,
// QImage::Format format, QImageCleanupFunction cleanupFunction = nullptr,
//void *cleanupInfo = nullptr),主要修改后两个非默认的参数
QImage img((uchar*)m.data,m.cols,m.rows,m.cols*1,QImage::Format_Grayscale8);
return img;
}
case CV_8UC3:{
QImage img((uchar*)m.data,m.cols,m.rows,m.cols*3,QImage::Format_RGB888);
return img.rgbSwapped();
}
case CV_8UC4:{
QImage img((uchar*)m.data,m.cols,m.rows,m.cols*4,QImage::Format_ARGB32);
return img;
}
default:{
QImage img;
return img;
}
}
}
void MainWindow::whiteFace(Mat &m) //改变Mat中所有像素点的对比度或者亮度
{
//理解Mat的原理,通过三层循环找到每一个像素点
for(int i = 0; i(i,j)[k] = saturate_cast(m_contrast * m_mat.at(i,j)[k] + m_bringtnees);
}
}
}
}
void MainWindow::openActionSlot() //打开文件的槽函数
{
//设置文件路径和打开文件的格式
fileName = QFileDialog::getOpenFileName(this, "选择图片",
"C:\\Users\\67098\\Desktop","*.png *.xpm *.jpg");
//如果打开文件不为空
if(!fileName.isEmpty())
{
src.load(fileName); //将图片导入图片src中
ui->label->setPixmap(QPixmap::fromImage(src)); //将图片放置在标签中,转换格式
//把QString转化成String类型
QByteArray ba;
ba.append(fileName);
//用string格式读取该路径下的图片,保存至Mat格式
m_mat = imread(ba.data());
//初始化rest,输入高度,宽度,类型
rest = Mat(m_mat.rows, m_mat.cols, m_mat.type());
}
}
void MainWindow::on_constrastSlider_valueChanged(int value) //对比度的槽函数
{
m_contrast = 1 + (float)value / 10; //对比度为当前值除以10加1
whiteFace(rest); //将需要修改的rest传入改变像素对比度
QImage src = MatToImage(rest); //将修改后的rest转化成QImage格式,保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
void MainWindow::on_brightSlider_valueChanged(int value) //亮度的槽函数
{
m_bringtnees = value; //亮度为改变的值
whiteFace(rest); //将需要修改的rest传入改变像素亮度
QImage src = MatToImage(rest); //将修改后的rest转化成QImage格式,保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
void MainWindow::on_originalButton_pressed() //原图按钮点击的槽函数
{
QImage src = MatToImage(m_mat); //将原始m_mat转化成QImage, 保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
void MainWindow::on_originalButton_released() //原图按钮松开的槽函数
{
QImage src = MatToImage(rest); //将修改后的rest转化成QImage格式,保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
void MainWindow::on_beautyButton_clicked() //磨皮按钮的槽函数
{
int val = 40; //先设置val, 可以通过opencv搜索双边滤波和高斯滤波
Mat bfMat;
//双边滤波
bilateralFilter(m_mat, bfMat, val, val*2, val/2);
//非锐化掩蔽 图像增强
GaussianBlur(bfMat, rest, Size(3,3), 1, 1);
addWeighted(bfMat, 1.5, rest, -0.5, 0, rest);//将模糊的图片bfMat和之前修改的图片叠加在一块,保存至rest
QImage src = MatToImage(rest); //将修改后的rest转化成QImage格式,保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
void MainWindow::on_matButton_clicked() //抠图按钮的槽函数
{
Mat hsvMat, destFrame;
//先把BGR模型转换成HSV
cvtColor(m_mat, hsvMat, COLOR_BGR2HSV);
//确定hsvMat中需要抠图的像素范围,并保存至desFrame中,不在范围的将是黑色,在范围内的是白色
inRange(hsvMat, Scalar(0, 1, 7), Scalar(170, 204, 254), destFrame);
//这一段用来输出图片中100行的所有像素的值,可以通过该值确定背景色的范围,从而选择出需要抠图的像素范围
// for(int i = 0; i < hsvMat.cols; i++)
// {
// qDebug() << hsvMat.at(100,i)[0] << hsvMat.at(100,i)[1] << hsvMat.at(100,i)[2];
// }
cvtColor(destFrame, destFrame, COLOR_GRAY2BGR); //将desFrame变成BGR格式,并保存在desFrame中
bitwise_and(m_mat, destFrame, rest); //通过原始图片和抠图图片进行与运算,保存至rest中
QImage src = MatToImage(rest); //将修改后的rest转化成QImage格式,保存至src中
ui->label->setPixmap(QPixmap::fromImage(src)); //用标签展示修改后的src
}
3.设置mainwindow.ui
4.点击编译,执行代码,先点击“打开”
5.选择需要美化的图片
6.修改对比度或者亮度
7.按下“原图”,变成原图,松开“原图”,变成修改后的图片
8.点击“磨皮”,图片质感变得柔和
9.点击抠图,因为代码中的抠图效果实现是通过排除背景色,所以如果人像中出现与背景色一致的颜色,则也会被处理