OpenCV图像旋转原理及示例

news2025/7/11 1:00:33

OpenCV计算机视觉开发实践:基于Qt C++ - 商品搜索 - 京东

图像旋转是数字图像处理的一个非常重要的环节,是图像的几何变换手法之一。图像旋转算法是图像处理的基础算法。在数字图像处理过程中,经常要用到旋转,例如在进行图像扫描时,需要运用旋转实现图像的倾斜校正;在进行多幅图像的比较、模式识别及对图像进行剪裁和拼接前,都需要进行图像的旋转处理。

图像旋转是指图像以某一点为中心旋转一定的角度,形成一幅新的图像的过程。图像旋转通常可以分为两种情况,一种是以坐标原点为中心进行旋转;另外一种是以任意图形中的某点为坐标原点进行旋转。图像的旋转变换是图像的位置变换,旋转后图像的大小一般会改变。在图像旋转变换中,既可以把转出显示区域的图像截去,也可以扩大图像范围以显示所有的图像。

1. 以坐标原点为中心进行旋转的原理

P0绕坐标原点逆时针旋转θ角度得到点P1,如图7-2所示。

图7-2

2. 以任意图形中的某点为坐标原点进行旋转的原理

以任意图形中的某点为坐标原点进行旋转的原理如图7-3所示。

图7-3

由图7-3可以看出,以任意图形中心点为坐标原点进行旋转需要如下3步:

   将坐标系Ⅰ变成坐标系Ⅱ。

由Figure1得到Figure2可知,变换矩阵为:

   在坐标系Ⅱ中旋转θ角度。参考以坐标原点为中心进行旋转的原理。

   将坐标系Ⅱ变成坐标系Ⅰ。

由图7-3中的Figure3得到Figure4可知,变换矩阵为(其实就是步骤01中变换矩阵的逆变换):

在OpenCV中,图像旋转首先根据旋转角度和旋转中心获取旋转矩阵,然后根据旋转矩阵进行变换,即可实现任意角度和任意中心的旋转效果。

下面我们实现图像旋转算法,有两种方式:一种是根据算法手动实现,另一种是根据OpenCV提供的现成函数自动实现。现在先来介绍根据算法手动实现的方式。

【例7.2】手动实现图像旋转

   打开Qt Creator,新建一个控制台工程,工程名是test。

   在工程中打开main.cpp,输入如下代码:

#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>
#include <cmath>

