PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换

news2024/11/18 9:28:12

为什么要进行Gamma校正

图像的 gamma 校正是一种图像处理技术,用于调整图像的亮度和对比度,让显示设备显示的亮度和对比度更符合人眼的感知。Gamma 校正主要用于修正显示设备的非线性响应,以及在图像处理中进行色彩校正和图像增强。

以前,大多数监视器是阴极射线管显示器(CRT)。这些显示器有一个物理特性就是两倍的输入电压产生的不是两倍的亮度。输入电压产生约为输入电压的2.2次幂的亮度,这叫做显示器Gamma。

Gamma也叫灰度系数,每种显示设备都有自己的Gamma值,都不相同,有一个公式:设备输出亮度 = 电压的Gamma次幂,任何设备Gamma基本上都不会等于1,等于1是一种理想的线性状态,这种理想状态是:如果电压和亮度都是在0到1的区间,那么多少电压就等于多少亮度。对于CRT,Gamma通常为2.2,因而,输出亮度 = 输入电压的2.2次幂,你可以从本节第二张图中看到Gamma2.2实际显示出来的总会比预期暗,相反Gamma0.45就会比理想预期亮,如果你讲Gamma0.45叠加到Gamma2.2的显示设备上,便会对偏暗的显示效果做到校正,这个简单的思路就是本节的核心

人类所感知的亮度恰好和CRT所显示出来相似的指数关系非常匹配(我猜并不是巧合,可能是物理原因)。为了更好的理解所有含义,请看下面的图片:

第一行是人眼所感知到的正常的灰阶,亮度要增加一倍(比如从0.1到0.2)你才会感觉比原来变亮了一倍(这里的意思是说比如一个东西的亮度0.3,让人感觉它比原来变亮一倍,那么现在这个亮度应该成为0.6,而不是0.4,也就是说人眼感知到的亮度的变化并非线性均匀分布的。问题的关键在于这样的一倍相当于一个亮度级,例如假设0.1、0.2、0.4、0.8是我们定义的四个亮度级别,在0.1和0.2之间人眼只能识别出0.15这个中间级,而虽然0.4到0.8之间的差距更大,这个区间人眼也只能识别出一个颜色)。然而,当我们谈论光的物理亮度,比如光源发射光子的数量的时候,底部(第二行)的灰阶显示出的才是物理世界真实的亮度。如底部的灰阶显示,亮度加倍时返回的也是真实的物理亮度(译注:这里亮度是指光子数量和正相关的亮度,即物理亮度,前面讨论的是人的感知亮度;物理亮度和感知亮度的区别在于,物理亮度基于光子数量,感知亮度基于人的感觉,比如第二个灰阶里亮度0.1的光子数量是0.2的二分之一),但是由于这与我们的眼睛感知亮度不完全一致(对比较暗的颜色变化更敏感),所以它看起来有差异。

因为人眼看到颜色的亮度更倾向于顶部的灰阶,显示器使用的也是一种指数关系(电压的2.2次幂),所以物理亮度通过监视器能够被映射到顶部的非线性亮度;因此看起来效果不错(译注:CRT亮度是是电压的2.2次幂而人眼相当于2次幂,因此CRT这个缺陷正好能满足人的需要)。

显示器的这个非线性映射的确可以让亮度在我们眼中看起来更好,但当渲染图像时,会产生一个问题:我们在应用中配置的亮度和颜色是基于显示器所看到的,这样所有的配置实际上是非线性的亮度/颜色配置。请看下图:

点线代表线性颜色/亮度值(译注:这表示的是理想状态,Gamma为1),实线代表显示器显示的颜色。如果我们把一个点线线性的颜色翻一倍,结果就是这个值的两倍。比如,光的颜色向量L¯=(0.5,0.0,0.0)代表的是暗红色。如果我们在线性空间中把它翻倍,就会变成(1.0,0.0,0.0),就像你在图中看到的那样。然而,由于我们定义的颜色仍然需要输出的显示器上,显示器上显示的实际颜色就会是(0.218,0.0,0.0)(0.218,0.0,0.0)。在这儿问题就出现了:当我们将理想中直线上的那个暗红色翻一倍时,在显示器上实际上亮度翻了4.5倍以上!

直到现在,我们还一直假设我们所有的工作都是在线性空间中进行的(Gamma为1),但最终还是要把所哟的颜色输出到显示器上,所以我们配置的所有颜色和光照变量从物理角度来看都是不正确的,在我们的显示器上很少能够正确地显示。出于这个原因,我们(以及艺术家)通常将光照值设置得比本来更亮一些(由于显示器会将其亮度显示的更暗一些),如果不是这样,在线性空间里计算出来的光照就会不正确。同时,还要记住,监视器所显示出来的图像和线性图像的最小亮度是相同的,它们最大的亮度也是相同的;只是中间亮度部分会被压暗。

