当前位置: 首页 > news >正文

7.1图像平移

目录

实验原理

示例代码1

运行结果1

示例代码2

运行结果2


实验原理

OpenCV中,图像平移是一种基本的几何变换,指的是将图像中的每一个像素点沿着水平方向或垂直方向移动一定的距离。图像平移不改变图像的大小和形状,只是改变了图像的位置。在计算机视觉和图像处理领域,平移操作可以用于数据增强、图像对齐等任务。

在OpenCV中,可以通过仿射变换(Affine Transformation)来实现图像的平移。

图像平移的原理图像平移实际上是一种特殊的仿射变换,其中不涉及旋转或缩放,只是简单地将图像沿水平或垂直方向移动一段固定的距离。

仿射变换的应用仿射变换可以用于多种几何变换,

例如:

•平移:只需要修改矩阵中的tx和ty值即可。

•旋转:需要构造一个包含旋转角度的矩阵。

•缩放:通过调整矩阵中的a和d值来控制水平和垂直方向的缩放比例。

•倾斜:通过调整矩阵中的b和c值来控制剪切(shear)效果。

要使用OpenCV进行图像平移,可以通过以下步骤实现:

1.定义平移矩阵: 

2.应用平移变换

使用 cv::warpAffine 函数可以应用这个变换到图像上。首先需要创建一个与上述形式一致的平移矩阵,然后使用该函数完成平移操作。

cv::warpAffine 是 OpenCV 库中用于执行仿射变换的一个函数,它可以实现图像的旋转、缩放、剪切以及平移等操作。其函数原型如下:

void warpAffine(InputArray src,            // 输入图像OutputArray dst,           // 输出图像InputArray M,              // 2x3 的变换矩阵  仿射变换矩阵Size dsize,                // 输出图像的大小int flags = INTER_LINEAR,  // 插值方法,默认为双线性插值int borderMode = BORDER_CONSTANT, // 边界模式const Scalar& borderValue = Scalar() // 边界填充值
);函数参数说明:
•src:输入图像,可以是任何类型的单通道或多通道图像。
•dst:输出图像,与输入图像具有相同的类型,大小由dsize参数指定。
•M:仿射变换矩阵,通常是一个2x3的浮点矩阵。这个矩阵包含仿射变换所需的六个参数。
•dsize:输出图像的大小。可以指定为Size(width, height)形式或者使用 src.size() 保持与源图像相同的大小。
•flags:插值方法,默认为INTER_LINEAR(双线性插值)。其他可选的插值方法包括: •INTER_NEAREST:最近邻插值。•INTER_LINEAR:双线性插值。•INTER_CUBIC:三次样条插值。•INTER_LANCZOS4:兰茨科斯插值。
•borderMode:边界处理模式,默认为BORDER_CONSTANT(用常数值填充边界)。其他可选的边界处理模式包括: •BORDER_CONSTANT:用常数值填充边界。•BORDER_REPLICATE:边界像素值向外复制。•BORDER_REFLECT:边界像素值向内反射。反射边界,如12345反射为45454。•BORDER_WRAP:边界像素值循环。循环边界,如12345循环为34512。•borderValue:边界填充值,默认为黑色(全零向量)。只有在borderMode为BORDER_CONSTANT时有效。

总结

图像平移是通过仿射变换来实现的,它涉及到将图像中的每一个像素按照一定的方向和距离移动到新的位置。在OpenCV中,可以通过构建一个2x3的仿射变换矩阵,并使用cv::warpAffine函数来实现图像的平移。通过调整平移参数tx和ty,可以控制图像在水平方向和垂直方向的平移量。此外,还可以通过指定不同的边界处理方式来处理平移后超出原图像范围的情况。

示例代码1

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <iostream>int main(int argc, char** argv)
{// 加载图像cv::Mat img = cv::imread("B3.png");if (img.empty()){std::cout << "Error: Image not found." << std::endl;return -1;}// 定义平移的距离int tx = 30; // 沿x轴平移30个像素int ty = -70; // 沿y轴平移-70个像素(向上)// 创建平移矩阵cv::Mat translationMatrix = (cv::Mat_<double>(2, 3) <<1, 0, tx,0, 1, ty);// 应用平移变换cv::Mat translatedImg;cv::warpAffine(img, translatedImg, translationMatrix, img.size());// 显示原图和翻译后的图像cv::namedWindow("Original Image", cv::WINDOW_NORMAL);cv::imshow("Original Image", img);cv::namedWindow("Translated Image", cv::WINDOW_NORMAL);cv::imshow("Translated Image", translatedImg);cv::waitKey(0);return 0;
}在这个例子中,我们加载了一张图片,
并定义了一个平移矩阵 translationMatrix。
接着我们使用 cv::warpAffine 函数,
输入原始图像、平移矩阵以及输出图像的尺寸(在这里我们保持了原始图像的大小)。
最后,我们显示原图和平移后的图像,并等待用户按键退出。

