图像处理 -- 仿射变换之Affine Transformation
仿射变换(Affine Transformation)
仿射变换是图像处理中的一种基本操作,通过线性变换和平移实现图像的几何变换。仿射变换包括旋转、缩放、平移、翻转、错切(shear)等操作。
1. 仿射变换的作用
- 旋转:将图像绕一个固定点(通常是图像中心)旋转一定角度。
- 缩放:对图像进行放大或缩小,改变图像的尺寸。
- 平移:将图像在平面上移动到指定位置。
- 翻转:沿特定轴将图像反转,比如水平或垂直翻转。
- 错切:将图像的某一个方向拉伸,使图像产生倾斜效果。
仿射变换在计算机视觉和图像处理中的应用非常广泛,比如在图像配准、目标检测、图像增强等领域中都可以看到仿射变换的身影。
2. 数学实现原理
仿射变换通过一个矩阵乘法和一个向量加法来实现。假设二维空间中的一个点的坐标为 ( x , y ) (x, y) (x,y),经过仿射变换后,该点的新坐标为 ( x ′ , y ′ ) (x', y') (x′,y′)。则有如下数学表达式:
( x ′ y ′ ) = ( a b c d ) ( x y ) + ( e f ) \begin{pmatrix} x' \\ y' \\ \end{pmatrix} = \begin{pmatrix} a & b \\ c & d \\ \end{pmatrix} \begin{pmatrix} x \\ y \\ \end{pmatrix} + \begin{pmatrix} e \\ f \\ \end{pmatrix} (x′y′)=(acbd)(xy)+(ef)
这里, ( a b c d ) \begin{pmatrix} a & b \\ c & d \end{pmatrix} (acbd) 是 2x2 仿射变换矩阵, ( e f ) \begin{pmatrix} e \\ f \end{pmatrix} (ef) 是平移向量。
具体仿射变换:
-
平移:
x ′ = x + e , y ′ = y + f x' = x + e, \quad y' = y + f x′=x+e,y′=y+f
其中, e e e 和 f f f 是平移量。 -
旋转:
x ′ = x ⋅ cos ( θ ) − y ⋅ sin ( θ ) , y ′ = x ⋅ sin ( θ ) + y ⋅ cos ( θ ) x' = x \cdot \cos(\theta) - y \cdot \sin(\theta), \quad y' = x \cdot \sin(\theta) + y \cdot \cos(\theta) x′=x⋅cos(θ)−y⋅sin(θ),y′=x⋅sin(θ)+y⋅cos(θ)
其中, θ \theta θ 是旋转角度。 -
缩放:
x ′ = x ⋅ s x , y ′ = y ⋅ s y x' = x \cdot s_x, \quad y' = y \cdot s_y x′=x⋅sx,y′=y⋅sy
其中, s x s_x sx 和 s y s_y sy 是在 x 轴和 y 轴上的缩放比例。 -
错切:
x ′ = x + λ y ⋅ y , y ′ = y + λ x ⋅ x x' = x + \lambda_y \cdot y, \quad y' = y + \lambda_x \cdot x x′=x+λy⋅y,y′=y+λx⋅x
其中, λ x \lambda_x λx 和 λ y \lambda_y λy 是在 x 轴和 y 轴上的错切系数。
3. 注意事项
-
矩阵可逆性:为了保证仿射变换能被逆变换,仿射变换矩阵 ( a b c d ) \begin{pmatrix} a & b \\ c & d \end{pmatrix} (acbd) 必须是非奇异的,即其行列式不为 0。这确保了变换后的图像可以通过逆变换恢复原状。
-
边界处理:仿射变换可能导致图像的一部分移出图像边界,或者图像空白区域增加。因此,通常需要对图像进行裁剪或填充处理。
-
插值方法:在仿射变换过程中,目标图像中的像素可能对应源图像中非整数坐标的点,因此需要使用插值方法(如最近邻插值、双线性插值或双三次插值)来计算这些点的像素值。
-
保持图像质量:频繁进行仿射变换可能导致图像质量下降,比如模糊、锯齿效应等。因此,在设计变换时需要考虑如何最小化质量损失。
-
变换顺序:如果需要执行多个变换,变换的顺序会影响最终结果。例如,旋转后再平移和先平移后旋转的结果是不一样的。因此,需要谨慎设计变换的顺序以达到预期效果。
C代码示例
#include <stdio.h>
#include <stdlib.h>
#include <math.h>#define IMAGE_WIDTH 1088
#define IMAGE_HEIGHT 1288
#define DEGREE_TO_RADIAN(deg) ((deg) * M_PI / 180.0)// 图像数据结构
typedef struct {int width;int height;unsigned char *data; // 指向图像像素数据的指针
} Image;// 从RAW8文件读取图像数据
Image *read_raw8_image(const char *filename, int width, int height) {FILE *file = fopen(filename, "rb");if (!file) {printf("无法打开文件 %s\n", filename);return NULL;}// 在堆上为图像数据分配内存unsigned char *data = (unsigned char *)malloc(width * height * sizeof(unsigned char));if (!data) {printf("内存分配失败\n");fclose(file);return NULL;}// 读取图像数据fread(data, sizeof(unsigned char), width * height, file);fclose(file);// 创建Image结构并返回Image *image = (Image *)malloc(sizeof(Image));image->width = width;image->height = height;image->data = data;return image;
}// 将图像数据写入RAW8文件
void write_raw8_image(const char *filename, Image *image) {FILE *file = fopen(filename, "wb");if (!file) {printf("无法打开文件 %s\n", filename);return;}// 写入图像数据fwrite(image->data, sizeof(unsigned char), image->width * image->height, file);fclose(file);
}
// 释放图像内存
void free_image(Image *image) {if (image) {if (image->data) {free(image->data);}free(image);}
}// 仿射变换函数:旋转图像
Image *affine_transform(Image *image, float angle) {int width = image->width;int height = image->height;// 角度转弧度float radians = DEGREE_TO_RADIAN(angle);float cos_theta = cos(radians);float sin_theta = sin(radians);// 中心点int center_x = width / 2;int center_y = height / 2;// 在堆上为旋转后的图像数据分配内存Image *rotated_image = (Image *)malloc(sizeof(Image));rotated_image->width = width;rotated_image->height = height;rotated_image->data = (unsigned char *)malloc(width * height * sizeof(unsigned char));// 初始化旋转后图像为0(黑色)for (int i = 0; i < width * height; i++) {rotated_image->data[i] = 0;}// 遍历原始图像的每一个像素for (int y = 0; y < height; y++) {for (int x = 0; x < width; x++) {// 计算相对于中心点的偏移int x_offset = x - center_x;int y_offset = y - center_y;// 进行仿射变换(旋转)int new_x = (int)(cos_theta * x_offset + sin_theta * y_offset) + center_x;int new_y = (int)(-sin_theta * x_offset + cos_theta * y_offset) + center_y;// 检查新坐标是否在图像范围内if (new_x >= 0 && new_x < width && new_y >= 0 && new_y < height) {rotated_image->data[new_y * width + new_x] = image->data[y * width + x];}}}return rotated_image;
}
int main() {// 读取RAW8图像Image *image = read_raw8_image("input.raw", IMAGE_WIDTH, IMAGE_HEIGHT);if (!image) {return 1;}// 对图像进行15度旋转Image *rotated_image = affine_transform(image, 15.0);// 保存旋转后的图像write_raw8_image("rotated_output.raw", rotated_image);// 释放内存free_image(image);free_image(rotated_image);return 0;
}
相关文章:
图像处理 -- 仿射变换之Affine Transformation
仿射变换(Affine Transformation) 仿射变换是图像处理中的一种基本操作,通过线性变换和平移实现图像的几何变换。仿射变换包括旋转、缩放、平移、翻转、错切(shear)等操作。 1. 仿射变换的作用 旋转:将图…...
Nuxt3【项目配置】nuxt.config.ts
按环境添加配置 export default defineNuxtConfig({// 生产环境的配置$production: {routeRules: {/**: { isr: true }}},// 开发环境的配置$development: {//} })运行时的配置 runtimeConfig export default defineNuxtConfig({runtimeConfig: {// 只在服务器端可用的私有键ap…...

中智讯“2024高校人工智能边缘应用项目实战师资培训班”圆满举办
7月24日——7月28日,中智讯“2024高校人工智能&边缘应用项目实战师资培训班”在昆明理工大学成功举办。本次培训由昆明理工大学人工智能产业学院主办,中智讯(武汉)科技有限公司承办。来自昆明理工大学、西南林业大学、云南民族…...

IIS发布打包后文件
1.打开IIS软件 2 添加网站, 自定义网站名称-选择要放置的资源路径-选择IP地址 3.打开放置的资源目录放置打包后文件 4.选择浏览 搜索不到IIS可进行一下操作 控制面板-程序和功能-启用或关闭windows功能-勾选IIS...

四个自定义 SHAP 图
超越 Python 包,创建 SHAP 值的定制可视化 SHAP 值是了解模型如何进行预测的绝佳工具。SHAP 包提供了许多可视化效果,使这个过程更加简单。话虽如此,我们不必完全依赖这个包。我们可以通过创建自己的 SHAP 图来进一步了解模型的工作原理。在本…...

为什么使用HTTPS?
HTTPS现在是所有Web活动的首选协议,因为它是用户保护敏感信息的最安全方式。 HTTPS不仅对请求用户信息的网站至关重要。除了用户直接发送的信息外,攻击者还可以从不安全的连接中跟踪行为和身份数据。 HTTP为网站所有者带来的好处除了数据安全之外&…...
软件设计-系统架构师(五十五)
1在网络规划中,政府内外网之间应该部署网络安全防护设备。在下图部署的设备A是(),对设备A作用描述错误的是()。 问题1 A IDS B 防火墙 C 网闸 D UTM 问题2 A 双主机系统,即使外网被黑客攻击…...
三分钟学会线缆电流估算
今天带你用三分钟的时间,学会电源线承受电流估算,不浪费时间,直接开始吧。 工作温度30℃,长期连续90%负载下的载流量 1.5平方毫米――14A 2.5平方毫米――26A 4平方毫米――32A 6平方毫米――47A 16平方毫米――92A 25平方毫米――120A 3…...

Snipaste 的一款替代工具 PixPin,支持 gif 截图、长截图和 OCR 文字识别,功能不是一点点强!
Snipaste 的一款替代工具 PixPin,支持 gif 截图、长截图和 OCR 文字识别,功能不是一点点强! PixPin 的名字来源于“Pixel Pin”,简单来说是一个截图、贴图的工具,但是 PixPin 以截图和贴图两大功能为核心做了大量的优…...
Oracle基础教程
体系结构 数据库 一个操作系统仅有一个数据库 实例 拥有一系列后台进程和存储结构,一个数据库可拥有一个或多个实例,一般只有1个实例 数据文件(.dbf/.ora) 数据文件是数据库的物理存储单元,一个表空间由一个或多…...

电脑如何录屏?三款电脑录屏工具分享
电脑如何录屏?作为一个经常需要录制电脑屏幕大职场人,不是为了制作教程、记录会议,就是偶尔想自己做个游戏解说视频。市面上的录屏软件琳琅满目,经过一番尝试和比较,我选出了三款我个人认为表现不错的软件,…...

idea2024建立maven web项目servlet 6.0
(1) 下载好tomcat 10.1.28 打开tomcat.apache.org官网下载 (2)配置好maven (3)idea 2024打开,建立项目 选择maven java项目 (4)在项目src/main/下 建立webapp/WEB-INF目录,在…...

游戏开放式新手引导框架设计
强制性引导:只能点某个按钮 优:程序简单 缺: 玩家体验差 开放式引导:不强制点 优:玩家体验好 缺: 程序复杂 需求分析: 1.开放式引导,引导是到达某个条件后进行一系列行为(…...

【Hot100】LeetCode—189. 轮转数组
目录 1- 思路自定义 reverse 翻转函数 2- 实现⭐189. 轮转数组——题解思路 3- ACM 实现 原题链接:189. 轮转数组 1- 思路 自定义 reverse 翻转函数 2- 实现 ⭐189. 轮转数组——题解思路 class Solution {public void rotate(int[] nums, int k) {k % nums.lengt…...

javaweb学习之HTML(一)
推荐学习使用网站 w3school 在线教程 认识HTML HTML(HyperText Markup Language)是超文本标记语言,它是一个用于创建网页和网页应用程序的标准标记语言。HTML文档由一系列的元素(elements)组成,这些元素通…...

项目实战:Qt+Opencv相机标定工具v1.3.0(支持打开摄像头、视频文件和网络地址,支持标定过程查看、删除和动态评价误差率,支持追加标定等等)
若该文为原创文章,转载请注明出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/141334834 长沙红胖子Qt(长沙创微智科)博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、Op…...

【数据结构】汇总八、排序算法
排序Sort 【注意】本章是 排序 的知识点汇总,全文1万多字,含有大量代码和图片,建议点赞收藏(doge.png)!! 【注意】在这一章,记录就是数据的意思。 排序可视化网站: D…...
Java-分割list并执行多线程任务的工具类
要创建一个用于分割列表并执行多线程任务的工具类,你可以使用 Java 的 ExecutorService 和 ThreadPoolExecutor 来实现。下面是一个详细的示例,展示了如何创建这样一个工具类。 步骤 1: 创建线程池 首先,创建一个线程池来执行任务。 步骤 2: 分割列表 接着,定义一个方…...
Springboot-从服务器获取一个输入流,转成视频文件存到oss
要在Spring Boot应用中从服务器获取一个输入流,然后将该流转换为视频文件并存储到阿里云 OSS中,你可以遵循以下步骤: 设置阿里云OSS客户端:首先,你需要配置阿里云OSS客户端,以便能够上传文件到OSS。 获取输入流:使用HTTP客户端(如RestTemplate或WebClient)从服务器…...

[Meachines] [Easy] Bastion SMB未授权访问+VHD虚拟硬盘挂载+注册表获取NTLM哈希+mRemoteNG远程管理工具权限提升
信息收集 IP AddressOpening Ports10.10.10.134TCP:22, 135, 139, 445, 5985, 47001, 49664, 49665, 49666, 49667, 49668, 49669, 49670 $ nmap -p- 10.10.10.134 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH fo…...

C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

DBLP数据库是什么?
DBLP(Digital Bibliography & Library Project)Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高,数据库文献更新速度很快,很好地反映了国际计算机科学学术研…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
前端高频面试题2:浏览器/计算机网络
本专栏相关链接 前端高频面试题1:HTML/CSS 前端高频面试题2:浏览器/计算机网络 前端高频面试题3:JavaScript 1.什么是强缓存、协商缓存? 强缓存: 当浏览器请求资源时,首先检查本地缓存是否命中。如果命…...

02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...