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線上,如圖所示 ...