概述
滤镜的本质是对图像进行某些像素级别的修改,因此,在Photoshop中的某些滤镜是可以使用Opencv模仿得到的。在本篇博文中,主要对下列滤镜进行了实现,
- 亮度效果
- 六十年代的老电视
- 浮雕
- 双色效果
- 棕黑效果
亮度效果
亮度是光的强度的一种表现,它可以在图像中使用HSV颜色通道进行操作。
下图给出了从左到右增加饱和度(S)和值矩阵(V)的效果。
从上图可以看到,当我们增加V矩阵的值时,颜色会变得更亮。因此,如果想要让图片变量,可以增加图像的饱和度和值矩阵。
下边给出一个调节图像亮度的代码。
import cv2
import numpy as np
def nothing(x):
pass
def brightness(img):
# 构建窗口,第二个参数设置为0表示可以缩放窗口大小
cv2.namedWindow('image', 0)
# val是组件的名字
# image是组件放置到某个窗口的名字
# 组件的默认值
# 组件的最大值
# 跟踪栏每次更改后激活nothing回调函数
cv2.createTrackbar('val', 'image', 100, 150, nothing)
while True:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
hsv = np.array(hsv, dtype=np.float64)
val = cv2.getTrackbarPos('val', 'image')
# 除以100是让范围限制在0-1.5
val = val/100
# 更改通道1的值,即修改饱和度
hsv[:, :, 1] = hsv[:, :, 1] * val
hsv[:, :, 1][hsv[:, :, 1] > 255] = 255
# 更改通道2的值,即修改V矩阵的值
hsv[:, :, 2] = hsv[:, :, 2] * val
hsv[:, :, 2][hsv[:, :, 2] > 255] = 255
# 转会uint8,确保能显示
hsv = np.array(hsv, dtype=np.uint8)
res = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow("original", img)
cv2.imshow('image', res)
# 按q推出程序
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
img = cv2.imread("test.jpg")
brightness(img)
测试效果如下
六十年代老电视效果
这样的效果是怎样的呢?应该是灰白的,并且有许多噪声的。
所以在实现这个效果时,需要考虑这两点。代码如下。
import cv2
import numpy as np
def nothing(x):
pass
def tv_60(img):
cv2.namedWindow('image')
# 这个控件着当前图像中的最大噪声量
cv2.createTrackbar('val', 'image', 0, 255, nothing)
# 这个控件表示受噪声影响的像素的百分比
cv2.createTrackbar('threshold', 'image', 0, 100, nothing)
while True:
height, width = img.shape[:2]
# 将图像变灰白
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 动态取得两个控件的输出值
thresh = cv2.getTrackbarPos('threshold', 'image')
val = cv2.getTrackbarPos('val', 'image')
# 由于添加噪声的过程为随机添加,因此在显示过程中有个动态的效果
for i in range(height):
for j in range(width):
if np.random.randint(100) <= thresh:
if np.random.randint(2) == 0:
# 添加噪声到图像,并且最大为255(偏白噪点)
gray[i, j] = min(gray[i, j] + np.random.randint(0, val+1), 255)
else:
# 将图像中的噪声减去,并且最小值为0(偏黑噪点)
gray[i, j] = max(gray[i, j] - np.random.randint(0, val+1), 0)
cv2.imshow('Original', img)
cv2.imshow('image', gray)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
img = cv2.imread("test.jpg")
tv_60(img)
浮雕效果
维基百科上的定义:是一种计算机图形技术,根据原始图像的明暗边界,图像的每个像素被一个高亮或阴影代替。低对比度的区域被灰色背景代替。
使用Opencv中实现这种效果十分简单,只要使用特殊的核对图像进行过滤即可。而且,附带的方向也可以根据内核的大小而改变。
下图给出了四个不同方向的内核。
可以看到,上述的内核其实本质是一样的,因此,我们可以只构建一个内核,然后使用旋转来获得其他三个不同方向的内核。
改变核的大小影响浮雕的强度。核尺寸越大,浮雕效果越显著。注意,所需的最小内核大小为2x2.
import cv2
import numpy as np
def nothing(x):
pass
# 初始内核生成函数
'''
如果size==3
0 -1 -1
1 0 -1
1 1 0
'''
def kernel_generator(size):
kernel = np.zeros((size, size), dtype=np.int8)
for i in range(size):
for j in range(size):
if i < j:
kernel[i][j] = -1
elif i > j:
kernel[i][j] = 1
return kernel
def emboss(img):
cv2.namedWindow('image')
# 该组件控制内核的大小
cv2.createTrackbar('size', 'image', 0, 8, nothing)
switch = '0 : BL n1 : BR n2 : TR n3 : BR'
# 该组件控制内核的方向
cv2.createTrackbar(switch, 'image', 0, 3, nothing)
while True:
size = cv2.getTrackbarPos('size', 'image')
# 对于每个内核的大小都加2,因为内核大小必须大于等于2
size += 2
s = cv2.getTrackbarPos(switch, 'image')
height, width = img.shape[:2]
y = np.ones((height, width), np.uint8) * 128
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 根据内核大小生成初始内核(bottom left)
kernel = kernel_generator(size)
# 根据s,即方向来旋转内核
# 逆时针旋转s个90度
kernel = np.rot90(kernel, s)
# filter2D,使用内核和图像进行卷积过滤
# add,使用add时浮雕背景设置为y,即灰色
res = cv2.add(cv2.filter2D(gray, -1, kernel), y)
cv2.imshow('Original', img)
cv2.imshow('image', res)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
img = cv2.imread("test.jpg")
emboss(img)
双色效果
没啥好说的,大伙自己看吧。
import cv2
import numpy as np
def nothing(x):
pass
def exponential_function(channel, exp):
table = np.array([min((i**exp), 255) for i in np.arange(0, 256)]).astype("uint8") # generating table for exponential function
channel = cv2.LUT(channel, table)
return channel
def duo_tone(img):
cv2.namedWindow('image')
cv2.createTrackbar('exponent', 'image', 0, 10, nothing)
switch1 = '0 : BLUE n1 : GREEN n2 : RED'
cv2.createTrackbar(switch1, 'image', 1, 2, nothing)
switch2 = '0 : BLUE n1 : GREEN n2 : RED n3 : NONE'
cv2.createTrackbar(switch2, 'image', 3, 3, nothing)
switch3 = '0 : DARK n1 : LIGHT'
cv2.createTrackbar(switch3, 'image', 0, 1, nothing)
while True:
exp = cv2.getTrackbarPos('exponent', 'image')
# 将值转换为1-2
exp = 1 + exp/100
s1 = cv2.getTrackbarPos(switch1, 'image')
s2 = cv2.getTrackbarPos(switch2, 'image')
s3 = cv2.getTrackbarPos(switch3, 'image')
res = img.copy()
for i in range(3):
if i in (s1, s2): # if channel is present
res[:, :, i] = exponential_function(res[:, :, i], exp) # increasing the values if channel selected
else:
if s3: # for light
res[:, :, i] = exponential_function(res[:, :, i], 2 - exp) # reducing value to make the channels light
else: # for dark
res[:, :, i] = 0 # converting the whole channel to 0
cv2.imshow('Original', img)
cv2.imshow('image', res)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
if __name__ == "__main__":
img = cv2.imread("test.jpg")
duo_tone(img)
棕色
这个就更好理解了,简单来说就是对图像进行调色。让一张普通的图像变为温暖的棕色。
import cv2
import numpy as np
def sepia(img):
res = img.copy()
# opencv读取图像后,一般为BGR的模式
# 为了实现棕色效果,我们需要将BGR还原为RGB
res = cv2.cvtColor(res, cv2.COLOR_BGR2RGB)
res = np.array(res, dtype=np.float64)
# 棕色矩阵,使用这个矩阵对图像进行转换即可。
res = cv2.transform(res, np.matrix([[0.393, 0.769, 0.189],
[0.349, 0.686, 0.168],
[0.272, 0.534, 0.131]]))
# 图像值裁剪,保证最大值为255
res[np.where(res > 255)] = 255
res = np.array(res, dtype=np.uint8)
res = cv2.cvtColor(res, cv2.COLOR_RGB2BGR)
cv2.imshow("original", img)
cv2.imshow("Sepia", res)
cv2.waitKey(0)
cv2.destroyAllWindows()
if __name__ == "__main__":
img = cv2.imread("test.jpg")
sepia(img)
不得不说,这个棕色效果,确实能给人一种温暖的感觉XD。