准备工作、安装Eigen矩阵库
0.1 下载Eigen源码
?0.2 解压并赋值到QT安装目录
?0.3 新建一个QT工程,并在.pro文件里添加Eigen目录
INCLUDEPATH += D:\Software\QT5.9.9\eigen-3.4.0
0.4 工程包含的头文件
#include <iostream>
#include <QWidget>
#include <QDebug>
#include <QImage>
#include <QPainter>
#include <QFileDialog>
#include <QMessageBox>
#include <QtCore/qmath.h>
#include <Eigen/Dense> //引入Eigen库
0.5 创建一个按钮用来加载某一目录下的图片
void imageWidget::on_OpenButton_clicked() //打开图片
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "../", tr("Images (*.jpg *.bmp *.tif)"));
if(fileName != NULL){
qDebug()<<fileName<<endl;
imgx1 = new QImage(fileName); //QImage *imgx1;放在类的public属性下
this->update();
}
}
一、伽马变换
也叫幂指数变换=>拉伸灰度值,适合图像整体像素偏向一边的灰度图
void imageWidget::on_GammaButton_clicked() //伽马变换
{
if(imgx1 == nullptr){
QMessageBox::warning(NULL,"提示","请先导入原图\r\n");
return;
}
imgx2 = new QImage();*imgx2 = *imgx1; //拷贝图片到imgx2
if(imgx2->format()!=QImage::Format_Grayscale8) //不是灰度图的转为灰度图
{
qDebug()<<"原图像格式!=QImage::Format_Grayscale8";
qDebug()<<"正在转换图像格式...";
*imgx2 = imgx2->convertToFormat(QImage::Format_Grayscale8);
qDebug()<<"转换后图片尺寸="<<imgx2->rect();
qDebug()<<"转换后图片格式="<<imgx2->format();
}
int imageWidth = imgx2->width(),imageHeight = imgx2->height(); //获取图片尺寸
//从comboBox获取伽马变换的两个参数
float c_x = (ui->comboBox_2->currentIndex()+1)*1.0/10.0;
float r_x = (ui->comboBox_3->currentIndex()+1)*1.0/10.0;
qDebug()<<"c_x="<<c_x<<","<<"r_x="<<r_x;
for(int j=0;j<imageHeight;j++){//横着扫描图片每个像素
uchar *pDest = (uchar *)imgx2->scanLine(j);
for(int i=0;i<imageWidth;i++)
{
pDest[i]= c_x * qPow(pDest[i]*1.0/255.0,r_x) * 255.0;
}
}
this->update();
}
二、直方图均衡
根据直方图让像素均匀的分布在0-255之间
?
void imageWidget::on_pushButton_6_clicked()//直方图均衡化
{
if(imgx1 == nullptr){
QMessageBox::warning(NULL,"提示","请先导入原图\r\n");
return;
}
imgx2 = new QImage();*imgx2 = *imgx1;
if(imgx2->format()!=QImage::Format_Grayscale8)
{
qDebug()<<"原图像格式!=QImage::Format_Grayscale8";
qDebug()<<"正在转换图像格式...";
*imgx2 = imgx2->convertToFormat(QImage::Format_Grayscale8);
qDebug()<<"转换后图片尺寸="<<imgx2->rect();
qDebug()<<"转换后图片格式="<<imgx2->format();
}
int imageWidth = imgx2->width(),imageHeight = imgx2->height();
float MN = imageWidth*imageHeight;
float L_1 = 255.0;
//一、求n(k)->统计得到直方图(纵坐标为概率)
float Nk[256]={0};
for(int j=0;j<imageHeight;j++){//横扫
uchar *pDest = (uchar *)imgx2->scanLine(j);
for(int i=0;i<imageWidth;i++)
{
Nk[pDest[i]]++;
}
}
for(int i = 0;i<256;i++)
{
Nk[i]/=MN;
}
//二、求s(k)->得到均衡化的直方图
float Sk[256]={0};
for(int i = 0;i<256;i++)
{
for(int j = 0;j<i; j++)
{
Sk[i] += (Nk[j]*L_1);
}
}
for(int i = 0;i<256;i++)
{
Sk[i]=(int)(Sk[i]+0.5f);
}
//三、根据直方图设置像素值
for(int j=0;j<imageHeight;j++){//横扫
ui->progressBar->setValue(0.5f+(j/(imageHeight*1.00))*100);
uchar *pDest = (uchar *)imgx2->scanLine(j);
for(int i=0;i<imageWidth;i++)
{
pDest[i] = Sk[pDest[i]];
}
}
this->update();
}
三、空间域=>算子滤波模板
例程是3*3模板,可修改tmpSize适配5*5模板
void imageWidget::on_pushButton_2_clicked()
{
if(imgx1 == nullptr||imgx2 == nullptr){
QMessageBox::warning(NULL,"提示","请先导入原图\r\n");
return;
}
imgx2 = new QImage();*imgx2 = *imgx1;qDebug()<<"直接操作模式";
if(imgx2->format()!=QImage::Format_Grayscale8)
{
qDebug()<<"原图像格式!=QImage::Format_Grayscale8";
qDebug()<<"正在转换图像格式...";
*imgx2 = imgx2->convertToFormat(QImage::Format_Grayscale8);
qDebug()<<"转换后图片尺寸="<<imgx2->rect();
qDebug()<<"转换后图片格式="<<imgx2->format();
}
//边缘模式
if(ui->comboBox->currentText()=="边缘补零") edgeMode = 0;
else if(ui->comboBox->currentText()=="边缘复制") edgeMode = 1;
else if(ui->comboBox->currentText()=="边缘限制") edgeMode = 2;
else {qDebug()<<"边缘参数错误";return;}
//获取图像尺寸
int tmpSize = 3; //模板深度
int imageWidth = imgx2->width(),imageHeight = imgx2->height();
//存储原始数据
Eigen::MatrixXf Image_Source(imageHeight,imageWidth);
for(int i=0;i<imageHeight;i++){
uchar *pDest = (uchar *)imgx2->scanLine(i);
for(int j=0;j<imageWidth;j++){ //i->纵,j->横
Image_Source(i,j)=pDest[j]; //m(纵,横)
}
}
//存储算子结果->(结果可能超越0-255,存储结果用于最终标定范围)
Eigen::MatrixXf Image_Result(imageHeight,imageWidth);
//创建一个空域算子
Eigen::MatrixXf Operator_Matrix(tmpSize,tmpSize);
Operator_Matrix<<ui->spinBox00->value(),ui->spinBox01->value(),ui->spinBox02->value(),
ui->spinBox10->value(),ui->spinBox11->value(),ui->spinBox12->value(),
ui->spinBox20->value(),ui->spinBox21->value(),ui->spinBox22->value();
std::cout<<Operator_Matrix<<std::endl;
//创建一个算子计算缓存
Eigen::MatrixXf Operator_Buffer(tmpSize,tmpSize);
Operator_Buffer<<+0.00,+0.00,+0.00,
+0.00,+0.00,+0.00,
+0.00,+0.00,+0.00;
//对原始图像进行算子计算
for(int i=0;i<imageHeight;i++){
ui->progressBar->setValue(0.5f+(i/(imageHeight*1.00))*100);
for(int j=0;j<imageWidth;j++) //i->纵,j->横
{
float tmpBufferSum = 0.00;//存储单个像素算子计算和
for(int y=0;y<tmpSize;y++)//对当前像素进行算子计算
for(int x=0;x<tmpSize;x++) //x->横,y->纵
{
//计算偏移坐标
int m_x = j-(tmpSize/2-x),m_y=i-(tmpSize/2-y);
switch (edgeMode) {
case 0 : //边缘补零处理
{
if (m_x >= 0 && m_x < imageWidth && m_y >= 0 && m_y < imageHeight)
Operator_Buffer(y,x) = Operator_Matrix(y,x)*Image_Source(m_y,m_x);
else
Operator_Buffer(y,x) = 0;
}
break;
case 1 : //边缘复制处理
{
if(m_x>imageWidth - 1) m_x=m_x-tmpSize/2;
else if(m_x<0) m_x=m_x+tmpSize/2;
if(m_y>imageHeight-1) m_y=m_y-tmpSize/2;
else if(m_y<0) m_y=m_y+tmpSize/2;
Operator_Buffer(y,x) = Operator_Matrix(y,x)*Image_Source(m_y,m_x);
}
case 2 : //边缘限制处理
{
if (i >= tmpSize/2 && i < imageWidth-tmpSize/2 && j >= tmpSize/2 && j < imageHeight-tmpSize/2)
Operator_Buffer(y,x) = Operator_Matrix(y,x)*Image_Source(y,x);
else
Operator_Buffer(y,x) = Image_Source(i,j)/(tmpSize*tmpSize*1.00); //如果坐标不合理,像素值不变
}
break;
default:break;
}
tmpBufferSum+=Operator_Buffer(y,x);
}
Image_Result(i,j)=tmpBufferSum;
}
}
//对算子结果进行范围标定(K=255)(fs=K(fm/max(fm)))
float k = 255.00;
float maxf = Image_Result.maxCoeff();
float minf = Image_Result.minCoeff();
float maxfm = maxf - minf;
if(maxfm == 0.00)maxfm+=0.01;
std::cout<<"k="<<k<<","<<"maxf="<<maxf<<","<<"minf="<<minf<<","<<"maxfm="<<maxfm<<std::endl;
for(int i=0;i<imageHeight;i++){
uchar *pDest = (uchar *)imgx2->scanLine(i);
for(int j=0;j<imageWidth;j++) //i->纵,j->横
{
pDest[j] = k*(Image_Result(i,j) - minf)/maxfm;
}
}
this->update();
QMessageBox::warning(NULL,"提示","滤波成功\r\n");
}
|