因为所有中间亮度都是线性空间计算出来的(计算的时候假设Gamma为1),显示器显以后,实际上都会不正确。当使用更高级的光照算法时,这个问题会变得越来越明显,你可以看看下图

Gamma校正

Gamma校正(Gamma Correction)的思路是在最终的颜色输出上应用显示器Gamma的倒数。回头看前面的Gamma曲线图,会有一个短划线,它是显示器Gamma曲线的翻转曲线。我们在颜色显示到显示器的时候把每个颜色输出都加上这个翻转的Gamma曲线,这样应用了显示器Gamma以后最终的颜色将会变为线性的。我们所得到的中间色调就会更亮,所以虽然监视器使它们变暗,但是我们又将其平衡回来了。

我们来看另一个例子。还是那个暗红色(0.5,0.0,0.0)。在将颜色显示到显示器之前,我们先对颜色应用Gamma校正曲线。线性的颜色显示在显示器上相当于降低了2.22.2次幂的亮度,所以倒数就是1/2.2次幂。Gamma校正后的暗红色就会成为

(0.5,0.0,0.0)^1/2.2=(0.5,0.0,0.0)^0.45=(0.73,0.0,0.0)(0.5,0.0,0.0)^1/2.2=(0.5,0.0,0.0)^0.45=(0.73,0.0,0.0)。

校正后的颜色接着被发送给监视器,最终显示出来的颜色是

(0.73,0.0,0.0)^2.2=(0.5,0.0,0.0)。

你会发现使用了Gamma校正,监视器最终会显示出我们在应用中设置的那种线性的颜色。

2.2通常是是大多数显示设备的大概平均gamma值。基于gamma2.2的颜色空间叫做sRGB颜色空间。每个监视器的gamma曲线都有所不同,但是gamma2.2在大多数监视器上表现都不错。出于这个原因,游戏经常都会为玩家提供改变游戏gamma设置的选项,以适应每个监视器(译注:现在Gamma2.2相当于一个标准,后文中你会看到。但现在你可能会问,前面不是说Gamma2.2看起来不是正好适合人眼么,为何还需要校正。这是因为你在程序中设置的颜色,比如光照都是基于线性Gamma,即Gamma1,所以你理想中的亮度和实际表达出的不一样,如果要表达出你理想中的亮度就要对这个光照进行校正)。

在 gamma 校正中,通过应用一个指数函数来调整图像的像素值,这个指数函数通常被称为 gamma 曲线。Gamma 曲线的形状决定了图像的亮度和对比度的变化程度。

一般而言,gamma 校正可以分为两种情况:

  1. 增加 gamma 值(大于1):这会使得图像中较暗的部分变得更暗,而较亮的部分变得更亮。这样做可以增强图像的对比度,使得细节更加清晰。这种调整通常称为对比度增强。

  2. 减小 gamma 值(小于1):这会使得图像中较亮的部分变得更暗,而较暗的部分变得更亮。这样做可以降低图像的对比度,使得图像更柔和。这种调整通常称为图像的色彩校正。

Gamma校正的算法

Gamma 校正是通过应用一个指数函数来调整图像的像素值,即将图像中的每个像素值 映射到一个新值

这里的 I 是原始的像素值, γ 是所谓的 gamma 参数,决定了调整的程度。

伽马变换对图像的修正作用其实就是通过增强低灰度或高灰度的细节实现的, 从下面的伽马曲线可以直观理解:

(生成这个交互式曲线图的python代码在文章的后面有提供)

Gamma 校正的算法步骤如下:

  1. 确定 gamma 值:首先需要确定用于 gamma 校正的 gamma 参数值。通常,gamma 参数取值在 0 到 1 之间会使图像变亮,而取值大于 1 会使图像变暗。

  2. 应用指数变换:对于图像中的每个像素,将原始像素值 应用指数变换得到校正后的像素值 。

  3. 归一化处理:根据需要,对校正后的像素值进行归一化处理,使得调整后的像素值范围在合适的范围内,通常是 0 到 255。

  4. 输出校正后的图像:将处理后的像素值重新组合成一个图像,并输出校正后的图像。

python实现图像的Gamma校正

PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

这段代码使用 OpenCV 读取和处理图像,并使用 Matplotlib 显示图像。它实现了对图像的两种不同的 Gamma 变换(sqrt 和 square),并显示了原始图像以及两种 Gamma 变换后的图像对比。

Matlab实现图像的Gamma校正

PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

这段 MATLAB 代码实现了对图像进行 Gamma 变换的功能,并提供了两种不同类型的 Gamma 变换:sqrt 和 square

  • gamma_correction 函数接受三个参数:
    • image:输入的彩色图像。
    • gamma_type:指定 Gamma 变换的类型,支持 ‘sqrt’ 和 ‘square’ 两种。
    • c:常数系数,用于调节变换后的亮度范围。

