Python 计算机视觉编程进阶之图像特效处理篇

 更新时间:2021年11月24日 09:56:18   作者:一马归一码  
计算机视觉这种技术可以将静止图像或视频数据转换为一种决策或新的表示。所有这样的转换都是为了完成某种特定的目的而进行的,本篇我们来学习下如何对图像进行特效处理

前言

参考的一些文章以及论文我都会给大家分享出来 —— 链接就贴在原文,论文我上传到资源中去,大家可以免费下载学习,如果当天资源区找不到论文,那就等等,可能正在审核,审核完后就可以下载了。大家一起学习,一起进步!加油!!

图像特效处理一般是对图像的像素点的通道、灰度值值等进行操作,达到想要的结果,下面将会给大家一一呈现一些简单特效的原理以及代码实现,希望能够对大家有一定的帮助。

话不多说,先是本系列文章的经典操作之读取图像信息:

"""
Author:XiaoMa
date:2021/11/16
"""
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt
 
img0 = cv2.imread('E:\From Zhihu\For the desk\cvfifteen1.jpg')
img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
h, w = img0.shape[:2]
print(h, w)
cv2.imshow("W0", img0)
cv2.imshow("W1", img1)
cv2.waitKey(delay = 0)

得到的图像信息如下:

386 686

1. 毛玻璃特效

毛玻璃特效的原理是在当前的像素点的邻域内随机取一个像素点来代替它,从而达到一个毛玻璃的模糊的效果。代码如下,已经添加了注释,如果有看不懂的地方评论区留言大家一起讨论。

#毛玻璃特效
img2 = np.zeros((h, w, 3), np.uint8)        #生成与原图像等大的全零矩阵
for i in range(0, h - 6):                   #防止下面的随机数超出边缘
    for j in range(0, w - 6):
        index = int(np.random.random()*6)   #0~6的随机数
        (b, g, r) = img0[i + index, j + index]
        img2[i, j] = (b, g, r)
cv2.imshow("W2", img2)
cv2.waitKey(delay = 0)

得到的效果如下:

由于取随机数的时候必须要减去边缘的那些像素点值,所以图像的右边界和下边界不可避免的出现了未填充区域。

在写博客的时候突然心生一计,如果我们在创建全零矩阵时就对边界进行限定不就可以了嘛,试了一下,果然可以!!如下:

#毛玻璃特效
img2 = np.zeros((h - 6, w - 6, 3), np.uint8)        #生成的全零矩阵考虑到了随机数范围,变小了
for i in range(0, h - 6):                   #防止下面的随机数超出边缘
    for j in range(0, w - 6):
        index = int(np.random.random()*6)   #0~6的随机数
        (b, g, r) = img0[i + index, j + index]
        img2[i, j] = (b, g, r)
cv2.imshow("W2", img2)
cv2.waitKey(delay = 0)

经过上述方式生成的毛玻璃特效就不会出现未填充部位,但图像的尺寸确实小了。

2. 浮雕特效

Python 实现浮雕特效的原理是先勾勒出图像的边界曲线,然后降低边界周围的像素值,从而得到一幅立体的浮雕形式的图像。

#浮雕特效(需要对灰度图像进行操作)
img3 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w - 2):                #减2的效果和上面一样
        grayP0 = int(img1[i, j])
        grayP1 = int(img1[i, j + 2])         #取与前一个像素点相邻的点
        newP = grayP0 - grayP1 + 150         #得到差值,加一个常数可以增加浮雕立体感
        if newP > 255:
            newP = 255
        if newP < 0:
            newP = 0
        img3[i, j] = newP
cv2.imshow("W3", img3)
cv2.waitKey(delay = 0)

得到效果如下:

3. 素描特效

该特效实现较为简单,直接在代码中给出注释:

#素描特效
img4 = 255 - img1                                               #对原灰度图像的像素点进行反转
blurred = cv2.GaussianBlur(img4, (21, 21), 0)                   #进行高斯模糊
inverted_blurred = 255 - blurred                                #反转
img4 = cv2.divide(img1, inverted_blurred, scale = 127.0)        #灰度图像除以倒置的模糊图像得到铅笔素描画
cv2.imshow("W4", img4)
cv2.waitKey(delay = 0)

4. 怀旧特效

怀旧特效需要专门的 R, G, B 通道的转换公式来对图像的三个通道进行处理,转换公式为:

\huge \\R = 0.393*r + 0.769*g + 0.189*b\\ G = 0.349*r + 0.686*g + 0.168*b\\ B = 0.272*r + 0.534*g + 0.131*b

实现代码如下:

