python使用numpy实现图像旋转

该代码段展示了如何使用Python的Skimage和Numpy库来旋转图像。通过建立矩阵运算,计算旋转后的图像尺寸,并应用双线性插值以提高旋转图像的质量。函数支持指定旋转角度、旋转中心,并可选择是否等比例缩放。

注释都在代码中:

from skimage import io, data
import numpy as np
import matplotlib.pyplot as plt
import math

# 加载图像
image = data.coffee()
# image = data.camera()


# 建立灰度图旋转函数
def image_rotate(img, degrees=0, x0=0, y0=0, resize=False):
    """
    :param img:
    :param degrees:
    :param x0: 这个是图像的宽
    :param y0: 这个是图像的高
    :param resize:
    :return:
    """
    # 建立旋转需要的全部矩阵
    # 将角度转为弧度和正弦余弦值
    radians = math.radians(degrees)
    sinA = math.sin(radians)
    cosA = math.cos(radians)
    # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标
    mat2dika2mat = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                   np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]) * \
                   np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])
    # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标(这是用于反向转回的矩阵)
    mat2dika2mat_r = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                     np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]).I * \
                     np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])

    # 给旋转后的图像大小一个初始值
    img_h, img_w = img.shape[:2]
    if len(img.shape) == 2:
        img_d = 0
    else:
        img_d = img.shape[2]
    # 首先求出旋转之后图像的大小
    if resize:
        # 将四个顶点分别进行计算旋转后的位置,以此确定旋转后图像多大
        # 注意:设定好的矩阵的运算中,横着向右代表矩阵坐标的横轴正方形,竖着向下代表矩阵坐标的竖轴正方向
        tops = np.mat([[0, 0, 1],
                         [0, img_h-1, 1],
                         [img_w-1, 0, 1],
                         [img_w-1, img_h-1, 1]])
        # 四个点分别进行旋转
        for i in range(tops.shape[0]):
            tops[i] = tops[i] * mat2dika2mat
        # 取出行和列的最大最小值
        max_hw = tops.max(axis=0)
        min_hw = tops.min(axis=0)
        max_w, max_h = max_hw[0, 0], max_hw[0, 1]
        min_w, min_h = min_hw[0, 0], min_hw[0, 1]
        # 设置旋转后图像的大小
        img_h, img_w = abs(int(max_h - min_h)), abs(int(max_w - min_w))
        # 重新建立新旋转中心的运算矩阵
        # 新的旋转中心找到之后,只需要替换旋转时从笛卡尔坐标系转换为矩阵坐标系那个公式中的旋转中心坐标
        x0_ = x0 * img_w // img.shape[1]
        y0_ = y0 * img_h // img.shape[0]
        # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标
        mat2dika2mat = np.mat([[1, 0, 0], [0, -1, 0], [-x0, y0, 1]]) * \
                       np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]) * \
                       np.mat([[1, 0, 0], [0, -1, 0], [x0_, y0_, 1]])
        # 矩阵坐标转笛卡尔坐标并旋转再转回矩阵坐标(这是用于反向转回的矩阵)
        mat2dika2mat_r = np.mat([[1, 0, 0], [0, -1, 0], [-x0_, y0_, 1]]) * \
                         np.mat([[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]).I * \
                         np.mat([[1, 0, 0], [0, -1, 0], [x0, y0, 1]])
    # 建立空白图像
    if img_d:
        img_new = np.zeros((img_h+1, img_w+1, img_d), dtype='uint8')
    else:
        img_new = np.zeros((img_h + 1, img_w + 1), dtype='uint8')
    # 循环旋转每一个像素点
    for i in range(img.shape[0]):
        for j in range(img.shape[1]):
            temp = np.mat([j, i, 1]) * mat2dika2mat
            x, y, t = temp[0, 0], temp[0, 1], temp[0, 2]
            x = int(x)
            y = int(y)
            if x > img_new.shape[1] - 1 or x < 0 or y > img_new.shape[0] - 1 or y < 0:
                continue
            img_new[y, x] = img[i, j]
    # 对全部的值进行双线性插值运算
    for i in range(img_new.shape[0]):
        for j in range(img_new.shape[1]):
            # if img[i, j] != 0:
            #     continue
            temp = np.mat([j, i, 1]) * mat2dika2mat_r
            x, y, t = temp[0, 0], temp[0, 1], temp[0, 2]
            if x > img.shape[1] - 1 or x < 0 or y > img.shape[0] - 1 or y < 0:
                continue
            n = int(x)
            m = int(y)
            u = x - n
            v = y - m
            if n >= img.shape[1] - 1:
                n = img.shape[1] - 2
            if m >= img.shape[0] - 1:
                m = img.shape[0] - 2
            img_new[i, j] = (1 - v) * (1 - u) * img[m, n] + (1 - v) * u * img[m, n + 1] + v * (1 - u) * img[
                m + 1, n] + v * u * img[m + 1, n + 1]
    # 返回旋转完成的图像
    return img_new


# 调用旋转函数
img = image_rotate(image, 60, image.shape[1]//2, image.shape[0]//2, False)
# 展示旋转图像
plt.imshow(img, cmap="gray")
plt.show()

不够好的地方,希望大家礼貌指出,谢谢。

### 图像旋转算法及实现方法 图像旋转图像处理中的一项基本操作,它允许将图像围绕某个点(通常是图像的中心)旋转指定的角度。常见的图像旋转算法主要基于插值方法来确定旋转后像素的位置和颜色值。 #### 基于Pillow库的实现 Python中的Pillow库提供了一个简单的方式来实现图像旋转。通过`Image.open()`函数可以加载图像,而`rotate()`函数则用于执行旋转操作。以下是一个示例代码片段,展示了如何使用Pillow库来实现图像旋转: ```python from PIL import Image def rotate_image(image_path, angle): # 打开图像 image = Image.open(image_path) # 旋转图像 rotated_image = image.rotate(angle) # 显示旋转后的图像 rotated_image.show() # 调用函数进行图像旋转 rotate_image('path/to/image.jpg', 45) ``` 这段代码定义了一个`rotate_image`函数,该函数接受图像文件路径和旋转角度作为参数,然后打开图像旋转图像并显示旋转后的结果。需要注意的是,旋转角度可以是正数也可以是负数,正数表示顺时针旋转,负数表示逆时针旋转[^1]。 #### 基于OpenCV库的实现 OpenCV是一个强大的计算机视觉库,它同样支持图像旋转操作。使用OpenCV进行图像旋转通常涉及到创建一个仿射变换矩阵,然后应用这个矩阵到图像上。下面是一个使用OpenCV进行图像旋转的例子: ```cpp #include <opencv2/opencv.hpp> void ImgRotate(cv::Mat &src, float angle, cv::Mat &dst) { cv::Point2f center(src.cols/2.0, src.rows/2.0); // 定义旋转中心 cv::Mat rot = cv::getRotationMatrix2D(center, angle * 180 / CV_PI, 1.0); // 获取旋转矩阵 cv::warpAffine(src, dst, rot, src.size()); // 应用旋转 } int main() { cv::Mat srcImg = cv::imread("test.jpg"); if (srcImg.empty()) { printf("srcImg load error \n"); system("pause"); exit(-1); } float angle = 30.0f * CV_PI / 180.0f; // 换为弧度制 cv::Mat dstImg; ImgRotate(srcImg, angle, dstImg); cv::imwrite("result.jpg", dstImg); cv::imshow("src", srcImg); cv::imshow("dst", dstImg); cv::waitKey(0); return 0; } ``` 在这个C++示例中,`ImgRotate`函数负责执行图像旋转。首先定义了旋转的中心点,接着使用`cv::getRotationMatrix2D`函数获取旋转矩阵,并且利用`cv::warpAffine`函数将旋转矩阵应用于源图像以得到目标图像[^4]。 #### 插值方法 在进行图像旋转时,由于像素位置的变化,可能需要计算新的像素值。这时就需要用到插值技术。最常用的插值方法包括最近邻插值、双线性插值等。这些方法可以帮助保持图像质量,减少因旋转导致的锯齿或模糊现象[^2]。 ---
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值