上采样学习

news2024/10/2 3:32:28

最近邻

简单来说就是x方向和y方向分别复制

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import numpy as np
import torch
from cv2 import cv2
from torch import nn


def numpy2tensor(x: np.ndarray) -> torch.Tensor:
    """
    (H,W) -> (1, 1, H, W)
    (H,W,C) -> (1, C, H, W)
    """
    if x.ndim == 2:
        x = x[:, :, None]
    else:
        x = cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
    return torch.from_numpy(x.transpose((2, 0, 1))).contiguous().unsqueeze(0)


def tensor2numpy(x: torch.Tensor) -> np.ndarray:
    """
    (B,C,H,W) -> (H, W, C)
    (B,1,H,W) -> (H, W)
    """
    x = x.clone().detach()
    x = x.to(torch.device('cpu'))
    x = x.squeeze(0)
    # x = x.mul_(255).add_(0.5).clamp_(0, 255)
    x = x.permute(1, 2, 0).type(torch.uint8).numpy()
    if x.shape[-1] == 3:
        return cv2.cvtColor(x, cv2.COLOR_RGB2BGR)
    return np.squeeze(x, axis=2)


def nearest1(x: np.ndarray, upscale: int) -> np.ndarray:
    if 2 == x.ndim:
        x = x[:, :, None]
    x = x.transpose((2, 0, 1))
    c, h, w = x.shape
    h_index = np.arange(h * upscale) // upscale
    w_index = np.arange(w * upscale) // upscale
    x = x[:, :, w_index]
    x = x[:, h_index, :]
    x = x.transpose((1, 2, 0))
    if 1 == c:
        return np.squeeze(x, -1)
    return x


def nearest2(x: np.ndarray, upscale: int) -> np.ndarray:
    if 2 == x.ndim:
        x = x[:, :, None]
    x = x.transpose((2, 0, 1))
    c, h, w = x.shape
    x = x[:, :, None, :, None].repeat(upscale, axis=-1).repeat(upscale, axis=2).reshape(c, h * upscale, w * upscale)
    x = x.transpose((1, 2, 0))
    if 1 == c:
        return np.squeeze(x, -1)
    return x


def nearest3(x: torch.Tensor, upscale: int) -> torch.Tensor:
    return x[:, :, :, None, :, None].expand(-1, -1, -1, upscale, -1, upscale).reshape(x.size(0), x.size(1),
                                                                                      x.size(2) * upscale,
                                                                                      x.size(3) * upscale)


if __name__ == '__main__':
    torch.use_deterministic_algorithms(True)
    # torch.backends.cudnn.enabled = False
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

    scale = 2
    img = cv2.imread('lena.png')
    h, w, _ = img.shape
    new_h = h * scale
    new_w = w * scale
    tensor = numpy2tensor(img)
    m = nn.Upsample(scale_factor=2, mode='nearest')
    result = [
        nearest1(img, scale),
        nearest2(img, scale),
        cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_NEAREST),
        tensor2numpy(nearest3(tensor, scale)),
        tensor2numpy(m(tensor)),
        tensor2numpy(m(tensor.to(torch.device('cuda:0'))))
    ]
    for i in range(1, len(result)):
        print(np.allclose(result[i], result[i - 1]))

双线性插值