#怀旧特效
img5 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w):
        B = 0.272 * img0[i, j][2] + 0.534 * img0[i, j][1] + 0.131 * img0[i, j][0]
        G = 0.349 * img0[i, j][2] + 0.686 * img0[i, j][1] + 0.168 * img0[i, j][0]
        R = 0.393 * img0[i, j][2] + 0.769 * img0[i, j][1] + 0.189 * img0[i, j][0]
        if B > 255:
            B = 255
        if G > 255:
            G = 255
        if R > 255:
            R = 255
        img5[i, j] = np.uint8((B, G, R))
cv2.imshow("W5", img5)
cv2.waitKey(delay = 0)

得到效果如下:

这个特效计算量比起前面的几种还是有点大的,需要对像素点进行遍历,然后计算每一个点的三个通道的值。

5. 流年特效

比起前面的怀旧特效,流年特效只需要对图像的每一个像素点的蓝色通道(B)进行简单调整就可以了,首先是对其开根号,然后乘以一个参数即可,实现代码如下:

#流年特效
img6 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w):
        B = math.sqrt(img0[i, j][0]) *14       # B通道的数值开平方乘以参数14
        G = img0[i, j][1]
        R = img0[i, j][2]
        if B > 255:
            B = 255
        img6[i, j] = np.uint8((B, G, R))
cv2.imshow("W6", img6)
cv2.waitKey(delay = 0)

大家可以多修改参数进行调试,观察不同的参数下的效果。

6. 水波特效

水波特效是使用三角函数得到波纹的传递函数,然后根据设定的中心进行特效的生成,该部分的算法有点难度,多尝试几次就可以了,以后博主有时间会专门出一片水波特效的介绍博文。实现代码如下:

#水波特效
img7 = np.zeros((h, w, 3), np.uint8)
wavelength = 20                                 #定义水波特效波长
amplitude = 30                                  #幅度
phase = math.pi / 4                             #相位
centreX = 0.5                                   #水波中心点X
centreY = 0.5                                   #水波中心点Y
radius = min(h, w) / 2
icentreX = w*centreX                            #水波覆盖宽度
icentreY = h*centreY                            #水波覆盖高度
for i in range(0, h):
    for j in range(0, w):
        dx = j - icentreX
        dy = i - icentreY
        distance = dx * dx + dy * dy
        if distance > radius * radius:
            x = j
            y = i
        else:
            # 计算水波区域
            distance = math.sqrt(distance)
            amount = amplitude * math.sin(distance / wavelength * 2 * math.pi - phase)
            amount = amount * (radius - distance) / radius
            amount = amount * wavelength / (distance + 0.0001)
            x = j + dx * amount
            y = i + dy * amount
        # 边界判断
        if x < 0:
            x = 0
        if x >= w - 1:
            x = w - 2
        if y < 0:
            y = 0
        if y >= h - 1:
            y = h - 2
        p = x - int(x)
        q = y - int(y)
        # 图像水波赋值
        img7[i, j, :] = (1 - p) * (1 - q) * img0[int(y), int(x), :] + p * (1 - q) * img0[int(y), int(x), :]
        + (1 - p) * q * img0[int(y), int(x), :] + p * q * img0[int(y), int(x), :]
cv2.imshow("W7", img7)
cv2.waitKey(delay = 0)

得到效果如下:

由于这张图片刚好波纹附近是头发,导致得到的波纹显得不太清晰,可以换几张图片尝试一下,看看该算法的效果。

7. 卡通特效

该特效主要原理是提取图像的边界轮廓,然后和原图像相与得到最终的卡通化效果,代码如下,已添加注释:

#卡通特效
num_bilateral = 7                                      #定义双边滤波的数目
for i in range(num_bilateral):                         #双边滤波处理,除去噪声,保留边界
    img_color = cv2.bilateralFilter(img0, d = 9, sigmaColor = 5, sigmaSpace = 3)
img_blur = cv2.medianBlur(img1, 7)                     # 中值滤波处理
img_edge = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize = 5, C = 2) #边缘检测及自适应阈值化处理,提取边界
img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)  #转换回彩色图像
img8 = cv2.bitwise_and(img0, img_edge)          #图像的与运算
cv2.imshow('W8', img8)
cv2.waitKey(delay = 0)

得到效果如下:

如果对实现的效果不满意,可以不断调整双边滤波和中值滤波的参数,直到找到较为满意的效果。

8. 将图像都汇总到一张图中

基础操作,没啥可注释的,直接上代码:

