我做了很多研究,但没有找到任何东西(但我也不知道要精确搜索哪种关键字)。我希望能够将输入的 RGB 图像转换为灰度,但是我希望能够或多或少地添加红色/黄色/绿色/青色/蓝色/ Magentas ,就像在 Photoshop 中一样。您知道方程式是什么,或者在哪里可以找到这些方程式,以便可以实现自己优化的RGB到灰度转换?
修改: 在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')
谢谢
答案 0 :(得分:2)
这里尝试使用PIL
而不是numpy
。它应该很容易转换。如果没有可供比较的Photoshop副本,我不能保证它与输出完全匹配,但是它确实会为您链接中显示的示例生成准确的值。值r_w, y_w, g_w, c_w, b_w, m_w
是要应用于每种颜色的权重,在相应的Photoshop滑块中1.0等于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])
答案 1 :(得分:0)
我通过添加代码的 numpy / scipy 版本回答我自己的问题,如果将来对任何人都感兴趣的话。 如果您想对答案进行投票,则应该对Mark Ransom的答案进行投票!
import numpy as np
import scipy.misc
import matplotlib.pyplot as plt
%matplotlib inline
def black_and_white_adjustment(img, weights):
rw, yw, gw, cw, bw, mw = weights / 100
h, w = img.shape[:2]
min_c = np.min(img, axis=-1).astype(np.float)
# max_c = np.max(img, axis=-1).astype(np.float)
# Can try different definitions as explained in the Ligtness section from
# https://en.wikipedia.org/wiki/HSL_and_HSV
# like: luminance = (min_c + max_c) / 2 ...
luminance = min_c
diff = img - min_c[:, :, None]
red_mask = (diff[:, :, 0] == 0)
green_mask = np.logical_and((diff[:, :, 1] == 0), ~red_mask)
blue_mask = ~np.logical_or(red_mask, green_mask)
c = np.min(diff[:, :, 1:], axis=-1)
m = np.min(diff[:, :, [0, 2]], axis=-1)
yel = np.min(diff[:, :, :2], axis=-1)
luminance = luminance + red_mask * (c * cw + (diff[:, :, 1] - c) * gw + (diff[:, :, 2] - c) * bw) \
+ green_mask * (m * mw + (diff[:, :, 0] - m) * rw + (diff[:, :, 2] - m) * bw) \
+ blue_mask * (yel * yw + (diff[:, :, 0] - yel) * rw + (diff[:, :, 1] - yel) * gw)
return np.clip(luminance, 0, 255).astype(np.uint8)
input_img = scipy.misc.imread("palette.jpg")
weights = np.array([106, 65, 17, 17, 104, 19])
bw_image = black_and_white_adjustment(input_img, weights)
plt.figure(figsize=(15, 20))
plt.imshow(bw_image, cmap="gray")
由于此代码使用vect操作,因此速度更快。