一维线性插值
已知两个点 ( x 1 , y 1 ) , ( x 2 , y 2 ) \left(x_1,y_1\right),\left(x_2,y_2\right) (x1,y1),(x2,y2)
给定一个 x x x,问在这个直线上,对应的 y y y是多少
y − y 1 x − x 1 = y 2 − y 1 x 2 − x 1 y = y 1 + y 2 − y 1 x 2 − x 1 ( x − x 1 ) y = x 2 − x x 2 − x 1 y 1 + x − x 1 x 2 − x 1 y 2 \begin{aligned} \frac{y - y_1}{x - x_1} &= \frac{y_2 - y_1}{x_2 - x_1}\\ y &= y_1 + \frac{y_2 - y_1}{x_2 - x_1}\left(x - x_1\right)\\ y &= \frac{x_2-x}{x_2 - x_1}y_1 + \frac{x-x_1}{x_2 - x_1}y_2\\ \end{aligned} xx1yy1yy=x2x1y2y1=y1+x2x1y2y1(xx1)=x2x1x2xy1+x2x1xx1y2
相当于两边加权求和
在这里插入图片描述
二维的时候类似
x x x方向插值,然后在 y y y方向插值
f ( x , y 1 ) = x 2 − x x 2 − x 1 f ( Q 11 ) + x − x 1 x 2 − x 1 f ( Q 21 ) f ( x , y 2 ) = x 2 − x x 2 − x 1 f ( Q 12 ) + x − x 1 x 2 − x 1 f ( Q 22 ) \begin{aligned} f\left(x,y_1\right) &= \frac{x_2-x}{x_2 - x_1}f\left(Q_{11}\right) + \frac{x-x_1}{x_2 - x_1}f\left(Q_{21}\right)\\ f\left(x,y_2\right) &= \frac{x_2-x}{x_2 - x_1}f\left(Q_{12}\right) + \frac{x-x_1}{x_2 - x_1}f\left(Q_{22}\right)\\ \end{aligned} f(x,y1)f(x,y2)=x2x1x2xf(Q11)+x2x1xx1f(Q21)=x2x1x2xf(Q12)+x2x1xx1f(Q22)
其中 f ( Q i j ) = f ( x i , y j ) f\left(Q_{ij}\right) = f\left(x_i,y_j\right) f(Qij)=f(xi,yj)
f ( x , y ) = y 2 − y y 2 − y 1 f ( x , y 1 ) + y − y 1 y 2 − y 1 f ( x , y 2 ) = y 2 − y y 2 − y 1 ( x 2 − x x 2 − x 1 f ( Q 11 ) + x − x 1 x 2 − x 1 f ( Q 21 ) ) + y − y 1 y 2 − y 1 ( x 2 − x x 2 − x 1 f ( Q 12 ) + x − x 1 x 2 − x 1 f ( Q 22 ) ) = 1 ( y 2 − y 1 ) ( x 2 − x 1 ) ( f ( Q 11 ) ( x 2 − x ) ( y 2 − y ) + f ( Q 21 ) ( x − x 1 ) ( y 2 − y ) + f ( Q 12 ) ( x 2 − x ) ( y − y 1 ) + f ( Q 22 ) ( x − x 1 ) ( y − y 1 ) ) = 1 ( y 2 − y 1 ) ( x 2 − x 1 ) ( x 2 − x x − x 1 ) T ( f ( Q 11 ) f ( Q 12 ) f ( Q 21 ) f ( Q 22 ) ) ( y 2 − y y − y 1 ) \begin{aligned} f\left(x,y\right) &= \frac{y_2 - y}{y_2 - y_1}f\left(x,y_1\right) + \frac{y-y_1}{y_2 - y_1}f\left(x,y_2\right)\\ &= \frac{y_2 - y}{y_2 - y_1}\left(\frac{x_2-x}{x_2 - x_1}f\left(Q_{11}\right) + \frac{x-x_1}{x_2 - x_1}f\left(Q_{21}\right)\right) + \frac{y-y_1}{y_2 - y_1}\left(\frac{x_2-x}{x_2 - x_1}f\left(Q_{12}\right) + \frac{x-x_1}{x_2 - x_1}f\left(Q_{22}\right)\right)\\ &= \frac{1}{\left(y_2 - y_1\right)\left(x_2 - x_1\right)}\left(f\left(Q_{11}\right)\left(x_2 - x\right)\left(y_2 - y\right) + f\left(Q_{21}\right)\left(x-x_1\right)\left(y_2-y\right) + f\left(Q_{12}\right)\left(x_2-x\right)\left(y-y_1\right) + f\left(Q_{22}\right)\left(x-x_1\right)\left(y-y_1\right)\right) \\ &= \frac{1}{\left(y_2 - y_1\right)\left(x_2 - x_1\right)}\begin{pmatrix} x_2-x\\ x-x_1\\ \end{pmatrix}^T\begin{pmatrix} f\left(Q_{11}\right)&f\left(Q_{12}\right)\\ f\left(Q_{21}\right)&f\left(Q_{22}\right)\\ \end{pmatrix}\begin{pmatrix} y_2-y\\ y-y_1\\ \end{pmatrix} \end{aligned} f(x,y)=y2y1y2yf(x,y1)+y2y1yy1f(x,y2)=y2y1y2y(x2x1x2xf(Q11)+x2x1xx1f(Q21))+y2y1yy1(x2x1x2xf(Q12)+x2x1xx1f(Q22))=(y2y1)(x2x1)1(f(Q11)(x2x)(y2y)+f(Q21)(xx1)(y2y)+f(Q12)(x2x)(yy1)+f(Q22)(xx1)(yy1))=(y2y1)(x2x1)1(x2xxx1)T(f(Q11)f(Q21)f(Q12)f(Q22))(y2yyy1)
容易验证先在 y y y方向,然后 x x x方向,得到的结果是一样的
在这里插入图片描述

pytorch align_corners=False

