美文网首页
图像的仿射变换

图像的仿射变换

作者: 原上的小木屋 | 来源:发表于2020-05-29 01:04 被阅读0次

    图像的平移

    • 假定图像中初始坐标为(x,y),经过平移得到新坐标(x',y'),即我们可以得到变换因子
    • x方向上为dx=x'-x
    • y方向上为dy=y‘-y
    • 我们又知道,矩阵同时也代表着运动,上述描述,可以写为
      \left[\begin{matrix}x'\\y'\\1\end{matrix}\right]\=\left[\begin{matrix}1&0&dx\\0&1&dy\\0&0&1\end{matrix}\right]\*\left[\begin{matrix}x\\y\\1\end{matrix}\right]\
    • 即可以得到反变换公式
    • x=x'-dx
    • y=y'-dy
    • 同样地,图像旋转和图像缩放也可以用这个矩阵来表示了
    • 即每个原图像上的像素点均可以通过这样的一一映射关系得到,则代码就很容易实现咯
    def bl_interpolate(img, dx=1, dy=1):
        H, W, C = img.shape  # 首先取得原图像的尺寸大小
        out = np.zeros((H, W, C), dtype=np.float)  # 重建图像
        for y in range(H):
            for x in range(W):
                for c in range(C):
                    y1 = y - dy#取得原图像坐标
                    x1 = x - dx#取得原图像坐标
                    if ((y1 > H-1 or y1 < 0 or x1 > W-1 or x1 < 0)):
                        pass
                    else:
                        out[y, x, c] = img[y1, x1, c]  # 根据上述推导的公式进行变换
        return out.astype(np.uint8)
    

    平移伸缩

    • 如果想为图像加上放大缩小然后再平移,上面的变换矩阵就变为了\left[\begin{matrix}tx&0&dx\\0&ty&dy\\0&0&1\end{matrix}\right]\tx与ty即对应着x方向和y方向上的伸缩变换,同时dx与dy对应着x和y方向上的平移变换,让我们来看一下反变换公式即
    • x方向上变为x=(x'-dx)/tx
    • y方向上变为x=(y'-dy)/ty
    def bl_interpolate(img, tx=1, ty=1, dx=1, dy=1):
        H, W, C = img.shape  # 首先取得原图像的尺寸大小
        aH = int(ty * H)  # 计算插值后的图像尺寸
        aW = int(tx * W)  # 计算插值后的图像尺寸
        out = np.zeros((aH, aW, C), dtype=np.float)  # 重建图像
        for y in range(aH):
            for x in range(aW):
                for c in range(C):
                    y1 = int((y - dy) // ty)
                    x1 = int((x - dx) // tx)
                    if ((y1 > H - 1 or y1 < 0 or x1 > W - 1 or x1 < 0)):
                        pass
                    else:
                        print(y, x, c)
                        print(y1, x1, c)
                        out[y, x, c] = img[y1, x1, c]  # 根据上述推导的公式进行变换
        return out.astype(np.uint8)
    

    旋转操作

    • 旋转操作同样可以用一个矩阵来说明,举个最简单的例子,直角坐标系中有一点(x,y),当期沿着原点逆时针旋转\alpha时,我们可以轻松地写出变换之后的坐标(x',y')即
    • x'=xcos\alpha-ysin\alpha
    • y'=xsin\alpha+ycos\alpha
      矩阵形式即\left[\begin{matrix}cos\alpha&-sin\alpha&\\sin\alpha&cos\alpha&\end{matrix}\right]\
    • 反变换公式即为
    • x=x'cos\alpha+y'sin\alpha
    • y=y'cos\alpha-x'sin\alpha
    • 如果再把旋转中心加上的话,情况会稍稍复杂一点,但仍然可以通过简单的画图将式子推导出来,即假设旋转中心为(a,b),即根据简单变换即可得到
    • x'-a=(x-a)cos\alpha-(y-b)sin\alpha
    • y'-b=(x-a)sin\alpha+(y-b)cos\alpha
    • 此时矩阵可以表示为\left[\begin{matrix}cos\alpha&-sin\alpha&a-acos\alpha+bsin\alpha\\sin\alpha&cos\alpha&b-asin\alpha-bcos\alpha\\0&0&1\end{matrix}\right]\
    • 反变换公式即为
    • x-a=(x'-a)cos\alpha+(y'-b)sin\alpha
    • y-b=(y'-b)cos\alpha-(x'-a)sin\alpha
    def affine(_img, a, b, c, d, tx, ty):
        H, W, C = _img.shape
        # temporary image
        img = np.zeros((H + 2, W + 2, C), dtype=np.float32)
        img[1:H + 1, 1:W + 1] = _img
        # get shape of new image
        H_new = np.round(H).astype(np.int)
        W_new = np.round(W).astype(np.int)
        out = np.zeros((H_new, W_new, C), dtype=np.float32)
        # get position of new image
        x_new = np.tile(np.arange(W_new), (H_new, 1))
        y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
        # get position of original image by affine
        adbc = a * d - b * c
        x = np.round((d * x_new - b * y_new) / adbc).astype(np.int) - tx + 1
        y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
        # adjust center by affine
        dcx = (x.max() + x.min()) // 2 - W // 2
        dcy = (y.max() + y.min()) // 2 - H // 2
        x -= dcx
        y -= dcy
        x = np.clip(x, 0, W + 1)
        y = np.clip(y, 0, H + 1)
        # assign pixcel
        out[y_new, x_new] = img[y, x]
        out = out.astype(np.uint8)
        return out
    # Read image
    img = cv2.imread(r"C:\Users\root\Desktop\123.jpg")
    # Affine
    A = 30.
    theta = - np.pi * A / 180.
    out = affine(img, a=np.cos(theta), b=-np.sin(theta), c=np.sin(theta), d=np.cos(theta),
                 tx=0, ty=0)
    

    图像仿射变换使图像倾斜

    • 本质相当于在x方向或y方向单独施加一个力,让图像发生x方向或y方向上的形变,即当只在x方向上作用时,y坐标范围不发生变化,而x坐标由于受到力的作用,范围变大,x坐标随y坐标的变化而产生变化,变换矩阵为\left[\begin{matrix}1&tx\\0&1\\\end{matrix}\right]\在此不做过多叙述,原理与上述平移旋转原理一致
    def affine(img, dx=30, dy=30):
        # get shape
        H, W, C = img.shape
        # Affine hyper parameters
        a = 1.
        b = dx / H
        c = dy / W
        d = 1.
        tx = 0.
        ty = 0.
        # prepare temporary
        _img = np.zeros((H+2, W+2, C), dtype=np.float32)
        # insert image to center of temporary
        _img[1:H+1, 1:W+1] = img
        # prepare affine image temporary
        H_new = np.ceil(dy + H).astype(np.int)
        W_new = np.ceil(dx + W).astype(np.int)
        out = np.zeros((H_new, W_new, C), dtype=np.float32)
        # preprare assigned index
        x_new = np.tile(np.arange(W_new), (H_new, 1))
        y_new = np.arange(H_new).repeat(W_new).reshape(H_new, -1)
        # prepare inverse matrix for affine
        adbc = a * d - b * c
        x = np.round((d * x_new  - b * y_new) / adbc).astype(np.int) - tx + 1
        y = np.round((-c * x_new + a * y_new) / adbc).astype(np.int) - ty + 1
        x = np.minimum(np.maximum(x, 0), W+1).astype(np.int)
        y = np.minimum(np.maximum(y, 0), H+1).astype(np.int)
        # assign value from original to affine image
        out[y_new, x_new] = _img[y, x]
        out = out.astype(np.uint8)
        return out
    # Read image
    img = cv2.imread(r"C:\Users\root\Desktop\123.jpg")
    # Affine
    out = affine(img, dx=0, dy=30)
    

    相关文章

      网友评论

          本文标题:图像的仿射变换

          本文链接:https://www.haomeiwen.com/subject/hwxtzhtx.html