10.2 矩阵乘法应用——二维图片变换

数学原理

  二维图片上每一个点,左乘以一个转换矩阵,就可以实现图片绕原点的旋转和拉伸。而这个转换矩阵,就是(1,0)和(0,1)转换后的点组成的。这个其实就是线性变换的思想了,一个线性变换把自然基变成什么样子,就会把其他向量变成什么样子。
  说了这么多,那不得来个例子啊,假设我们要绕原点顺时针旋转90°。首先(1,0)绕原点顺时针旋转90°后变成什么了呢?变成了(0,-1),而(0,1)呢,变成了(1,0)。所以这个变换矩阵为:
[ 0 1 − 1 0 ] \left[ \begin{matrix} 0 & 1\\ -1 & 0 \end{matrix} \right] [0110]
  假设将图形上的一个点,坐标为(1,1),转换后的点,用线性代数计算一下:
[ 0 1 − 1 0 ] × [ 1 1 ] = [ 1 − 1 ] \left[ \begin{matrix} 0 & 1\\ -1 & 0 \end{matrix} \right]\times \left[ \begin{matrix} 1\\ 1 \end{matrix} \right]=\left[ \begin{matrix} 1\\ -1 \end{matrix} \right] [0110]×[11]=[11]
  这两个点用图像表示就是下面这个样子:
在这里插入图片描述
  但是这个旋转拉伸操作,是绕着原点进行的。而实际应用图片的旋转,是两个运算,第一个运算是绕着原点的旋转,第二个是图形的平移。可以这样理解,矩阵乘法顺时针旋转90°,其实是绕着原点,把图像旋转到了第三象限,然后只有往上平移才能把图片拉回到第一象限。图形的旋转可以用矩阵与向量的乘法进行计算,图像的平移就使用向量的加法进行计算。

java实现

  Java转换代码如下:

public class ImageConvertor {

    private Matrix<Integer> matrix;
    private Integer[] moveVector;

    public ImageConvertor(Matrix<Integer> matrix, Integer[] moveVector) {
        this.matrix = matrix;
        this.moveVector = moveVector;
    }

    public BufferedImage convert(BufferedImage source) {
        final int width = source.getWidth();
        final int height = source.getHeight();
        final BufferedImage target = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        final Graphics2D graphics = (Graphics2D) target.getGraphics();
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                final int rgb = source.getRGB(i, j);
                // 运用矩阵乘法,算出这个点在哪里
                final int sx = i;
                final int sy = j;
                final Integer[][] integers = matrix.multiply(new IntegerMatrix(new Integer[][]{{sx}, {sy}}));
                graphics.setColor(new Color(rgb));
                final int x = integers[0][0] + moveVector[0];
                final int y = integers[1][0] + moveVector[1];
                graphics.drawLine(x, y, x, y);
                System.out.println("source:(" + sx + "," + sy + "),target:(" + x + "," + y + ")," + rgb);
            }
        }
        return target;
    }
}

  测试类如下:

@Test
public void test() throws IOException {
    // 顺时针旋转90°,100X100图片
    final Integer[][] array = {{0, -1}, {1, 0}};
    final IntegerMatrix matrix = new IntegerMatrix(array);
    final ImageConvertor imageConvertor = new ImageConvertor(matrix, new Integer[]{99, 0});
    final BufferedImage image = ImageIO.read(new File("e.png"));
    final BufferedImage target = imageConvertor.convert(image);
    ImageIO.write(target, "png", new File("out.png"));
}

  效果如下:
在这里插入图片描述
在这里插入图片描述

Python实现

  Python的图形库是opencv-python

pip install opencv-python

  代码和Java类似

import numpy as np

from com.youngthing.mathalgorithm.matrix import Matrix


class ImageConvertor:

    def __init__(self, matrix: Matrix, move_vector: list):
        self.__matrix = matrix
        self.__move_vector = move_vector

    def convert(self, image):
        width = len(image[0])
        height = len(image)
        target = np.zeros((width, height, 3), np.uint8)
        for (y, line) in enumerate(image):
            for (x, color) in enumerate(line):
                m = Matrix([[x, y]]) * self.__matrix
                d = m + self.__move_vector
                print(d.lines[0][1], d.lines[0][0], np.uint8(color), color)
                target[d.lines[0][1]][d.lines[0][0]] = np.uint8(color)
        return target
测试类代码
from com.youngthing.mathalgorithm.matrix import Matrix

import cv2
from com.youngthing.mathalgorithm.image.image_process import ImageConvertor

if __name__ == '__main__':
    img = cv2.imread('F:\learn\math-algorithm\e.png')
    rotate_matrix = Matrix([[0, 1], [-1, 0]])
    move_matrix = Matrix([[99, 0]])
    ic = ImageConvertor(rotate_matrix, move_matrix)
    new_img = ic.convert(img)
    cv2.imshow('img', new_img)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

执行效果在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

醒过来摸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值