0

0

使用三角函数实现图像中心旋转教程

DDD

DDD

发布时间:2025-12-04 23:05:31

|

986人浏览过

|

来源于php中文网

原创

使用三角函数实现图像中心旋转教程

本教程详细讲解如何利用基础三角函数(正弦和余弦)实现图像的像素级旋转,而非依赖于高级图形库的变换功能。文章将从二维点旋转的数学原理出发,分析直接应用旋转公式可能导致的问题——图像围绕其左上角旋转,并提供一个修正方案,通过坐标系平移确保图像围绕其几何中心正确旋转,并附带java代码示例。

1. 二维点旋转的数学基础 在二维平面上,一个点 (x, y) 绕原点 (0, 0) 逆时针旋转 θ 角度后,其新坐标 (x', y') 可以通过以下三角函数公式计算:

x' = x * cos(θ) - y * sin(θ)y' = x * sin(θ) + y * cos(θ)

在Java中,我们可以实现一个辅助方法来完成这个点的旋转计算。这个方法接收点的原始坐标 (posx, posz) 和旋转角度 angle,并返回旋转后的新坐标。

public int[] rotateByAngle(int posx, int posz, double angle){
    double radians = Math.toRadians(angle); // 将角度转换为弧度
    double cos = Math.cos(radians);
    double sin = Math.sin(radians);

    // 应用旋转公式
    int rotate_x  = (int) Math.floor((posx * cos - posz * sin)) ;
    int rotate_z  = (int) Math.floor((posx * sin  + posz * cos)) ;

    return new int[] {rotate_x ,rotate_z };
}

这个 rotateByAngle 方法能够正确地将任何给定的 (posx, posz) 点绕坐标原点 (0,0) 旋转指定的角度。

2. 图像旋转的常见误区与问题 当尝试将上述点旋转逻辑应用于图像时,一个常见的错误是直接将图像的像素坐标 (x2, y2) 视为相对于旋转中心的坐标。例如,如果图像的左上角是 (0,0),其像素坐标 (x2, y2) 实际上是相对于图像左上角的偏移量。

如果直接将这些像素坐标传入 rotateByAngle 方法,图像会围绕其自身的左上角 (0,0) 进行旋转。这会导致图像在旋转时看起来像是围绕一个固定的左上角点“甩”出去一样,而不是原地打转。

以下是直接应用旋转的错误示例代码:

Frase
Frase

Frase是一款出色的长篇 AI 写作工具,快速创建seo优化的内容。

下载
public void drawImageWrong(MapCanvas canvas, int x, int y, BufferedImage image, double angle) {
    // 假设 MapPalette.imageToBytes 能够将 BufferedImage 转换为字节数组像素数据
    byte[] bytes = MapPalette.imageToBytes(image); 

    for(int x2 = 0; x2 < image.getWidth(); ++x2) {
        for(int y2 = 0; y2 < image.getHeight(); ++y2) {
            byte c = bytes[y2 * image.getWidth() + x2];
            if(c == 0) continue; // 跳过透明像素,假设0代表透明

            // 错误:直接将像素坐标 (x2, y2) 作为绕原点旋转的点
            // 此时的 (x2, y2) 是相对于图像左上角的坐标
            int[] sol = rotateByAngle(x2, y2, angle);

            // 将旋转后的点绘制到画布上
            // x, y 是图像在画布上的起始位置
            canvas.setPixel(x + sol[0], y + sol[1], c);
        }
    }
}

这段代码会导致图像围绕其左上角进行旋转,这通常不是我们期望的围绕图像中心旋转的效果。

3. 修正旋转中心:实现图像中心旋转 要实现图像围绕其几何中心旋转,我们需要进行一个坐标系的转换。核心思想是:

  1. 将图像的每个像素坐标 (x2, y2) 从“相对于图像左上角”的坐标系,转换到“相对于图像中心”的坐标系。
  2. 在这个新的坐标系中,应用我们之前定义的 rotateByAngle 方法进行旋转。
  3. 旋转完成后,rotateByAngle 返回的坐标是相对于图像中心的。我们再将这个坐标加上图像在画布上的整体位置 (x, y),以确定最终的绘制位置。

