python实现图像的平移、镜像、旋转(不调用CV库)

news/2024/5/20 2:48:03/文章来源:https://blog.csdn.net/weixin_51002159/article/details/130032306

python实现图像的平移、镜像、旋转(不调用CV库)

老师布置的作业。。。。。

平移图像

图像的平移在几何变换中算是最简单的变换之一,话不多说,直奔主题

image-20230413220258017

由图可知,在opencv中图像的原点一般为左上角,设初始坐标为(x0,x0)(x_{0}, x_{0})(x0,x0)的经过平移(△x,△y)(\bigtriangleup x, \bigtriangleup y)(x,y)后,坐标变为(x1,y1)(x_{1}, y_{1})(x1,y1)

则很容易得出两点之间的位置关系:
{x1=x0+△xy1=y0+△y\begin{cases} x_{1} = x_{0} + \bigtriangleup x \\y_{1} = y_{0} + \bigtriangleup y \end{cases} {x1=x0+xy1=y0+y
在python中我们可以使用简单for循环实现:

import cv2 as cv
import numpy as npdef show_Img(name, img):cv.imshow(name, img)cv.waitKey(0)cv.destroyAllWindows()def translate_img(img, move_y, move_x):h, w, c = img.shapetranslated_img = np.zeros((h, w, c), dtype=np.uint8)for i in range(h):for j in range(w):if i >= move_y and j >= move_x:translated_img[i, j] = img[i - move_y, j - move_x]return translated_imgimg = cv.imread("images/cat.jpg")
h, w, c = img.shape
translated_img = translate_img(img, h // 3, w // 3)
img_all = np.hstack((img, translated_img))
show_Img("img", img_all)

image-20230413221349660

而通常我们一般是用矩阵形式表示:
[x1,y1,1]=[x0,y0,1][100010△x△y1]\left [ x_{1} , y_{1}, 1\right ] = \left [ x_{0} , y_{0} , 1 \right ] \begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ \bigtriangleup x & \bigtriangleup y&1 \end{bmatrix} [x1,y1,1]=[x0,y0,1]10x01y001
python实现为:

def translate_image(image, move_x, move_y):# 平移矩阵translation_matrix = np.array([[1, 0, 0], [0, 1, 0], [move_x, move_y, 1]])height, width = image.shape[:2]translated_image = np.zeros([height, width, 3], dtype=np.uint8)for y in range(height):for x in range(width):translated_x, translated_y, _ = np.dot([x, y, 1], translation_matrix)if 0 <= translated_x < width and 0 <= translated_y < height:translated_image[translated_y, translated_x] = image[y, x]return translated_image

镜像图像

图像镜像也是最为常用的一种变换,镜像就是相对某一参照面旋转180°的图像,又通常成为对称变换。

这里主要介绍三种镜像方式:

  • 水平镜像
  • 垂直镜像
  • 斜对角线镜像

水平镜像

image-20230413222438042

经数学分析得水平镜像后的x1与x0和为图像宽度,而y点不变,所以:
{x1=w−x0y1=y0\begin{cases} x_{1} = w - x_{0}\\ y_{1} = y_{0} \end{cases} {x1=wx0y1=y0
转换为矩阵得:
[x1,y1,1]=[x0,y0,1][−100010w01]\left [ x_{1}, y_{1}, 1 \right ] = \left[x_{0}, y_{0}, 1 \right]\begin{bmatrix} -1 & 0 & 0\\ 0 & 1 & 0 \\ w & 0 & 1 \end{bmatrix} [x1,y1,1]=[x0,y0,1]10w010001

垂直镜像

同理:
[x1,y1,1]=[x0,y0,1][1000−100y1]\left [ x_{1}, y_{1}, 1 \right ] = \left[x_{0}, y_{0}, 1 \right]\begin{bmatrix} 1 & 0 & 0\\ 0 & -1 & 0 \\ 0 & y & 1 \end{bmatrix} [x1,y1,1]=[x0,y0,1]10001y001

斜对角线镜像

同理:
[x1,y1,1]=[x0,y0,1][−1000−10wy1]\left [ x_{1}, y_{1}, 1 \right ] = \left[x_{0}, y_{0}, 1 \right]\begin{bmatrix} -1 & 0 & 0\\ 0 & -1 & 0 \\ w & y & 1 \end{bmatrix} [x1,y1,1]=[x0,y0,1]10w01y001
综上所述,用python实现为:

def flip_image(image, flip):h, w = image.shape[:2]fliped_image = np.zeros((h, w, 3), dtype=np.uint8)# 矩阵的w-1和y-1是防止图片的索引值超出范围if flip == "x":flip_matrix = np.array([[-1, 0, 0], [0, 1, 0], [w - 1, 0, 1]])elif flip == "y":flip_matrix = np.array([[1, 0, 0], [0, -1, 0], [0, h - 1, 1]])elif flip == "x-y":flip_matrix = np.array([[-1, 0, 0], [0, -1, 0], [w - 1, h - 1, 1]])else:flip_matrix = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])for y in range(h):for x in range(w):flip_x, flip_y, _ = np.dot([x, y, 1], flip_matrix)fliped_image[flip_y, flip_x] = image[y, x]return fliped_image
img = cv.imread("images/dog2.jpg")
h, w, c = img.shape
img = cv.resize(img, (w // 4, h // 4))
fliped_img_x = flip_image(img, "x")
fliped_img_y = flip_image(img, "y")
fliped_img_x_y = flip_image(img, "x-y")
img_up = np.hstack((img, fliped_img_x))
img_down = np.hstack((fliped_img_y, fliped_img_x_y))
img_all = np.vstack((img_up, img_down))
show_Img("img_all", img_all)

image-20230413224058277

旋转图像

图像的选装相比平移和镜像就稍微复杂了一些

image-20230413224354192

如图可知,初始点为(x,y)(x, y)(x,y)逆时针旋转β\betaβ角度后为(x′,y′)(x', y')(x,y)

数学分析:
{x=Dcosαy=Dsinα\begin{cases} x = Dcos\alpha \\y = Dsin\alpha \end{cases} {x=Dcosαy=Dsinα

{x′=Dcos(α+β)=D(cosαcosβ−sinαsinβ)=xcosβ−ysinβy′=Dsin(α+β)=D(sinαcosβ+cosαsinβ)=ycosβ+xsinβ\begin{cases} x'=Dcos(\alpha+\beta)=D(cos\alpha cos\beta - sin\alpha sin\beta) = xcos\beta - ysin\beta\\ y'=Dsin(\alpha+\beta)=D(sin\alpha cos\beta + cos\alpha sin\beta) = ycos\beta + xsin\beta \end{cases} {x=Dcos(α+β)=D(cosαcosβsinαsinβ)=xcosβysinβy=Dsin(α+β)=D(sinαcosβ+cosαsinβ)=ycosβ+xsinβ

用矩阵表示为:
[x′,y′,1]=[x,y,1][cosβsinβ0−sinβcosβ0001]\left [ x', y', 1 \right ] = \left[x, y, 1\right]\begin{bmatrix} cos\beta & sin\beta & 0\\ -sin\beta & cos\beta & 0\\ 0 & 0 & 1 \end{bmatrix} [x,y,1]=[x,y,1]cosβsinβ0sinβcosβ0001
但这并不是整个图像旋转的原理,因为还要指定旋转点,这里假设图像旋转点为图像的中心,即(w/2,h/2)(w/2, h/2)(w/2,h/2),则在旋转时需要将图像的坐标系移动到原本图像的中心上:
[x′,y′,1]=[x,y,1][100010−w/2−y/21]\left [ x' , y', 1\right ] = \left [ x , y , 1 \right ] \begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ -w/2 & -y/2&1 \end{bmatrix} [x,y,1]=[x,y,1]10w/201y/2001
image-20230413231431473

由上图可知,旋转时,整个图像的大小也随之改变,新的高度与宽度为:
{w′=w∗∣cosβ∣+h∗∣sinβ∣h′=h∗∣cosβ∣+w∗∣sinβ∣\begin{cases} w' = w*|cos\beta|+ h*|sin\beta| \\ h' = h * |cos\beta| + w * |sin\beta| \end{cases} {w=wcosβ+hsinβh=hcosβ+wsinβ
旋转完后的图像在需要平移到原来的位置:
{△x=(w′−w)∗0.5+(w/2−1)△y=(h′−h)∗0.5+(h/2−1)\begin{cases} \bigtriangleup x = (w' - w) * 0.5 + (w/2 - 1) \\ \bigtriangleup y = (h'- h) * 0.5 + (h/2 - 1) \end{cases} {x=(ww)0.5+(w/21)y=(hh)0.5+(h/21)
总的矩阵为:
[x′,y′,1]=[x,y,1][100010−w/2−y/21][cosβsinβ0−sinβcosβ0001][100010△x△y1]\left [ x' , y', 1\right ] = \left [ x , y , 1 \right ] \begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ -w/2 & -y/2&1 \end{bmatrix}\begin{bmatrix} cos\beta & sin\beta & 0\\ -sin\beta & cos\beta & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ \bigtriangleup x & \bigtriangleup y&1 \end{bmatrix} [x,y,1]=[x,y,1]10w/201y/2001cosβsinβ0sinβcosβ000110x01y001

前向映射

import cv2 as cv
import numpy as npdef show_Img(name, img):cv.imshow(name, img)cv.waitKey(0)cv.destroyAllWindows()# 前向映射旋转
def front_rotate_image(image, angle):# 将角度转换为弧度radians = np.deg2rad(-angle)# 计算旋转矩阵cos_theta = np.around(np.cos(radians), decimals=4)sin_theta = np.around(np.sin(radians), decimals=4)rotation_matrix = np.array([[-cos_theta, -sin_theta, 0], [sin_theta, -cos_theta, 0], [0, 0, 1]])# 计算旋转后的图像大小height, width = image.shape[:2]new_width = int(np.round(width * abs(cos_theta) + height * abs(sin_theta)))new_height = int(np.round(height * abs(cos_theta) + width * abs(sin_theta)))print(new_width, new_height)# 创建新图像rotated_image = np.zeros((new_height, new_width, 3), dtype=np.uint8)# 计算旋转中心点center_x = width / 2center_y = height / 2# 将坐标系平移回原来的位置,加上自定义旋转点的偏移量x_step = (new_width - width) * (center_x / width) + (center_x - 1)y_step = (new_height - height) * (center_y / height) + (center_y - 1)translation_matrix1 = np.array([[1, 0, 0], [0, 1, 0], [-center_x, -center_y, 1]])translation_matrix2 = np.array([[1, 0, 0], [0, 1, 0], [x_step, y_step, 1]])# 遍历每个像素并进行变换for y in range(height):for x in range(width):# 将坐标系平移至中心点translated_x, translated_y, _ = np.dot([x, y, 1], translation_matrix1)# 计算旋转后的坐标rotated_x, rotated_y, _ = np.dot([translated_x, translated_y, 1], rotation_matrix)rotated_x, rotated_y, _ = np.dot([rotated_x, rotated_y, 1], translation_matrix2)# 如果旋转后的坐标在原图像范围内,则将该像素复制到新图像中if 0 <= rotated_x < new_width and 0 <= rotated_y < new_height:rotated_image[int(np.round(rotated_y)), int(np.round(rotated_x))] = image[y, x]return rotated_imageimg = cv.imread("images/kunkun.jpg")
theta = 60
h, w, c = img.shape
img = cv.resize(img, (w // 2, h // 2))
img_rotated = front_rotate_image(img, theta)
show_Img("img_rotated", img_rotated)

原图:

在这里插入图片描述

结果:

image-20230413232930045
从上面看来,使用前向映射会造成许多网格状,这是因为有原图到旋转后的图,会生成小数坐标,导致丢失一部分像素,而后面会使用后向映射加线性插值的方法解决此问题。

后向映射

学业繁忙,后面慢慢更新。。。。。

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1 Spark的环境搭建

1 Spark的环境搭建 1.1 Windows - Spark安装 一、下载并安装软件 \1. 下载并安装Java8&#xff1a;https://www.oracle.com/java/technologies/downloads/ &#xff08;1&#xff09; 原因&#xff1a;Spark由Scala语言开发。而Scala代码会被编译成Java字节码。因此Spark的…

总结821

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 暴力英语&#xff1a;早上背颂并默写第19篇文章《I always knew I was going to be rich》&#xff0c;还有两三篇就达成…

一图看懂 xlwt 模块:读写 Excel 文件的数据和格式信息, 资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创&#xff0c;转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 xlwt 模块&#xff1a;读写 Excel 文件的数据和格式信息, 资料整理笔记&#xff08;大全&#xff09;摘要模块图类关系图模块全展开【xlwt】统计常量模块1 xlwt.compat2 xl…

中核科技:科技匠心 智启未来

​  2023 年4月 13—15 日&#xff0c;2023年易派客工业品展览会、石油石化工业展览会、第七届中国石油和化工行业采购年会&#xff0c;在苏州国际博览中心胜利召开。本次展会展览面积53000平方米&#xff0c;参展企业500余家&#xff0c;汇集了中国工业制造领域的大型国企央…

第一章 webpack与构建发展简史

官方loader和插件 Loaders | webpack Plugins | webpack 为什么需要构建工具&#xff1f; 初识webpack webpack默认配置文件&#xff1a;webpack.config.js 可以通过webpack --config <config_file_name>指定配置文件 rules是个数组&#xff0c;一个打包配置可以有多…

直方图 颜色映射

文章目录hist map1. 原理2.灰度图3. 对于彩色图像4. 直方图规定化效果hist map 1. 原理 code:https://github.com/rossgoodwin/hmap 利用队列记录 hist src > tgt, src < tgt , src tgt的 索引。 然后&#xff0c;对于每个hist excess, 将其移动到 hist deficit 进行…

PS学习记录-基础操作与快捷键

1、复制图层 在【移动工具】状态下&#xff0c;配合【alt】按键拖动图像&#xff0c;可以进行复制图层 当然&#xff0c;PS里复制图层的方式很多&#xff0c;比如&#xff1a;选中图层&#xff0c;按【ctrlJ】&#xff0c;也是复制图层 2、多选图层 2.1同上&#xff0c;也是…

微信支付,JSAPI支付,APP支付,H5支付,Native支付,小程序支付功能详情以及回调处理

一.支付相关文档地址支付wiki&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml支付api: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/index.shtml开发工具包(SDK)下载&#xff1a;https://pay.weixin.qq.com/wiki/doc/apiv3/wechatpay/wechatpay6_0.shtm…

【你听说了吗】GPT-5据说已经学完了世界上现存所有的视频

文章目录前言一、GPT-5会带来什么&#xff1f;二、我们该怎么办&#xff1f;总结前言 最近半年要说最火的产品&#xff0c;无疑是ChatGPT &#xff0c;很多同学都在用 GPT 帮助自己工作&#xff0c;学习&#xff0c;提高效率&#xff01;尤其是 GPT4&#xff0c;性能强 GPT3.5…

Thymeleaf select回显并选中多个

语法&#xff1a;${#strings.indexOf(name,frag)} 或者 ${#lists.contains(list, element)} 或者 ${#strings.contains(name,ez)} 或者 ${#strings.containsIgnoreCase(name,ez)} 多选语法 &#xff1a; <select class"required" data-live-search"true&…

Tomcat处理请求的全过程

文章目录一、组件详解二、请求处理流程1.总体流程图2.Worker线程任务流程三、源码跟踪1.Tomcat启动线程组件2.Acceptor3.Poller4.Worker总结一、组件详解 在Tomcat处理客户端请求的过程中&#xff0c;这里面有三个组件概念&#xff0c;他们都是线程&#xff0c;分别负责不同的…

能翻译大量文字的软件-正规的翻译软件

复制自动翻译软件是一种能够复制并自动翻译文本的工具。当您阅读某一种语言的文本时&#xff0c;这种软件可以快速识别并翻译出来&#xff0c;以方便您更好地理解内容。与其他翻译软件不同的是&#xff0c;复制自动翻译软件可以直接在游览网站的过程中&#xff0c;直接对用户正…

贝叶斯优化 | BO-RF贝叶斯优化随机森林多输入单输出回归预测(Matlab完整程序)

贝叶斯优化 | BO-RF贝叶斯优化随机森林多输入单输出回归预测(Matlab完整程序) 目录 贝叶斯优化 | BO-RF贝叶斯优化随机森林多输入单输出回归预测(Matlab完整程序)预测结果基本介绍评价指标程序设计参考资料预测结果 基本介绍 贝叶斯优化 | BO-RF贝叶斯优化随机森林多输入单…

全球6G技术大会总结报告

全球6G技术大会 论坛B&#xff1a;天地融合智能组网技术 论坛D&#xff1a;2030技术发展趋势 论坛E&#xff1a;6G无线空口传输技术 论坛F&#xff1a;6G通感算架构及关键技术 论坛H&#xff1a;6G网络架构及关键技术 论坛B&#xff1a;天地融合智能组网技术 论坛B中包含…

【大数据Hadoop】HDFS3.3.1-Namenode-租约管理

租约管理前言LeaseManager.LeaseLeaseManager添加租约 - addLease租约检查 - FsNamesystem.checkLease租约更新 - renewLease删除租约 - removeLease租约检查 - Monitor 线程租约恢复 - Monitor 线程发起租约恢复 - 其他方式发起前言 我们知道 HDFS 文件是 write-once-read-man…

C++的命名空间

C和C语言是有一些相似的地方的&#xff0c;而且C就是C语言的改进版本&#xff0c;所以学习C也得学习C语言&#xff0c;但是他们又是有很多不同的地方 下面我们就看一下C的命名空间 我们首先看一下 如果是这一段代码&#xff0c;那么这里输出的是多少呢&#xff1f; 很好这里输…

2023MathorcupC题电商物流网络包裹应急调运与结构优化问题建模详解+模型代码(一)

电商物流网络包裹应急调运与结构优化问题 第三次继续写数模文章和思路代码了&#xff0c;不知道上次美赛和国赛大家有没有认识我&#xff0c;没关系今年只要有数模比赛艾特我私信我&#xff0c;要是我有时间我一定免费出文章代码好吧&#xff01;博主参与过十余次数学建模大赛…

Flink时间属性

1.概述 Flink支持三种与流数据处理相关的时间概念&#xff1a;Processing Time、Event Time和Ingestion Time。具体如下图所示&#xff1a; 当前Flink仅支持Processing Time和Event Time EventTime&#xff1a;您提供的事件时间&#xff08;通常是数据的最原始的创建时间&…

大数据学习路线图(2023完整版)适合收藏

大数据开发是一门涉及处理和分析大规模数据的技术领域&#xff0c;随着大数据技术的不断发展和应用&#xff0c;对大数据开发人员的需求也在逐渐增加。就业前景相对较好&#xff0c;尤其在科技行业和数据驱动型企业中。大数据开发的前景还是有很多优势的&#xff0c;就业范围广…

锂电池寿命预测 | Python实现基于Qore-learning神经网络的锂电池寿命预测

文章目录 预测效果文章概述程序设计参考资料预测效果 文章概述 锂电池寿命预测 | Python实现基于Qore-learning神经网络的锂电池寿命预测 程序设计 import numpy as np import matplotlib