( 3 , 3 ) \left(3,3\right) (3,3)的图像放大成 ( 9 , 9 ) \left(9,9\right) (9,9)
原本图像的中心是 ( 1 , 1 ) \left(1,1\right) (1,1),放大后中心是 ( 4 , 4 ) \left(4,4\right) (4,4)
但是这时候就会发现 4 1 ≠ 3 1 \frac{4}{1}\neq \frac{3}{1} 14=13,中心对不上
而实际上,中心计算公式为
s r c = ( d s t + 0.5 ) 1 s c a l e − 0.5 = ( d s t + 0.5 ) s r c s i z e d s t s i z e − 0.5 src = \left(dst + 0.5\right)\frac{1}{scale}-0.5 = \left(dst + 0.5\right)\frac{src_{size}}{dst_{size}}-0.5 src=(dst+0.5)scale10.5=(dst+0.5)dstsizesrcsize0.5
然后一些其他细节
1. s r c src src计算完了,要 c l i p clip clip [ 0 , s i z e − 1 ] \left[0,size-1\right] [0,size1]
2. x 2 − x 1 = y 2 − y 1 = 1 x_2 - x_1 = y_2 - y_1 = 1 x2x1=y2y1=1
3. x 1 , y 1 x_1,y_1 x1,y1 c l i p clip clip [ 0 , s i z e − 2 ] \left[0,size-2\right] [0,size2]之间,防止 x 2 , y 2 x_2,y_2 x2,y2越界

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import numpy as np
import torch
from cv2 import cv2
from torch import nn


def numpy2tensor(x: np.ndarray) -> torch.FloatTensor:
    """
    (H,W) -> (1, 1, H, W)
    (H,W,C) -> (1, C, H, W)
    """
    if x.ndim == 2:
        x = x[..., None]
    else:
        x = cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
    return torch.from_numpy(x.transpose((2, 0, 1))).contiguous().unsqueeze(0).float()


def tensor2numpy(x: torch.FloatTensor) -> np.ndarray:
    """
    (B,C,H,W) -> (H, W, C)
    (B,1,H,W) -> (H, W)
    """
    x = x.clone().detach()
    x = x.to(torch.device('cpu'))
    x = x.squeeze(0)
    x = x.clamp_(0, 255)
    # x = x.permute(1, 2, 0).type(torch.uint8).numpy()
    x = x.permute(1, 2, 0).numpy()
    if x.shape[-1] == 3:
        return cv2.cvtColor(x, cv2.COLOR_RGB2BGR)
    return np.squeeze(x, axis=2)


def bilinear1(img: np.ndarray, upscale: int, align_corners=False) -> np.ndarray:
    if 2 == img.ndim:
        img = img[..., None]
    h, w, c = img.shape
    new_h, new_w = h * upscale, w * upscale
    result = np.zeros((new_h, new_w, c), dtype=float)
    for i in range(new_h):
        for j in range(new_w):
            if not align_corners:
                x = np.clip((i + 0.5) * h / new_h - 0.5, 0, h - 1)
                y = np.clip((j + 0.5) * w / new_w - 0.5, 0, w - 1)

                x1 = min(int(np.floor(x)), h - 2)
                y1 = min(int(np.floor(y)), w - 2)

                x2 = x1 + 1
                y2 = y1 + 1
            else:
                x = np.clip(i * (h - 1) / (new_h - 1), 0, h - 1)
                y = np.clip(j * (w - 1) / (new_w - 1), 0, w - 1)

                x1 = int(np.floor(x))
                y1 = int(np.floor(y))

                x2 = int(np.ceil(x))
                y2 = int(np.ceil(y))

            q11 = img[x1, y1]
            q12 = img[x1, y2]
            q21 = img[x2, y1]
            q22 = img[x2, y2]

            u = x2 - x
            v = y2 - y
            _1_u = 1 - u
            _1_v = 1 - v

            result[i, j] = (q11 * u * v + q21 * _1_u * v + q12 * u * _1_v + q22 * _1_u * _1_v)
    if 1 == c:
        return result.squeeze(-1)
    return result


def bilinear2(img: np.ndarray, upscale: int, align_corners=False) -> np.ndarray:
    if 2 == img.ndim:
        img = img[..., None]
    h, w, c = img.shape
    new_h, new_w = h * upscale, w * upscale

    if not align_corners:
        x = np.clip((np.arange(new_h) + 0.5) * h / new_h - 0.5, 0, h - 1)
        y = np.clip((np.arange(new_w) + 0.5) * w / new_w - 0.5, 0, w - 1)
        x = np.repeat(x[:, None], new_w, axis=1)
        y = np.repeat(y[None, :], new_h, axis=0)

        x1 = np.clip(np.floor(x), 0, h - 2).astype(int)
        y1 = np.clip(np.floor(y), 0, w - 2).astype(int)
        x2 = x1 + 1
        y2 = y1 + 1
    else:
        x = np.clip(np.arange(new_h) * (h - 1) / (new_h - 1), 0, h - 1)
        y = np.clip(np.arange(new_w) * (w - 1) / (new_w - 1), 0, w - 1)
        x = np.repeat(x[:, None], new_w, axis=1)
        y = np.repeat(y[None, :], new_h, axis=0)

        x1 = np.floor(x).astype(int)
        y1 = np.floor(y).astype(int)
        x2 = np.ceil(x).astype(int)
        y2 = np.ceil(y).astype(int)

    q11 = img[x1, y1]
    q12 = img[x1, y2]
    q21 = img[x2, y1]
    q22 = img[x2, y2]

    u = (x2 - x)[..., None]
    v = (y2 - y)[..., None]
    _1_u = 1 - u
    _1_v = 1 - v

    w11 = u * v
    w12 = u * _1_v
    w21 = _1_u * v
    w22 = _1_u * _1_v

    result = q11 * w11 + q12 * w12 + q21 * w21 + q22 * w22

    if 1 == c:
        return result.squeeze(-1)
    return result


