JavaScript图像处理:深入理解仿射变换与实现

作者:异步漫步

时间:2026-10-26

浏览:93

本文深入解析JavaScript中的仿射变换技术,从数学原理出发推导旋转与平移公式,并展示如何构建变换矩阵。通过具体的代码实现,详细讲解如何利用[[wp:a2]]矩阵对图像进行缩放、旋转和平移操作,包括核心算法逻辑与像素遍历处理细节。

文章目录
前言

仿射变换概述

在上一篇关于图像金字塔的文章之后,本节我们将重点探讨仿射变换这一概念。

什么是仿射变换?

从数学定义来看,任何仿射变换均可分解为两个部分:首先乘以一个矩阵以执行线性变换,随后加上一个向量以执行平移操作。

本质上,仿射变换描述了源图像与目标图像之间的几何映射关系。

利用这种变换,我们可以对图像执行缩放、旋转以及平移等多种几何操作。

数学原理推导

预备数学知识

在正式处理仿射变换之前,我们需要先解决一个基础的几何数学问题。

仿射变换概述

如图所示,假设有一个点坐标为(x1, y1),若该点绕原点旋转角度a,我们需要确定其旋转后的新坐标位置。

为了简化计算,我们将直角坐标系转换为极坐标系。此时,点(x1, y1)表示为(r, β),其中r为半径,β为角度。

旋转后,该点的极坐标变为(r, α+ β),其中α为旋转角度。

接下来,我们需要利用三角函数公式将极坐标重新转换回直角坐标系。

根据和角公式,cos(α+β)展开为cosαcosβ-sinαsinβ。

同理,sin(α+β)展开为sinαcosβ+cosαsinβ。

已知原点在直角坐标系中的坐标为(cosβ * r, sinβ * r),结合上述公式,可以推导出旋转后的新坐标为(x1 * cosα - y1 * sinα, x1 * sinα + y1 * cosα)。

基于上述推导,我们可以得出旋转变换的通用公式。

仿射变换概述

相比之下,平移变换更为直观,只需在坐标基础上加上一个平移向量(c, d)即可实现。

矩阵构建与代码实现

变换矩阵函数的具体实现

在编程实践中,我们通常使用2 \times 3矩阵来统一表示仿射变换过程。

A = \begin{bmatrix} a_{00} & a_{01} \\ a_{10} & a_{11} \end{bmatrix}_{2 \times 2} B = \begin{bmatrix} b_{00} \\ b_{10} \end{bmatrix}_{2 \times 1} M = \begin{bmatrix} A & B \end{bmatrix} =\begin{bmatrix} a_{00} & a_{01} & b_{00} \\ a_{10} & a_{11} & b_{10}\end{bmatrix}_{2 \times 3}

在该矩阵中,A部分负责旋转和缩放变换,B部分负责平移变换。最终的变换结果T需满足特定的矩阵乘法关系。

具体表达式为T = A \cdot \begin{bmatrix}x \\ y\end{bmatrix} + B,或者可以表示为另一种形式。

T = M \cdot [x, y, 1]^{T}

即最终变换遵循T = \begin{bmatrix} a_{00}x + a_{01}y + b_{00} \\ a_{10}x + a_{11}y + b_{10} \end{bmatrix}的规则。

以下是生成旋转矩阵的具体代码实现:

var getRotationArray2D = function(__angle, __x, __y){
var sin = Math.sin(__angle) || 0,
cos = Math.cos(__angle) || 1,
x = __x || 0,
y = __y || 0;
return [cos, -sin, -x,
sin, cos, -y
]; 
};

通过上述代码,我们成功构建了一个用于仿射变换的矩阵对象。

需要注意的是,该实现存在局限性,因为其原点被固定在了图像的左上角,这可能影响某些场景下的变换效果。

图像变换函数实现

仿射变换函数的完整实现

以下是执行仿射变换的核心函数代码:

var warpAffine = function(__src, __rotArray, __dst){
(__src && __rotArray) || error(arguments.callee, IS_UNDEFINED_OR_NULL/* {line} */);
if(__src.type && __src.type === "CV_RGBA"){
var height = __src.row,
width = __src.col,
dst = __dst || new Mat(height, width, CV_RGBA),
sData = new Uint32Array(__src.buffer),
dData = new Uint32Array(dst.buffer);
var i, j, xs, ys, x, y, nowPix;
for(j = 0, nowPix = 0; j < height; j++){
xs = __rotArray[1] * j + __rotArray[2];
ys = __rotArray[4] * j + __rotArray[5];
for(i = 0; i < width; i++, nowPix++, xs += __rotArray[0], ys += __rotArray[3]){
if(xs > 0 && ys > 0 && xs < width && ys < height){
y = ys | 0;
x = xs | 0;
dData[nowPix] = sData[y * width + x];
}else{
dData[nowPix] = 4278190080; //Black
} 
} 
} 
}else{
error(arguments.callee, UNSPPORT_DATA_TYPE/* {line} */);
} 
return dst;
};

这个函数先把矩阵数据变成32位形式,操作每个元素就等同于操作每一个像素。

然后遍历所有元素,对对应的点进行赋值。

效果

 仿射变换概述

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章