天天看點

【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦

簡介

在圖像進行中,平移變換、旋轉變換以及放縮變換是一些基礎且常用的操作。這些幾何變換并不改變圖象的象素值,隻是在圖象平面上進行象素的重新排列。在一幅輸入圖象 [ u , v ] [u,v] [u,v]中,灰階值僅在整數位置上有定義。然而,輸出圖象[x,y]的灰階值一般由處在非整數坐标上的 ( u , v ) (u,v) (u,v)值來決定。這就需要插值算法來進行處理,常見的插值算法有最近鄰插值、雙線性插值和三次樣條插值。

算法理論介紹與推薦

最近鄰插值算法原理

【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦
【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦

實作代碼 numpy和cv2

import numpy as np
def near_insert_1color(pic_dt, resize, x_scale=None, y_scale=None):
	"""
	最近鄰插值(圖檔 m * n * 圖層)
	param pic_dt: 為一個圖檔的一個圖層的資料 len(pic_dt) == 2
	param resize: set (長, 寬)
	param x_scale: float 長度縮放大小
	param y_scale: float 寬帶縮放大小
	"""
    m, n = pic_dt.shape
    # 擷取新的圖像的大小
    if resize is None:
        n_new, m_new  =  np.round(x_scale * n).astype(int), np.round(y_scale * m).astype(int)
    else:
        n_new, m_new  = resize
    
    fx, fy = n / n_new, m / m_new # src_{長}/dst_{長}, src_{寬}/dst_{寬}
    # 初始化X, Y的位置點
    idx_x_orign = np.array(list(range(n_new)) * m_new).reshape(m_new, n_new)
    idx_y_orign = np.repeat(list(range(m_new)), n_new).reshape(m_new, n_new)
    # 需要的近鄰的位置
    x_indx = np.round(idx_x_orign * fx).astype(int)
    y_indx = np.round(idx_y_orign * fy).astype(int)
    return   pic_dt[y_indx, x_indx]

def near_insert(pic_dt_, resize, fx=None, fy=None):
    # 三個通道分開處理再合并
    if len(pic_dt_.shape) == 3:
        out_img0 = near_insert_1color(pic_dt_[:,:,0], resize=resize, x_scale=fx, y_scale=fy)
        out_img1 = near_insert_1color(pic_dt_[:,:,1], resize=resize, x_scale=fx, y_scale=fy)
        out_img2 = near_insert_1color(pic_dt_[:,:,2], resize=resize, x_scale=fx, y_scale=fy)
        out_img_all = np.c_[out_img0[:,:,np.newaxis], out_img1[:,:,np.newaxis], out_img2[:,:,np.newaxis]]
    else:
        out_img_all = near_insert_1color(pic_dt_, resize=resize, x_scale=fx, y_scale=fy)
    return out_img_al
           
import cv2 
"""
v2.resize(
src	【必需】原圖像
dsize	【必需】輸出圖像所需大小 (長 , 寬) (shape[1], shape[0])
fx	【可選】沿水準軸的比例因子
fy	【可選】沿垂直軸的比例因子
interpolation	【可選】插值方式
)

cv.INTER_NEAREST	最近鄰插值
cv.INTER_LINEAR	雙線性插值
cv.INTER_CUBIC	基于4x4像素鄰域的3次插值法
cv.INTER_AREA	基于局部像素的重采樣
"""
# 讀取圖檔
img =  cv2.imread(pic_fil, cv2.IMREAD_UNCHANGED) 
# cv2.resize 方法 放大1.5倍
resized1_5_img_near = cv2.resize(img
				, dsize=None
				, fx=1.5
				, fy=1.5
				, interpolation=cv2.INTER_NEAREST)

# 用自己寫的函數實作近鄰插值
out_img_all = near_insert(img, resize=None, fx=1.5, fy=1.5)
           

缺點: 用該方法作放大處理時,在圖象中可能出現明顯的塊狀效應

雙線性插值算法

線性插值多項式:

【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦

雙線性插值就是線性插值在二維時的推廣,在兩個方向上做三次線性插值,具體操作如下圖所示:

【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦
【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦
【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦

映射方法

向前映射法

可以将幾何運算想象成一次一個象素地轉移到輸出圖像中。如果一個輸入象素被映射到四個輸出像素之間的位置,則其灰階值就按插值算法在4個輸出象素之間進行配置設定。稱為向前映射法,或象素移交影射。 注:從原圖象坐标計算出目标圖象坐标鏡像、平移變換使用這種計算方法

向後映射法

向後映射法(或象素填充算法)是輸出象素一次一個地映射回到輸入象素中,以便确定其灰階級。如果一個輸出象素被映射到4個輸入象素之間,則其灰階值插值決定,向後空間變換是向前變換的逆。

注:從結果圖象的坐标計算原圖象的坐标

旋轉、拉伸、放縮可以使用

解決了漏點的問題,出現了馬賽克

實作

【CV視覺基礎】圖像插值算法&OpenCV架構簡介算法理論介紹與推薦

通常,縮小使用cv.INTER_AREA,放縮使用cv.INTER_CUBIC(較慢)和cv.INTER_LINEAR(較快效果也不錯)。預設情況下,所有的放縮都使用cv.INTER_LINEAR。

import cv2
 
if __name__ == "__main__":
    img = cv2.imread('D:/image/yuner.jpg', cv2.IMREAD_UNCHANGED)
    
    print('Original Dimensions : ',img.shape)
    
    scale_percent = 30       # percent of original size
    width = int(img.shape[1] * scale_percent / 100)
    height = int(img.shape[0] * scale_percent / 100)
    dim = (width, height)
    # resize image
    resized = cv2.resize(img, dim, interpolation = cv2.INTER_LINEAR)

    fx = 1.5
    fy = 1.5

    resized1 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_NEAREST)
    
    resized2 = cv2.resize(resized, dsize=None, fx=fx, fy=fy, interpolation = cv2.INTER_LINEAR)
    print('Resized Dimensions : ',resized.shape)
    
    cv2.imshow("Resized image", resized)
    cv2.imshow("INTER_NEAREST image", resized1)
    cv2.imshow("INTER_LINEAR image", resized2)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
           

繼續閱讀