减淡和加深技术
减淡可以减少我们希望在图像A中变得比以前更亮的图像区域的曝光。在图像处理中,我们通常选择或指定使用蒙版更改的图像区域。蒙版B是与图像尺寸相同的数组,蒙版将应用于图像,可以将蒙版视为一张纸,这张纸上有若干个小孔,蒙版将覆盖在图像上。纸的“孔”以255表示,不透明区域则以 0 表示。
以下代码接受两个矩阵(image和mask)并返回混合图像
def dodge_native(image,mask):
#确定输入图像形状
width,height = image.shape[:2]
#准备和图像一样大小的输出参数
blend = np.zeros((width,height),np. uint8)
for c in range(width):
for r in range(height):
#按8位移位图像的像素值
#除以蒙版的负片
result = (image[c,r]<<8)/(255 - mask[c,r])
#确保结果值在范围内
blend[c,r] = min(255,result)
return blend
像素级的除法还可以用cv2.divide函数实现。因此可以改进dodge函数
def dodge(image,mask):
return cv2.divide(image,255 - mask,scale = 256)
应用铅笔素描变换效果
我们先将图像转化成灰度图,
rimg_gray = cv2.cvtColor(img_rgb,cv2.COLOR_RGB2GRAY)
输入图像无论是RGB还是BGR都没关系,最终都可以获得一幅很好的灰度图像
将图像反转并使用大小为(21,21)的高斯内核对其进行模糊处理
inv_gray = 255 - gray_image
blurd_img = cv2.GaussianBlur(inv_gray,(21,21),0,0)
高斯模糊的数学基础是高斯函数,它是一个关于实数的钟形曲线,其公式为:
使用dodge模式将原始灰度图像与模糊之后的负片混合在一起。
gray_sketch = cv2.divide(gray_image,255 - Fuzzy_image,scale = 256)
优化思路,将变换之后的图像与背景混合在一起,使其看起来像是在画布上绘制图像一样。因此,在返回结果之前,我们希望将其与canvas混合
def convert_to_pencil_sketch(rgb_image):
gray_image = cv2.cvtColor(rgb_image,cv2.COLOR_RGB2GRAY)
blurred_image = cv2.GaussianBlur(gray_image,(21,21),0,0)#使用高斯去模糊
gray_sketch = cv2.divide(gray_image,blurred_image,scale = 256)# 将原始灰度图像除以模糊后的图像,得到素描效果,并将结果缩放到0-255的范围。
if canvas is not None:
gray_sketch = cv2.multiply(gray_sketch,canvas,scale = 1/256)
return cv2.cvtColor(gray_sketch,cv2.COLOR_GRAY2RGB)
这就是优化后的convert_to_pencil_sketch函数,它带有可选的canvas参数,可以为铅笔素描增加艺术感
生成冷调和暖调
为了操纵图像的感知色温,我们将实现曲线滤镜,这些滤镜在图像的不同区域之间控制颜色过渡,从而使我们可以巧妙地移动色谱,而不会给图像增加看起来不自然的整体色调
通过曲线平移使用颜色操作
{ (x0,y0),(x1,y1),....(xn,yn) }
每个锚点都是一对数字,分别代表输入和输出像素值。列入数字对(30,90)表示将输入像素值30增加到
如果想要使灰度图像稍微亮一些,则可以使用带有以下控制点集的曲线滤镜:
{(0,0) (128,192),(255,255)}
这意味着除0和255之外的所有输入像素值都会略微增加,从而对图像产生整体的增亮效果。
使用查找表实现曲线滤镜
def spline_to_lookup_table(spline_breaks:list,break_values:list):
spl = UnivariateSpline(spline_breaks,break_values)
return spl(range(256))
函数return参数是256个元素的列表,其中包含x的每个可能值的内插 f (x) 值。
UnivariateSpline
是 SciPy 库中的一个类,它用于创建一维数据的平滑样条。这个类通过最小二乘方法和罚项来控制平滑度,从而在拟合数据的准确度和模型的平滑度之间找到最佳平衡点。
现在我们需要做的是提出一组锚点(xi,yi),并且已经做好了准备,可以将滤镜应用于灰度输入图像
import cv2
import numpy as np
x = [0, 128, 255]
y = [0, 192, 255]
myLUT = spline_to_lookup_table(x,y)
img_curved = cv2.LUT(img_gray,myLUT).astype(np.uint8)
设计暖调和冷调效果
先定义两个通用曲线滤镜
一个可以按照趋势增加通道的所有像素值,另一个则是减少它们:
INCREASE_LOOKUP_TABLE = spline_to_lookup_table([0,64,128,192,256]
[0,70,140,210,256])
DECREASE_LOOKUP_TABLE = spline_to_lookup_table([0,64,128,192,256]
[0,30,80, 120,192])
cv2.LUT
是 OpenCV 中的一个函数,它用于执行查找表(LUT,Look-Up Table)转换。这个函数根据提供的查找表对输入图像的每个像素值进行转换
v2.LUT(src, lut[, dst]) -> dst
,其中 src
是输入的源图像,lut
是查找表,dst
是输出图像,如果未指定,则会创建一个新的图像
对于 src
中的每个元素(像素点),cv2.LUT
会通过查找 lut
表来找到对应的值,并填充到输出数组 dst
中对应的位置。具体来说,如果 src
的深度是 CV_8U
(8位无符号整数),则 d=0
;如果 src
的深度是 CV_8S
(8位有符号整数),则 d=128
。公式为:dst(I) = lut(src(I) + d)
如何将LUT查找表应用于RGB图像
首先将图片分解为不同的通道
c_r,c_g,c_b = cv2.split(rgb_image)
然后将滤镜应用于每个通道
if green_filter is not None:
c_g = cv2.LUT(c_g,green_filter).astype(np.uint8)
对RGB图像中的3个通道都执行次操作,可获得以下辅助函数
def apply_rgb_filters(rgb_image,*,red_filter=None,green_filter=None,blue_filter = None):
c_r,c_g,c_b = cv2.split(rgb_image)
if red_filter is not None:
c_r = cv2.LUT(c_r,red_filter).astype(np.uint8)
if green_filter is not None:
c_g = cv2.LUT(c_g,green_filter).astype(np.uint8)
if blue_filter is not None:
c_b = cv2.LUT(c_b,blue_filter).astype(np.uint8)
return cv2.merge((c_r,c_g,c_b))
要使图像看起来是在炎热的晴天拍摄的,最简单的方法是增加图像中的红色,并通过增加色彩饱和度使颜色显得更加鲜艳。这可以分以下两个步骤实现。
(1)分别使用INCREASE_LOOKUP_TABLE和DECREASE_LOOKUP_TABLE增加R通道,并减少RGB彩色的B通道中的像素值
interim_img = apply_rgb_filters(rgb_image,
red_filter = INCREASE_LOOKUP_TABLE,
blue_filter = DECREASE_LOOKUP_TABEL)
(2)将图像转换为 HSV 色彩空间——H表示色相,S表示饱和度,V表示值,并使用INCREASE_LOOKUP_TABLE增加S通道的值,这可以通过apply_hue_filters函数来实现,该函数需要采用一幅RGB彩色图像和一个查找表作为输入的参数
def apply_hue_filter(rgb_image,hue_filter):
c_h,c_s,c_v = cv2.split(cv2.cvtColor(rgb_image,cv2.COLOR_RGB2HSV))
c_s = cv2.LUT(c_s,hue_filter).astype(np.uint8)
return cv2.cvtColor(cv2.merge((c_h,c_s,c_v)),cv2.COLOR_HSV2RGB)
类似的也可以定义一个冷调滤镜,减少RGB图像的R通道中的像素值,增加RGB图像的B通道的像素值,然后再将图像转化为HSV色彩空间,并通过S通道降低色彩饱和度。
def _render_cool(rgb_image:np.ndarray)->np.ndarray:
interim_img = apply_rgb_filters(rgb_image,
red_filter = DECREASE_LOOKUP_TABLE,
blue_filter = INCREASE_LOOKUP_TABLE)
return apply_hue_filter(interim_img,DECREASE_LOOKUP_TABLE)