def bilinear3(img: torch.FloatTensor, upscale: int, align_corners=False) -> torch.FloatTensor:
    B, c, h, w = img.shape
    new_h, new_w = h * upscale, w * upscale
    result = torch.zeros(B, c, new_h, new_w, dtype=torch.float)
    for i in range(new_h):
        for j in range(new_w):
            if not align_corners:
                x = np.clip((i + 0.5) * h / new_h - 0.5, 0, h - 1)
                y = np.clip((j + 0.5) * w / new_w - 0.5, 0, w - 1)

                x1 = min(int(np.floor(x)), h - 2)
                y1 = min(int(np.floor(y)), w - 2)

                x2 = x1 + 1
                y2 = y1 + 1
            else:
                x = np.clip(i * (h - 1) / (new_h - 1), 0, h - 1)
                y = np.clip(j * (w - 1) / (new_w - 1), 0, w - 1)

                x1 = int(np.floor(x))
                y1 = int(np.floor(y))

                x2 = int(np.ceil(x))
                y2 = int(np.ceil(y))

            q11 = img[..., x1, y1]
            q12 = img[..., x1, y2]
            q21 = img[..., x2, y1]
            q22 = img[..., x2, y2]

            u = x2 - x
            v = y2 - y
            _1_u = 1 - u
            _1_v = 1 - v

            result[..., i, j] = (q11 * u * v + q21 * _1_u * v + q12 * u * _1_v + q22 * _1_u * _1_v)
    return result


def bilinear4(img: torch.FloatTensor, upscale: int, align_corners=False) -> torch.FloatTensor:
    B, c, h, w = img.shape
    new_h, new_w = h * upscale, w * upscale
    if not align_corners:
        x = torch.clip((torch.arange(new_h, dtype=torch.double) + 0.5) * h / new_h - 0.5, 0, h - 1)
        y = torch.clip((torch.arange(new_w, dtype=torch.double) + 0.5) * w / new_w - 0.5, 0, w - 1)
        x = x[:, None].expand(-1, new_w)
        y = y[None, :].expand(new_h, -1)

        x1 = torch.clip(torch.floor(x), 0, h - 2).long()
        y1 = torch.clip(torch.floor(y), 0, w - 2).long()
        x2 = x1 + 1
        y2 = y1 + 1
    else:
        x = torch.clip(torch.arange(new_h, dtype=torch.double) * (h - 1) / (new_h - 1), 0, h - 1)
        y = torch.clip(torch.arange(new_w, dtype=torch.double) * (w - 1) / (new_w - 1), 0, w - 1)
        x = x[:, None].expand(-1, new_w)
        y = y[None, :].expand(new_h, -1)

        x1 = torch.floor(x).long()
        y1 = torch.floor(y).long()
        x2 = torch.ceil(x).long()
        y2 = torch.ceil(y).long()

    q11 = img[..., x1, y1]
    q12 = img[..., x1, y2]
    q21 = img[..., x2, y1]
    q22 = img[..., x2, y2]

    u = (x2 - x)[None, None, ...]
    v = (y2 - y)[None, None, ...]
    _1_u = 1 - u
    _1_v = 1 - v

    w11 = u * v
    w12 = u * _1_v
    w21 = _1_u * v
    w22 = _1_u * _1_v

    result = q11 * w11 + q12 * w12 + q21 * w21 + q22 * w22

    return result.float()
    return result