运行结果1

示例代码2

// test.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include "pch.h"
#include <iostream>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>//#pragma comment(lib, "opencv_world450d.lib")  //引用引入库 //平移操作,图像大小不变
cv::Mat imageTranslation1(cv::Mat & srcImage, int x0ffset, int y0ffset)
{int nRows = srcImage.rows;int nCols = srcImage.cols;cv::Mat resultImage(srcImage.size(), srcImage.type());//遍历图像for (int i = 0; i < nRows; i++){for (int j = 0; j < nCols; j++){int x = j - x0ffset;int y = i - y0ffset;//边界判断if (x >= 0 && y >= 0 && x < nCols && y < nRows){resultImage.at<cv::Vec3b>(i, j) = srcImage.ptr<cv::Vec3b>(y)[x]; }}}return resultImage;
}
//平移操作,图形大小改变
cv::Mat imageTranslation2(cv::Mat & srcImage, int x0ffset, int y0ffset)
{//设置平移尺寸int nRows = srcImage.rows + abs(y0ffset);int nCols = srcImage.cols + abs(x0ffset);cv::Mat resultImage(nRows, nCols, srcImage.type());//图像遍历for (int i = 0; i < nRows; i++){for (int j = 0; j < nCols; j++){int x = j - x0ffset;int y = i - y0ffset;//边界判断if (x >= 0 && y >= 0 && x < nCols && y < nRows){resultImage.at<cv::Vec3b>(i, j) = srcImage.ptr<cv::Vec3b>(y)[x]; }}}return resultImage;
}int main()
{//读取图像cv::Mat srcImage = cv::imread("02.jpeg");if (srcImage.empty()){return -1;}//显示原图像cv::namedWindow("原图", CV_WINDOW_NORMAL);cv::imshow("原图", srcImage);int x0ffset = 50;int y0ffset = 80;cv::Mat resultImage1 = imageTranslation1(srcImage, x0ffset, y0ffset);cv::namedWindow("移动1", CV_WINDOW_NORMAL);cv::imshow("移动1", resultImage1);cv::Mat resultImage2 = imageTranslation2(srcImage, x0ffset, y0ffset);cv::namedWindow("移动3", CV_WINDOW_NORMAL);cv::imshow("移动3", resultImage1);x0ffset = -50;y0ffset = -80;cv::Mat resultImage3 = imageTranslation1(srcImage, x0ffset, y0ffset);cv::namedWindow("移动2", CV_WINDOW_NORMAL);cv::imshow("移动2", resultImage3);cv::waitKey(0);return 0;
}

运行结果2

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 安科瑞Acrel-1000DP分布式光伏监控系统平台的设计与应用-安科瑞 蒋静
  • 哈希表、算法
  • jupyter notebook详细介绍-学习篇
  • 网络编程(UDP)
  • 云原生周刊:OpenTofu Registry 获得用户界面和 API|2024.9.9
  • 【C语言】揭开计数制的面纱:深入浅出二进制及二进制计算
  • JavaEE 第23节 TCP的流量控制与阻塞控制详解
  • 芝法酱学习笔记(0.1)——Ubuntu下,Java开发环境的基本搭建
  • 解锁Python中的人脸识别:Face Recognition库详解与应用
  • jmeter基准测试详解
  • Unity TextMeshPro 设置竖排
  • 常见概念 -- 光回波损耗
  • 快速入门游戏领域,开发游戏需要哪些技术?
  • 数理金融工程毕业之后求职应用方向,量化交易方面如何
  • 深度学习中的常用线性代数知识汇总——第一篇:基础概念、秩、奇异值
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • co.js - 让异步代码同步化
  • ComponentOne 2017 V2版本正式发布
  • Fastjson的基本使用方法大全
  • HashMap剖析之内部结构
  • HomeBrew常规使用教程
  • java2019面试题北京
  • JS数组方法汇总
  • Mybatis初体验
  • ReactNative开发常用的三方模块
  • Unix命令
  • vue 配置sass、scss全局变量
  • 从伪并行的 Python 多线程说起
  • 翻译--Thinking in React
  • 给github项目添加CI badge
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 诡异!React stopPropagation失灵
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 深度学习中的信息论知识详解
  • 使用 Docker 部署 Spring Boot项目
  • 使用parted解决大于2T的磁盘分区
  • 手写双向链表LinkedList的几个常用功能
  • 一个项目push到多个远程Git仓库
  • 一文看透浏览器架构
  • 阿里云IoT边缘计算助力企业零改造实现远程运维 ...
  • 如何在 Intellij IDEA 更高效地将应用部署到容器服务 Kubernetes ...
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • # wps必须要登录激活才能使用吗?
  • #前后端分离# 头条发布系统
  • $$$$GB2312-80区位编码表$$$$
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (pycharm)安装python库函数Matplotlib步骤
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (附源码)ssm教材管理系统 毕业设计 011229
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (全注解开发)学习Spring-MVC的第三天