IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 36、基于QT+Eigen的数字图像处理算法 -> 正文阅读

[数据结构与算法]36、基于QT+Eigen的数字图像处理算法

准备工作、安装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");
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-16 19:53:24  更:2021-10-16 19:55:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:39:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码