Photoshop“黑白”调整图层背后的算法是什么?

2024-01-17

我做了很多研究,但没有找到任何东西(但我也不知道到底要搜索什么样的关键字)。我希望能够转换输入RGB图像到灰度但我希望能够添加更多或更少红色/黄色/绿色/青色/蓝色/洋红色Photoshop。您知道等式是什么吗?或者我在哪里可以找到这些等式,以便我可以实现自己优化的 RGB 到灰度转换?

Edit: 在 Photoshop 中它被称为黑/白调整图层。我发现了一些东西,但实际上它似乎不起作用。这是我的实现(注释中是理解算法所需的资源):

import numpy as np
import scipy.misc
import matplotlib.pyplot as plt


%matplotlib inline

# Adapted from the answers of Ivan Kuckir and Royi here:
# https://dsp.stackexchange.com/questions/688/what-is-the-algorithm-behind-photoshops-black-and-white-adjustment-layer?newreg=77420cc185fd44099d8be961e736eb0c

def rgb2hls(img):
    """Adapted to use numpy from
       https://github.com/python/cpython/blob/2.7/Lib/colorsys.py"""
    r, g, b = img[:, :, 0], img[:, :, 1], img[:, :, 2]

    maxc = np.max(img, axis=-1)
    minc = np.min(img, axis=-1)
    l = (minc + maxc) / 2

    mask = np.ones_like(r)
    mask[np.where(minc == maxc)] = 0
    mask = mask.astype(np.bool)

    smask = np.greater(l, 0.5).astype(np.float32)

    s = (1.0 - smask) * ((maxc - minc) / (maxc + minc)) + smask * ((maxc - minc) / (2.0 - maxc - minc))
    s[~mask] = 0
    rc = np.where(mask, (maxc - r) / (maxc - minc), 0)
    gc = np.where(mask, (maxc - g) / (maxc - minc), 0)
    bc = np.where(mask, (maxc - b) / (maxc - minc), 0)

    rmask = np.equal(r, maxc).astype(np.float32)
    gmask = np.equal(g, maxc).astype(np.float32)
    rgmask = np.logical_or(rmask, gmask).astype(np.float32)

    h = rmask * (bc - gc) + gmask * (2.0 + rc - bc) + (1.0 - rgmask) * (4.0 + gc - rc)
    h = np.remainder(h / 6.0, 1.0)
    h[~mask] = 0
    return np.stack([h, l, s], axis=-1)


def black_and_white_adjustment(image, weights):  
    # normalize input image to (0, 1) if uint8
    if 'uint8' in (image).dtype.name:
        image = image / 255

    # linearly remap input coeff [-200, 300] to [-2.5, 2.5]
    weights = (weights - 50) / 100
    n_weights = len(weights)
    h, w = image.shape[:2]

    # convert rgb to hls
    hls_img = rgb2hls(image)

    output = np.zeros((h, w), dtype=np.float32)

    # see figure 9 of https://en.wikipedia.org/wiki/HSL_and_HSV
    # to understand the algorithm
    for y in range(h):
        for x in range(w):
            hue_val = 6 * hls_img[y, x, 0]

            # Use distance on a hexagone (maybe circular distance is better?)
            diff_val = min(abs(0 - hue_val), abs(1 - (0 - hue_val)))
            luminance_coeff = weights[0] * max(0, 1 - diff_val)

            for k in range(1, n_weights):
                luminance_coeff += weights[k] * max(0, 1 - abs(k - hue_val))

            # output[y, x] = min(max(hls_img[y, x, 1] * (1 + luminance_coeff), 0), 1)
            output[y, x] = hls_img[y, x, 1] * (1 + luminance_coeff)


    return output


image = scipy.misc.imread("your_image_here.png")
w = np.array([40, 85, 204, 60, 20, 80])
out = black_and_white_adjustment(image, w)
plt.figure(figsize=(15, 20))
plt.imshow(out, cmap='gray')

谢谢