#将所有图像保存到一张图中
plt.rcParams['font.family'] = 'SimHei'
imgs = [img0, img1, img2, img3, img4, img5, img6, img7, img8]
titles = ['原图', '灰度图', '毛玻璃特效', '浮雕特效', '素描特效', '怀旧特效', '流年特效', '水波特效', '卡通特效']
for i in range(9):
    imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB)
    plt.subplot(3, 3, i + 1)
    plt.imshow(imgs[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.suptitle('图像特效处理')
plt.savefig('E:\From Zhihu\For the desk\cvfifteenresult.jpg', dpi = 1080)
plt.show()

得到最终的总图 :

9. 总体代码

修改一下图像读取路径就可以使用了。还是那句话,建议从头慢慢来一遍,当然如果你只是想给女朋友生成一张素描或者浮雕的话那就无所谓了哈哈哈。

"""
Author:XiaoMa
date:2021/11/16
"""
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt
 
img0 = cv2.imread('E:\From Zhihu\For the desk\cvfifteen1.jpg')
img1 = cv2.cvtColor(img0, cv2.COLOR_BGR2GRAY)
h, w = img0.shape[:2]
print(h, w)
cv2.imshow("W0", img0)
cv2.imshow("W1", img1)
cv2.waitKey(delay = 0)
#毛玻璃特效
img2 = np.zeros((h - 6, w - 6, 3), np.uint8)        #生成的全零矩阵考虑到了随机数范围,变小了
for i in range(0, h - 6):                   #防止下面的随机数超出边缘
    for j in range(0, w - 6):
        index = int(np.random.random()*6)   #0~6的随机数
        (b, g, r) = img0[i + index, j + index]
        img2[i, j] = (b, g, r)
cv2.imshow("W2", img2)
cv2.waitKey(delay = 0)
#浮雕特效(需要对灰度图像进行操作)
img3 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w - 2):                #减2的效果和上面一样
        grayP0 = int(img1[i, j])
        grayP1 = int(img1[i, j + 2])         #取与前一个像素点相邻的点
        newP = grayP0 - grayP1 + 150         #得到差值,加一个常数可以增加浮雕立体感
        if newP > 255:
            newP = 255
        if newP < 0:
            newP = 0
        img3[i, j] = newP
cv2.imshow("W3", img3)
cv2.waitKey(delay = 0)
#素描特效
img4 = 255 - img1                                               #对原灰度图像的像素点进行反转
blurred = cv2.GaussianBlur(img4, (21, 21), 0)                   #进行高斯模糊
inverted_blurred = 255 - blurred                                #反转
img4 = cv2.divide(img1, inverted_blurred, scale = 127.0)        #灰度图像除以倒置的模糊图像得到铅笔素描画
cv2.imshow("W4", img4)
cv2.waitKey(delay = 0)
#怀旧特效
img5 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w):
        B = 0.272 * img0[i, j][2] + 0.534 * img0[i, j][1] + 0.131 * img0[i, j][0]
        G = 0.349 * img0[i, j][2] + 0.686 * img0[i, j][1] + 0.168 * img0[i, j][0]
        R = 0.393 * img0[i, j][2] + 0.769 * img0[i, j][1] + 0.189 * img0[i, j][0]
        if B > 255:
            B = 255
        if G > 255:
            G = 255
        if R > 255:
            R = 255
        img5[i, j] = np.uint8((B, G, R))
cv2.imshow("W5", img5)
cv2.waitKey(delay = 0)
#流年特效
img6 = np.zeros((h, w, 3), np.uint8)
for i in range(0, h):
    for j in range(0, w):
        B = math.sqrt(img0[i, j][0]) *14       # B通道的数值开平方乘以参数14
        G = img0[i, j][1]
        R = img0[i, j][2]
        if B > 255:
            B = 255
        img6[i, j] = np.uint8((B, G, R))
cv2.imshow("W6", img6)
cv2.waitKey(delay = 0)
#水波特效
img7 = np.zeros((h, w, 3), np.uint8)
wavelength = 20                                 #定义水波特效波长
amplitude = 30                                  #幅度
phase = math.pi / 4                             #相位
centreX = 0.5                                   #水波中心点X
centreY = 0.5                                   #水波中心点Y
radius = min(h, w) / 2
icentreX = w*centreX                            #水波覆盖宽度
icentreY = h*centreY                            #水波覆盖高度
for i in range(0, h):
    for j in range(0, w):
        dx = j - icentreX
        dy = i - icentreY
        distance = dx * dx + dy * dy
        if distance > radius * radius:
            x = j
            y = i
        else:
            # 计算水波区域
            distance = math.sqrt(distance)
            amount = amplitude * math.sin(distance / wavelength * 2 * math.pi - phase)
            amount = amount * (radius - distance) / radius
            amount = amount * wavelength / (distance + 0.0001)
            x = j + dx * amount
            y = i + dy * amount
        # 边界判断
        if x < 0:
            x = 0
        if x >= w - 1:
            x = w - 2
        if y < 0:
            y = 0
        if y >= h - 1:
            y = h - 2
        p = x - int(x)
        q = y - int(y)
        # 图像水波赋值
        img7[i, j, :] = (1 - p) * (1 - q) * img0[int(y), int(x), :] + p * (1 - q) * img0[int(y), int(x), :]
        + (1 - p) * q * img0[int(y), int(x), :] + p * q * img0[int(y), int(x), :]
