Python 实现图像特效中的油画效果

何川
何川
发布时间:2026-10-15| 5人浏览过
原创

本文介绍利用 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 图像油画效果相关内容,请查阅本站往期文章或继续浏览后续内容。感谢大家的支持!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。