在不使用cv2等庫的情況下利用numpy實現雙線性插值縮放影像

早安660發表於2023-01-18

起因

我看到了一個別人的作業,他們老師讓不使用cv2等影像處理庫縮放影像

演算法介紹

如果你仔細看過一些庫裡縮放影像的方法引數會發現有很多可選項,其中一般預設是使用雙線性插值。具體步驟:

  • 計算目標圖座標對應原圖中哪些座標來填充
  • 根據雙線性插值的公式寫出程式碼

其中縮放函式使用numpy來加快速度,使用for迴圈縮放影像到1024*1024我的cpu執行了36s,使用numpy執行了0.38秒快了近100倍

程式碼

重點在於寫一個函式 def resize(src, width,height):,引數是目標影像的寬高

import cv2
import numpy as np
import time

def resize(src, width,height):
    dst_w =  width
    dst_h = height
    src_h, src_w = src.shape[:2] # 源影像寬高
    if src_h == dst_h and src_w == dst_w:
        return src.copy()
    scale_x = float(src_w) / dst_w # x縮放比例
    scale_y = float(src_h) / dst_h # y縮放比例
    dst = np.zeros((dst_h, dst_w, 3), dtype=np.uint8)

下面可能比較難理解,np_src_x代表目標影像的x座標,src_x也是代表目標影像的x座標只是它有3個維度,是為了之後的索引做準備。從src_x_dst開始是計算目標圖座標需要哪些原始圖座標來填充。

    np_src_x = np.arange(0, dst.shape[1])
    np_src_y = np.arange(0, dst.shape[0]).reshape((dst.shape[0], 1))
    src_x = (np_src_x + np.zeros(dst.shape[:2]))[:, :, np.newaxis] + np.zeros(dst.shape)
    src_y = (np_src_y + np.zeros(dst.shape[:2]))[:, :, np.newaxis] + np.zeros(dst.shape)
    # 計算目標圖座標對應的原始圖座標
    src_x_dst = src_x * scale_x
    src_y_dst = src_y * scale_y
    srcX0 = np.floor(src_x_dst).astype(int)
    srcY0 = np.floor(src_y_dst).astype(int)
    srcX1 = np.minimum(srcX0 + 1, src_w - 1)
    srcY1 = np.minimum(srcY0 + 1, src_h - 1)

three_axis也是為之後的索引做準備,對了,這個函式只能處理有RGB或BGR這種有3個通道的圖形,其實改進應該也不難有想法的同學可以試一下。後面的value0就是具體的公式計算了

    three_axis = np.zeros(dst.shape, dtype=int)
    three_axis[:, :, 1] = 1
    three_axis[:, :, 2] = 2
    # 根據公式計算值
    value0 = (srcX1 - src_x_dst) * src[srcY0, srcX0, three_axis] + (src_x_dst - srcX0) * src[srcY0, srcX1, three_axis]
    value1 = (srcX1 - src_x_dst) * src[srcY1, srcX0, three_axis] + (src_x_dst - srcX0) * src[srcY1, srcX1, three_axis]
    dst = ((srcY1 - src_y_dst) * value0 + (src_y_dst - srcY0) * value1).astype(np.uint8)
    return dst

完整的程式碼在這裡ScaleImage.py

這是效果圖:
image
...縮放影像看不出來效果

相關文章