圖片展示 [ Numpy 處理, Matplotlib 展示 ]

Jason990420發表於2020-03-14

檔案建立日期: 2020/03/14
最後修訂日期: None
相關軟體資訊:

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的使用.

  1. 目標

    • 以各種方式來呈現一張圖片
    • 方式有很多, 目前只提供以下幾種
      • 亮度變化
      • 捲動式或拖動式
      • 圓形展示
      • 方形展示
      • 隨機展式
    • 全部圖片的處理只能使Numpy (偶爾會有到list)
  2. 展示

  1. 程式碼及說明

    • 相關庫的匯入
 ```python
 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), 這樣只會改變亮度, 不會改變色.

 ``` Python
 def black_to_show(array, interval, mode=0):
     for i in range(interval, -1, -1):
         yield array-array*i/interval
 ```
  • 以方形的方式, 顯示圖片, 共有8種模式, 主要是依照每個點的索引值來作方形的判斷, 再以boolean值來作為圖片的陣列索引. 函式的內容雖長, 但8種模式的內容大同小異.
 ``` Python
 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陣列作為圖片陣列的索引.
 ``` Python
 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
 ```
  • 分塊隨機顯示, 簡單的圖片子陣列替換
 ``` Python
 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), 這樣只會改變亮度, 不會改變色.

 ``` Python
 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 用來暫停以更新圖片.

 ``` Python
 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)
 ```
  • 圖片的載入

    為免圖片檔案需另外存在, 直接從網頁上下載一張圖片, 供全程使用.

 ``` Python
 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 初使化, 主要還是隱藏座標軸
 ``` Pyt
 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))
 ```
  • 顯示各函式的展示功能
 ``` Python
 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)
 ```
  • 關閉繪圖介面
 ``` Python
 plt.close()
 ```
本作品採用《CC 協議》,轉載必須註明作者和本文連結

Jason Yang

相關文章