[OpenCV学习笔记]Qt+OpenCV实现图像灰度反转、对数变换和伽马变换
目录
- 1、介绍
- 1.1 灰度反转
- 1.2 图像对数变换
- 1.3 图像伽马变换
- 2、效果图
- 3、代码实现
- 4、源码展示
1、介绍
1.1 灰度反转
灰度反转是一种线性变换,是将某个范围的灰度值映射到另一个范围内,一般是通过灰度的对调,突出想要查看的灰度区间。
S = L − 1 − r ( r ⊂ [ 0 , L − 1 ] ) S = L -1-r (r \subset [0,L-1]) S=L−1−r(r⊂[0,L−1])
比如在以下胸片图像中提取白色絮状形状,在黑色背景下看的不太明显,就可以使用灰度反转增强图像的可视化效果。
output_img = input_img.clone();
for(int i = 0; i < input_img.rows; i++)
{for(int j = 0; j < input_img.cols; j++){output_img.at<uchar>(i, j) = 255 - input_img.at<uchar>(i, j)}
}
1.2 图像对数变换
对数变换可以将图像中低灰度值的部分进行提升,显示出低灰度部分的特征,对高灰度值部分进行抑制,减少高灰度值部分的细节,从而实现增项图像俺不细节,优化图像的对比度。
S = c log ( 1 + r ) S=c\log(1+r) S=clog(1+r)
其原理就是,对数曲线在像素值低的区域斜率大,在像素值高的地方斜率小。
对数变换后图像的灰度值可能会超出0~255的区间,所以在对数变换后要进行归一化处理,将图像灰度值调节回0-255的区间。
Mat LogarithmImg = grayImg.clone();for(int i=0;i<grayImg.rows;i++){for(int j=0;j<grayImg.cols;j++){LogarithmImg.at<uchar>(i,j) = 6*log((double)grayImg.at<uchar>(i,j) + 1);}}normalize(LogarithmImg, LogarithmImg, 0, 255,NORM_MINMAX);convertScaleAbs(LogarithmImg,LogarithmImg);
1.3 图像伽马变换
图像的伽马变换其实就是通过非线性变换将图像中较暗区域的灰度值进行增强,对较亮区域的灰度值进行抑制,从而获得图像比较好的细节特征。
s = c r γ ( r ∈ [ 0 , 1 ] ) s=cr^\gamma (r\in[0, 1]) s=crγ(r∈[0,1])
r为灰度的输入值,c为灰度缩放系数,伽马因子控制整个变换的缩放程度。
Mat gammaImg = grayImg.clone();for(int i=0;i<grayImg.rows;i++){for(int j=0;j<grayImg.cols;j++){gammaImg.at<uchar>(i,j) = 6*pow((double)grayImg.at<uchar>(i,j), 0.5);}}normalize(gammaImg, gammaImg, 0, 255,NORM_MINMAX);convertScaleAbs(gammaImg,gammaImg);
2、效果图
使用lena图进行灰度反转、对数变换、伽马变化测试,在Qt上实现加载和变换。
3、代码实现
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "opencv2/opencv.hpp"
#include <QResizeEvent>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEusing namespace cv;
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_btn_loadPic_clicked();void on_btn_InversionTrans_clicked();void on_btn_logarithmTrans_clicked();void on_btn_gammaTrans_clicked();void on_btn_resetPic_clicked();private:Ui::Widget *ui;// 灰度图像Mat grayImg;// Mat图像类型转换为QImageQImage cvMat2QImage(const cv::Mat &mat);
};
#endif // WIDGET_H
widget.cpp
#pragma execution_character_set("utf-8")
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);this->setWindowTitle("OpenCV图像变换");
}Widget::~Widget()
{delete ui;
}void Widget::on_btn_loadPic_clicked()
{Mat Img = imread("lena.png");cvtColor(Img, grayImg, COLOR_BGR2GRAY);QImage qImg_Gray = cvMat2QImage(grayImg);ui->lbl_grayPic->setPixmap(QPixmap::fromImage(qImg_Gray.scaled(ui->lbl_grayPic->size())));
}void Widget::on_btn_InversionTrans_clicked()
{Mat InversionImg = grayImg.clone();for(int i=0;i<grayImg.rows;i++){for(int j=0;j<grayImg.cols;j++){InversionImg.at<uchar>(i,j) = 255 - grayImg.at<uchar>(i,j);}}QImage qImg_Inversion = cvMat2QImage(InversionImg);ui->lbl_InversionPic->setPixmap(QPixmap::fromImage(qImg_Inversion.scaled(ui->lbl_InversionPic->size())));
}void Widget::on_btn_logarithmTrans_clicked()
{Mat LogarithmImg = grayImg.clone();for(int i=0;i<grayImg.rows;i++){for(int j=0;j<grayImg.cols;j++){LogarithmImg.at<uchar>(i,j) = 6*log((double)grayImg.at<uchar>(i,j) + 1);}}normalize(LogarithmImg, LogarithmImg, 0, 255,NORM_MINMAX);convertScaleAbs(LogarithmImg,LogarithmImg);QImage qImg_Logarithm = cvMat2QImage(LogarithmImg);ui->lbl_LogPic->setPixmap(QPixmap::fromImage(qImg_Logarithm.scaled(ui->lbl_LogPic->size())));
}void Widget::on_btn_gammaTrans_clicked()
{Mat gammaImg = grayImg.clone();for(int i=0;i<grayImg.rows;i++){for(int j=0;j<grayImg.cols;j++){gammaImg.at<uchar>(i,j) = 6*pow((double)grayImg.at<uchar>(i,j), 0.5);}}normalize(gammaImg, gammaImg, 0, 255,NORM_MINMAX);convertScaleAbs(gammaImg,gammaImg);QImage qImg_Gamma = cvMat2QImage(gammaImg);ui->lbl_GammaPic->setPixmap(QPixmap::fromImage(qImg_Gamma.scaled(ui->lbl_GammaPic->size())));
}void Widget::on_btn_resetPic_clicked()
{ui->lbl_grayPic->clear();ui->lbl_InversionPic->clear();ui->lbl_LogPic->clear();ui->lbl_GammaPic->clear();
}QImage Widget::cvMat2QImage(const cv::Mat &mat)
{switch ( mat.type() ){// 8-bit 4 channelcase CV_8UC4:{QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB32 );return image;}// 8-bit 3 channelcase CV_8UC3:{QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_RGB888 );return image.rgbSwapped();}// 8-bit 1 channelcase CV_8UC1:{static QVector<QRgb> sColorTable;// only create our color table onceif ( sColorTable.isEmpty() ){sColorTable.resize( 256 );for ( int i = 0; i < 256; ++i ){sColorTable[i] = qRgb( i, i, i );}}QImage image( (const uchar*)mat.data, mat.cols, mat.rows, static_cast<int>(mat.step), QImage::Format_Indexed8 );image.setColorTable( sColorTable );return image;}default:qDebug("Image format is not supported: depth=%d and %d channels\n", mat.depth(), mat.channels());qWarning() << "cvMatToQImage - cv::Mat image type not handled in switch:" << mat.type();break;}return QImage();
}
4、源码展示
本小例程的代码放到我的开源gitte项目里,欢迎一起学习交流,也希望能收获你的小星星。
项目源码GrayTrans
相关文章:

[OpenCV学习笔记]Qt+OpenCV实现图像灰度反转、对数变换和伽马变换
目录 1、介绍1.1 灰度反转1.2 图像对数变换1.3 图像伽马变换 2、效果图3、代码实现4、源码展示 1、介绍 1.1 灰度反转 灰度反转是一种线性变换,是将某个范围的灰度值映射到另一个范围内,一般是通过灰度的对调,突出想要查看的灰度区间。 S …...

【大数据】Flink学习笔记
文章目录 认识FlinkDocker安装Flink基本概念Flink的特点Flink 和 Spark Streaming 对比 基本使用WordCount实现依赖 批模式代码流模式代码网络流模式代码在web UI上提交代码创建项目[^1]编写代码配置打包在Web UI上提交 Flink 架构系统架构核心概念并行度算子链(Opeartor Chain…...

社交网络的未来:Facebook如何塑造数字社交的下一章
引言 社交网络已成为我们生活中不可或缺的一部分,而Facebook作为其领军者,一直在塑造着数字社交的未来。本文将深入探讨Facebook在未来如何塑造数字社交的下一章,并对社交网络的发展趋势进行展望和分析。 1. 引领虚拟社交的潮流 Facebook将…...

RabbitMQ 延时消息实现
1. 实现方式 1. 设置队列过期时间:延迟队列消息过期 死信队列,所有消息过期时间一致 2. 设置消息的过期时间:此种方式下有缺陷,MQ只会判断队列第一条消息是否过期,会导致消息的阻塞需要额外安装 rabbitmq_delayed_me…...

【Django】枚举类型数据
模型 在模型里主要增加两项内容: 枚举表字段增加choices class Snort(CoreModel):PAGE_TYPE_CHOICES [(1, 失陷主机检测), # 1是保存到数据库里的数据,失陷主机检测是显示在前端的(2, 远程漏洞攻击检测),(3, 可疑流量行为),(4, WEB检测),]page_type…...

java实现https连接总是要报no cipher suites in common
遇到“no cipher suites in common”这样的错误通常意味着客户端和服务器之间没有共同支持的加密套件(Cipher Suite)。这个问题可能由多个原因引起,包括但不限于SSL/TLS配置错误、Java安全策略限制、客户端或服务器不支持的加密算法等。解决这…...

[C++初阶] 爱上C++ : 与C++的第一次约会
🔥个人主页:guoguoqiang 🔥专栏:我与C的爱恋 本篇内容带大家浅浅的了解一下C中的命名空间。 在c中,名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象等等。工程越大,名称…...

STM32技术打造:智能考勤打卡系统 | 刷卡式上下班签到自动化解决方案
文章目录 一、简易刷卡式打卡考勤系统(一)功能简介原理图设计程序设计 哔哩哔哩: https://www.bilibili.com/video/BV1NZ421Y79W/?spm_id_from333.999.0.0&vd_sourcee5082ef80535e952b2a4301746491be0 一、简易刷卡式打卡考勤系统 &…...

module ‘numpy‘ has no attribute ‘int‘
在 NumPy 中,如果遇到了错误提示 "module numpy has no attribute int",这通常意味着正在尝试以错误的方式使用 NumPy 的整数类型。从 NumPy 1.20 版本开始,numpy.int 已经不再是一个有效的属性,因为 NumPy 不再推荐使用…...

MFC(一)搭建空项目
安装MFC支持库 创建空白桌面程序 项目相关设置 复制以下代码 // mfc.h #pragma once #include <afxwin.h>class MyApp : public CWinApp { public:virtual BOOL InitInstance(); };class MyFrame : public CFrameWnd { public:MyFrame();// 消息映射机制DECLARE_…...

OKCC的API资源管理平台怎么用?
API资源管理平台,重点是“资源”管理平台,不是API接口管理平台。 天天讯通推出的API资源管理平台,类似昆石的VOS系统,区别是VOS是SIP资源管理系统,我们的API资源管理平台是API资源管理系统(AXB、AX、回拨AP…...

CentOS 7 安装python 3.7 需要必要的依赖。
在 CentOS 7 上部署 Python 3.7 可以通过源代码编译安装来实现。以下是大致的步骤: 安装必要的依赖: bashCopy Code sudo yum install gcc openssl-devel bzip2-devel libffi-devel 下载 Python 3.7 源代码并进行编译安装: bashCopy Code wg…...

美术馆设计方案优化布局与设施提升观众体验!
如今,美术馆不仅仅是作为展示艺术作品的平台,也是吸引公众参与和创造独特体验的数字艺术体验空间,因此许多传统美术馆在进行翻修改造时,都会更加注重用户体验,并在其中使用大量的多媒体互动,让参观者能够在…...

数据库基础原理
宏观 数据库的实现原理分为四个部分: 网络通信 网络协议 硬盘存储 内存分配 微观 硬盘存储 数据库是持久化的,而持久化如何实现的,我们不难想到磁盘可以持久化存储,所以数据库所有持久化的数据都是以文件形式存在磁盘中的…...

Pandas操作MultiIndex合并行列的Excel,写入读取以及写入多余行及Index列处理,插入行,修改某个单元格的值,多字段排序
Pandas操作MultiIndex合并行列的excel,写入读取以及写入多余行及Index列处理,多字段排序尽量保持原来的顺序 1. 效果图及问题2. 源码参考 今天是谁写Pandas的 复合索引MultiIndex,写的糊糊涂涂,晕晕乎乎。 是我呀… 记录下&#…...

工作总结5
1.taro框架使用map标签出现的错误 这个问题困扰很长时间,在频繁切换页面渲染的时候出现左边不显示,我理解的是变量没有到达map标签的属性上,那我就想是不是setState太慢了,然后又用了变量,本地缓存等,都没有…...

速通汇编(二)汇编mov、addsub指令
一,mov指令 mov指令的全称是move,从字面上去理解,作用是移动(比较确切的说是复制)数据,mov指令可以有以下几种形式 无论哪种形式,都是把右边的值移动到左边 mov 寄存器,数据&#…...

软考 - 系统架构设计师 - 构件组装技术
概念 构件组装是将库中的构件经修改后相互连接,或者将它们和当前开发项目中的软件元素进行连接,最终构成新的目标构件。 构件组装技术是基于构件的软件开发的核心技术,也是构件技术研究的重点和难点。构件组装的目的是利用现有的构件组装成新…...

2010年之前电脑ubuntu安装nvidia驱动黑屏处理
装好驱动 仿真fps直接到60Hz 陈旧设备 都是非常老旧的电脑,没钱换新电脑,就这么穷…… 电脑详细配置: 冲动 想装显卡驱动提升一下性能,结果……黑了 黑习惯了也无所谓,几分钟就能解决,关键还是太穷&…...

类与对象中C++
加油!!! 文章目录 前言 一、类的6个默认成员函数 编辑 二、构造函数 1.概念 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 拷贝构造函数典型调用场景 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 赋值运算符重载格式…...

k8s 集群重启报错:The connection to the server 192.168.92.26:6443 was refused
[rootk8s-master ~]# kubectl get node The connection to the server 192.168.92.26:6443 was refused - did you specify the right host or port?查到是kubelet进程没有启动 [rootk8s-master ~]# systemctl status kubelet ● kubelet.service - kubelet: The Kubernetes …...

国内好用的chatGPT和AI绘图工具
分享一个比较好用的AI 分享一个比较好用的AI,只是需要开通会员,目前官网的价格是:298,开通之后可以使用chatgpt4、AI绘画、图片融合等等!不开通的话是可以免费使用15次的,下面是一些介绍图片!链…...

蚂蚁庄园3.31今日答案春季美食“雷竹笋”之所以得名是因为出笋与打雷有关吗?
蚂蚁庄园是一款爱心公益游戏,用户可以通过喂养小鸡,产生鸡蛋,并通过捐赠鸡蛋参与公益项目。用户每日完成答题就可以领取鸡饲料,使用鸡饲料喂鸡之后,会可以获得鸡蛋,可以通过鸡蛋来进行爱心捐赠。其中&#…...

零基础入门转录组数据分析——绘制差异火山图
零基础入门转录组数据分析——绘制差异火山图 差异分析的火山图(Volcano Plot)在生物信息学数据分析中,特别是在基因表达差异分析中,是一个非常直观和有用的工具。 本教程将从导入的数据结构开始,一步步带大家在R中绘制好看的火山图,最后对火山图进行解读,确保读者理解…...

C++进阶,手把手带你学继承
🪐🪐🪐欢迎来到程序员餐厅💫💫💫 主厨:邪王真眼 主厨的主页:Chef‘s blog 所属专栏:c大冒险 总有光环在陨落,总有新星在闪烁 【本节目标】 1.继…...

Java自带的线程池及调用、ThreadPoolExecutor类(线程池的7大参数)、任务队列及底层原理
day32 线程池 引入 一个线程完成一项任务所需时间为: 创建线程时间 - Time1线程中执行任务的时间 - Time2销毁线程时间 - Time3 注意:优化在Time1,Time3(创建销毁线程费时间) 为什么需要线程池 线程池技术正是关注如何缩短或调整Time1和Tim…...

ThreadPool-线程池使用及原理
1. 线程池使用方式 示例代码: // 一池N线程 Executors.newFixedThreadPool(int) // 一个任务一个任务执行,一池一线程 Executors.newSingleThreadExecutorO // 线程池根据需求创建线程,可扩容,遇强则强 Executors.newCachedThre…...

高性能服务系列【十一】主题匹配
主题匹配核心算法就是字符串匹配,在字符串匹配基础上,会加入分段匹配需求,类似URL的点分式字符串。这个算法在几个场景中十分普遍。 1、应用层的路由寻址。比如反向代理中,根据请求中的URL,转发到对应的后台服务。 2…...

Vue 2 组件发布到 npm 的常见问题解决
按照 Vue 2 组件打包并发布到 npm 的方法配置项目后,项目在实际开发过程中,随着代码写法的多样性增加而遇到的各种打包问题,本文将予以逐一解决: 本文目录 同时导出多个组件 样式表 import 问题解决 Json 文件 import 问题解决…...

p2p原理
p2p原理 P2P (Peer-to-Peer) 是一种分布式计算和网络架构模型,它允许对等节点之间直接通信和共享资源,而无需通过集中的服务器。P2P 原理的核心概念是平等性(peer equality),即所有节点在网络中都具有相同的功能和能力…...