当前位置: 首页 > news >正文

使用Python实现图像的手绘风格效果

使用Python实现图像的手绘风格效果

  • 一、引言
  • 二、代码详细解释与示例
  • 三、完整框架流程
  • 四、运行
  • 五、结论
  • 附:完整代码

一、引言

在数字图像处理领域,模拟手绘风格是一项有趣且具有挑战性的任务。手绘风格图像通常具有独特的纹理和深浅变化,给人一种亲切和艺术感。本文旨在通过计算图像的梯度并模拟光照效果,实现一种简单而有效的手绘风格图像生成方法。

二、代码详细解释与示例

  1. 导入必要的库

    from PIL import Image
    import numpy as np
    import os
    
    • PIL(Pillow):用于图像的打开、转换和保存。
    • NumPy:用于数组和矩阵操作,以及数学计算。
    • os:用于文件和目录操作。
  2. 计算图像的阴影效果

     def calculate_shading(img, depth, vec_el, vec_az):# 计算图像在x和y方向上的梯度grad = np.gradient(img)grad_x, grad_y = grad  # grad_x是x方向的梯度,grad_y是y方向的梯度# 根据深度因子调整梯度大小grad_x *= depth / 100.grad_y *= depth / 100.# 计算梯度的模(大小),并添加一个小常数以避免除以零A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1e-7)  # 1e-7是为了数值稳定性# 计算单位梯度向量(在x, y, z方向上的分量)# 这里我们假设z方向上的分量为1/A,因为它代表图像表面的“法线”方向uni_x = grad_x / Auni_y = grad_y / Auni_z = 1. / A# 计算光源方向向量(在x, y, z方向上的分量)dx = np.cos(vec_el) * np.cos(vec_az)  # 光源在x方向的影响dy = np.cos(vec_el) * np.sin(vec_az)  # 光源在y方向的影响dz = np.sin(vec_el)                   # 光源在z方向(垂直于图像平面)的影响# 计算光源方向与单位梯度向量的点积,模拟光照效果# 点积越大,表示该点越亮;点积越小(越接近-1),表示该点越暗(但由于我们取绝对值并映射到0-255,所以实际上表现为更深的阴影)# 但由于我们是模拟手绘风格,所以直接乘以255并裁剪到0-255范围内b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)# 裁剪结果到0-255范围内,确保图像数据的有效性b = b.clip(0, 255)return b
    
    • 函数calculate_shading接收一个灰度图像数组img、深淡程度depth、光源的俯视角度vec_el和方位角度vec_az作为参数。
    • 使用np.gradient计算图像在x和y方向上的梯度,得到grad_xgrad_y
    • 根据depth因子调整梯度大小,然后计算梯度的模A,并添加一个小常数以避免除以零的错误。
    • 计算单位梯度向量uni_xuni_yuni_z(假设z方向上的分量为1/A)。
    • 计算光源方向向量dxdydz
    • 通过计算光源方向与单位梯度向量的点积,模拟光照效果,得到带有阴影效果的图像数组b
    • 使用clip函数将结果裁剪到0-255范围内,确保图像数据的有效性。

    示例
    假设我们有一个灰度图像img_array,我们可以调用这个函数来计算阴影效果:

    shaded_img = calculate_shading(img_array, depth=50.0, vec_el=np.pi / 2.2, vec_az=np.pi / 4.0)
    
  3. 将输入图片处理成手绘风格并保存

     # 将输入图片处理成手绘风格并保存为新文件def img_handpainted(input_img_path, depth=20.0, vec_el=np.pi / 2.2, vec_az=np.pi / 4.0):"""将指定路径的灰度图像转换成手绘风格的图像并保存。参数:input_img_path (str): 输入图片的路径。depth (float): 深淡程度控制因子,默认为20.0。vec_el (float): 光源的俯视角度(俯仰角),默认为np.pi/2.2。vec_az (float): 光源的方位角度(方位角),默认为np.pi/4.0。"""# 检查输入文件是否存在if not os.path.exists(input_img_path):raise FileNotFoundError(f"The file {input_img_path} does not exist.")# 打开并转换图像为灰度图,然后转换为NumPy数组img = np.array(Image.open(input_img_path).convert('L')).astype('float')# 从文件路径中提取图像名称(不包括扩展名)img_name = os.path.basename(input_img_path)[:-4]# 计算阴影效果shaded_img = calculate_shading(img, depth, vec_el, vec_az)# 将结果转换回图像格式并保存img_handwrite = Image.fromarray(shaded_img.astype('uint8'))outname = './' + img_name + '_handpainted.jpg'img_handwrite.save(outname)print(f"Saved image as {outname}")
    • 函数img_handpainted接收输入图片的路径input_img_path、深淡程度depth、光源的俯视角度vec_el和方位角度vec_az作为参数。
    • 检查输入文件是否存在,如果不存在则抛出FileNotFoundError异常。
    • 打开并转换图像为灰度图,然后转换为NumPy数组。
    • 从文件路径中提取图像名称(不包括扩展名)。
    • 调用calculate_shading函数计算阴影效果。
    • 将结果转换回图像格式,并保存为新的JPEG文件。
    • 打印保存的文件名。

    示例
    假设我们有一个灰度图像文件example.jpg,我们可以调用这个函数来生成手绘风格的图像:

    img_handpainted('./example.jpg', depth=30.0)
    