该函数首先将输入图像分割成三个通道(蓝色、绿色和红色)。然后根据指定的 Gamma 类型进行 Gamma 变换,计算每个通道的 Gamma 变换后的像素值。最后,将各通道的像素值进行缩放以控制亮度范围,并合并三个通道,返回进行 Gamma 变换后的图像。

  • img_gamma 函数负责读取图像并调用 gamma_correction 函数进行 Gamma 变换。它显示原始图像和两种 Gamma 变换后的彩色图像对比,以直观展示 Gamma 变换的效果。

这段代码的主要功能是通过 Gamma 变换来调整图像的亮度和对比度,从而改善图像的视觉效果。

工程解析

工程层次图

demo18相比,只是多了一个img_gamma的模块,也就是下面这一段代码,在从SDRAM读出来之后,经它处理后再输出hdmi_tx模块。

代码解析

对于FPGA做log运算最好的办法是我们先用matlab或者python把gamma运算的结果计算出来,然后存到FPGA的ROM中,运行时FPGA从ROM中查表获取c*f(r)运算的结果即可。

这个工程的算法流程就是一个查表操作,img_gamma.v代码中的注释也很详细,请不一一解释了。

代码中我们提供了GAMMA_SQUARE和GAMMA_SQRT两个gamm计算方法,它们分别表示什么含义呢?

GAMMA_SQUARE 和 GAMMA_SQRT 是两种不同的 Gamma 校正算法的表示。

  • GAMMA_SQUARE 表示使用 Gamma 平方校正算法。在这种算法中,对输入信号的每个分量进行平方操作,以实现 Gamma 校正。
  • GAMMA_SQRT 表示使用 Gamma 平方根校正算法。在这种算法中,对输入信号的每个分量进行平方根操作,以实现 Gamma 校正。

这两种算法的选择会影响最终的图像效果,因为它们在处理输入信号时采用了不同的数学操作。

这两种算法的rom.v如何生成呢?我们提供了matlab代码和python代码。

python版gamma rom生成代码

PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

matlab版代码

PotatoPie 4.0 实验教程(23) —— FPGA实现摄像头图像伽马(Gamma)变换-Anlogic-安路论坛-FPGA CPLD-ChipDebug

这段 MATLAB 代码完成了以下功能:

  1. 定义了灰度级数目和灰度级数组。
  2. 计算了使用平方根算法和平方算法的伽马变换后的灰度值。
  3. 将伽马变换后的灰度值写入了 COE 文件中,用于 Verilog 仿真。
  4. 生成了伽马变换的 Verilog 源文件,其中包含模块定义、端口声明和组合逻辑。
  5. 绘制了原始灰度级和两种伽马变换方式的输出灰度级的图像。

管脚约束

与PotatoPie 4.0 实验教程(18) —— FPGA实现OV5640摄像头采集以SDRAM作为显存进行HDMI输出显示相同,不作赘述。

时序约束

与PotatoPie 4.0 实验教程(18) —— FPGA实现OV5640摄像头采集以SDRAM作为显存进行HDMI输出显示相同,不作赘述。

实验结果

由于rgb用的同一个gamma,导致画面偏紫,大家可以自行调整参数生成不同的gamma表。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1629833.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JAVA 中间件之 Mycat2

Mycat2应用与实战教程 1.Mycat2概述 1.1 什么是MyCat 官网: http://mycatone.top/ Mycat 是基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和…

1. 房屋租赁管理系统(基于springboot/vue的Java项目)

1.此系统的受众 1.1 在校学习的学生,可用于日常学习使用或是毕业设计使用 1.2 毕业一到两年的开发人员,用于锻炼自己的独立功能模块设计能力,增强代码编写能力。 1.3 亦可以部署为商化项目使用。 2. 技术栈 jdk8springbootvue2mysq5.7&8…

C++ 动态链接库DLL创建及使用

一、动态链接库DLL创建 使用VS2022 创建 1、创建新解决方案 创建即可 2、创建动态链接库新项目 右键解决方案 语言选择C,选择动态链接库 填入项目名称,勾选:将解决方案和项目放在同一目录中 点击创建 3、创建后,显示dllmai…

西湖大学赵世钰老师【强化学习的数学原理】学习笔记2节

强化学习的数学原理是由西湖大学赵世钰老师带来的关于RL理论方面的详细课程,本课程深入浅出地介绍了RL的基础原理,前置技能只需要基础的编程能力、概率论以及一部分的高等数学,你听完之后会在大脑里面清晰的勾勒出RL公式推导链条中的每一个部…

使用frp实现内网穿透教程

文章目录 简介frp 是什么?为什么选择 frp? 概念工作原理代理类型 内网穿透教程服务端安装和配置本地Windows(客户端)安装和配置本地Linux虚拟机(客户端)安装和配置使用 systemd 管理服务端注意事项 简介 f…