using namespace cv;
Mat imgRotate(Mat matSrc, float angle, bool direction)
{
    float theta = angle * CV_PI / 180.0;
    const int nRowsSrc = matSrc.rows;
    const int nColsSrc = matSrc.cols;
    // 如果是顺时针旋转
    if (!direction)
        theta = 2 * CV_PI - theta;
    // 全部以逆时针旋转来计算
    // 逆时针旋转矩阵
    float matRotate[3][3]{
        {std::cos(theta), -std::sin(theta), 0},
        {std::sin(theta), std::cos(theta), 0 },
        {0, 0, 1}
    };
    float pt[3][2]{		{ 0, (float)nRowsSrc},		{(float)nColsSrc, (float)nRowsSrc},		{(float)nColsSrc, 0}
    };
    for (int i = 0; i < 3; i++)
    {
        float x = pt[i][0] * matRotate[0][0] + pt[i][1] * matRotate[1][0];
        float y = pt[i][0] * matRotate[0][1] + pt[i][1] * matRotate[1][1];
        pt[i][0] = x;
        pt[i][1] = y;
    }
    // 计算出旋转后图像的极值点和尺寸
    float fMin_x = min(min(min(pt[0][0], pt[1][0]), pt[2][0]), (float)0.0);
    float fMin_y = min(min(min(pt[0][1], pt[1][1]), pt[2][1]), (float)0.0);
    float fMax_x = max(max(max(pt[0][0], pt[1][0]), pt[2][0]), (float)0.0);
    float fMax_y = max(max(max(pt[0][1], pt[1][1]), pt[2][1]), (float)0.0);
    int nRows = cvRound(fMax_y - fMin_y + 0.5) + 1;
    int nCols = cvRound(fMax_x - fMin_x + 0.5) + 1;
    int nMin_x = cvRound(fMin_x + 0.5);
    int nMin_y = cvRound(fMin_y + 0.5);
    // 拷贝输出图像
    Mat matRet(nRows, nCols, matSrc.type(), Scalar(0));
    for (int j = 0; j < nRows; j++)
    {
        for (int i = 0; i < nCols; i++)
        {
            // 计算出输出图像在原图像中对应点的坐标,然后复制该坐标的灰度值
            // 因为是逆时针转换,所以这里映射到原图像时可以看作输出图像顺时针旋转到原图像
            // 而顺时针旋转矩阵刚好是逆时针旋转矩阵的转置
            // 同时还要考虑把旋转后的图像的左上角移动到坐标原点
            int x = (i + nMin_x) * matRotate[0][0] + (j + nMin_y) * matRotate[0][1];
            int y = (i + nMin_x) * matRotate[1][0] + (j + nMin_y) * matRotate[1][1];
            if (x >= 0 && x < nColsSrc && y >= 0 && y < nRowsSrc)
            {
                matRet.at<Vec3b>(j, i) = matSrc.at<Vec3b>(y, x);
            }
        }
    }
    return matRet;
}
 int main()
 {
    Mat matSrc = imread("cat.png");
    if (matSrc.empty())
        return 1;
    float angle = 30;
    Mat matRet = imgRotate(matSrc, angle, true);
    imshow("src", matSrc);
    imshow("rotate", matRet);
    // 保存图像
    imwrite("rotate_panda.jpg", matRet);

    waitKey();
    return 0;
 }

以上代码完全是根据前面的算法原理公式来实现的。图像旋转是指图像按照某个位置转动一定角度的过程,旋转中图像仍保持原始尺寸。图像旋转后,图像的水平对称轴、垂直对称轴及中心坐标原点都可能发生变换,因此需要对图像旋转中的坐标进行相应转换。

   保存工程并运行,结果如图7-4所示。

如果不想通过算法公式手动实现图像旋转,也可以利用OpenCV提供的库函数getRotationMatrix2D来实现图像旋转。该函数用来计算旋转矩阵,其声明如下:

Mat getRotationMatrix2D(Point2f center, double angle, double scale);

其中参数center表示旋转的中心点;angle表示旋转的角度;scale表示图像缩放因子。该函数的返回值为一个2×3的矩阵,其中矩阵前两列代表旋转,最后一列代表平移。

​​​​​​​图7-4

计算出旋转矩阵后,还需要把旋转应用到仿射变换的输出,仿射变换函数是warpAffine,该函数在下一节介绍。

【例7.3】使用函数实现图像的旋转

   打开Qt Creator,新建一个控制台工程,工程名是test。

   在工程中打开main.cpp,输入如下代码:

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;

// 图像旋转,angle表示要旋转的角度
void Rotate(const Mat &srcImage, Mat &destImage, double angle)
{
	Point2f center(srcImage.cols / 2, srcImage.rows / 2);// 中心
	Mat M = getRotationMatrix2D(center, angle, 1);// 计算旋转的仿射变换矩阵 
	// 现在把旋转应用到仿射变换的输出
	warpAffine(srcImage, destImage, M, Size(srcImage.cols, srcImage.rows));
	// 仿射变换  
	circle(destImage, center, 2, Scalar(255, 0, 0));
}

int main()
{
	// 读入图像,并判断图像是否读入正确
	cv::Mat srcImage = imread("lena.png");
	if (!srcImage.data)
	{
		puts("Fail to open file.");
		return -1;
	}
	imshow("srcImage", srcImage); // 原图像也绘制出来以作参照
	
	Mat destImage;
	double angle = 9.9;// 角度
	Rotate(srcImage, destImage, angle);
	// 最后把仿射变换和旋转的结果绘制在窗体中
	imshow("dst", destImage);
	waitKey(0);
	return 0;
}

保存工程并运行,结果如图7-5所示。