if __name__ == '__main__':
    torch.use_deterministic_algorithms(True)
    # torch.backends.cudnn.enabled = False
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

    x = cv2.imread('lena.png')
    h, w = x.shape[:2]
    scale = 2
    new_h = h * scale
    new_w = w * scale

    tensor = numpy2tensor(x)
    m1 = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
    m2 = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
    # align_corners_true = [
    #     tensor2numpy(m1(tensor)),
    #     bilinear1(x, 2, align_corners=True),
    #     bilinear2(x, 2, align_corners=True),
    #     tensor2numpy(bilinear3(tensor, 2, align_corners=True)),
    #     tensor2numpy(bilinear4(tensor, 2, align_corners=True)),
    #     tensor2numpy(m1(tensor.to(torch.device('cuda:0')))),
    #     cv2.resize(x, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    # ]
    # # 0==5 0!=1 0!=6 1==2==3==4 1!=6
    # for i in range(1, len(align_corners_true)):
    #     print(np.allclose(align_corners_true[i], align_corners_true[i - 1]))
    # 
    # print()
    # print()
    align_corners_false = [
        tensor2numpy(m2(tensor)),
        bilinear1(x, 2, align_corners=False),
        bilinear2(x, 2, align_corners=False),
        tensor2numpy(bilinear3(tensor, 2, align_corners=False)),
        tensor2numpy(bilinear4(tensor, 2, align_corners=False)),
        tensor2numpy(m2(tensor.to(torch.device('cuda:0')))),
        cv2.resize(x, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    ]
    # 除了opencv 其他都一样
    for i in range(1, len(align_corners_false)):
        print(np.allclose(align_corners_false[i], align_corners_false[i - 1]))


pytorch align_corners=True

这个图,上面是原图,下面是插值后的图
6 6 6插值成 12 12 12
这里的操作相当于原图有 5 5 5个区域,插值后有 11 11 11个区域
中心计算公式为
s r c = d s t × s r c s i z e − 1 d s t s i z e − 1 src = dst\times\frac{src_{size} -1}{dst_{size} - 1} src=dst×dstsize1srcsize1
在这里插入图片描述

这个代码写的有点问题

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import numpy as np
import torch
from cv2 import cv2
from torch import nn


def numpy2tensor(x: np.ndarray) -> torch.FloatTensor:
    """
    (H,W) -> (1, 1, H, W)
    (H,W,C) -> (1, C, H, W)
    """
    if x.ndim == 2:
        x = x[..., None]
    else:
        x = cv2.cvtColor(x, cv2.COLOR_BGR2RGB)
    return torch.from_numpy(x.transpose((2, 0, 1))).contiguous().unsqueeze(0).float()


def tensor2numpy(x: torch.FloatTensor) -> np.ndarray:
    """
    (B,C,H,W) -> (H, W, C)
    (B,1,H,W) -> (H, W)
    """
    x = x.clone().detach()
    x = x.to(torch.device('cpu'))
    x = x.squeeze(0)
    x = x.clamp_(0, 255)
    # x = x.permute(1, 2, 0).type(torch.uint8).numpy()
    x = x.permute(1, 2, 0).numpy()
    if x.shape[-1] == 3:
        return cv2.cvtColor(x, cv2.COLOR_RGB2BGR)
    return np.squeeze(x, axis=2)


def bilinear1(img: np.ndarray, upscale: int, align_corners=False) -> np.ndarray:
    if 2 == img.ndim:
        img = img[..., None]
    h, w, c = img.shape
    new_h, new_w = h * upscale, w * upscale
    result = np.zeros((new_h, new_w, c), dtype=float)
    for i in range(new_h):
        for j in range(new_w):
            if not align_corners:
                x = np.clip((i + 0.5) * h / new_h - 0.5, 0, h - 1)
                y = np.clip((j + 0.5) * w / new_w - 0.5, 0, w - 1)

                x1 = min(int(np.floor(x)), h - 2)
                y1 = min(int(np.floor(y)), w - 2)

                x2 = x1 + 1
                y2 = y1 + 1
            else:
                x = np.clip(i * (h - 1) / (new_h - 1), 0, h - 1)
                y = np.clip(j * (w - 1) / (new_w - 1), 0, w - 1)

                x1 = int(np.floor(x))
                y1 = int(np.floor(y))

                x2 = int(np.ceil(x))
                y2 = int(np.ceil(y))

            q11 = img[x1, y1]
            q12 = img[x1, y2]
            q21 = img[x2, y1]
            q22 = img[x2, y2]

            u = x2 - x
            v = y2 - y
            _1_u = 1 - u
            _1_v = 1 - v

            result[i, j] = (q11 * u * v + q21 * _1_u * v + q12 * u * _1_v + q22 * _1_u * _1_v)
    if 1 == c:
        return result.squeeze(-1)
    return result


def bilinear2(img: np.ndarray, upscale: int, align_corners=False) -> np.ndarray:
    if 2 == img.ndim:
        img = img[..., None]
    h, w, c = img.shape
    new_h, new_w = h * upscale, w * upscale

    if not align_corners:
        x = np.clip((np.arange(new_h) + 0.5) * h / new_h - 0.5, 0, h - 1)
        y = np.clip((np.arange(new_w) + 0.5) * w / new_w - 0.5, 0, w - 1)
        x = np.repeat(x[:, None], new_w, axis=1)
        y = np.repeat(y[None, :], new_h, axis=0)

        x1 = np.clip(np.floor(x), 0, h - 2).astype(int)
        y1 = np.clip(np.floor(y), 0, w - 2).astype(int)
        x2 = x1 + 1
        y2 = y1 + 1
    else:
        x = np.clip(np.arange(new_h) * (h - 1) / (new_h - 1), 0, h - 1)
        y = np.clip(np.arange(new_w) * (w - 1) / (new_w - 1), 0, w - 1)
        x = np.repeat(x[:, None], new_w, axis=1)
        y = np.repeat(y[None, :], new_h, axis=0)

        x1 = np.floor(x).astype(int)
        y1 = np.floor(y).astype(int)
        x2 = np.ceil(x).astype(int)
        y2 = np.ceil(y).astype(int)

    q11 = img[x1, y1]
    q12 = img[x1, y2]
    q21 = img[x2, y1]
    q22 = img[x2, y2]

    u = (x2 - x)[..., None]
    v = (y2 - y)[..., None]
    _1_u = 1 - u
    _1_v = 1 - v

    w11 = u * v
    w12 = u * _1_v
    w21 = _1_u * v
    w22 = _1_u * _1_v

    result = q11 * w11 + q12 * w12 + q21 * w21 + q22 * w22

    if 1 == c:
        return result.squeeze(-1)
    return result


def bilinear3(img: torch.FloatTensor, upscale: int, align_corners=False) -> torch.FloatTensor:
    B, c, h, w = img.shape
    new_h, new_w = h * upscale, w * upscale
    result = torch.zeros(B, c, new_h, new_w, dtype=torch.float)
    for i in range(new_h):
        for j in range(new_w):
            if not align_corners:
                x = np.clip((i + 0.5) * h / new_h - 0.5, 0, h - 1)
                y = np.clip((j + 0.5) * w / new_w - 0.5, 0, w - 1)

                x1 = min(int(np.floor(x)), h - 2)
                y1 = min(int(np.floor(y)), w - 2)

                x2 = x1 + 1
                y2 = y1 + 1
            else:
                x = np.clip(i * (h - 1) / (new_h - 1), 0, h - 1)
                y = np.clip(j * (w - 1) / (new_w - 1), 0, w - 1)

                x1 = int(np.floor(x))
                y1 = int(np.floor(y))

                x2 = int(np.ceil(x))
                y2 = int(np.ceil(y))

            q11 = img[..., x1, y1]
            q12 = img[..., x1, y2]
            q21 = img[..., x2, y1]
            q22 = img[..., x2, y2]

            u = x2 - x
            v = y2 - y
            _1_u = 1 - u
            _1_v = 1 - v

            result[..., i, j] = (q11 * u * v + q21 * _1_u * v + q12 * u * _1_v + q22 * _1_u * _1_v)
    return result


def bilinear4(img: torch.FloatTensor, upscale: int, align_corners=False) -> torch.FloatTensor:
    B, c, h, w = img.shape
    new_h, new_w = h * upscale, w * upscale
    if not align_corners:
        x = torch.clip((torch.arange(new_h, dtype=torch.double) + 0.5) * h / new_h - 0.5, 0, h - 1)
        y = torch.clip((torch.arange(new_w, dtype=torch.double) + 0.5) * w / new_w - 0.5, 0, w - 1)
        x = x[:, None].expand(-1, new_w)
        y = y[None, :].expand(new_h, -1)

        x1 = torch.clip(torch.floor(x), 0, h - 2).long()
        y1 = torch.clip(torch.floor(y), 0, w - 2).long()
        x2 = x1 + 1
        y2 = y1 + 1
    else:
        x = torch.clip(torch.arange(new_h, dtype=torch.double) * (h - 1) / (new_h - 1), 0, h - 1)
        y = torch.clip(torch.arange(new_w, dtype=torch.double) * (w - 1) / (new_w - 1), 0, w - 1)
        x = x[:, None].expand(-1, new_w)
        y = y[None, :].expand(new_h, -1)

        x1 = torch.floor(x).long()
        y1 = torch.floor(y).long()
        x2 = torch.ceil(x).long()
        y2 = torch.ceil(y).long()

    q11 = img[..., x1, y1]
    q12 = img[..., x1, y2]
    q21 = img[..., x2, y1]
    q22 = img[..., x2, y2]

    u = (x2 - x)[None, None, ...]
    v = (y2 - y)[None, None, ...]
    _1_u = 1 - u
    _1_v = 1 - v

    w11 = u * v
    w12 = u * _1_v
    w21 = _1_u * v
    w22 = _1_u * _1_v

    result = q11 * w11 + q12 * w12 + q21 * w21 + q22 * w22

    return result.float()


if __name__ == '__main__':
    torch.use_deterministic_algorithms(True)
    # torch.backends.cudnn.enabled = False
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

    x = cv2.imread('lena.png')
    h, w = x.shape[:2]
    scale = 2
    new_h = h * scale
    new_w = w * scale

    tensor = numpy2tensor(x)
    m1 = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
    m2 = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
    align_corners_true = [
        tensor2numpy(m1(tensor)),
        bilinear1(x, 2, align_corners=True),
        bilinear2(x, 2, align_corners=True),
        tensor2numpy(bilinear3(tensor, 2, align_corners=True)),
        tensor2numpy(bilinear4(tensor, 2, align_corners=True)),
        tensor2numpy(m1(tensor.to(torch.device('cuda:0')))),
        cv2.resize(x, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    ]
    # 0==5 0!=1 0!=6 1==2==3==4 1!=6
    for i in range(1, len(align_corners_true)):
        print(np.allclose(align_corners_true[i], align_corners_true[i - 1]))

    print()
    print()
    align_corners_false = [
        tensor2numpy(m2(tensor)),
        bilinear1(x, 2, align_corners=False),
        bilinear2(x, 2, align_corners=False),
        tensor2numpy(bilinear3(tensor, 2, align_corners=False)),
        tensor2numpy(bilinear4(tensor, 2, align_corners=False)),
        tensor2numpy(m2(tensor.to(torch.device('cuda:0')))),
        cv2.resize(x, (new_w, new_h), interpolation=cv2.INTER_LINEAR)
    ]
    # 除了opencv 其他都一样
    for i in range(1, len(align_corners_false)):
        print(np.allclose(align_corners_false[i], align_corners_false[i - 1]))


参考
https://zhuanlan.zhihu.com/p/141681355

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/348131.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ShardingSphere-Proxy5按月分表

0、软件版本 ShardingSphere-Proxy: 5.2.0 MySQL: 8.0.30 系统: win10 1、ShardingSphere-Proxy下载 我们可以在 官网 找到最新版ShardingSphere-Proxy下载,也可以在ShardingSphere仓库中下载 2、ShardingSphere-Proxy配置 …

shell编程经典案例,建议收藏

1、编写hello world脚本 #!/bin/bash# 编写hello world脚本echo "Hello World!"2、通过位置变量创建 Linux 系统账户及密码 #!/bin/bash# 通过位置变量创建 Linux 系统账户及密码#$1 是执行脚本的第一个参数,$2 是执行脚本的第二个参数 useradd "$1" …

Linux C++ 200行完成线程池类

文章目录1、atomic使用2、volatile关键字3、条件变量4、成员函数指针使用5、线程池6、主线程先退出对子线程影响7、return、exit、pthread_exit区别8、进程和线程的区别1、atomic使用 原子操作,不可分割的操作,要么完整,要么不完整。 #includ…

vscode开发基于Vue的健身房管理系统node.js

该系统的基本功能包括管理员、会员、教练三个角色功能模块。 对于管理员可以使用的功能模块主要有首页、个人中心,系统公告管理、健身常识管理,会员管理、教练管理、教练考勤管理、会员咨询管理、商品信息管理、团课管理、团课预约管理、论坛管理、系统管…

十三、二叉排序树

1、先看一个需求 给你一个数列 {7, 3, 10, 12, 5, 1, 9} ,要求能够高效的完成对数据的查询和添加 2、解决方案分析 使用数组 数组未排序,优点:直接在数组尾添加,速度快。缺点:查找速度慢 数组排序,优点&…

如何推出 NFT 游戏并获得收益?- 综合指南

NFT Gaming - 简介 - NFT 是代表独特内容所有权的数字资产,例如游戏中的一件艺术品或收藏品。它们建立在区块链解决方案之上,允许这些数字资产的真正所有权和稀缺性。 在游戏行业,NFT 用于创建玩家可以拥有和交易的独一无二的游戏内物品。这允…

政企服务机构如何进行数字化转型?

对于服务于政府和企业的产业机构来说,将政府政策和企业发展做完美匹配结合是其根本。在这个过程中,政策信息的准确性、前瞻性、核心价值是服务的基础,只有在政策下可行性高的解决方案才能为政府吸引更多的企业入驻。 那么该类产业机构该如何…

如何理解​session、cookie、token的区别与联系?

session、cookie、token。 相信学过接口的朋友都特别熟悉了。 但是对我一个刚接触接口测试的小白来说,属实有点分不清楚。 下文就是我通过查阅各种资料总结出来的一点理解,不准确的地方还请各位指正。 (文末送洗浴中心流程指南&#xff09…

C语言(函数和递归)

函数是完成特定任务的独立程序代码单元。 目录 一.函数 1.创建一个简单的函数 2.定义带形式参数的函数 3.使用return从函数中返回值 二.递归 一.函数 1.创建一个简单的函数 #include <stdio.h> void print(void); //函数原型 int main(){ print(); //函…

Weblogic CVE之旅之T3协议浅学习

前言 这篇文章主要是学习Weblogic CVE漏洞中的过程中&#xff0c;对其中的一种利用方式T3协议反序列化漏洞进行分析。 前置 什么是T3协议&#xff1f; T3协议是一种Weblogic RMI 调用时的通信协议, 对于JAVA RMI(Remote Method Invocation) 来说&#xff0c;基础的通信协议…

Web前端:使用Angular CLI时的最佳实践和专业技巧

在web开发业务中&#xff0c;构建高性能的应用程序是首要因素。此外&#xff0c;用开发人员最流行的语言开发一个健壮的网站将始终为构建高功能的网站提供适当的基础网站。相比之下&#xff0c;不可否认&#xff0c;Angular CLI是建立得最好且正在成长的框架之一。Angular CLI简…

【蓝桥杯嵌入式】第十三届蓝桥杯嵌入式 国赛 程序设计试题以及详细题解

文章目录原题展示原题分析详细题解LED模块按键模块串口LCD模块模拟电压读取(ADC)脉冲输入输出文章福利原题展示 原题分析 本届国赛试题主要包含LCD、LED、按键、EEPROM、串口、模拟电压输入、脉冲输入输出七大部分&#xff0c;其中前面三个部分是蓝桥杯嵌入式的“亲儿子”(必考…

2023年妇女节是哪一天 妇女节是2023年几月几日?

2023年妇女节是哪一天是2023年几月几日&#xff1f; 2023年妇女节是2023年3月8日 三八妇女节是国家法定节假日吗&#xff1f; 妇女节不是国家法定节假日&#xff0c;而国家法定节假日包括&#xff1a;元旦、春节、清明节、劳动节、端午节、中秋节、国庆节&#xff1b; 关于三…

操作系统(day09) -- 连续分配管理方式

连续分配管理方式 单元连续分配 动态分区分配 1.系统要用什么样的数据结构记录内存的使用情况&#xff1f; 两种常用的数据结构 空闲分区表 每个空闲分区对应一个表项。表项中包含分区号、分区大小、分区起始地址等信息空闲分区链 每个分区的起始部分和末尾部分分别设置前向…

硬件学习 软件Cadence day02 画原理图的基本操作 (键盘快捷键 , 原理图设计流程 , 从开始到导出网表流程)

1. ORCAD Capture cls 界面的快捷键 键盘 按键对应的操作I放大 &#xff08;可以滚轮操作&#xff09;O缩小 &#xff08;可以滚轮操作&#xff09;W画线Esc退出现在的状态 &#xff08;画图界面 右键 End xxx&#xff09;N放置网络标号J放置节点 (控制…

花2个月面过华为测开岗,拿个30K不过分吧?

背景介绍 美本计算机专业&#xff0c;代码能力一般&#xff0c;之前有过两段实习以及一个学校项目经历。第一份实习是大二暑期在深圳的一家互联网公司做前端开发&#xff0c;第二份实习由于大三暑假回国的时间比较短&#xff08;小于两个月&#xff09;&#xff0c;于是找的实…

ChatGPT is not all you need,一文看尽SOTA生成式AI模型:6大公司9大类别21个模型全回顾(一)

文章目录ChatGPT is not all you need&#xff0c;一文看尽SOTA生成式AI模型&#xff1a;6大公司9大类别21个模型全回顾&#xff08;一&#xff09;Text-to-Image 模型DALL-E 2IMAGENStable DiffusionMuseText-to-3D 模型DreamfusionMagic3DChatGPT is not all you need&#x…

Python和Java语言,哪个更适合做自动化测试?

经常有测试新手问我&#xff1a;Python和Java语言&#xff0c;哪个更适合做自动化测试&#xff1f;本来想简单的回答一下的&#xff0c;但又觉得对不起大家对小编的信任。因此&#xff0c;小编今天专门写了一篇文章来回答这个问题。欢迎各位大佬补充~1、什么是自动化测试&#…

大数据框架之Hadoop:HDFS(八)HDFS HA高可用

8.1 HA概述 1&#xff09;所谓HA&#xff08;High Available&#xff09;&#xff0c;即高可用&#xff08;7*24小时不中断服务&#xff09;。 2&#xff09;实现高可用最关键的策略是消除单点故障。HA严格来说应该分成各个组件的HA机制&#xff1a;HDFS的HA和YARN的HA。 3&…

一文优化java.lang.StackOverflowError的堆栈溢出问题及递归引发的java.lang.StackOverflowError错误

文章目录1. 问题引出2. 分析问题2.1 为什么递归调用会导致堆栈溢出2.2 数组太大或分配内存多于可用内存导致堆栈异常3. 优化避免栈溢出3.1 尾递归优化3.2 循环替代递归4. 重要总结1. 问题引出 今天在编码时&#xff0c;出现了java.lang.StackOverflowError&#xff0c;就感觉很…