Python 实现图像特效中的油画效果
本文介绍利用 Python 和 OpenCV 库实现图像油画特效的方法。核心原理包括将图像转为灰度、划分为局部区域(如 4x4 像素块)、对灰度值进行量化统计,并选取出现频率最高的灰度等级计算平均值以替换原像素。文章提供了完整的代码实现及保存示例,适用于希望了解基础图像算法的开发者。
在之前的文章《Python 计算机视觉(十五)—— 图像特效处理》中,已介绍多种图像特效处理方法,但遗漏了油画特效。本文将简述油画特效的基本原理并提供代码实现。感兴趣的用户可以跟随代码操作,或直接运行查看效果。
一 基本原理
如图所示,恰当的油画处理能使图像呈现出独特的艺术感。

原始拍摄图像

转换后的油画风格图像
将普通图像转换为油画风格通常包含以下步骤:
(1)将原始图像转换为灰度图像。
(2)将图像划分为若干个小方框(例如 4*4 或 6*6 像素),并统计每个方框内所有像素点的像素值。
(3)对方框内的像素灰度值进行量化处理(具体可参考之前的量化文章),并统计不同量化等级下的像素点数量。
(4)找出方框中出现次数最多的灰度等级,并计算属于该等级的像素点的灰度平均值。
(5)使用该平均值替换原图像中对应像素点的像素值。
二 代码实现
首先执行常规操作,读取图像数据:
"""
Author:XiaoMa
date:2021/12/10
"""
import cv2
import numpy as np
img = cv2.imread(r'E:\From Zhihu\For the desk\cvyouhua.jpg')
img = cv2.resize(img, dsize = None, fx = 0.2, fy = 0.2) #由于该算法计算量较大,首先对其大小进行调整
cv2.imshow('W0', img)
cv2.waitKey(0)
#获取图片宽高
height, width = img.shape[:2]
print(height, width)
获取的图像信息如下:


对图像应用油画特效处理,代码已添加详细注释。若对注释部分有疑问,可在评论区讨论或私信留言,作者会及时回复:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#将图像转化为灰度图像
dst = np.zeros((height, width, 3), np.uint8)#创建一个和原图等大小的全零矩阵
#-----------------------------------------------------------------------
#使用for循环嵌套来遍历图像中的每一个像素点
#-----------------------------------------------------------------------
for i in range(2, height-2):
for j in range(2, width-2):
# ----------------------------------------------------------
# 方框为4*4,对方框内像素点进行量化并记录不同等级的像素点的个数
# ------------------------------------------------------------
array1 = np.zeros(8, np.uint8)#将像素点的值量化为8份,定义数组记录不同等级像素点的个数
for m in range(-2, 2):
for n in range(-2, 2):
p1 = int(gray[i+m, j+n]/32)#量化操作
array1[p1] = array1[p1] + 1#该数组用来记录不同量化级别下的像素点,比如array1[0]代表等级一下的像素点的个数,即像素值为(0~64)的像素点的个数
#-----------------------------------------------------------
#在上面的数组中寻找最大值,即寻找数目最多的像素等级
#------------------------------------------------------------
currentMax = array1[0]
l = 0#用来封装最大值在数组中的位置
for k in range(0, 8):
if currentMax < array1[k]:
currentMax = array1[k]
l = k
#------------------------
#求数目最多的像素等级的平均
#------------------------
for m in range(-2, 2):
for n in range(-2, 2):
if gray[i + m, j + n] >= (l * 32) and gray[i + m, j + n] <= ((l + 1) * 32):
(b, g, r) = img[i + m, j + n]
dst[i, j] = (b, g, r)
cv2.imshow('youhua', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
处理后的结果如下:

三 总体实现代码以及保存
以下是完整的代码实现及图像保存方式。用户只需修改读取和保存的文件路径即可使用。若希望深入理解算法逻辑,建议手动输入并运行代码:
"""
Author:XiaoMa
date:2021/12/15
"""
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread(r'E:\From Zhihu\For the desk\cvyouhua.jpg')
img = cv2.resize(img, dsize = None, fx = 0.2, fy = 0.2) #由于该算法计算量较大,首先对其大小进行调整
cv2.imshow('W0', img)
cv2.waitKey(0)
#获取图片宽高
height, width = img.shape[:2]
print(height, width)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)#将图像转化为灰度图像
dst = np.zeros((height, width, 3), np.uint8)#创建一个和原图等大小的全零矩阵
#-----------------------------------------------------------------------
#使用for循环嵌套来遍历图像中的每一个像素点
#-----------------------------------------------------------------------
for i in range(2, height-2):
for j in range(2, width-2):
# ----------------------------------------------------------
# 方框为4*4,对方框内像素点进行量化并记录不同等级的像素点的个数
# ------------------------------------------------------------
array1 = np.zeros(8, np.uint8)#将像素点的值量化为8份,定义数组记录不同等级像素点的个数
for m in range(-2, 2):
for n in range(-2, 2):
p1 = int(gray[i+m, j+n]/32)#量化操作
array1[p1] = array1[p1] + 1#该数组用来记录不同量化级别下的像素点,比如array1[0]代表等级一下的像素点的个数,即像素值为(0~64)的像素点的个数
#-----------------------------------------------------------
#在上面的数组中寻找最大值,即寻找数目最多的像素等级
#------------------------------------------------------------
currentMax = array1[0]
l = 0#用来封装最大值在数组中的位置
for k in range(0, 8):
if currentMax < array1[k]:
currentMax = array1[k]
l = k
#------------------------
#求数目最多的像素等级的平均
#------------------------
for m in range(-2, 2):
for n in range(-2, 2):
if gray[i + m, j + n] >= (l * 32) and gray[i + m, j + n] <= ((l + 1) * 32):
(b, g, r) = img[i + m, j + n]
dst[i, j] = (b, g, r)
cv2.imshow('youhua', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
#------------------------------------------------
#保存图像(以前的文章中介绍过,有不懂的地方可以去考古)
#------------------------------------------------
plt.rcParams['font.family'] = 'SimHei' #将全局中文字体改为黑体
ImgGroup = [img, gray, dst]
ImgTitle = ['原图', '灰度图', '油画']
a = plt.figure(figsize=(30, 10)) #创建画布
for i in range(0, 3):
ImgGroup[i] = cv2.cvtColor(ImgGroup[i], cv2.COLOR_BGR2RGB)
plt.subplot(1, 3, i + 1)
plt.imshow(ImgGroup[i])
plt.title(ImgTitle[i])
plt.suptitle('图像油画特效')
plt.xticks([])
plt.yticks([])
plt.savefig(r'E:\From Zhihu\For the desk\Acvyouhua.jpg')
plt.show()
最终得到的结果如下:

至此,关于 Python 实现图像油画特效的介绍结束。如需了解更多 Python 图像油画效果相关内容,请查阅本站往期文章或继续浏览后续内容。感谢大家的支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