三、完整框架流程

  1. 准备阶段

    • 安装必要的Python库:Pillow(PIL)和NumPy。
    • 准备一张灰度图像作为输入。
  2. 计算阴影效果

    • 读取输入图像并转换为灰度图。
    • 将灰度图转换为NumPy数组,以便进行数学计算。
    • 调用calculate_shading函数,根据光源方向和深淡程度计算阴影效果。
  3. 生成手绘风格图像

    • 将计算得到的阴影效果应用到原始灰度图像上。
    • 将结果转换回图像格式。
    • 保存为新的JPEG文件。
  4. 运行脚本

    • 执行脚本,查看生成的手绘风格图像。

四、运行

原图片:
请添加图片描述
执行代码后生成的图片:
请添加图片描述

五、结论

通过本文介绍的方法,我们可以轻松地将普通灰度图像转换成具有手绘风格效果的图像。这种方法不仅简单易行,而且生成的图像具有独特的手绘质感,非常适合用于艺术创作和图像处理领域。希望本文能够帮助读者理解和实现这一有趣的技术。

附:完整代码

# -*- coding: utf-8 -*-
# @Time : 2021/7/4 22:30
# @Author : Leuanghing Chen
# @Blog : https://blog.csdn.net/weixin_46153372?spm=1010.2135.3001.5421
# @File : 手绘效果图.py
# @Software : PyCharmfrom PIL import Image
import numpy as np
import os# 计算图像的阴影效果,模拟手绘风格的深浅变化
def calculate_shading(img, depth, vec_el, vec_az):"""计算并返回带有阴影效果的灰度图像。参数:img (numpy.ndarray): 输入的灰度图像,应该是一个二维数组。depth (float): 深淡程度控制因子,范围0-100。值越大,阴影效果越明显。vec_el (float): 光源的俯视角度(俯仰角),以弧度为单位。控制光源相对于图像平面的垂直角度。vec_az (float): 光源的方位角度(方位角),以弧度为单位。控制光源在图像平面上的水平位置。返回:numpy.ndarray: 带有阴影效果的灰度图像,与输入图像尺寸相同。"""# 计算图像在x和y方向上的梯度grad = np.gradient(img)grad_x, grad_y = grad  # grad_x是x方向的梯度,grad_y是y方向的梯度# 根据深度因子调整梯度大小grad_x *= depth / 100.grad_y *= depth / 100.# 计算梯度的模(大小),并添加一个小常数以避免除以零A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1e-7)  # 1e-7是为了数值稳定性# 计算单位梯度向量(在x, y, z方向上的分量)# 这里我们假设z方向上的分量为1/A,因为它代表图像表面的“法线”方向uni_x = grad_x / Auni_y = grad_y / Auni_z = 1. / A# 计算光源方向向量(在x, y, z方向上的分量)dx = np.cos(vec_el) * np.cos(vec_az)  # 光源在x方向的影响dy = np.cos(vec_el) * np.sin(vec_az)  # 光源在y方向的影响dz = np.sin(vec_el)                   # 光源在z方向(垂直于图像平面)的影响# 计算光源方向与单位梯度向量的点积,模拟光照效果# 点积越大,表示该点越亮;点积越小(越接近-1),表示该点越暗(但由于我们取绝对值并映射到0-255,所以实际上表现为更深的阴影)# 但由于我们是模拟手绘风格,所以直接乘以255并裁剪到0-255范围内b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)# 裁剪结果到0-255范围内,确保图像数据的有效性b = b.clip(0, 255)return b# 将输入图片处理成手绘风格并保存为新文件
def img_handpainted(input_img_path, depth=20.0, vec_el=np.pi / 2.2, vec_az=np.pi / 4.0):"""将指定路径的灰度图像转换成手绘风格的图像并保存。参数:input_img_path (str): 输入图片的路径。depth (float): 深淡程度控制因子,默认为20.0。vec_el (float): 光源的俯视角度(俯仰角),默认为np.pi/2.2。vec_az (float): 光源的方位角度(方位角),默认为np.pi/4.0。"""# 检查输入文件是否存在if not os.path.exists(input_img_path):raise FileNotFoundError(f"The file {input_img_path} does not exist.")# 打开并转换图像为灰度图,然后转换为NumPy数组img = np.array(Image.open(input_img_path).convert('L')).astype('float')# 从文件路径中提取图像名称(不包括扩展名)img_name = os.path.basename(input_img_path)[:-4]# 计算阴影效果shaded_img = calculate_shading(img, depth, vec_el, vec_az)# 将结果转换回图像格式并保存img_handwrite = Image.fromarray(shaded_img.astype('uint8'))outname = './' + img_name + '_handpainted.jpg'img_handwrite.save(outname)print(f"Saved image as {outname}")# 当脚本作为主程序运行时,调用img_handpainted函数
if __name__ == '__main__':img_handpainted('./1.jpg')

