大家好,我是小小明,在學習 好友葉庭云 介紹的一門中國大學MOOC的課程中,學到手繪影像,下面我測驗并總結一下,
課程鏈接是:https://www.icourse163.org/course/BIT-1001870002?from=searchPage
下面使用Python Imaging Library ( PIL ) 進行影像處理,安裝方式:
pip install pillow
彩色圖片轉手繪線稿的原理簡述
對于一張手繪圖,其特征主要是邊界線條較重、相同或相近色彩趨于白色、略有光源效果,
將彩色圖片轉換為手繪線稿,首先需要將圖片轉換為灰度圖片,
灰度值實際代表了影像明暗的變化,而梯度代表了灰度的變化率,
調整像素的梯度值可以間接改變影像的明暗程度,
下面以如下圖片為例進行測驗:
from PIL import Image
import numpy as np
im = Image.open('001.jpg')
im

轉換為灰度模式:
im = im.convert("L")
im

獲取灰度圖片像素點資料的numpy陣列:
data = np.array(im)
data.shape, data.dtype
((300, 300), dtype('uint8'))
調整像素的梯度值
調整像素的梯度值間接改變影像的明暗程度
首先提取出x和y方向的梯度:
grad_x, grad_y = np.gradient(data)
print(grad_x.shape, grad_y.shape)
(300, 300) (300, 300)
深度值的取值范圍為0-100,決定了梯度的縮放比例,現在預設深度值為10:
depth = 10
grad_x /= 100/depth
grad_y /= 100/depth
光源效果
根據灰度變化來模擬人類視覺的遠近程度
- 設計一個位于影像斜上方的虛擬光源
- 光源相對于影像的俯視角為 eLevation,方位角為 Azimuth
- 建立光源對個點梯度值的影響函式
- 運算出各點的新像素值
]
假設俯視角eLevation= π 2.2 \frac \pi {2.2} 2.2π?,方位角Azimuth= π 4 \frac \pi {4} 4π?:
eLevation = np.pi / 2.2
azimuth = np.pi / 4
# 光源對x/y/z軸三個方向的影響程度
dx = np.cos(eLevation) * np.cos(azimuth)
dy = np.cos(eLevation) * np.sin(azimuth)
dz = np.sin(eLevation)
梯度歸一化
構造x和y軸梯度的三維歸一化單位坐標系:
A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
uni_x = grad_x / A
uni_y = grad_y / A
uni_z = 1. / A
梯度與光源相互作用,將梯度轉化為灰度:
b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)
最終看看轉換效果:
Image.fromarray(b.clip(0, 255).astype('uint8'))

代碼封裝
from PIL import Image
import numpy as np
from PIL.ImageFile import ImageFile
from typing import Union
def img2sketch(img: Union[str, ImageFile], depth=10, eLevation=np.pi / 2.2, azimuth=np.pi / 4):
assert isinstance(img, str) or isinstance(img, ImageFile)
assert 0 < depth <= 100
if isinstance(img, str):
im = Image.open(img)
else:
im = img
data = np.array(im.convert("L"))
grad_x, grad_y = np.gradient(data)
# 根據深度縮放梯度
grad_x /= 100/depth
grad_y /= 100/depth
# 光源對x/y/z軸三個方向的影響程度
dx = np.cos(eLevation) * np.cos(azimuth)
dy = np.cos(eLevation) * np.sin(azimuth)
dz = np.sin(eLevation)
# 構造x和y軸梯度的三維歸一化單位坐標系
A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.)
uni_x = grad_x / A
uni_y = grad_y / A
uni_z = 1. / A
# 梯度與光源相互作用,將梯度轉化為灰度
b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z)
return Image.fromarray(b.clip(0, 255).astype('uint8'))
調整一下深度和光源方向測驗一下:
img2sketch('001.jpg', 5, azimuth=-5/4*np.pi)

影像處理中的三個基本操作
反相:
對于三通道的RGB圖片:
t = [255, 255, 255] - data # 計算RGB三個通道的補值
Image.fromarray(t.astype('uint8'))
對于單通道的灰度圖片:
t = 255 - data
Image.fromarray(t.astype('uint8'))
區間變換(灰度影像):
t = (100 / 255) * data + 150 # 區間變換
Image.fromarray(t.astype('uint8'))
像素取平方(灰度影像):
t = 255 * (data / 255) ** 2 # 像素平方
Image.fromarray(e.astype('uint8'))
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/290269.html
標籤:python
下一篇:python進階練習之——算素數