​​​​​​​图7-5

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【实战篇】数字化打印——打印部署管理接口开发

前言 前面的章节已经介绍了打印管理模块的主要界面设计&#xff0c;本篇介绍用myBuilder开发界面接口&#xff0c;实现最终的功能。 1. 配置打印应用菜单 首先配置挂载好模块菜单 让菜单点击能访问到对应的页面 2. 打印部署管理数据表详细设计 以下是打印部署管理的数据表字…

MacOS Python3安装

python一般在Mac上会自带&#xff0c;但是大多都是python2。 python2和python3并不存在上下版本兼容的情况&#xff0c;所以python2和python3可以同时安装在一台设备上&#xff0c;并且python3的一些语法和python2并不互通。 所以在Mac电脑上即使有自带python&#xff0c;想要使…

idea启动报错:java: 警告: 源发行版 11 需要目标发行版 11(亲测解决)

引起原因 idea的jdk没有替换干净 1.配置project file–Project Structrue–Project 2.配置Modules-Sources file–Project Structrue–Modules-Sources 改为jdk11 3.配置Modules-Dependencies file–Project Structrue–Modules-Dependencies

《Adversarial Sticker: A Stealthy Attack Method in the Physical World》论文分享(侵删)

原文链接&#xff1a;Adversarial Sticker: A Stealthy Attack Method in the Physical World | IEEE Journals & Magazine | IEEE Xplore author{Xingxing Wei and Ying Guo and Jie Yu} 摘要 为了评估深度学习在物理世界中的脆弱性&#xff0c;最近的工作引入了对抗补丁…

嵌入式STM32学习——继电器

继电器模块引脚说明 VCC&#xff08;&#xff09;&#xff1a; 供电正极。连接此引脚到电源&#xff08;通常是直流电源&#xff09;&#xff0c;以提供继电器线圈所需的电流。 GND&#xff08;-&#xff09;&#xff1a; 地。连接此引脚到电源的负极或地。 IN&#xff08;或…

从基础到实习项目:C++后端开发学习指南

在当今技术快速迭代的背景下&#xff0c;后端开发作为软件工程的核心支柱持续发挥着关键作用。C凭借其卓越的性能表现和系统级控制能力&#xff0c;依然是构建高性能后端服务的首选语言之一。本文将系统性地解析现代C后端开发的核心技术体系&#xff0c;包括从语言特性精要到架…

Xinference推理框架

概述 GitHub&#xff0c;官方文档。 核心优势 性能优化&#xff1a;通过vLLM、SGLang等引擎实现低延迟推理&#xff0c;吞吐量提升2-3倍&#xff1b;企业级支持&#xff1a;支持分布式部署、国产硬件适配及模型全生命周期管理&#xff1b;生态兼容&#xff1a;无缝对接LangC…

前端ECS简介

ECS概念 ECS是一种软件架构模式&#xff0c;常见于游戏业务场景&#xff0c;其主要对象分类为 • Entity 实体,ECS架构中所有的业务对象都必须拥有一个唯一的Entity实体 • Component 组件,存储着数据结构,对应着某一种业务属性,一个Entity上可以动态挂载多个Component • …

Dify与n8n全面对比指南:AI应用开发与工作流自动化平台选择【2025最新】

Dify与n8n全面对比指南&#xff1a;AI应用开发与工作流自动化平台选择【2025最新】 随着AI技术与自动化工具的迅速发展&#xff0c;开发者和企业面临着多种平台选择。Dify和n8n作为两个备受关注的自动化平台&#xff0c;分别专注于不同领域&#xff1a;Dify主要面向AI应用开发&…

【深度学习之四】知识蒸馏综述提炼

知识蒸馏综述提炼 目录 知识蒸馏综述提炼 前言 参考文献 一、什么是知识蒸馏&#xff1f; 二、为什么要知识蒸馏&#xff1f; 三、一点点理论 四、知识蒸馏代码 总结 前言 知识蒸馏作为一种新兴的、通用的模型压缩和迁移学习架构&#xff0c;在最近几年展现出蓬勃的活力…