这是一个尝试使用PIL而不是numpy。它应该很容易转换。如果没有 Photoshop 的副本进行比较,我无法保证它与输出完全匹配,但它确实会为链接中显示的示例生成准确的值。价值r_w, y_w, g_w, c_w, b_w, m_w是应用于每种颜色的权重,1.0 相当于相应 Photoshop 滑块中的 100%。当然,它们也可以是负面的。

from PIL import Image
im = Image.open(r'c:\temp\temp.png')
def ps_black_and_white(im, weights):
    r_w, y_w, g_w, c_w, b_w, m_w = [w/100 for w in weights]
    im = im.convert('RGB')
    pix = im.load()
    for y in range(im.size[1]):
        for x in range(im.size[0]):
            r, g, b = pix[x, y]
            gray = min([r, g, b])
            r -= gray
            g -= gray
            b -= gray
            if r == 0:
                cyan = min(g, b)
                g -= cyan
                b -= cyan
                gray += cyan * c_w + g * g_w + b * b_w
            elif g == 0:
                magenta = min(r, b)
                r -= magenta
                b -= magenta
                gray += magenta * m_w + r * r_w + b * b_w
            else:
                yellow = min(r, g)
                r -= yellow
                g -= yellow
                gray += yellow * y_w + r * r_w + g * g_w
            gray = max(0, min(255, int(round(gray))))
            pix[x, y] = (gray, gray, gray)
    return im

使用此提供的测试图像,以下是一些示例结果。

