目录
前言
一、总体设计
1.1 主要功能
1.2 UML类图
二、代码实现
2.1 父类method
2.2 子类线性增强算法
2.3 gamma校正
2.4 管理类Manage.h
2.5 选择图像
2.6 保存和撤销图像
三、测试与分析
四、完整代码
4.1 method.h
4.2 method.cpp
4.3 manage.h
4.4 manage.cpp
4.5 mainwindow.cpp
总结
本次课设实现的简易图像处理主要采用了C++和OpenCV+Qt结合的方式,利用C++类的封装、多态、继承继承机制实现了对输入图像进行线性灰度变换、对数变换、gamma变换、拉普拉斯算子增强、直方图均衡化、rbg2gray、模糊图像增强七种处理方式,在线性变换和gamma变换的时候利用QMessageBox类实现弹窗功能,用户可以自己输入相关值对图像进行增强或对比度降低的操作,同时还利用栈的方式对图像操作进行撤销,最后将算法打包成了动态库,采用隐式调用.dll文件的方式实现了代码共享。
提示:以下是本篇文章正文内容,下面案例可供参考
(1)选择一张图像,对图像进行线性灰度变换、对数变换、gamma变换、拉普拉斯算子增强、直方图均衡化、rbg2gray、模糊图像增强处理;
(2)显示图像、将结果图像保存到文件;
(3)对图像所做操作进行撤销;
(4)利用对话框的形式显示算法简介。
系统实现:首先将算法抽象成一个类模板method,然后对类method针对数据类型
将图像增强算法抽象成一个类method,并将其写成一个模板类,然后针对Mat数据类型对类实现特化,编写setImage,getImage,imag_gray,isEmpty成员函数。
template
class METHOD_EXPORT method
{
public:
method();
method(string str) //带参构造函数
{
setImage(str);
}
virtual ~method()
{
cout<<"end of method!"<img = img;
}
cv::Mat getImage()
{
return this->img;
}
cv::Mat isEmpty()
{
if(img.empty())
{
cout<<"读入图片失败!"<
class method //模板类特化
{
public:
method();
method(string str)
{
setImage(str);
}
virtual ~method()
{
cout<<"end of method!"<img = img;
}
cv::Mat getImage()
{
return this->img;
}
cv::Mat img_gray(cv::Mat s) //彩色图转换为灰度图像
{
cv::Mat gray;
if(!isEmpty())
{
cvtColor(s,gray,CV_BGR2GRAY);
return gray;
}
}
bool isEmpty()
{
if(img.empty())
{
cout<<"Loading false!"<
线性灰度变换的公式是:g(x,y)=k*f(x,y)+b,类LinearChange继承父类method,定义两个私有变量k,b,根据用户需要进行输入,然后重写父类method方法,对输入图像逐像元进行线性变换。
//图像的灰度线性变化
class LinearChange:public method
{
public:
LinearChange();
LinearChange(string str):method(str){};
~LinearChange()
{
cout<<"LInearChange is end!"<getImage();
if(srcImg.empty())
{
cout<<"读入图片失败"<
dstImg.at(i,j)[c] = saturate_cast
(k*(srcImg.at(i,j)[c])+b);
}
}
}
return dstImg;
}
gamma变换的公式:s=c*f(x,y)^gamma,当gamma>1时,低灰度值区间的动态范围变小,高灰度值区间的动态范围变大,整体来说降低图像对比度,当0
//图像的gamma校正
class gammaTransform:public method
{
public:
gammaTransform();
gammaTransform(string str):method(str){};
~gammaTransform()
{
cout<<"gammaTransform is end!"<预补偿-->反归一化;s=pow(f,r)
};
Mat gammaTransform::runMethod()
{
Mat srcImg=this->getImage();
if(srcImg.empty())
{
cout<<"读入图片失败"<(f*255.0f-0.5f);
}
Mat imagegamma = srcImg.clone();
//判断图像的通道数
if(srcImg.channels()==1) //灰度图像
{
//迭代器
MatIterator_ iterator = imagegamma.begin();
MatIterator_ iteratorEnd = imagegamma.end();
for(;iterator!=iteratorEnd;iterator++)
{
*iterator = LUT[(*iterator)];
}
}
else
{
//输入通道为三通道时,需要对每个通道分别进行变换
MatIterator_ iterator = imagegamma.begin();
MatIterator_ iteratorEnd = imagegamma.end();
//通过查表进行转换
for(;iterator!=iteratorEnd;iterator++)
{
(*iterator)[0] = LUT[((*iterator)[0])];
(*iterator)[1] = LUT[((*iterator)[1])];
(*iterator)[2] = LUT[((*iterator)[2])];
}
}
return imagegamma;
}
定义一个保存图像的栈,将每次操作的图像入栈,删除之后出栈,stack_Number用来计数栈中元素,sign作为标识,以便撤销处理,如果sign == false且stack_Number == 0,则弹出误操作提示框,如果sian==true且stack_Number == 0 则说明已撤销至初始状态。
class manage
{
public:
string imagePath; //图片路径
stack imageStack; //存储图片的栈
//int stack_Number = 0; //初始化栈中元素为空
manage():imagePath("none"){};
~manage();
void giveImage_path(string path);
void saveImage(string path);
void pushStack(Mat image); //将执行操作的图片入栈
cv::Mat undoImage(); //撤销
};
#include "manage.h"
#include
using namespace std;
manage::~manage()
{
}
void manage::giveImage_path(string path)
{
this->imagePath = path;
}
void manage::saveImage(string path)
{
cv::Mat element;
element=this->imageStack.top();
imwrite(path,element);
}
void manage::pushStack(Mat image) //操作图像入栈
{
this->imageStack.push(image);
//this->stack_Number++;
}
cv::Mat manage::undoImage() //撤销
{
cv::Mat dstImg;
if(this->imageStack.size()==1)
{
dstImg = this->imageStack.top();
this->imageStack.pop();
//this->stack_Number--;
return dstImg;
}
else if(this->imageStack.size()>1)
{
this->imageStack.pop();
//this->stack_Number--;
return this->imageStack.top();
}
}
//选择图像
void MainWindow::on_pushButton_9_clicked()
{
QString fileName,openPath;
fileName=QFileDialog::getOpenFileName(this,tr("选择图像"),"D:/FengGeQY/imgData/RGB4.jpg",
tr("Images (*.png *.bmp *.jpg *.tif *.GIF )"));
//四个参数说明
//1、第一个参数parent,用于指定父组件
//2、第二个参数caption,是对话框的标题
//3、dir,是对话框显示时默认打开的目录
//4、filter,是对话框的后缀名过滤器,比如我们使用"Image Files(*.jpg *.png)"就让它只能显示后缀名是jpg或者png的文件。
//4、如果需要使用多个过滤器,使用";;"分割,比如"JPEG Files(*.jpg);;PNG Files(*.png)";
if(!fileName.isEmpty())
{
QImage* img=new QImage;
if(! ( img->load(fileName) ) )
{ //加载图像
QMessageBox::information(this,tr("打开图像失败"),tr("打开图像失败!"));
delete img;
}
//将所得路径保存到图片管理栈中的路径
string s1 =fileName.toStdString();
imgManage.giveImage_path(s1);
//显示图片
Mat image=imread(s1,1);
QImage qimage = Mat2QImage(image);
ui->label_4->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_4->size()));
//在文本框中显示图片路径
openPath = QFileInfo(fileName).filePath();
ui->lineEdit->setText(openPath);
}
}
//保存图像
void MainWindow::on_pushButton_10_clicked()
{
//判断管理栈是否为空
if(!(imgManage.imageStack.empty()))
{ //保存文件对话框API函数:getSaveFileName
QString filename1 = QFileDialog::getSaveFileName(this, tr("保存图像"), "", tr("Images (*.png *.bmp *.jpg *jpeg *GIF)"));
//获取保存的图像的指针
QScreen *screen = QGuiApplication::primaryScreen();
//得到图像
screen->grabWindow(ui->label_6->winId()).save(filename1);
}
else
{
int ret = QMessageBox::information(this,QObject::tr("提示"),
QObject::tr("没有可保存的图像,请重新确认"),QMessageBox::Ok);
if(ret == QMessageBox::Ok)
qDebug()<imgManage.imageStack.empty())
{
int ret = QMessageBox::critical(this,QObject::tr("误操作提示"),QObject::tr("没有可撤销的操作,请操作后再撤消!"),QMessageBox::YesAll);
if(ret == QMessageBox::YesAll)
{
qDebug()<imgManage.undoImage();
//if(this->imgManage.imageStack.size()==0)
if(this->imgManage.imageStack.empty())
{
ui->label_6->setText(" 已无更多操作,恢复至初始状态 ");
}
else
{
QImage qimage=Mat2QImage(img);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
}
}
(1)初始界面
图 3-1 系统初始界面
(2)依次展示系统功能
图 3-2 线性灰度变换输入系数K
图 3-3 线性灰度变换结果
图 3-4 对数灰度变换c=3时的结果
图 3-6 gamma=2.6时的结果
图 3-7 拉普拉斯算子增强结果
图 3-8 直方图均衡化增强结果
图 3-10 模糊图像变清晰
(3)保存图像
图 3-11 选择保存路径
图 3-12 保存结果展示
(4)撤销操作
图 3-13 撤销结果展示
(5)算法简介按钮
图 3-14 算法简介按钮结果展示
根据测试结果来看,拉普拉斯算子增强算法对对比度高的图像增强效果不佳,会使图像过于偏亮、失真,因为它是根据拉普拉斯算子局部增强,如果再图像中一个较暗的区域中出现一个亮点,那么用拉普拉斯算子会使这个亮点变得更亮。通常适用于以突出图像中孤立点、孤立线或线端点为目的的场合。接下来用一张对比度低的图像测试:
可以看到图像对比度提升了不少,使图像细节更清晰。还有模糊图像变清晰算法也是只有部分增强,没有达到理想效果。
(6)动态库
#ifndef METHOD_H
#define METHOD_H
#include "method_global.h"
#include
using namespace std;
#include
#include
#include
#include
#include
using namespace cv;
template
class METHOD_EXPORT method
{
public:
method();
method(string str) //带参构造函数
{
setImage(str);
}
virtual ~method()
{
cout<<"end of method!"<img = img;
}
cv::Mat getImage()
{
return this->img;
}
cv::Mat isEmpty()
{
if(img.empty())
{
cout<<"读入图片失败!"<
class method //模板类特化
{
public:
method();
method(string str)
{
setImage(str);
}
virtual ~method()
{
cout<<"end of method!"<img = img;
}
cv::Mat getImage()
{
return this->img;
}
cv::Mat img_gray(cv::Mat s) //彩色图转换为灰度图像
{
cv::Mat gray;
if(!isEmpty())
{
cvtColor(s,gray,CV_BGR2GRAY);
return gray;
}
}
bool isEmpty()
{
if(img.empty())
{
cout<<"Loading false!"<
{
public:
LinearChange();
LinearChange(string str):method(str){};
~LinearChange()
{
cout<<"LInearChange is end!"<
{
public:
LogTransform();
LogTransform(string str):method(str){};
~LogTransform()
{
cout<<"LogTransform is end!"<
{
public:
gammaTransform();
gammaTransform(string str):method(str){};
~gammaTransform()
{
cout<<"gammaTransform is end!"<预补偿-->反归一化;s=pow(f,r)
};
//拉普拉斯算子增强局部的图像对比度
class LaplaeOperator:public method
{
public:
LaplaeOperator();
LaplaeOperator(string str):method(str){};
~LaplaeOperator()
{
cout<<"LaplaeOperator is end!"<
{
public:
HistogramEq();
HistogramEq(string str):method(str){};
~HistogramEq()
{
cout<<"HistorgramEq is end!"<
{
public:
Transform();
Transform(string str):method(str){};
~Transform()
{
cout<<"Transform is end!"<76*R+150*G+30*B
Mat imgRGB = this->getImage();
//创建结果图像
Mat imgGray = Mat(imgRGB.rows, imgRGB.cols, CV_8UC1);
for(int i = 0 ;i < imgRGB.rows ; i++)
{
for(int j = 0 ;j < imgRGB.cols ; j++)
{
//OpenCV读取彩色影像的是BGR的顺序
uchar B = imgRGB.at(i,j)[0];
uchar G = imgRGB.at(i,j)[1];
uchar R = imgRGB.at(i,j)[2];
imgGray.at(i,j) = 0.2126*R + 0.7152*G + 0.0722*B; //两种效果差不多
//imgGray.at(i,j) = 0.2989*R + 0.587*G + 0.114*B;
}
}
return imgGray;
}
};
#endif // METHOD_H
#include "method.h"
//图像的灰度线性变化
Mat LinearChange::runMethod()
{
Mat srcImg=this->getImage();
if(srcImg.empty())
{
cout<<"读入图片失败"<
dstImg.at(i,j)[c] = saturate_cast
(k*(srcImg.at(i,j)[c])+b);
}
}
}
return dstImg;
}
//图像的对数变换
Mat LogTransform::runMethod()
{
Mat srcImg=this->getImage();
if(srcImg.empty())
{
cout<<"读入图片失败"<(i,j)[0] = c*log(1+srcImg.at(i,j)[0]);
imageLog.at(i,j)[1] = c*log(1+srcImg.at(i,j)[1]);
imageLog.at(i,j)[2] = c*log(1+srcImg.at(i,j)[2]);
}
}
//归一化到0~255
normalize(imageLog,imageLog,0,255,CV_MINMAX);
//convertScaleAbs():先缩放元素再取绝对值,最后转换格式为8bit型
//这里仅为将格式转换为8bit型
convertScaleAbs(imageLog,imageLog);
return imageLog;
}
//图像的gamma校正
Mat gammaTransform::runMethod()
{
Mat srcImg=this->getImage();
if(srcImg.empty())
{
cout<<"读入图片失败"<(f*255.0f-0.5f);
}
Mat imagegamma = srcImg.clone();
//判断图像的通道数
if(srcImg.channels()==1) //灰度图像
{
//迭代器
MatIterator_ iterator = imagegamma.begin();
MatIterator_ iteratorEnd = imagegamma.end();
for(;iterator!=iteratorEnd;iterator++)
{
*iterator = LUT[(*iterator)];
}
}
else
{
//输入通道为三通道时,需要对每个通道分别进行变换
MatIterator_ iterator = imagegamma.begin();
MatIterator_ iteratorEnd = imagegamma.end();
//通过查表进行转换
for(;iterator!=iteratorEnd;iterator++)
{
(*iterator)[0] = LUT[((*iterator)[0])];
(*iterator)[1] = LUT[((*iterator)[1])];
(*iterator)[2] = LUT[((*iterator)[2])];
}
}
return imagegamma;
}
//拉普拉斯算子增强局部的图像对比度
Mat LaplaeOperator::runMethod()
{
Mat image=this->getImage();
if(image.empty())
{
cout<<"读入图像失败"<(3,3)<<0,-1,0,0,5,0,0,-1,0);
//Mat kernel = (Mat_(3,3)<<1,1,1,1,-8,1,1,1,1);
//filter2D():opencv进行图像卷积运算的函数
filter2D(image,imageLaplace,CV_8UC3,kernel);
return imageLaplace;
}
//彩色直方图均衡化
Mat HistogramEq::runMethod()
{
Mat image=this->getImage();
if(image.empty())
{
cout<<"读入图像失败"<getImage(); //输入的图像
Mat dstImg; //输出的图像
Mat mean;
int MaskWidth=20,MaskHeight=20;
float factor = 1.3;
//等价于求指定范围窗口内的均值
blur(image,mean,Size(MaskWidth,MaskHeight));
dstImg.create(image.size(),image.type());
if(image.type()==CV_8UC1)
{
for(int i=0;i(i);
uchar *mptr = mean.ptr(i);
uchar *optr = dstImg.ptr(i);
for(int j=0;j( round((rptr[j] - mptr[j])*factor)+rptr[j]*1.0f);
}
}
}
else if(image.type()==CV_8UC3)
{
for(int i=0;i(i);
uchar *mptr = mean.ptr(i);
uchar *optr = dstImg.ptr(i);
for(int j=0;j(round((rptr[j * 3] - mptr[j * 3])*factor) + rptr[j * 3] * 1.0f);
optr[j*3+1] = saturate_cast(round((rptr[j * 3+1] - mptr[j * 3+1])*factor) + rptr[j * 3+1] * 1.0f);
optr[j*3+2] = saturate_cast(round((rptr[j * 3+2] - mptr[j * 3+2])*factor) + rptr[j * 3+2] * 1.0f);
}
}
}
return dstImg;
}
#ifndef MANAGE_H
#define MANAGE_H
#include"method.h"
#include
class manage
{
public:
string imagePath; //图片路径
stack imageStack; //存储图片的栈
//int stack_Number = 0; //初始化栈中元素为空
manage():imagePath("none"){};
~manage();
void giveImage_path(string path);
void saveImage(string path);
void pushStack(Mat image); //将执行操作的图片入栈
cv::Mat undoImage(); //撤销
};
#endif // MANAGE_H
#include "manage.h"
#include
using namespace std;
manage::~manage()
{
}
void manage::giveImage_path(string path)
{
this->imagePath = path;
}
void manage::saveImage(string path)
{
cv::Mat element;
element=this->imageStack.top();
imwrite(path,element);
}
void manage::pushStack(Mat image) //操作图像入栈
{
this->imageStack.push(image);
//this->stack_Number++;
}
cv::Mat manage::undoImage() //撤销
{
cv::Mat dstImg;
if(this->imageStack.size()==1)
{
dstImg = this->imageStack.top();
this->imageStack.pop();
//this->stack_Number--;
return dstImg;
}
else if(this->imageStack.size()>1)
{
this->imageStack.pop();
//this->stack_Number--;
return this->imageStack.top();
}
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
using namespace cv;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
QImage Mat2QImage(const cv::Mat &mat){
switch (mat.type())
{
// 8-bit, 4 channel
case CV_8UC4:
{
QImage image(mat.data, mat.cols, mat.rows, static_cast(mat.step), QImage::Format_ARGB32);
return image;
}
// 8-bit, 3 channel
case CV_8UC3:
{
QImage image(mat.data, mat.cols, mat.rows, static_cast(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(mat.step), QImage::Format_Grayscale8);
#else
static QVector 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(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 MainWindow::on_pushButton_7_clicked()
//{
// //QMessageBox::information(NULL,"这是测试","123456",QMessageBox::Yes | QMessageBox::No,QMessageBox::Yes);
// createMenu();
//}
//模糊图片变清晰
void MainWindow::on_pushButton_8_clicked()
{
Transform img = Transform(imgManage.imagePath);
cv::Mat run = img.Emphasize();
this->imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
//选择图像
void MainWindow::on_pushButton_9_clicked()
{
QString fileName,openPath;
fileName=QFileDialog::getOpenFileName(this,tr("选择图像"),"D:/FengGeQY/imgData/RGB4.jpg",
tr("Images (*.png *.bmp *.jpg *.tif *.GIF )"));
//四个参数说明
//1、第一个参数parent,用于指定父组件
//2、第二个参数caption,是对话框的标题
//3、dir,是对话框显示时默认打开的目录
//4、filter,是对话框的后缀名过滤器,比如我们使用"Image Files(*.jpg *.png)"就让它只能显示后缀名是jpg或者png的文件。
//4、如果需要使用多个过滤器,使用";;"分割,比如"JPEG Files(*.jpg);;PNG Files(*.png)";
if(!fileName.isEmpty())
{
QImage* img=new QImage;
if(! ( img->load(fileName) ) )
{ //加载图像
QMessageBox::information(this,tr("打开图像失败"),tr("打开图像失败!"));
delete img;
}
//将所得路径保存到图片管理栈中的路径
string s1 =fileName.toStdString();
imgManage.giveImage_path(s1);
//显示图片
Mat image=imread(s1,1);
QImage qimage = Mat2QImage(image);
ui->label_4->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_4->size()));
//在文本框中显示图片路径
openPath = QFileInfo(fileName).filePath();
ui->lineEdit->setText(openPath);
}
}
//保存图像
void MainWindow::on_pushButton_10_clicked()
{
//判断管理栈是否为空
if(!(imgManage.imageStack.empty()))
{ //保存文件对话框API函数:getSaveFileName
QString filename1 = QFileDialog::getSaveFileName(this, tr("保存图像"), "", tr("Images (*.png *.bmp *.jpg *jpeg *GIF)"));
//获取保存的图像的指针
QScreen *screen = QGuiApplication::primaryScreen();
//得到图像
screen->grabWindow(ui->label_6->winId()).save(filename1);
}
else
{
int ret = QMessageBox::information(this,QObject::tr("提示"),
QObject::tr("没有可保存的图像,请重新确认"),QMessageBox::Ok);
if(ret == QMessageBox::Ok)
qDebug()<imgManage.imageStack.empty())
{
int ret = QMessageBox::critical(this,QObject::tr("误操作提示"),QObject::tr("没有可撤销的操作,请操作后再撤消!"),QMessageBox::YesAll);
if(ret == QMessageBox::YesAll)
{
qDebug()<imgManage.undoImage();
//if(this->imgManage.imageStack.size()==0)
if(this->imgManage.imageStack.empty())
{
ui->label_6->setText(" 已无更多操作,恢复至初始状态 ");
}
else
{
QImage qimage=Mat2QImage(img);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
}
}
//直方图均衡化增强
void MainWindow::on_pushButton_5_clicked()
{
HistogramEq hist = HistogramEq(imgManage.imagePath);
cv::Mat run=hist.runMethod();
this->imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
//拉普拉斯算子局部增强
void MainWindow::on_pushButton_4_clicked()
{
LaplaeOperator la = LaplaeOperator(imgManage.imagePath);
cv::Mat run = la.runMethod();
this->imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
//gamma变换
void MainWindow::on_pushButton_3_clicked()
{
bool ok;
double value1= QInputDialog::getDouble(this,QObject::tr("输入参数"),QObject::tr("输入参数gamma:0~10之间的数值"),
0.5,0,10,1,&ok);
//四个数字分别是初始显示数,起始数,终止数,保留小数位数
if(ok)
{
qDebug()<<"value1:"<imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
}
//对数变换
void MainWindow::on_pushButton_2_clicked()
{
bool ok;
int value2= float(QInputDialog::getInt(this,QObject::tr("对数变换:s=c*log(1+r)"),QObject::tr("输入参数c:-10~10之间的数值"),
1,-10,10,1,&ok));
//四个数字分别是初始显示数,起始数,终止数,保留小数位数
if(ok)
{
qDebug()<<"value2:"<imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
}
//彩色图像转换为灰度图像
void MainWindow::on_pushButton_6_clicked()
{
Transform img = Transform(imgManage.imagePath);
cv::Mat run = img.RGB_to_Gray();
this->imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
//线性灰度变换
void MainWindow::on_pushButton_clicked()
{
bool ok1,ok2;
double value1= QInputDialog::getDouble(this,QObject::tr("线性灰度变换"),QObject::tr("输入参数k:-10~10之间的数值"),
1,-10,10,1,&ok1);
//四个数字分别是初始显示数,起始数,终止数,保留小数位数
int value2= QInputDialog::getInt(this,QObject::tr("线性灰度变换"),QObject::tr("输入参数b:-20~20之间的数值"),
0,-20,20,1,&ok2);
//线性灰度变换:k>1时,增加图像对比度,整体效果被增强;k=1,通过调整b,实现对图像亮度的调整;
//当0imgManage.imageStack.push(run);
QImage qimage=Mat2QImage(run);
ui->label_6->setPixmap(QPixmap::fromImage(qimage).scaled(ui->label_6->size()));
}
}
//算法简介
void MainWindow::on_pushButton_7_clicked()
{
int ret1 = QMessageBox::information(this,QObject::tr("算法简介"),
QObject::tr("线性灰度变换:k>1时,增加图像对比度;k=1,通过调整b,实现对图像亮度的调整当0
4.6 mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"method.h"
#include"manage.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
namespace Ui { class Widget; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
manage imgManage;
private slots:
void on_pushButton_8_clicked();
void on_pushButton_9_clicked();
void on_pushButton_10_clicked();
void on_pushButton_11_clicked();
void on_pushButton_5_clicked();
void on_pushButton_4_clicked();
void on_pushButton_3_clicked();
void on_pushButton_2_clicked();
void on_pushButton_6_clicked();
void on_pushButton_clicked();
void on_pushButton_7_clicked();
private:
Ui::MainWindow *ui;
};
QImage Mat2QImage(const cv::Mat &mat);
#endif // MAINWINDOW_H
该处使用的url网络请求的数据。
此时实验基于前面实验的学习和OpenCV标准库实现,抽象类的设计运行了C++面向对象编程的核心:封装、继承和多态。将方法抽象成一个method作为父类并设计成模板类,针对Mat数据类型对模板类特化,使其对图像处理进行实现,成员函数runMethod设置为纯虚函数,让其真正的算法子类进行实现,再子类中对于输入变量用private修饰,在外部调用的时候用友元类的方式实现。同时实验中我用到OpenCV库进行图像,使其弹窗、读入图像等都更方便实现,另外第一次接触Qt图形化界面,也是花费了大量时间,相比于JAVA它直接拖动功能功能标签,然后转到槽会自动关系按钮与事件,我们只需要实现行为代码,在制作图像化界面的时候很方便,最后还将主要算法封装成动态库,达到了代码共享的效果。
待改进之处:本次系统只有一个页面,功能单一,而且在读入图像的时候是默认读入彩色图像,不能自己选择图像类型,因此没有将灰度图转为彩色图像的功能;不会制作多级菜单,于是在算法简介功能中是采用弹框的形式,这显然不符合软件设计,可以在将算法简介按钮设置成转换界面按钮,点击跳转到简介页面,根据需要点击相关按钮在页面显示算法的基本内容,而且将算法简介可以从文件读取或链接的形式实现,避免在代码中出现过多文字。
Qt配置OpenCV:(1条消息) Qt配置OpenCV教程,亲测已试过(详细版)_Wi~的博客-CSDN博客_qt配置opencv
创建动态库方法:QT生成动态链接库及调用详细步骤_姗郁的博客-CSDN博客_qt 动态库