PS 色阶调整之算法公式原理详解及 Python 实现(色阶原理)
本文介绍了 PS 中色阶的实现原理及公式,并用 Python 实现,自测与 PS 的色阶调整效果基本完全一样(使用和 PS 中色阶相同的参数对比效果,包括各极限值,本文只实现了 RGB 整体色阶的处理,对各个通道的处理逻辑公式是一样的,实际使用会用 OpenGL 实现)
如下图是 PS 中色阶调整的操作面板,可以对 R、G、B 单独的通道或 RGB 整体通道做色阶调整。每个通道或整体有五个参数(红色箭头所指的五个滑块,调整时也可以直接输入值):
inputShadows: 输入图像的黑场阈值,作用是将输入图像中低于该阈值的全变成 0
inputHighlit: 输入图像的白场阈值,作用是将输入图像中高于该阈值的全变成 255
midtone: 中间调,范围是 [0.01, 9.99],默认值是 1.0 在中间,[9.99 – 1.0 – 0.01],从中间往左调,即[1.0, 9.99] 加灰降对比度,往右调减灰加对比度(RGB通道)
outputShadows: 输出图像的黑场阈值,输出图像的最低值为该阈值
outputHighlight: 输出图像的白场阈值,输出图像的最高值为该阈值
色阶调整的处理转换公式如下:
分输入色阶映射、中间调调整、输出色阶映射共三步处理,上一步处理的输出做为下一步的输入(以下公式用 MarkDown Latex 语法编辑)。
输入色阶映射公式:
Vout=255∗Vin−inShadowsinHighlights−inShadowsVout = 255 * \frac{Vin - inShadows}{inHighlights - inShadows} Vout=255∗inHighlights−inShadowsVin−inShadows
Vout={0if Vout<0255if Vout>255Vout = \left\{ \begin{array}{ll} 0 & \textrm{if $Vout<0$}\\ 255 & \textrm{if $Vout>255$}\\ \end{array} \right. Vout={0255if Vout<0if Vout>255
中间调调整:
Vout=255∗(Vin255.0)1midtonesVout = 255 * (\frac{Vin}{255.0})^\frac{1}{midtones} Vout=255∗(255.0Vin)midtones1
输出色阶映射:
Vout=Vin255.0∗(outLighhights−outShadows)+outShadowsVout = \frac{Vin}{255.0} * (outLighhights - outShadows) + outShadows Vout=255.0Vin∗(outLighhights−outShadows)+outShadows
Vout={0if Vout<0255if Vout>255Vout = \left\{ \begin{array}{ll} 0 & \textrm{if $Vout<0$}\\ 255 & \textrm{if $Vout>255$}\\ \end{array} \right. Vout={0255if Vout<0if Vout>255
完整 python 代码如下:
# -*- coding: utf-8 -*-
# @Time : 2021-02-24 16:45
# @Author : AlanWang4523
# @FileName: ps_levels.pyimport os
import sys
import cv2
import numpy as npclass Levels:"""@Author : AlanWang4523色阶调整类,根据输入参数调整图片色阶,并输出处理后的图片"""def __init__(self):self.channel = 0self.input_shadows = 0self.input_highlights = 255self.midtones = 1.0self.output_shadows = 0self.output_highlights = 255def adjust_image(self, img):print("Levels Params:")print(" channel:", self.channel)print(" input_shadows:", self.input_shadows)print(" input_highlights:", self.input_highlights)print(" midtones:", self.midtones)print(" output_shadows:", self.output_shadows)print("output_highlights:", self.output_highlights)print("")img = img.astype(np.float)# 输入色阶映射img = 255 * ((img - self.input_shadows) / (self.input_highlights - self.input_shadows))img[img < 0] = 0img[img > 255] = 255# 中间调处理img = 255 * np.power(img / 255.0, 1.0 / self.midtones)# 输出色阶映射img = (img / 255) * (self.output_highlights - self.output_shadows) + self.output_shadowsimg[img < 0] = 0img[img > 255] = 255img = img.astype(np.uint8)return imgdef level_adjust_and_save_img(origin_image):levels.input_shadows = 40levels.input_highlights = 240levels.midtones = 0.60levels.output_shadows = 30levels.output_highlights = 220image = levels.adjust_image(origin_image)cv2.imwrite('py_test_out.png', image)def level_adjust(path):"""色阶调整"""origin_image = cv2.imread(path)levels = Levels()def update_input_shadows(x):if (x < levels.input_highlights):levels.input_shadows = xdef update_input_highlights(x):if (x > levels.input_shadows):levels.input_highlights = xdef update_midtones(x):# 由于 midtones 的调整范围是 [9.99, 0.01],Python 滑杆无法自定义显示小数,因此将滑杆的 [0, 100] 映射到 [9.99, 0.01]midtones = 1.0if (x < 50):midtones = 1 + 9 * ((50.0 - x) / 50.0)elif (x > 50):midtones = 1 - (x - 50) / 50.0levels.midtones = np.clip(midtones, 0.01, 9.99)# levels.midtones = 0.6 # 直接测试某个参数值def update_output_shadows(x):if (x < levels.output_highlights):levels.output_shadows = xdef update_output_highlights(x):if (x > levels.output_shadows):levels.output_highlights = x# 创建图片显示窗口title = "Levels"cv2.namedWindow(title, cv2.WINDOW_NORMAL) cv2.resizeWindow(title, 800, 600)cv2.moveWindow(title, 0, 0)# 创建色阶操作窗口option_title = "Option"cv2.namedWindow(option_title, cv2.WINDOW_NORMAL) cv2.resizeWindow(option_title, 400, 200)cv2.moveWindow(option_title, 800, 0)cv2.createTrackbar(' input_shadows', option_title, levels.input_shadows, 255, update_input_shadows)cv2.createTrackbar(' input_highlights', option_title, levels.input_highlights, 255, update_input_highlights)cv2.createTrackbar(' midtones', option_title, 50, 100, update_midtones)cv2.createTrackbar(' output_shadows', option_title, levels.output_shadows, 255, update_output_shadows)cv2.createTrackbar('output_highlights', option_title, levels.output_highlights, 255, update_output_highlights)while True:image = levels.adjust_image(origin_image)cv2.imshow(title, image)if cv2.waitKey(1) == ord('q'):breakcv2.destroyAllWindows() if __name__ == '__main__':'''Author: AlanWang4523运行环境:Python 3执行:python3 ps_levels.py <图片路径>如:python3 ps_levels.py test.jpg'''if len(sys.argv) == 1:print("参数错误:未传入图片路径!")sys.exit(-1)img_path = sys.argv[1]print("img_path Params:", img_path)level_adjust(img_path)
def update_midtones(x):# 由于 midtones 的调整范围是 [9.99, 0.01],Python 滑杆无法自定义显示小数,因此将滑杆的 [0, 100] 映射到 [9.99, 0.01]midtones = 1.0if (x < 50):midtones = 1 + 9 * ((50.0 - x) / 50.0)elif (x > 50):midtones = 1 - (x - 50) / 50.0levels.midtones = np.clip(midtones, 0.01, 9.99)# levels.midtones = 0.6 # 直接测试某个参数值
使用和 PS 相同的参数,效果和 PS 上的完全一致,各参数下和 PS 对比效果如下:
(截图上半部部分为用 Python 使用与 PS 相同参数的效果,下半部分为 PS 的效果)
① Python 和 PS 都使用如下参数:
inputShadows: 50
inputHighlit: 52
midtone: 0.50 (根据上面的映射公式,python 实现的 midtones 的滑块在 75 的位置)
outputShadows: 50
outputHighlight: 200
效果如下:
② Python 和 PS 都使用如下参数:
inputShadows: 0
inputHighlit: 255
midtone: 0.10
outputShadows: 0
outputHighlight: 255
效果如下:
参考文档:
Adobe 官网的 Levels Adjustment
Algorithm for adjustment of image levels
PS 色阶调整之算法公式原理详解及 Python 实现(色阶原理)相关推荐
- 视频教程-深度学习原理详解及Python代码实现-深度学习
深度学习原理详解及Python代码实现 大学教授,美国归国博士.博士生导师:人工智能公司专家顾问:长期从事人工智能.物联网.大数据研究:已发表学术论文100多篇,授权发明专利10多项 白勇 ¥88.0 ...
- java源码系列:HashMap底层存储原理详解——4、技术本质-原理过程-算法-取模具体解决什么问题
目录 简介 取模具体解决什么问题? 通过数组特性,推导ascii码计算出来的下标值,创建数组非常占用空间 取模,可保证下标,在HashMap默认创建下标之内 简介 上一篇文章,我们讲到 哈希算法.哈希 ...
- google authenticator python_Google Authenticator TOTP原理详解(以Python为例)
http://xsboke.blog.51cto.com 如果有疑问,请点击此处,然后发表评论交流,作者会及时回复(也可以直接在当前文章评论). -------谢谢您的参考,如有疑问,欢迎交流 一. ...
- 字典树原理详解及其Python实现
一.原理详解 1.初步介绍: 字典树又名前缀树,Trie树,是一种存储大量字符串的树形数据结构,经常被搜索引擎系统用于文本词频统计. 除此之外也常用于计算左右信息熵.计算点互信息. 下图演示了一个保存 ...
- python google auth totp_Google Authenticator TOTP原理详解(以Python为例)
如果有疑问,请点击此处,然后发表评论交流,作者会及时回复(也可以直接在当前文章评论). -------谢谢您的参考,如有疑问,欢迎交流 一. 原理详解(图片可以点击然后放大查看) 二. 验证 1.下载 ...
- Xgboost算法原理详解及python实现
Xgboost算法(回归树) 1.算法原理 2.对数据的要求(无需规范化) 3.算法的优缺点 4.XGB.GBDT.LR与RF 5.python代码实现 导入相关包 读取数据并预处理 训练 贝叶斯初步 ...
- 随机森林原理详解及python代码实现
随机森林(RF)算法 1.算法原理 2.对数据的要求(无需规范化) 3.算法的优缺点 4.算法需要注意的点 5.python代码实现(待更......) 导入相关包 读取数据并预处理(必须处理缺失值) ...
- 决策树原理详解及python代码实现
决策树算法(信贷中常用来寻找规则) 1.算法原理 1.1 ID3(多叉树分类) 1.2 C4.5(多叉树分类) 1.3 Cart(二叉树分类+回归) 2.ID3.C4.5与Cart比较 3.算法优缺点 ...
- 集成经验模态(EEMD)原理详解与python实现
文章目录 1 经验模态分解(EMD) 1.1 本征模态函数(IMF) 1.2 sifting算法 1.3 原始序列重构 2 集成经验模态分解(EEMD) 2.1 EEMD算法步骤 集成经验模态分解的关 ...
最新文章
- 从时间管理聊到技术人如何保持竞争力?
- mysql索引与优化
- python知识:@classmethod和@staticmethod的异同
- python nonetype object has no_为什么会出现这个?'NoneType' object has no attribute 'contet
- Draconian,自由或保姆状态:Java,C#,C,C ++,Go和Rust中的并发意识形态
- mysql 左连接 和全连接_mysql左连接,右连接,内连,全连
- java在线聊天项目 使用SWT快速制作登录窗口,可视化窗口Design 更换窗口默认皮肤(切换Swing自带的几种皮肤如矩形带圆角)...
- mysql for 循环删除_Java增强for循环中删除元素抛异常问题
- 2021年中国船用蓄电池市场趋势报告、技术动态创新及2027年市场预测
- linux 重启mysql_Grafana+Prometheus 监控 MySql服务
- Pytorch测试模型的GFLOPs和Param大小
- 修改oracle用户密码永不过期的方法
- 使用学信网认证,免费获取JetBrains学习产品
- 用行列式的定义方法求解n阶行列式的值(C++)
- 生鲜配送系统软件排名
- knex 找不到mysql_node knex mysql ER_NOT_SUPPORTED_AUTH_MODE
- electron 自动更新 热跟新
- 如何自创一门计算机语言
- GitHub 热点速览 Vol.32:VScode 韭菜基金插件,极大提高“工作”效率
- 【人工智能毕设之基于Python+flask+bilstm的评论情感分析系统-哔哩哔哩】 https://b23.tv/QU56eTl
热门文章
- 关于Vue中nextTick异步调用videoaudio的方法失效解决方案
- Windows系统下使用pyinstaller打包PaddleOCR中表格识别PP-Structure
- Mac 电脑能联网但打不开网页
- Nginx下载安装以及简单使用
- html 怎么播放avi视频,Uniboy跳舞激怒Kanavi,JDG让一追二,艰难战胜V5
- Evil Coordinate
- 应用案例 | 2012 款大众途观车怠速抖动、加速无力故障诊断
- ios运行.php,ios - 真机运行报错 怎么解决 !!!
- Pytorch中.new()的作用
- 挂脖式运动蓝牙耳机什么牌子的好、运动蓝牙挂脖耳机推荐