ps_black_and_white(im, [-17, 300, -100, 300, -200, 300])
ps_black_and_white(im, [40, 60, 40, 60, 20, 80])
ps_black_and_white(im, [106, 65, 17, 17, 104, 19])
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Photoshop“黑白”调整图层背后的算法是什么? 的相关文章

  • 在Python中,如何将矩阵逆时针旋转90度?

    gt gt gt def rotate matrix k List List int For example if I have m 1 2 3 2 3 3 5 4 3 rotate matrix m should give me 3 3
  • Python 转换矩阵

    我有一个如下所示的列表 2 1 3 1 2 3 1 2 2 2 我想要的是一个转换矩阵 它向我显示如下序列 1 后跟 1 的频率是多少 1 后面跟着 2 的频率是多少 1 后跟 3 的频率是多少 2 后跟 1 的频率是多少 2 后跟 2 的
  • 如何使用一个模型中间层的输出作为另一个模型的输入?

    我训练一个模型A并尝试使用中间层的输出name layer x 作为模型的附加输入B 我尝试像 Keras 文档一样使用中间层的输出https keras io getting started faq how can i obtain th
  • Matplotlib 图例,跨列添加项目而不是向下添加项目

    对于下面的简单绘图 有没有办法让 matplotlib 填充图例 以便它从左到右填充行 而不是第一列然后第二列 gt gt gt from pylab import gt gt gt x arange 2 pi 2 pi 0 1 gt gt
  • 查找正在导入哪些 python 模块

    从应用程序中使用的特定包中查找所有 python 模块的简单方法是什么 sys modules是将模块名称映射到模块的字典 您可以检查其键以查看导入的模块 See http docs python org library sys html
  • 在linux上安装python ssl模块,无需重新编译

    是否可以在已经安装了 OpenSSL 的 Linux 机器上安装 python 的 SSL 模块 而无需重新编译 python 我希望它就像复制几个文件并将它们包含在库路径中一样简单 Python版本是2 4 3 谢谢 是否可以在已经安装了
  • 如何使用网格分割图像并保留透明度边界框

    我有一些 png 图像 我想将其分成几个部分 例如按网格或大小 但每个部分应具有与原始图像相同的边界框 透明度 Example 将图像分成两部分 原来的 200 89 Output 部分 1 png 200 89 第2部分 png 200
  • 数据框中 .map(str) 和 .astype(str) 有什么区别

    我有一个数据框 其列名为 col1 和 col2 的整数类型条目 我想将 col1 和 col2 的条目以及其间的 点 连接起来 我搜索并发现添加两个列条目 df col df col1 map str df col2 map str 并添
  • Python-验证我的文档 xls 中是否存在工作表

    我正在尝试在空闲时间设计一个小程序 加载 xls 文件 然后在要扫描的文档中选择一张纸 步骤1 用户导入 xls文件 导入程序后检查文件是否存在 我能做到的 第 2 步 我要求用户提供要分析的文档表 xls 的名称 这就是它停止的地方 该程
  • 在 Matlab 中保存 Kinect 深度图像?

    通过使用 Kinect 我可以获得深度图像 其中每个深度图像像素存储相机和物体之间的距离 以毫米为单位 现在我想保存它们以便以后使用 最好的推荐是什么 我正在考虑将深度图像保存为图像 jpg png等 然而 该值通常是从50毫米到10000
  • Python:在字典中查找具有唯一值的键?

    我收到一个字典作为输入 并且想要返回一个键列表 其中字典值在该字典的范围内是唯一的 我将用一个例子来澄清 假设我的输入是字典 a 构造如下 a dict a cat 1 a fish 1 a dog 2 lt unique a bat 3
  • 无法使用 python rasterio、gdal 打开 jp2 (来自哨兵)

    我试图在 python 中将 jp2 栅格产品作为栅格打开 但当我们使用 raterio 和 gdal 包时没有成功 我收到此错误 RasterioIOError b4 jp2 not recognized as a supported f
  • Seaborn 中没有线性拟合的散点图

    我想知道是否有办法关闭seaborn中的线性拟合lmplot或者是否有一个等效函数可以生成散点图 当然 我也可以使用 matplotlib 但是 我发现 seaborn 中的语法和美学非常吸引人 例如 我想绘制以下情节 import sea
  • Django 2、python 3.4 无法解码 urlsafe_base64_decode(uidb64)

    我正在尝试通过电子邮件激活用户 电子邮件有效 编码有效 我使用了 django1 11 中的方法 该方法运行成功 在 Django 1 11 中 以下内容成功解码为 28 其中 uidb64 b Mjg force text urlsafe
  • 如何在matplotlib中调整x轴

    I have a graph like this x轴上的数据表示小时 所以我希望x轴设置为0 24 48 72 而不是现在的值 很难看到 0 100 之间的数据 fig1 plt figure ax fig1 add subplot 11
  • 从 wxPython 事件处理程序中调用函数

    我正在努力寻找一种在 wxPython 事件处理函数中使用函数的方法 假设我有一个按钮 单击该按钮时 它会使用事件处理程序运行一个名为 OnRun 的函数 但是 用户忘记单击 OnRun 按钮之前的 RadionButton 我想弹出一个
  • 无需访问 Internet 即可部署 Django 的简单方法?

    我拥有的是使用 Django 开发的 Intranet 站点的开发版本以及放置在 virtualenv 中的一些外部库 它运行良好 我可以在任何具有互联网连接的计算机上使用相同的参数 使用 pip 轻松设置 virtualenv 但是 不幸
  • Python:如何在不先创建整个列表的情况下计算列表的总和?

    通常我们必须 1 声明一个列表 2 使用以下方法计算该列表的总和sum 但现在我希望指定一个以 1 开头 间隔为 4 100 个元素的列表 如下所示 1 5 9 13 17 21 25 29 33 37 我不想涉及数学公式 所以 1 如何在
  • 如何使用 enumerate 来倒数?

    letters a b c 假设这是我的清单 在哪里for i letter in enumerate letters 将会 0 a 1 b 2 c 我怎样才能让它向后枚举 如 2 a 1 b 0 c 这是一个很好的解决方案并且工作完美 i
  • python中有没有一种方法可以将存储在列表中的正则表达式模式列表应用到单个字符串?

    我有一个正则表达式模式列表 存储在列表类型中 我想将其应用于字符串 有谁知道一个好方法 将列表中的每个正则表达式模式应用于字符串 和 如果匹配 则调用与列表中该模式关联的不同函数 如果可能的话我想用 python 来做这件事 提前致谢 im

随机推荐