所以我有一个灰度图像,它可能有一个alpha通道(透明度),它包含强度信息,但没有颜色信息。
现在我想给它着色,这意味着我有一个单一的RGB颜色,任何RGB颜色,我想合并的颜色和图像,以产生一个新的单调的图像。没有灰度图像,结果将是一个与灰度图像相同大小的图像充满给定的颜色。灰度图像使某些区域变亮或变暗,使新的图像具有可辨别的特征。
我试过了,但结果是错的:
import cv2
import numpy as np
def colorize(img, rgb):
grey = img[..., 0]
channels = [grey * (channel / 256) for channel in rgb[::-1]]
if img.shape[2] == 4:
channels.append(img[..., 3])
return np.dstack(channels).astype(np.uint8)
原始图像:
我的原始图像是透明的,我用cv2.IMREAD_UNCHANGED
标志加载它。
我想用(128,192,255)来着色它,GIMP 2的预期结果是:
但我得到了这个,这张照片太暗了:
我现在意识到,要获得与GIMP 2中相同的效果,我需要创建一个所需颜色的泛色填充图像,并将其与源图像混合,并使用“硬光”作为混合模式。
但从语义上讲,我原本想实现的是用HSV颜色模型中新颜色的HS替换原始图像每个像素的色调分量和饱和度分量,并使用原始图像的亮度作为新图像的亮度来添加阴影。
我刚才描述的是HSL颜色混合模式。
谷歌搜索任何超过几个字提供任何相关的,但搜索关键字"blend mode"
给我Blend modes Wikipedia和Blend modes CSS specification,我也读过GIMP 2 docs。
这里没有列出Python实现,但这不会阻止我。我非常聪明,公式看起来并不复杂,我可以在几个小时内实现所有38个公式,我会花一天的时间来实现它们。我也在学习C++,所以我也会尝试用C++实现它们。
然而,我不认为我的自定义实现将是最有效的,可能有库方法,至少完成了部分工作,使用它们将提高效率,但我不知道这些方法。cv2
库提供了635个函数,如果我逐一检查所有函数,将花费大量时间。
我发现他们使用以下内容:
import cv2
from pathlib import Path
from typing import Callable
cv2_functions = [f'cv2.{k}' for k, v in cv2.__dict__.items() if isinstance(v, Callable)]
Path('D:/cv2_functions.txt').write_text('\n'.join(cv2_functions))
我没有使用inspect
,因为:
In [74]: import inspect
In [75]: inspect.isfunction(cv2.multiply)
Out[75]: False
In [76]: inspect.ismethod(cv2.multiply)
Out[76]: False
In [77]: inspect.iscode(cv2.multiply)
Out[77]: False
现有的答案实现了乘法混合模式,与我的原始代码具有相同的效果,但未能给予期望的结果。
实现强光混合模式和HSL颜色混合模式需要新的答案,所以我可以知道如何更有效地实现混合模式。
我不是在这里寻求软件推荐。问题的范围仅限于numpy
和cv2
,我在numpy
中实现混合模式,但cv2
模块提供了423个方法,其中一些方法可能至少已经完成了这里的部分工作,因此使用这些方法可以使代码更高效,但我不知道该用什么方法
因此,我想要使用cv2
提供的方法实现混合模式的示例。
至于我的目的,我目前正在用Python和PyQt 6编写一个带有AI和GUI的Tic-Tac-Toe游戏。
我已经完成了人工智能部分,但我不熟悉GUI编程,我正在努力创建GUI。
我希望用户能够完全自定义GUI来更改所有内容的颜色和样式,因此我需要找到在运行中对图片进行着色的方法。
当程序完成后,我会在代码审查上发布程序,然后我会根据反馈尝试用C++重新实现程序。
我已经实现了大部分的混合模式,我正在实现其余的混合模式。这里是它们的选择,我不会发布所有的混合模式,这样问题就不会被代码弄乱,我会为它们发布一个单独的问题,因为我不知道如何使用Alpha通道混合图像,公式中没有提到透明度:
import numpy as np
import cv2
def scale_down(base: np.ndarray, top: np.ndarray) -> np.ndarray:
return base / 255, top / 255
def scale_up(img: np.ndarray) -> np.ndarray:
return (img * 255).astype(np.uint8)
def blend_overlay(base: np.ndarray, top: np.ndarray) -> np.ndarray:
mask = base >= 0.5
result = np.zeros_like(base)
result[~mask] = (mult_2 := (2 * base * top))[~mask]
result[mask] = (2 * base + 2 * top - mult_2 - 1)[mask]
return result
def blend_hardlight(base: np.ndarray, top: np.ndarray) -> np.ndarray:
return blend_overlay(top, base)
def blend_multiply(base: np.ndarray, top: np.ndarray) -> np.ndarray:
return base * top
def blend_screen(base: np.ndarray, top: np.ndarray) -> np.ndarray:
return base + top - base * top
def blend_softlight(base: np.ndarray, top: np.ndarray) -> np.ndarray:
return (1 - 2 * top) * base**2 + 2 * base * top
def blend_colorburn(base: np.ndarray, top: np.ndarray) -> np.ndarray:
result = np.zeros_like(base)
result[ones := base == 1.0] = 1
result[zeros := top == 0.0] = 0
mask = (~ones == ~zeros) == (ones == 0)
result[mask] = 1 - np.minimum(1, (1 - base[mask]) / top[mask])
return result
1条答案
按热度按时间0g0grzrc1#
这在Python/OpenCV中很好用。
请注意,显示的结果不会显示透明度。如果您只是查看而不是保存它,这可能是您的问题。
输入:
测试结果: