Learn OpenCV----使用Opencv构建Photoshop滤镜

  • 时间:
  • 来源:互联网
  • 文章标签:

阅读原文

使用Opencv构建Photoshop滤镜

  • 概述
  • 亮度效果
  • 六十年代老电视效果
  • 浮雕效果
  • 双色效果
  • 棕色

概述

滤镜的本质是对图像进行某些像素级别的修改,因此,在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。

本文链接http://www.taodudu.cc/news/show-1944640.html