redis解决常见的秒杀问题

title: redis解决常见的秒杀问题 date: 2025-03-07 14:24:13 tags: redis categories: redis的应用 秒杀问题 每个店铺都可以发布优惠券&#xff0c;保存到 tb_voucher 表中&#xff1b;当用户抢购时&#xff0c;生成订单并保存到 tb_voucher_order 表中。 订单表如果使用数据…

TypeScript中文文档

最近一直想学习TypeScript&#xff0c;一直找不到一个全面的完整的TypeScript 中文文档。在网直上找了了久&#xff0c;终于找到一个全面的中文的typescript中文学习站&#xff0c;有学习ts的朋友可以年。 文档地址&#xff1a;https://typescript.uihtm.com 该TypeScript 官…

Function Calling

在介绍Function Calling之前我们先了解一个概念,接口。 接口 两种常见接口: 人机交互接口,User Interface,简称 UI应用程序编程接口,Application Programming Interface,简称 API接口能「通」的关键,是两边都要遵守约定。 人要按照 UI 的设计来操作。UI 的设计要符合人…

面试--HTML

1.src和href的区别 总结来说&#xff1a; <font style"color:rgb(238, 39, 70);background-color:rgb(249, 241, 219);">src</font>用于替换当前元素&#xff0c;指向的资源会嵌入到文档中&#xff0c;例如脚本、图像、框架等。<font style"co…

SparkSQL操作Mysql-准备mysql环境

我们计划在hadoop001这台设备上安装mysql服务器&#xff0c;&#xff08;当然也可以重新使用一台全新的虚拟机&#xff09;。 以下是具体步骤&#xff1a; 使用finalshell连接hadoop001.查看是否已安装MySQL。命令是: rpm -qa|grep mariadb若已安装&#xff0c;需要先做卸载MyS…

DeepBook 与 CEX 的不同

如果你曾经使用过像币安或 Coinbase 这样的中心化交易所&#xff08;CEX&#xff09;&#xff0c;你可能已经熟悉了订单簿系统 — — 这是一种撮合买卖双方进行交易的机制。而 DeepBook 是 Sui 上首个完全链上的中央限价订单簿。 那么&#xff0c;是什么让 DeepBook 如此独特&…

Scrapy框架下地图爬虫的进度监控与优化策略

1. 引言 在互联网数据采集领域&#xff0c;地图数据爬取是一项常见但具有挑战性的任务。由于地图数据通常具有复杂的结构&#xff08;如POI点、路径信息、动态加载等&#xff09;&#xff0c;使用传统的爬虫技术可能会遇到效率低下、反爬策略限制、任务进度难以监控等问题。 …

城市扫街人文街头纪实胶片电影感Lr调色预设,DNG/手机适配滤镜!

调色详情 城市扫街人文街头纪实胶片电影感 Lr 调色是通过 Lightroom&#xff08;Lr&#xff09;软件&#xff0c;对城市街头抓拍的人文纪实照片进行后期调色处理。旨在赋予照片如同胶片拍摄的质感以及电影般浓厚的叙事氛围&#xff0c;不放过每一个日常又珍贵的瞬间&#xff0c…

让AI帮我写一个word转pdf的工具

需求分析 前几天&#xff0c;一个美女找我&#xff1a; 阿瑞啊&#xff0c;能不能帮我写个工具&#xff0c;我想把word文件转为pdf格式的 我说&#xff1a;“你直接网上搜啊&#xff0c;网上工具多了去了” 美女说&#xff1a; 网上的要么是需要登录注册会员的&#xff0c;要…

OrangePi Zero 3学习笔记(Android篇)10 - SPI和从设备

目录 1. 配置内核 2. 修改设备数 3. 修改权限 4. 验证 Zero 3的板子有2个SPI Master接口&#xff0c;其中SPI0接的是板载16MB大小的SPI Nor Flash&#xff0c;SPI1则是导出到26pin的接口上。 spi和i2c有点不同&#xff0c;spi是直接生成spi虚拟设备&#xff0c;所以在dev里…