PS 色彩平衡之算法公式原理详解及 Python 实现
本文介绍了 PS 中色阶的实现原理及公式,并用 Python 实现,自测与 PS 的色阶调整效果基本完全一样。
PS 中色彩平衡可以对高光、中间调、阴影 三个色调进行调整,每个色调中有可以对 RGB 三个通道调整,每个通道的调整区间范围是 [-100, 100]
色彩平衡之高光
高光各色条的现象及规律如下:
- a. 对于正向的调整,只增加输入图像中该通道的值,其他两个通道不变,比如只调整蓝色 +100,那么原图中蓝色通道值会增加,红色通道和绿色通道不变,如下图;
- b. 对于负向的调整,该通道值不变,其他两个通道值增加,比如同样只调整蓝色 -100,那么原图中蓝色通道值不变,红色通道和绿色通道值增加,如下图;
- c. 此外如果将三个调整滑杆都拖动相同的数值,那么原图没有变化。如 RGB 三个滑杆值每个通道都加或减相同数值,效果一样,如 (+10, +20, +30)的效果等价于 (-10, 0, 10) 的效果(RGB 三个滑杆都减 20),也等价于 (20, 30, 40) 的效果(RGB 三个滑杆都加 10)可通过 PS 验证。
- d. 生成一张 255x255 的图,其从左到右每个像素点 RGB 每个通道的颜色值从 0~255,然后将该图通过 PS 做色彩平衡处理并存处理后的图片,下图中横轴是取的 0~255,纵轴是取的通过 PS 处理后的 RGB 各个通道的值并画线
- e. 通过设置不同的参数值导出多张图,然后拟合出调整系数(上图中变化直线斜率)与滑杆调整值[0, 100]的关系(见上图高光下加不同蓝色值对应的输出曲线),只测正值即可,负值相当于其另外两个通道做正向调整(公式如下,Vin 为输入图像的 RGB,a 为固定系数,X 为各通道的正向调节值 [0, 100];
色彩平衡-高光映射公式:
Vout=255∗Vin255−XVout = \frac{255 * Vin}{255 - X} Vout=255−X255∗Vin
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
色彩平衡之阴影调整
阴影各色条的现象及规律如下:
- a. 对于正向的调整,该通道值不变,其他两个通道值减小,比如同样只调整蓝色 +100,那么原图中蓝色通道值不变,红色通道和绿色通道值减小,如下图;
- b. 对于负向的调整,只减少输入图像中该通道的值,其他两个通道不变,比如只调整蓝色 -100,那么原图中蓝色通道值会减小,红色通道和绿色通道不变,如下图;
- c. 此外如果将三个调整滑杆都拖动相同的数值,那么原图没有变化。如果 RGB 三个滑杆值每个通道都加或减相同数值,效果一样。
- d. 生成一张 255x255 的图,其从左到右每个像素点 RGB 每个通道的颜色值从 0~255,然后将该图通过 PS 做色彩平衡处理并存处理后的图片,下图中横轴是取的 0~255,纵轴是取的通过 PS 处理后的 RGB 各个通道的值并画线
- e. 通过设置不同的参数值导出多张图,然后拟合出直线斜率、截距与滑杆调整值[0, 100]的关系(见上图阴影下加不同蓝色值对应的输出曲线),只测负值即可,正值相当于其另外两个通道做负向调整(公式如下,Vin 为输入图像的 RGB,X 为各通道的正向调节值 [0, 100])
色彩平衡-阴影映射公式:
Vout=255∗(Vin−X)255−XVout = \frac{255 * (Vin - X)}{255 - X} Vout=255−X255∗(Vin−X)
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
代码如下:
# -*- coding: utf-8 -*-
# @Time : 2021-03-09 11:05
# @Author : AlanWang4523
# @FileName: ps_color_balance_test.pyimport os
import sys
import cv2
import numpy as npTONE_SHADOWS = 0
TONE_MIDTONE = 1
TONE_HIGHLIGHT = 2
SH_COEFFICIENTS = 0.0039216 # 1.0/255
MID_COEFFICIENTS = 0.0033944class ColorBalance:"""色彩平衡调整"""def __init__(self):self.tone = TONE_SHADOWSself.tone_arguments = np.zeros([3,3], dtype=np.int)self.tone_coefficients = np.zeros([3,3])self.sh_coef_self = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])self.sh_coef_other = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]])self.mid_coef_self = np.array([[1, -1, -1], [-1, 1, -1], [-1, -1, 1]])def update_tones(self, x):self.tone = x;def update_cyan_red(self, x):self.tone_arguments[self.tone, 0] = xdef update_magenta_green(self, x):self.tone_arguments[self.tone, 1] = xdef update_yellow_blue(self, x):self.tone_arguments[self.tone, 2] = xdef adjust_image(self, img):print("ColorBalance Params:")print(" Shadows: ", self.tone_arguments[TONE_SHADOWS][:])print(" Midtones: ", self.tone_arguments[TONE_MIDTONE][:])print("Highlights: ", self.tone_arguments[TONE_HIGHLIGHT][:])# print(" Shadows: %d, %d, %d" % (self.tone_arguments[TONE_SHADOWS, 0], self.tone_arguments[TONE_SHADOWS, 1], self.tone_arguments[TONE_SHADOWS, 2]))# print(" Midtones: %d, %d, %d" % (self.tone_arguments[TONE_MIDTONE, 0], self.tone_arguments[TONE_MIDTONE, 1], self.tone_arguments[TONE_MIDTONE, 2]))# print("Highlights: %d, %d, %d" % (self.tone_arguments[TONE_HIGHLIGHT, 0], self.tone_arguments[TONE_HIGHLIGHT, 1], self.tone_arguments[TONE_HIGHLIGHT, 2]))temp = np.sort(self.tone_arguments[TONE_SHADOWS][:])self.tone_coefficients[TONE_SHADOWS][:] = (self.tone_arguments[TONE_SHADOWS][:] - temp[1]) * SH_COEFFICIENTStemp = np.sort(self.tone_arguments[TONE_MIDTONE][:])self.tone_coefficients[TONE_MIDTONE][:] = (self.tone_arguments[TONE_MIDTONE][:] - temp[1]) * MID_COEFFICIENTStemp = np.sort(self.tone_arguments[TONE_HIGHLIGHT][:])self.tone_coefficients[TONE_HIGHLIGHT][:] = (self.tone_arguments[TONE_HIGHLIGHT][:] - temp[1]) * SH_COEFFICIENTSprint("tone_coefficients:")print(" Shadows: ", self.tone_coefficients[TONE_SHADOWS][:])print(" Midtones: ", self.tone_coefficients[TONE_MIDTONE][:])print("Highlights: ", self.tone_coefficients[TONE_HIGHLIGHT][:])test_array = self.tone_coefficients[TONE_HIGHLIGHT][:]self.tone_coefficients[TONE_HIGHLIGHT][:] = np.dot(np.where(test_array > 0, test_array, 0), self.sh_coef_self) +\np.dot((-1) * np.where(test_array < 0, test_array, 0), self.sh_coef_other)test_array = self.tone_coefficients[TONE_SHADOWS][:]self.tone_coefficients[TONE_SHADOWS][:] = np.dot(np.where(test_array > 0, test_array, 0), self.sh_coef_other) +\np.dot((-1) * np.where(test_array < 0, test_array, 0), self.sh_coef_self) # test_array = self.tone_coefficients[TONE_MIDTONE][:]# self.tone_coefficients[TONE_MIDTONE][:] = np.dot(test_array, self.mid_coef_self)# self.tone_coefficients[TONE_MIDTONE][:] = np.power(e, np.dot(test_array, self.mid_coef_self))print("after_tone_coefficients:")print(" Shadows: ", self.tone_coefficients[TONE_SHADOWS][:])print(" Midtones: ", self.tone_coefficients[TONE_MIDTONE][:])print("Highlights: ", self.tone_coefficients[TONE_HIGHLIGHT][:])# r, g, b = img = img.astype(np.float)b, g ,r =cv2.split(img)r = r / (1.0 - self.tone_coefficients[TONE_HIGHLIGHT, 0])g = g / (1.0 - self.tone_coefficients[TONE_HIGHLIGHT, 1])b = b / (1.0 - self.tone_coefficients[TONE_HIGHLIGHT, 2])r[r > 255] = 255g[g > 255] = 255b[b > 255] = 255r = (r - 255.0 * self.tone_coefficients[TONE_SHADOWS, 0]) / (1.0 - self.tone_coefficients[TONE_SHADOWS, 0])g = (g - 255.0 * self.tone_coefficients[TONE_SHADOWS, 1]) / (1.0 - self.tone_coefficients[TONE_SHADOWS, 1])b = (b - 255.0 * self.tone_coefficients[TONE_SHADOWS, 2]) / (1.0 - self.tone_coefficients[TONE_SHADOWS, 2])r[r < 0] = 0g[g < 0] = 0b[b < 0] = 0img = cv2.merge([b, g, r])img = img.astype(np.uint8)return img def color_balance_adjust(path):"""色彩平衡调整"""origin_image = cv2.imread(path)cloorBalance = ColorBalance()title = "ColorBalance"# 阴影cloorBalance.update_tones(0)cloorBalance.update_cyan_red(0)cloorBalance.update_magenta_green(-100)cloorBalance.update_yellow_blue(0)# 中间调cloorBalance.update_tones(1)cloorBalance.update_cyan_red(-30)cloorBalance.update_magenta_green(-50)cloorBalance.update_yellow_blue(-50)# 高光cloorBalance.update_tones(2)cloorBalance.update_cyan_red(100)cloorBalance.update_magenta_green(0)cloorBalance.update_yellow_blue(0)image = cloorBalance.adjust_image(origin_image) cv2.namedWindow(title, cv2.WINDOW_NORMAL) cv2.resizeWindow(title, 800, 600)cv2.moveWindow(title, 0, 0)while True:cv2.imshow(title, image)if cv2.waitKey(1) == ord('q'):breakcv2.destroyAllWindows() if __name__ == '__main__':'''运行环境:Python 3执行:python3 ps_color_balance_test.py <图片路径>如:python3 ps_color_balance_test.py test.jpg'''if len(sys.argv) == 1:print("参数错误:未传入图片路径!")sys.exit(-1)img_path = sys.argv[1]print("img_path Params:", img_path)color_balance_adjust(img_path)
感谢:
https://zhuanlan.zhihu.com/p/59450298
PS 色彩平衡之算法公式原理详解及 Python 实现相关推荐
- PS 色阶调整之算法公式原理详解及 Python 实现(色阶原理)
本文介绍了 PS 中色阶的实现原理及公式,并用 Python 实现,自测与 PS 的色阶调整效果基本完全一样(使用和 PS 中色阶相同的参数对比效果,包括各极限值,本文只实现了 RGB 整体色阶的处理 ...
- 视频教程-深度学习原理详解及Python代码实现-深度学习
深度学习原理详解及Python代码实现 大学教授,美国归国博士.博士生导师:人工智能公司专家顾问:长期从事人工智能.物联网.大数据研究:已发表学术论文100多篇,授权发明专利10多项 白勇 ¥88.0 ...
- 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算法步骤 集成经验模态分解的关 ...
- KNN算法原理详解及python代码实现
KNN算法 算法原理 对数据的要求 算法的优缺点 算法需要注意的点 算法实现(python) 算法原理 计算待测样本与train_data的距离d并保存数组中 对d进行排序,取d最近的k个样本 统计样 ...
最新文章
- 学习Python往哪个方向发展好
- localdate转date时区问题_时间戳和LocalDateTime和Date互转和格式化
- Oracle中的Union、Union All、Intersect、Minus 使用用法区别
- 一个线性几何不等式猜想
- Nova计算节点安装配置
- Note for Consulting Handbook5
- linux文件编程(1)—— open、write、read、lseek、阻塞问题
- Avalonia跨平台入门第四篇之Popup在uos下问题
- linux path减少,Linux的环境变量PATH中所带来的问题及解决方法
- 使用路标的Scala和Java的Twitter REST API
- 中yeti不能加载_第二十章_类的加载过程详解
- MFC中CString.Format的用法
- 知道这些用于数据科学和机器学习的GitHub存储库和Reddit主题吗?
- 细谈最近上线的Vue2.0项目(一)
- binder 从c到java_Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析...
- Python的单链表实现
- Apache Maven --- [标准目录布局]
- 鸿蒙系统桌面天气如何设置,怎么设置桌面时间和天气预报?
- 曹金明:Zynga大败局--数据控是如何把游戏做败的
- 网易云信服务监控平台实践