http://www.mrgr.cn/news/69522.html

相关文章:

  • 仪表板展示|DataEase看中国:历年双十一电商销售数据分析
  • python共享全局变量的方案
  • 七大经典基于比较排序算法【Java实现】
  • 1111111111待修改--大流量分析(三)-BUUCTF
  • conda 启动时添加执行脚本
  • Spring 解析xml中的 BeanDefination 大概过程
  • STM32 4X4 键盘
  • 3.1 > Shell
  • python实战案例——爬取A站视频,m3u8格式视频抓取(内含完整代码!)
  • 离散数学的一些个人另类理解
  • I/O操作完成事件
  • Linux 下 mysql 9.1 安装设置初始密码 【附脚本】
  • DreamCut:AI驱动的视频编辑与屏幕录制工具
  • 从零开始的python学习(四)P54+P55+P56+P57+P58
  • 模型训练中GPU利用率低?
  • python编写学生管理系统
  • 树莓派安装FreeSWITCH
  • 背包问题(三)
  • STM32F103C8T6单片机
  • 边缘计算在智能交通系统中的应用
  • 科研绘图系列:R语言组合多个不同图形(violin density barplot heatmap)
  • Python毕业设计选题:基于django+vue的荣誉证书管理系统
  • 数据分析:16s差异分析DESeq2 | Corncob | MaAsLin2 | ALDEx2
  • Windows下Python环境安装GDAL
  • Windows上安装与使用 Jupyter Notebook
  • Android Studio 将项目打包成apk文件