图片展示 [ Numpy 处理, Matplotlib 展示 ]
文件建立日期: 2020/03/14
最后修订日期: 2020/04/05 内容格式调整
相关软件信息:
Win10 | Python 3.7.6 | Requests 2.23.0 | Matplotlib 3.2.0 | Numpy 1.18.1 | Pillow 7.0.0 |
说明: 本文请随意引用或更改, 只须标示出处及作者, 作者不保证内容絶对正确无误, 如造成任何后果, 请自行负责.
标题: 图片展示 [ Numpy处理, Matplotlib展示 ]
PIL (Pillow) 可以用来作图片的处理, 因为要处理的不是静态的图片, 也不太会动到图片的内容, 再加上对Numpy有点生疏, 因此借由Numpy来作整个片的分割处理, 让自己再更深入了解Numpy的使用.
目标
- 以各种方式来呈现一张图片
- 方式有很多, 目前只提供以下几种
- 亮度變化
- 卷动式或拖动式
- 圆形展示
- 方形展示
- 随机展式
- 全部图片的处理只能使Numpy (偶尔会有到list)
展示
代码及说明
- 相关库的导入
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from time import sleep
import random
import requests
from io import BytesIO
图片由黑到显示
数组中的值 (也就是R, G B三色) 按各点颜色的比例从 (0, 0, 0) 到 该点的 (R, G, B), 这样只会改变亮度, 不会改变色.
def black_to_show(array, interval, mode=0):
for i in range(interval, -1, -1):
yield array-array*i/interval
- 以方形的方式, 显示图片, 共有8种模式, 主要是依照每个点的索引值来作方形的判断, 再以boolean值来作为图片的数组索引. 函数的内容虽长, 但8种模式的内容大同小异.
def box(array, interval, mode):
h, w = array.shape[0], array.shape[1]
half = int(interval/2)
y0 = np.linspace(0, array.shape[0], interval)
x0 = np.linspace(0, array.shape[1], interval)
filter = np.indices(array.shape[0:2])
im_blank = np.full(array.shape, 255, dtype=np.float)
if mode == 0:
for x, y in zip(x0, y0):
check = np.logical_and(filter[0]<=y, filter[1]<=x)
im_blank[check] = array[check]
yield im_blank
elif mode == 1:
for x, y in zip(x0[::-1], y0[::-1]):
check = np.logical_and(filter[0]>=y, filter[1]>=x)
im_blank[check] = array[check]
yield im_blank
elif mode == 2:
for x, y in zip(x0, y0[::-1]):
check = np.logical_and(filter[0]>=y, filter[1]<=x)
im_blank[check] = array[check]
yield im_blank
elif mode == 3:
for x, y in zip(x0[::-1], y0):
check = np.logical_and(filter[0]<=y, filter[1]>=x)
im_blank[check] = array[check]
yield im_blank
elif mode == 4:
for x, y in zip(x0[half:], y0[half:]):
check = np.logical_and(
np.logical_and(h-y<=filter[0], filter[0]<=y),
np.logical_and(w-x<=filter[1], filter[1]<=x))
im_blank[check] = array[check]
yield im_blank
elif mode == 5:
for x, y in zip(x0[half:], y0[half:]):
check = np.logical_or(
np.logical_and(h-y<=filter[0], filter[0]<=y),
np.logical_and(w-x<=filter[1], filter[1]<=x))
im_blank[check] = array[check]
yield im_blank
elif mode == 6:
for x, y in zip(x0[::-1][:half], y0[::-1][:half]):
check = np.logical_or(
np.logical_or(filter[0]>=y, filter[0]<=h-y),
np.logical_or(filter[1]>=x, filter[1]<=w-x))
im_blank[check] = array[check]
yield im_blank
elif mode == 7:
for x, y in zip(x0[::-1][:half], y0[::-1][:half]):
check = np.logical_and(
np.logical_or(filter[0]>=y, filter[0]<=h-y),
np.logical_or(filter[1]>=x, filter[1]<=w-x))
im_blank[check] = array[check]
yield im_blank
- 圆形展示, 分为由外向内或由内向外两种. 处理方式以各点至中心点的距离作判断, 预先计算所有点的距离, 再以boolean数组作为图片数组的索引.
def circle(array, interval, mode=0):
h, w = array.shape[0]/2, array.shape[1]/2
value = (((np.arange(array.shape[0])-h)**2)[:, None] +
(np.arange(array.shape[1])-w)**2)
m = np.max(value)
radius = np.linspace(0, m, interval)
im_blank = np.full(array.shape, 255, dtype=np.float)
if mode == 0:
for r in radius:
im_blank[value<=r,:] = im_np[value<=r,:]
yield im_blank
else:
for r in radius[::-1]:
im_blank[value>=r,:] = im_np[value>=r,:]
yield im_blank
- 分块随机显示, 简单的图片子数组替换
def random_block(array, interval, mode=0):
im_blank = np.full(array.shape, 255, dtype=np.float)
y = np.linspace(0, array.shape[0], interval+1).astype(np.int)
x = np.linspace(0, array.shape[1], interval+1).astype(np.int)
where = [(i, j) for i in range(interval) for j in range(interval)]
np.random.shuffle(where)
for i, j in where:
im_blank[y[j]:y[j+1], x[i]:x[i+1]] = array[y[j]:y[j+1], x[i]:x[i+1]]
yield im_blank
- 卷动式的图片展示, 这里也有八种方式, 四个方向 (上, 下, 左, 右), 以及拖动或显示. 这部份更简单了, 就只是图片的子数组代入.
def scroll(array, interval, mode=0):
im_blank = np.full(array.shape, 255, dtype=np.float)
if mode < 4:
for i in np.linspace(1, array.shape[1]-1, interval):
if mode == 0:
im_blank[:, :int(i)] = array[:, :int(i)]
elif mode == 1:
im_blank[:, :int(i)] = array[:, -int(i):]
elif mode == 2:
im_blank[:, -int(i):] = array[:, :int(i)]
elif mode == 3:
im_blank[:, -int(i):] = array[:, -int(i):]
yield im_blank
else:
for i in np.linspace(1, array.shape[0]-1, interval):
if mode == 4:
im_blank[:int(i)] = array[:int(i)]
elif mode == 5:
im_blank[:int(i)] = array[-int(i):]
elif mode == 6:
im_blank[-int(i):] = array[:int(i)]
elif mode == 7:
im_blank[-int(i):] = array[-int(i):]
yield im_blank
图片由白到显示
数组中的值 (也就是R, G B三色) 按各点颜色的比例从 (255, 255, 255) 到 该点的 (R, G, B), 这样只会改变亮度, 不会改变色.
def white_to_show(array, interval, mode=0):
for i in range(interval, -1, -1):
yield array+i*(255 - array)/interval
显示函数
调用相关的函数, 设定间隔及模式, 因为有时间的关系, 所以各函数都采用 yield 来迭代输出, Matplot 中的 set_data 可以不用多作已画图像的删除, draw_idle 函数用来更新, pause 用来暂停以更新图片.
def show(func, array, interval, mode=0):
for data in func(array, interval, mode):
im_plt.set_data(np.clip(data.astype(int), 0, 255))
fig.canvas.draw_idle()
plt.pause(0.001)
图片的加载
为免图片文件需另外存在, 直接从网页上下载一张图片, 供全程使用.
url = 'https://p2.bahamut.com.tw/WIKI/82/00365182.JPG'
response = requests.get(url)
im = Image.open(BytesIO(response.content))
im_np = np.array(im, dtype=np.float)
- Matplotlib 初使化, 主要还是隐藏坐标轴
fig,ax = plt.subplots(1,1)
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
im_plt = ax.imshow(np.full(im_np.shape, 255))
- 显示各函数的展示功能
show(white_to_show, im_np, 10)
show(black_to_show, im_np, 10)
for mode in range(8):
show(scroll, im_np, 10, mode=mode)
show(random_block, im_np, 5)
show(circle, im_np, 20, mode=0)
show(circle, im_np, 20, mode=1)
for mode in range(4, 8):
show(box, im_np, 20, mode=mode)
- 关闭绘图接口
plt.close()
本作品采用《CC 协议》,转载必须注明作者和本文链接