cv2.imshow("W7", img7)
cv2.waitKey(delay = 0)
#卡通特效
num_bilateral = 7                                      #定义双边滤波的数目
for i in range(num_bilateral):                         #双边滤波处理
    img_color = cv2.bilateralFilter(img0, d = 9, sigmaColor = 5, sigmaSpace = 3)
img_blur = cv2.medianBlur(img1, 7)                     # 中值滤波处理
img_edge = cv2.adaptiveThreshold(img_blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, blockSize = 5, C = 2) #边缘检测及自适应阈值化处理
img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)  #转换回彩色图像
img8 = cv2.bitwise_and(img0, img_edge)          #图像的与运算
cv2.imshow('W8', img8)
cv2.waitKey(delay = 0)
#将所有图像保存到一张图中
plt.rcParams['font.family'] = 'SimHei'
imgs = [img0, img1, img2, img3, img4, img5, img6, img7, img8]
titles = ['原图', '灰度图', '毛玻璃特效', '浮雕特效', '素描特效', '怀旧特效', '流年特效', '水波特效', '卡通特效']
for i in range(9):
    imgs[i] = cv2.cvtColor(imgs[i], cv2.COLOR_BGR2RGB)
    plt.subplot(3, 3, i + 1)
    plt.imshow(imgs[i])
    plt.title(titles[i])
    plt.xticks([])
    plt.yticks([])
plt.suptitle('图像特效处理')
plt.savefig('E:\From Zhihu\For the desk\cvfifteenresult.jpg', dpi = 1080)
plt.show()

结束语

本篇文章总结了图像特效处理中的毛玻璃、浮雕、素描等一些操作的原理和简单实现,对于一些比较复杂的算法后面有时间再专门写一篇博文进行介绍,还有油画特效本文也没有介绍,由于该特效算法也和水波特效一样有难度,所以后面等更新完这个系列我再慢慢补坑吧。

到此这篇关于Python 计算机视觉编程进阶之图像特效处理篇的文章就介绍到这了,更多相关Python 图像特效处理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python GAE、Django导出Excel的方法

    Python GAE、Django导出Excel的方法

    在Python中操作Excel的方法可以通过COM,最常用的跨平台的方法是使用pyExcelerator,pyExcelerator的使用方法可以参考limodou的《使用pyExcelerator来读写Excel文件》。
    2008-11-11
  • Python Pandas中rolling方法的使用指南

    Python Pandas中rolling方法的使用指南

    在数据分析和时间序列数据处理中,经常需要执行滚动计算或滑动窗口操作,Pandas库提供了rolling方法,用于执行这些操作,下面我们就来学习一下rolling方法的具体使用吧
    2023-11-11
  • Python渗透测试入门之Scapy库的使用详解

    Python渗透测试入门之Scapy库的使用详解

    Scapy 是一个用来解析底层网络数据包的Python模块和交互式程序,该程序对底层包处理进行了抽象打包,使得对网络数据包的处理非常简便。本文就来聊聊它的具体使用,希望对大家有所帮助
    2023-03-03
  • python中使用.py配置文件的方法详解

    python中使用.py配置文件的方法详解

    这篇文章主要介绍了python中使用.py配置文件的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • python检测远程服务器tcp端口的方法

    python检测远程服务器tcp端口的方法

    这篇文章主要介绍了python检测远程服务器tcp端口的方法,涉及Python操作socket检测tcp端口的技巧,需要的朋友可以参考下
    2015-03-03
  • python如何启动cmd批处理文件

    python如何启动cmd批处理文件

    这篇文章主要介绍了python如何启动cmd批处理文件问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • python一秒搭建FTP服务器

    python一秒搭建FTP服务器

    今天给大家分享一篇教程关于python一秒搭建FTP服务器的教程,在搭建过程中需要用到pyftpdlib模块,对python FTP服务器搭建过程感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • pycharm远程调试openstack的图文教程

    pycharm远程调试openstack的图文教程

    这篇文章主要为大家详细介绍了pycharm远程调试openstack的图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • Python中私有属性的定义方式

    Python中私有属性的定义方式

    这篇文章主要介绍了Python中私有属性的定义方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • python输入多行的方法总结

    python输入多行的方法总结

    Python中的Input()函数在输入时,遇到回车符,那么一次输入就结束了,这不能满足输入多行文本并且行数也不确定的情形,当然输入空行也是允许的,本文给大家总结了python输入多行的方法,需要的朋友可以参考下
    2024-04-04

最新评论