- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试为图像编写色相/饱和度/亮度滤镜(使用 C++)。 RGB->HSL 转换工作正常,但当考虑到每个像素具有不同的初始饱和度和亮度这一事实时,我的问题就来了。
对于每个像素,我计算了源 HSL 并将 HSL 值作为滤波器输入(在 [0, 1] 范围内)。我想将 0.5 设置为所有默认值(输出与输入相同),饱和度 0.0 表示灰度或全黑表示亮度,1.0 表示完全饱和或全白。与饱和度和亮度不同,色调部分很简单:只需添加并包裹在 [0, 1] 范围内即可。
那么任务来了:我们如何根据过滤器输入转换每个像素的饱和度和亮度值?
想到的一个解决方案:
Out.H = Wrap(In.H + Filter.H - 0.5f, 0.0f, 1.0f);
Out.S = std::clamp(In.S * Filter.S * 2.0f, 0.0f, 1.0f);
Out.L = std::clamp(In.L * Filter.L * 2.0f, 0.0f, 1.0f);
其中Out
是输出,In
是源图像,Filter
是滤镜设置。但是,如果源图像与其有很大的对比度,则图像最初较亮的部分会快速剪辑(固定为纯色 1.0f),失去细节,而较暗的部分可能仍然几乎不可见。因此,相反,我想也许可以应用一些曲线来防止这种削波,同时仍然让 0.5f 返回原始值。我想到了使用幂函数并计算所需的功率。我想到了:
f(x) = x ^ log_1/2(a)
其中 a
是输入像素处的值(函数在 x = 0.5f 处的值)。例如:
此函数 f(x) = x ^ log_1/2(0.2)
通过 (0,0)、(0.5, 0.2) 和 (1, 1)。因此,如果输入像素的饱和度为 0.2f 并且来自用户的滤波器饱和度输入为 x,则通过此函数运行它会起作用。您需要将函数中的 0.2 替换为输入像素的饱和度。据说,同样的事情也可以用于亮度。因此,代码变为:
Out.H = Wrap(In.H + Filer.H - 0.5f, 0.0f, 1.0f);
Out.S = pow(In.S, log(Filter.S) / log(0.5f));
Out.L = pow(In.L, log(Filter.L) / log(0.5f));
这适用于具有中等饱和度和亮度的图像。但是,如果它最初非常高或非常低,这种方法可能意味着函数的下降非常接近 0 或 1。例如,如果饱和度最初为 0.97,函数如下所示:
(有一个点在(0.5,0.97),我忘了标记它)。
这意味着您必须先将饱和度降低到 0.001 之类的值,然后才能开始看到任何实际差异。我遇到过这个测试图像的问题:
原始(饱和度 = 0.5):
饱和度 = 0.001
饱和度 = 0.0
此时我被卡住了。 有没有办法在不丢失细节或剪裁的情况下调整饱和度和亮度?也许可以使用另一种弯曲方法?有没有我找不到的标准方法?提前致谢。
用 Desmos 制作的图表在线图形计算器。
最佳答案
好吧,我仍然不知道有什么“标准”方法可以做到这一点,但我发现即使对于高度饱和的图像,三角曲线也能相对较好地工作。
使用两个函数a*sin(x*PI) where {0 <= x <= 0.5}
和 1+(a-1)*sin(x*PI) where {.5 < x <= 1.0}
, 可以创建如下曲线:
初始饱和度 ( a
) = 0.2:
初始饱和度 = 0.97:
代码:
Out.H = Wrap(In.H + Filter.H - 0.5f, 0.0f, 1.0f);
Out.S = (Filter.S <= 0.5f) ? (In.S * sin(Filter.S * PI)) : (1.0f - (1.0f - In.S) * sin(Filter.S * PI));
Out.L = (Filter.L <= 0.5f) ? (In.L * sin(Filter.L * PI)) : (1.0f - (1.0f - In.L) * sin(Filter.L * PI));
显然这并不完美,但现在看来已经足够了,并且比幂函数可以进行更清晰的图像调整。这也意味着不同的像素正在以与以前不同的速率失去和获得饱和度,这可能与大多数 HSL 调整过滤器不同。如果有人碰巧知道“标准”或通常的处理方式,请分享!
关于C++:在不裁剪的情况下调整图像的 HSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47973697/
我是 Java 新手,这是我的代码, if( a.name == b.name && a.displayname == b.displayname && a.linknam
在下面的场景中,我有一个 bool 值。根据结果,我调用完全相同的函数,唯一的区别是参数的数量。 var myBoolean = ... if (myBoolean) { retrieve
我是一名研究 C++ 的 C 开发人员: 我是否正确理解如果我抛出异常然后堆栈将展开直到找到第一个异常处理程序?是否可以在不展开的情况下在任何 throw 上打开调试器(即不离开声明它的范围或任何更高
在修复庞大代码库中的错误时,我观察到一个奇怪的情况,其中引用的动态类型从原始 Derived 类型更改为 Base 类型!我提供了最少的代码来解释问题: struct Base { // some
我正在尝试用 C# 扩展给定的代码,但由于缺乏编程经验,我有点陷入困境。 使用 Visual Studio 社区,我尝试通过控制台读出 CPU 核心温度。该代码使用开关/外壳来查找传感器的特定名称(即
这可能是一个哲学问题。 假设您正在向页面发出 AJAX 请求(这是使用 Prototype): new Ajax.Request('target.asp', { method:"post", pa
我有以下 HTML 代码,我无法在所有浏览器中正常工作: 我试图在移动到
我对 Swift 很陌生。我如何从 addPin 函数中检索注释并能够在我的 addLocation 操作 (buttonPressed) 中使用它。我正在尝试使用压力触摸在 map 上添加图钉,在两
我设置了一个详细 View ,我是否有几个 Nib 文件根据在 Root View Controller 的表中选择的项目来加载。 我发现,对于 Nibs 的类,永远不会调用 viewDidUnloa
我需要动态访问 json 文件并使用以下代码。在本例中,“bpicsel”和“temp”是变量。最终结果类似于“data[0].extit1” var title="data["+bpicsel+"]
我需要使用第三方 WCF 服务。我已经在我的证书存储中配置了所需的证书,但是在调用 WCF 服务时出现以下异常。 向 https://XXXX.com/AHSharedServices/Custome
在几个 SO 答案(1、2)中,建议如果存在冲突则不应触发 INSERT 触发器,ON CONFLICT DO NOTHING 在触发语句中。也许我理解错了,但在我的实验中似乎并非如此。 这是我的 S
如果进行修改,则会给出org.hibernate.NonUniqueObjectException。在我的 BidderBO 类(class)中 @Override @Transactional(pr
我使用 indexOf() 方法来精细地查找数组中的对象。 直到此刻我查了一些资料,发现代码应该无法正常工作。 我在reducer中尝试了上面的代码,它成功了 let tmp = state.find
假设我有以下表格: CREATE TABLE Game ( GameID INT UNSIGNED NOT NULL, GameType TINYINT UNSIGNED NOT NU
代码: Alamofire.request(URL(string: imageUrl)!).downloadProgress(closure: { (progress) in
我是一名优秀的程序员,十分优秀!