Odoo:全球排名第一的免费开源PLM管理系统介绍

概述 利用开源智造OdooPLM产品生命周期管理应用,重塑创新 实现产品生命周期管理数字化,高效定义、开发、交付和管理创新的可持续产品,拥抱数字化供应链。 通过开源智造基于Odoo开源技术平台打造数字化的产品生命周期管理(PLM&am…

MongoDB的安装(Linux环境)

登录到Linux服务器执行 lsb_release -a ,即可得知服务器的版本信息为:CentOS 7。 # CentOS安装lsb_release包 [rootlinux100 ~]# sudo yum install redhat-lsb# 查看Linux版本 [rootlinux100 ~]# lsb_release -a LSB Version: :core-4.1-amd64:core-…

redis7 for windows的安装教程

本篇博客主要介绍redis7的windows版本下的安装教程 1.redis介绍 Redis(Remote Dictionary Server)是一个开源的,基于内存的数据结构存储系统,可用作数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希表、列…

Django中的事务

1 开启全局的事务 DATABASES {default: {ENGINE: django.db.backends.mysql, # 使用mysql数据库NAME: tracerbackend, # 要连接的数据库USER: root, # 链接数据库的用于名PASSWORD: 123456, # 链接数据库的用于名HOST: 192.168.1.200, # mysql服务监听的ipPORT: 3306, …

四、OSPF域间路由

注:区域(area)是以接口进行划分的 描述: R1的g0/0/1接口属于area 0 √ R1属于区域0和区域1 1.设计原则 1、OSPF区域的设计原则: 骨干区域有且只能存在一个 非骨干区域必须和骨干区域相连 多区域时&#…

【Linux实践室】Linux文件打包和解压缩实战指南:tar打包命令操作详解(文末送书)

🌈个人主页:聆风吟_ 🔥系列专栏:Linux实践室、网络奇遇记 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 一. ⛳️任务描述二. ⛳️相关知识2.1 🔔打包2.1.1 👻知识点讲解2.1.2 &…

CTFHub Web 信息泄漏(一)

目录遍历 打开题目 点击开始寻找flag 发现在flag_in_here页面中有四个文件夹 点击打开第一个文件夹 发现里面还有四个文件夹 再次点击打开第一个文件夹 里面什么都没有 尝试对所有文件夹依次都点击打开 在2/4中发现flag.txt 点击打开即可得到flag 不太懂这题的难点&#…

碎碎念,最近做了几款小产品...

极简番茄时钟 一款 Mac 版「极简番茄时钟」软件。 知识卡片制作工具 主打简单,同时支持 Markdown 语法。 智能微信助手 让管理变得轻松,沟通更加高效。 感兴趣,欢迎来这里一起交流,限时免费 ~

揭示C++设计模式中的实现结构及应用——行为型设计模式

简介 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。 行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。 通过行为型模式,可以更加清晰地划分类与对象的职责,并…

(学习日记)2024.04.29:UCOSIII第五十三节:User文件夹函数概览(uC-LIB文件夹)第三部分

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

python升级打怪(3)

条件语句,如果if否则else还有一个elif 另外一个搭配是if if else,在Python当中缩进很重要,4个空格或者一个tab。看到缩进你就能知道他跟谁是同一级别的,然后这个:表示的是条件结束。在Python中负数%2它是大于等于1的,…

如何替代传统的方式,提高能源企业敏感文件传输的安全性?

能源行业是一个关键的基础设施领域,它涉及能源的勘探、开采、生产、转换、分配和消费。随着全球经济的发展和人口的增长,能源需求持续上升,这对能源行业的可持续发展提出了挑战。能源行业的传输场景多种多样,需要重点关注能源企业…

语音导航系统:盲人出行的新领航者,实时避障让每一步都安心

在这个日益智能化的社会,一款名为蝙蝠避障专为盲人设计的辅助应用正以其创新的语音导航系统悄然改变着视障群体的出行方式。这款应用凭借其强大的实时避障功能,成为了盲人朋友探索世界的可靠伙伴,让每一次外出都充满了信心与自由。 语…

AMBA-CHI协议详解(二)

《AMBA 5 CHI Architecture Specification》 文章目录 2.1 Channels综述2.2 Channel域段2.2.1 request fields2.2.2 Response fields2.2.3 Snoop request fields2.2.4 Data fields 2.3 事务结构2.3.1 Read transactions2.3.1.1 Allocating Read2.3.1.2 Non-allocating Read 2.…

go稀疏数组

稀疏数组 稀疏数组 稀疏数组 package testimport ("encoding/json""fmt""io/ioutil""log""reflect""testing" )type ValNode struct {Row int json:"row"Col int json:"col"Val int json:&qu…