Numpy+PIL实现图片的自由旋转

news/2024/10/25 15:24:36/

1.内容简介

使用PIL和Numpy编程实现图片的自由旋转。

2.技术要点

(1)用Python PIL库将图片读取为NumPy 数组。
(2)采用旋转后图像幅面放大的图像旋转变换方式,根据旋转角度和原图像尺寸计算图像像素点的旋转变换矩阵。
(3)用旋转变换矩阵计算原图像四个顶点旋转后的像素坐标,用最大坐标减去最小坐标的方式计算旋转后图像新尺寸,创建存储新图像的NumPy数组。
(4)依据反向映射的方式,扫描新图像的像素,通过逆变换的方式确定对应的原图像像素点,将其RGB值赋给新图像的像素点。
(5)将NumPy数组保存为图像输出。

3.代码实现

def rotateImageWithZoom(image_path: str, rotate_angle: float):"""放大图幅的图片旋转:param image_path: 图片路径:param rotate_angle: 旋转角度,单位:degree,顺时针为正:return: 新的图片numpy数组"""img = Image.open(image_path)img_mat = np.asarray(img)beta = deg2rad(rotate_angle)h = img_mat.shape[0]w = img_mat.shape[1]K1 = np.array([[0, -1, 0.5 * h], [1, 0, 0.5 * w], [0, 0, 1]])K2 = np.array([[cos(beta), sin(beta), 0], [-sin(beta), cos(beta), 0], [0, 0, 1]])# 坐标变换矩阵K = np.matmul(K1, K2)# 旋转后左上角像素点位置left_up = np.matmul(K, np.array([[0], [0], [1]]))# 旋转后左下角像素点位置left_down = np.matmul(K, np.array([[h - 1], [0], [1]]))# 旋转后右上角像素点位置right_up = np.matmul(K, np.array([[0], [w - 1], [1]]))# 旋转后右下角像素点位置right_down = np.matmul(K, np.array([[h - 1], [w - 1], [1]]))# 确定外接矩形尺寸x1 = np.array([left_up.reshape((left_up.shape[0],)),left_down.reshape((left_up.shape[0],)),right_up.reshape((left_up.shape[0],)),right_down.reshape((left_up.shape[0],))]).astype(int)# 旋转后图像尺寸new_h = np.max(x1[:, 0]) - np.min(x1[:, 0])new_w = np.max(x1[:, 1]) - np.min(x1[:, 1])x_min = np.min(x1[:, 0])y_min = np.min(x1[:, 1])# 新图像new_img_mat = np.ones((new_h, new_w, 3)) * 255# 反向映射K_inv = np.linalg.inv(K)for x in range(new_img_mat.shape[0]):for y in range(new_img_mat.shape[1]):old_pos = np.matmul(K_inv, np.array([[x + x_min + 1], [y + y_min + 1], [1]])).astype(int)if 0 <= old_pos[0] < h and 0 <= old_pos[1] < w:new_img_mat[x, y] = img_mat[old_pos[0], old_pos[1]]# numpy数组转图片new_img_mat = new_img_mat.astype(int)new_img = Image.fromarray(new_img_mat.astype(np.uint8))new_img.save('photos/rotated_photo_{}.png'.format(rotate_angle))plt.imshow(new_img_mat)plt.xlabel("${} ^0$".format(rotate_angle))plt.show()return new_img_mat.astype(int)

4.实现效果

使用方法如下:

if __name__ == '__main__':rotateImageWithZoom('photos/takagi.jpeg', -60.3)

原图:
在这里插入图片描述

旋转-60.3°:
在这里插入图片描述
注意:matplotlib绘制图片时x轴是图片高度,y轴是图片宽度,而一般的图片查看器x轴是宽度,y轴是高度。

5.结果分析

旋转后的图片幅面大小发生了明显变化,放大后也可以看出旋转-61.3°的图片变模糊了,原因是旋转变换时每个像素点被视作为没有尺寸的理想点,旋转后的坐标会出现小数(即亚像素坐标),在反向映射时坐标被取整,故存在舍入误差,导致某些像素点丢失。对于0°,90°,180°和-90°这些角度,舍入误差是0,故旋转后除了图幅改变,清晰度没有变化。
结论对图像做旋转变换时,尽量选择特殊角度,以免像素损失,导致图像质量下降,对于非特殊角度,如-10°,-61.3°等旋转后需要去模糊,才能保证清晰度基本不变


http://www.ppmy.cn/news/5765.html

相关文章

Feign和restTemplate 单个接口超时拦截处理

文章目录1. Feign超时2. restTemplate超时&#xff08;全局&#xff09;3. restTemplate超时&#xff08;指定接口&#xff0c;用注解实现切面拦截&#xff09;以5s超时为例。超时的接口数据&#xff0c;就不要了&#xff0c;默认为空1. Feign超时 feign:client:config:defaul…

Halcon常用算子(库函数)整理

目录一. 常规操作类1.1 tuple_length()1.2 tuple_find_first()1.3 tuple_gen_const()二. 机器视觉操作类2.1 read_image()2.2 get_image_size()2.3 intensity()2.4 zoom_image_factor()2.5 median_image()2.6 Gauss_filter()2.7 fft_generic()2.8 convol_fft()2.9 sub_image()2…

webgl—将多组点传给webgl系统中

webgl应用的整体流程&#xff1a; 获取webgl绘图上下文---- 初始化着色器— 设置点的坐标信息— 设置canvas背景色---- 清空canvas— 绘制 1.webgl借助canvas绘制的 2.绘制线 首先确定线的点坐标&#xff0c;Webgl运行在GPU中&#xff0c;而js代码运行在CPU中&#xff0c;最终…

[Python图像处理] 使用 HSV 色彩空间检测病毒对象

使用 HSV 色彩空间检测病毒对象前言检测病毒对象相关链接前言 在本节中&#xff0c;我们将学习如何使用 OpenCV 在 HSV 色彩空间中使用特定颜色检测感兴趣对象。我们需要通过指定颜色值范围识别和提取感兴趣的对象&#xff0c;使用具有病毒的血细胞图像&#xff0c;我们的目标…

11个案例讲透 Python 函数参数

今天给大家分享一下自己整理的一篇 Python 参数的内容&#xff0c;内容非常的干&#xff0c;全文通过案例的形式来理解知识点&#xff0c;自认为比网上 80% 的文章讲的都要明白&#xff0c;如果你是入门不久的 python 新手&#xff0c;相信本篇文章应该对你会有不小的帮助。 接…

nginx架构解析:朴实中见真知

目录前言为什么高并发很重要Apache可以做到吗使用nginx会更有优势吗&#xff1f;nginx架构概览代码结构Workers模型nginx进程规则nginx缓存概览nginx配置nginx内部典型的HTTP请求处理循环课程总结前言 nginx&#xff08;发音“engine x”&#xff09;是俄国的软件工程师Igor S…

【3.3 ads篇(重点)】

3.3 ads篇(重点) 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、基本概念1.1 基本定义1.2 关键类型二、数据类型2.1 ads数据类型2.2 类型转换2.3 结果缓冲区总结前言 提示:以下是本篇文章正文内容,下面案例可供参考 一、基本概念 …

第4、5、6 章

第4章 数据库编程 用如下拼接sql的方式检验用户名和密码&#xff1a; select * from user where useridaa and userpwda or 11 &#xff1a; where条件为真。所以是不安全的。 避免方式&#xff1a;在sql中使用"?"进行预编译 第5章 JavaBean简介 JavaBean是Java W…