提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
最近在做HDR图像的课题,这里对HDR图像处理里面的关键技术进行记录和总结
import cv2
# 读取照片
img = cv2.imread('photo.jpg')
# 显示照片
cv2.imshow('Photo', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
import cv2
# 读取照片
img = cv2.imread('photo.hdr',cv2.IMREAD_ANYDEPTH)
cv2.IMREAD_ANYDEPTH参数告诉OpenCV要读取所有像素值,包括高动态范围(HDR)像素值。
除此之外,还可这样读取HDR图像:
import cv2
# 读取照片
img = cv2.imread('photo.hdr',cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
以上两句话在读取HDR图像时是等价的(来自chatgpt)
一般情况下,读取了HDR图像后,需要对其进行归一化等操作(也就是映射到LDR域)。如果不进行归一化等操作,直接使用imshow可能会报错,或者图像一片白,因为HDR图像的单个像素点的亮度值非常高,早就超出了0-255的这个范围,比如如下代码:
import cv2
# 读取照片
img = cv2.imread('gt.hdr',cv2.IMREAD_UNCHANGED)
# 显示照片
cv2.imshow('Photo', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这时候展示出的图像一片白
如果不用opencv,用一些自带色调映射的图像查看编辑器也是可以的,比如我自己用的是2345看图王,可以打开HDR,EXR等文件
这些色调映射方法的提出时间是不同的,大致如下:
Reinhard:2001年
Drago:2003年
Durand:2005年
Mantiuk:2008年
这些方法的提出都是为了解决数字图像处理中的色调映射问题,但是它们的具体实现方式和效果略有不同。在实际应用中,可以根据需要选择适合的色调映射方法。
1)Reinhard
import cv2
# 读取HDR图像
src_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
# 创建Reinhard色调映射对象
Reinhard = cv2.createTonemapReinhard()
# 对HDR图像进行色调映射
dst_img = Reinhard.process(src_img)
# 保存输出图像
cv2.imwrite('Reinhard.jpg', dst_img * 255)
img=cv2.imread('Reinhard.jpg')
cv2.imshow('Reinhard', img)
# 等待按键按下
cv2.waitKey(0)
# 释放窗口
cv2.destroyAllWindows()
2)Drago
import cv2
# 读取HDR图像
src_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
# 创建Reinhard色调映射对象
Drago = cv2.createTonemapDrago()
# 对HDR图像进行色调映射
dst_img = Drago.process(src_img)
# 保存输出图像
cv2.imwrite('Drago.jpg', dst_img * 255)
img=cv2.imread('Drago.jpg')
cv2.imshow('Drago', img)
# 等待按键按下
cv2.waitKey(0)
# 释放窗口
cv2.destroyAllWindows()
3)Durand
import cv2
# 读取HDR图像
src_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
# 创建Reinhard色调映射对象
Durand = cv2.createTonemapDurand()
# 对HDR图像进行色调映射
dst_img = Durand.process(src_img)
# 保存输出图像
cv2.imwrite('Durand.jpg', dst_img * 255)
img=cv2.imread('Durand.jpg')
cv2.imshow('Durand', img)
# 等待按键按下
cv2.waitKey(0)
# 释放窗口
cv2.destroyAllWindows()
4)Mantiuk
import cv2
# 读取HDR图像
src_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
# 创建Reinhard色调映射对象
Mantiuk = cv2.createTonemapMantiuk()
# 对HDR图像进行色调映射
dst_img = Mantiuk.process(src_img)
print(dst_img)
# 保存输出图像
cv2.imwrite('Mantiuk.jpg', dst_img * 255)
img=cv2.imread('Mantiuk.jpg')
cv2.imshow('Mantiuk', img)
# 等待按键按下
cv2.waitKey(0)
# 释放窗口
cv2.destroyAllWindows()
值得注意的是,使用cv2.createToneXXXX函数时,返回的是一个归一化到0-1的numpy数组,所以后续的展示imshow中需要乘上255。当然如果不乘上255也是可以显示的:虽然像素值被归一化到[0,1]的浮点数范围内,但在显示图像时,imshow函数会自动将像素值转换为[0,255]的整数,然后再进行显示。这是因为在显示图像时,需要将像素值映射到显示设备的亮度范围内,而通常情况下,显示设备的亮度范围是[0,255]的整数。因此,即使像素值已经归一化到[0,1]的浮点数范围内,imshow函数仍然可以正常显示图像。
我们来看一下三种算法对比效果(Durand报错了 这里不展示):

从左到右依次为Reinhard Drago Mantiuk
代码如下:
import cv2
import numpy as np
# 加载HDR图像
src_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR)
xianxing = cv2.normalize(src_img, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC3)
# 创建色调映射对象
Reinhard = cv2.createTonemapReinhard()
Drago = cv2.createTonemapDrago()
Mantiuk = cv2.createTonemapMantiuk()
# 对HDR图像进行色调映射
Reinhard_img = Reinhard.process(src_img)
Drago_img = Drago.process(src_img)
Mantiuk_img = Mantiuk.process(src_img)
# 将四幅图像拼接为2×2的矩阵
result = np.hstack((Reinhard_img, Drago_img, Mantiuk_img))
# 显示结果
cv2.imshow('Result', result)
cv2.waitKey()
cv2.destroyAllWindows()
我们再来看看线性映射的结果(强行弄成0-255):

可以看出效果非常不好
代码如下,主要靠的是这句话:ldr_image = cv2.normalize(hdr_image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC3)
import cv2
# 读取HDR图像
hdr_image = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH | cv2.IMREAD_COLOR )
print(hdr_image.shape)
# 转换图像格式
ldr_image = cv2.normalize(hdr_image, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC3)
# 显示图像
cv2.imshow('HDR Image', ldr_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
在目前很多的HDR图像生成的国内硕士论文里,大多提到了这种方法:
μ律本身是用于压缩音频信号动态范围的算法,但是它也可以用于压缩 HDR 图像的动态范围。μ律色调映射公式如下:

其中,
H 表示被归一化到 [0,1] 范围的 HDR 图像,T 表示色调映射后的图像。
这里u的取值论文里都不太一样 ,有些是500,5000
以下是chatgpt生成的代码:
import cv2
import numpy as np
def mu_law_tonemap(hdr_img, mu=5000):
hdr_img = np.float32(hdr_img)
L = np.log(1 + mu * hdr_img) / np.log(1 + mu)
L = np.uint8(L * 255)
return L
# 读取HDR图像
hdr_img = cv2.imread('gt.hdr', cv2.IMREAD_ANYDEPTH|cv2.IMREAD_COLOR)
# 进行μ律色调映射
tonemapped_img = mu_law_tonemap(hdr_img)
# 显示结果
cv2.imshow('HDR Image', hdr_img)
cv2.imshow('Tonemapped Image', tonemapped_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司