假设图像的宽度为 width,高度为 height。那么图像的中心点坐标为 (width/2, height/2)。 对于图像中的任意像素 (x2, y2):

  • 它相对于图像中心的坐标是 (x2 - width/2, y2 - height/2)。
  • 将这个相对坐标传入 rotateByAngle 进行旋转。
  • rotateByAngle 返回的 (sol[0], sol[1]) 已经是相对于图像中心的旋转结果。
  • 最后,将这个结果加上图像在画布上的起始位置 (x, y) 即可。

以下是修正后的 drawImage 方法:

public void drawImage(MapCanvas canvas, int x, int y, BufferedImage image, double angle) {
    byte[] bytes = MapPalette.imageToBytes(image); // 假设这是一个获取像素数据的方法

    // 计算图像的中心点相对于其左上角的偏移
    int real_x = image.getWidth() / 2;
    int real_y = image.getHeight() / 2;

    for(int x2 = 0; x2 < image.getWidth(); ++x2) {
        for(int y2 = 0; y2 < image.getHeight(); ++y2) {
            byte c = bytes[y2 * image.getWidth() + x2];
            if(c == 0) continue; // 跳过透明像素

            // 关键修正:将像素坐标 (x2, y2) 转换为相对于图像中心的坐标 (x2 - real_x, y2 - real_y),
            // 然后再对这个中心化的点进行旋转。
            int[] sol = rotateByAngle(x2 - real_x, y2 - real_y, angle);

            // sol[0] 和 sol[1] 是旋转后像素相对于图像中心的偏移量。
            // 将这些偏移量加上图像在画布上的起始位置 (x, y),得到最终的绘制坐标。
            canvas.setPixel(x + sol[0], y + sol[1], c);
        }
    }
}

通过上述修改,图像将围绕其自身的中心进行旋转,达到预期的效果。

4. 注意事项与性能考量

  • 像素映射与空洞问题: 这种逐像素旋转的方法在某些旋转角度下,可能会导致目标位置的像素点不连续,从而在旋转后的图像中出现“空洞”或锯齿状边缘(走样)。这是因为我们是从源图像的每个像素出发计算其目标位置,而不是从目标图像的每个位置反推其源像素。更高级的旋转算法会使用插值(如双线性插值)和逆向映射来解决这个问题。
  • 性能: 逐像素遍历和计算三角函数会带来一定的性能开销。对于需要频繁旋转或处理大型图像的应用,使用图形库(如Java的 java.awt.geom.AffineTransform 或其他图像处理库)提供的优化过的API通常会更高效,因为它们通常利用硬件加速或更复杂的算法来提高性能和质量。
  • 坐标取整: Math.floor 会向下取整。在某些情况下,使用 Math.round (四舍五入) 或 Math.ceil (向上取整) 可能会对视觉效果产生细微影响。这取决于具体的应用场景和对像素精度的要求。
  • 透明像素处理: 代码中通过 if(c == 0) continue; 跳过了透明像素的绘制,这对于某些图像格式(如PNG)是必要的。

总结 本教程演示了如何仅使用基础三角函数实现图像的中心旋转。核心在于理解旋转操作的坐标原点,并通过坐标平移将图像的几何中心对齐到旋转原点。虽然这种方法在处理图像质量(如抗锯齿)和性能方面可能不如专业的图形库API,但它提供了一个深入理解图像变换底层原理的良好实践。在不需要高级特性或追求极致性能的场景下,这种纯数学实现方式是一个有效的选择。

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

838

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

742

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

737

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

399

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16926

2023.08.03

Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

0

2026.01.20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.7万人学习

C# 教程
C# 教程

共94课时 | 7.1万人学习

Java 教程
Java 教程

共578课时 | 48.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号