目标:
1.运用科学计算库进行矩阵分析和数值运算;
2.掌握numpy库的使用。
要点:这是一个使用
numpy
和PIL
库提取图像特征形成手绘效果的实例。
使用PIL库获取了图像的轮廓,虽然提取了轮廓,但这个轮廓缺少立体感,视觉效果不够丰满。
光线照射使立体物出现明暗变化,运用这个原理是空间素描的基本方法,本文介绍采用Python程序增加深浅层次变化,从而使图像轮廓更富立体感、空间感和色泽感,接近人类手绘效果。
一、原理
(一)图像的数组表示
import numpy as np
from PIL import Image
im=np.array(Image.open('D:\\小窝海绵宝宝.png'))
print(im.shape,im.dtype)
- 图像转换对应的ndarray类型是3维数据,如(809, 1499, 4) 其中,前两维表示图像的长度和宽度,单位是像素
第三维表示每个像素点的RGB值,每个RGB值是一个单字节整数。
(二)像素处理
- PIL库包括图像转换函数,能够改变图像为单个像素的表示形式。
使用convert()
函数,这是’L’模式,表示将像素表示从RGB的3字节形式转变为单一数值形式, 这个数值范围在0到255,表示灰度色彩变化。
此时,图像从彩色变为带有灰度的黑白色。转换后,图像的ndarray类型变为二维数据,每个像素点色彩只由一个整数表示。
im=np.array(Image.open('D:\\小窝海绵宝宝.png').convert('L'))
print(im.shape,im.dtype)
- 通过对图像的数组转换,可以利用numpy 访问图像上任意像素值
例如,获取访问位于坐标(20, 300)像素的颜色值或获取图像中最大和最小的像素值。
也可以采用切片方式获取指定行或列的元素值,甚至修改这些值。
- 将图像读入ndarray数组对象后,可以通过任意数学操作来获取相应的图像变换。
以灰度变换为例,分别对灰度变化后的图像进行反变换、区间变化和像素值平方处理。
需要注意,有些数学变换会改变图像的数据类型,如变成整数型等,所以在重
新生成PIL图像前要先将数据类型通过numpy.uint()
变换成整数
灰度值指黑白图像中点的颜色深度,范围从0到255,白色为255,黑色为0,因此.黑白图像也被称为灰度图像。
黑白图像主要用于构建非可见光图像,例如医学中超声波形成的图像等。RGB 彩色图片可以通过如下公式转换成灰度值:
Gray=R0.3+G0.59+B*0.11
严格说,黑白图像是计算机计算能力或存储能力不充分时形成图像的重要方式,
如果单个像素点能获得数据值种类超过256且计算资源足够,采用彩色图像也可以
构建非可见光图谱,例如医学应用中新发展的彩色超声波成像等。
二、实例
(一)图像的数组表示和像素计算
将原图、反变化后、区间变化后、平方值处理后的四张图效果放在一起
import numpy as np
from PIL import Image
im0=np.array(Image.open('小窝海绵宝宝.png').convert('L'))
im1=255-im0#反变换
im2=(100/255)*im0+150#区间变换
im3=255*(im1/255)**2#像素平方处理
pil_im=Image.fromarray(np.uint(im1))#将数据类型重新变换成整数
pil_im.show()
pil_im=Image.fromarray(np.uint(im2))
pil_im.show()
pil_im=Image.fromarray(np.uint(im3))
pil_im.show()
原图:
(二)图像的手绘效果
根据自己喜欢的风格调整光源参数(俯视、方位角度等)、梯度值或其他参数实现图像的手绘风。
通常获得铅笔画风格图像采用ImageFilter.CONTOUR
滤镜,它能够将图像的轮廓信息提取出来,原图像
在视觉上更加的立体,获得的轮廓图像缺乏立体感。
为了实现手绘风格,即黑白轮廓描绘,首先需要读取原图像的明暗变化,即灰度值。从直观视觉感受上定义,图像灰度值显著变化的地方就是梯度,它描述了图像灰度变化的强度。
通常可以使用梯度计算来提取图像轮廓,numpy 中提供了直接获取灰度图像梯度的函数gradient(),传入图像数组表示即可返回代表x和y各自方向上梯度变化的二维元组。
from PIL import Image
import numpy as np
#定义光源
vec_e1=np.pi/2.2 #光源的俯视角度,弧度值
vec_az=np.pi/4. #光源的方位角度,弧度值
depth=10. ##(0-100)
im=Image.open('小窝海绵宝宝.png').convert('L')
a=np.asarray(im).astype('float')
grad=np.gradient(a) #取图像灰度的梯度值
grad_x,grad_y=grad #分别取横纵图像梯度值
#给x和y方向梯度值赋权值depth
grad_x=grad_x*depth/100.
grad_y=grad_y*depth/100.
#转化为立体坐标体系
dx=np.cos(vec_e1)*np.cos(vec_az) #光源对x轴的影响
dy=np.cos(vec_e1)*np.sin(vec_az) #光源对y轴的影响
dz=np.sin(vec_e1)#光源对z轴的影响
A=np.sqrt(grad_x**2 + grad_y**2+1.)
#总梯度除以幅值得到每个像素单元的梯度值
uni_x=grad_x/A
uni_y=grad_y/A
uni_z=1./A
a2=255*(dx*uni_x + dy*uni_y + dz*uni_z)
a2=a2.clip(0,255)
im2=Image.fromarray(a2.astype('uint8'))
im2.save('手绘小窝海绵宝宝.png')
这段代码是一个Python脚本,用于将一张灰度图转化为带有光影效果的手绘风格的图片。
首先,通过PIL库中的Image类读取一张图片,这里的图片是一张名为“小窝海绵宝宝.png”的PNG图像。.convert('L')
指令将彩色图片转化为灰度图。
然后,定义光源的方向,包括俯视角度和方位角度,以及深度值(范围在0-100之间),并将其赋值给各自的变量。这些值将影响后面的光影效果。
接下来,用numpy库中的gradient函数求取图像灰度的梯度值(即图像中每个像素点在x与y方向上的梯度),并分别赋值给grad_x
和grad_y
两个数组变量。
然后,将x和y方向上的梯度值分别乘以depth(深度)除以100后再赋值给grad_x
和grad_y
,这一步是为了给梯度值赋予更大的权值,从而加深光影效果。
接着,将梯度值转化为立体坐标体系,即将光源的影响分别对应到x、y、z三个轴上,这一步会得到3个系数dx、dy、dz。
再计算每个像素单元的梯度值,即通过勾股定理求出总梯度值,再除以幅值得到,分别赋值给uni_x
、uni_y
、uni_z
三个数组变量。
最后,通过计算每个像素单元在x、y、z三个方向上的光源强度,将其加权后并将取值范围限制在0-255之间,赋值给变量a2,并用clip()
函数将其限制在0-255的范围内。
最后,利用PIL库中的Image类将a2数组变量以uint8格式存储,并将其保存为一张名为“手绘小窝海绵宝宝.png”的PNG图像。文章来源:https://www.toymoban.com/news/detail-464347.html
文章来源地址https://www.toymoban.com/news/detail-464347.html
到了这里,关于python实现科学计算与自定义手绘风的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!