補充 雙線性差值

2021-10-14 07:04:59 字數 4041 閱讀 7532

opencv使用函式cv2.resize()進行影象縮放的時候,預設使用使用的插值方式是雙線性插值(cv2.inter_linear)。

我們知道,fcn是在用雙線性插值的方式來初始化反卷積的卷積核。所以在這裡補充一下。但是其他**很少用這種方式。**放在這裡,能跑通。自己用不用都行,會呼叫就行了 。想深究的可以自己來。

import cv2

import numpy as np

def bilinear_interpolation(src, new_size):

"""使用雙線性插值方法放大影象

para:

src(np.ndarray):輸入影象,沒擴大之前的

new_size:(tuple): 目標尺寸

ret:

dst(np.ndarray): 目標影象

"""dst_h, dst_w = new_size # 目標影象的高和寬

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 # 縮放比例

scale_y = float(src_h) / dst_h

# 遍歷目標圖上的每乙個畫素,由原圖的點插入數值

dst = np.zeros((dst_h, dst_w, 3), dtype=np.uint8) # 生成一張目標尺寸大小的空白圖,遍歷插值。構建空白圖。彩色,通道數為3.

for n in range(3): # 迴圈channel

for dst_y in range(dst_h): # 迴圈height

for dst_x in range(dst_w): # 迴圈width

# 目標畫素在源圖上的座標

# src_x + 0.5 = (dst_x + 0.5) * scale_x

src_x = (dst_x + 0.5) * scale_x - 0.5 # 乙個畫素預設為1*1的小格仔,其中心在畫素座標點加0.5的位置,避免縮小的時候有的畫素點沒被計算到。

src_y = (dst_y + 0.5) * scale_y - 0.5

# 計算在源圖上四個近鄰點的位置

src_x_0 = int(np.floor(src_x)) # 向下取整 floor(1.2) = 1.0

src_y_0 = int(np.floor(src_y))

src_x_1 = min(src_x_0 + 1, src_w - 1) # 防止出界

src_y_1 = min(src_y_0 + 1, src_h - 1)

# 雙線性插值 新影象每個畫素的值來自於原影象上畫素點的組合插值

value0 = (src_x_1 - src_x) * src[src_y_0, src_x_0, n] + (src_x - src_x_0) * src[src_y_0, src_x_1, n]

value1 = (src_x_1 - src_x) * src[src_y_1, src_x_0, n] + (src_x - src_x_0) * src[src_y_1, src_x_1, n]

dst[dst_y, dst_x, n] = int((src_y_1 - src_y) * value0 + (src_y - src_y_0) * value1)

return dst

if __name__ == '__main__':

img_in = cv2.imread('lenna.bmp')

print(img_in.shape)

img_out = bilinear_interpolation(img_in, (800, 800))

print(img_out.shape)

cv2.imshow('src_img', img_in)

cv2.imshow('dst_img', img_out)

cv2.waitkey()

cv2.destroyallwindows()

結果:

"""使用雙線性插值的方法初始化卷積層中卷積核的權重引數

para:

in_channels(int): 輸入通道數

out_channels(int): 輸出通道數

kernel_size() : 卷積核大小

ret:

torch.tensor : a bilinear filter kernel

"""factor = (kernel_size + 1) // 2

center = kernel_size / 2

og = np.ogrid[:kernel_size, :kernel_size] #根據卷積核的大小構建網格。

filt = (1 - abs(og[0] - center) / factor) * (1 - abs(og[1] - center) / factor)

weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size), dtype='float32')

weight[range(in_channels), range(out_channels), :, :] = filt

return torch.from_numpy(weight) #從numpy轉成tensor。返回的是tensor.

# 測試

x = plt.imread("lenna.bmp")

print(x.shape)

x = torch.from_numpy(x.astype('float32')).permute(2, 0, 1).unsqueeze(0) # .unsqueeze(0) 增加 batch_size 通道

conv_trans = nn.convtranspose2d(3, 3, 4, 2, 1) #定義轉置卷積。輸入通道、輸出通道、卷積核大小、步長、padding。通過這樣乙個引數搭配,把原圖尺寸擴大2倍。

# 將其定義為 bilinear kernel

conv_trans.weight.data = bilinear_kernel(3, 3, 4) #權重引數 = 使用雙線性插值的方法得到的權重引數。

# print(conv_trans.weight)

# print(conv_trans.weight.data)

y = conv_trans(x).data.squeeze().permute(1, 2, 0).numpy() #反卷積擴大。

img = image.open("lenna.bmp").convert("rgb")

plt.subplot(121)

plt.imshow(img)

plt.subplot(122)

plt.imshow(y.astype('uint8'))

plt.show()

print(y.shape)

結果:

雙線性插值

雙線性插值作為opencv中預設使用的影象縮放演算法,其效果和速度都是不錯的。並且效果也比較穩定,計算複雜度並不算太高。我看了很多網上的演算法,自己也沒看太懂,下面是從網上找的雙線性插值 演算法的講解。影象的雙線性插值放大演算法中,目標影象中新創造的象素值,是由源影象位置在它附近的2 2區域4個鄰近...

雙線性插值

轉至 雙線性插值,這個名字咋一聽很高大上的樣紙,再在維基百科上一查 見文末,我去,一堆的公式嚇死人 像俺這種半文盲,看到公式腦子就懵的型別,真心給跪。雖然看著好複雜,但仔細一看道理再簡單不過了,所以還是自己梳理一下好。雙線性插值,顧名思義就是兩個方向的線性插值加起來 這解釋過於簡單粗暴,哈哈 所以只...

雙線性插值

雙線性插值就是在x軸和y軸兩個方向上進行插入操作。假設a b兩個點,要在ab中間插入乙個點c c座標在ab連線上 就直接讓c的值落在ab的連線上即可。例如a點座標 0,0 值為3,b點座標 0,2 值為5,要對座標 0,1 的點c進行插值,就讓c落在ab上,值就為4。如果c點不在ab線上,如圖所示 ...