使用c++程序,实现图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转

数字图像处理–实验三A图像的基本变换

实验内容

A实验:
(1)使用VC++设计程序:实现图像平移变换,图像缩放、图像裁剪、图像对角线镜像。
(2)使用VC++设计程序:对一幅高度与宽度均相等的图像,实现逆时针90度旋转。—这个直接使用B实验的代码也可以完成(B–任意大小图片旋转任意角度)

一、图像平移变换

1. 实验原理

图像的平移:通过直角坐标系的平移变换公式:
x’ = x +dx
y’ = y + dy

注:
(x,y)为源图像的坐标,(x’, y’)为新图像的坐标,dx对应x的偏移量,dy对应y的偏移量。即:平移之后新图像上坐标为(x’, y’)的像素点的颜色值,应该等于原图像上坐标为(x, y)的像素点的颜色值。

2. 实验代码

void CImageProcessingView::OnGeoTranslation()
{// 实验 图像平移//MessageBox("请在这里添加图像平移的代码");// 获得当前文档对象CImageProcessingDoc* pDoc = GetDocument();// 判断图像是否已被加载if( pDoc->m_pDibInit->IsEmpty() ){MessageBox("图像未加载");return;}int width = pDoc->m_pDibInit->GetWidth();int height = pDoc->m_pDibInit->GetHeight();int bitCount = pDoc->m_pDibInit->GetBitCount();// 将 m_pDibInit 拷贝至 m_pDibTestpDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);// 设置 pDoc->m_pDibTest 为全白图像int i, j;RGBQUAD rgbQuad1;rgbQuad1.rgbBlue = 255;rgbQuad1.rgbGreen = 255;rgbQuad1.rgbRed = 255;rgbQuad1.rgbReserved = 0;for(i=0; i<width; i++){for(j=0; j<height; j++){pDoc->m_pDibTest->SetPixelColor(i,j,&rgbQuad1);}}//************************图像平移****************************//RGBQUAD Quad;//新的像素点float  translatepixel = 2 ;int newwidth=width*translatepixel;//移动后的新的画布的大小int newheight=height*translatepixel;pDoc->m_pDibTest->SetWidthHeight(newwidth,newheight);//重设画布大小//将像素点的值进行移动for(i=0;i<width;i++)for(j=0;j<height;j++){Quad =pDoc->m_pDibInit->GetPixelColor(i,j);//获取原图像的像素点的值pDoc->m_pDibTest->SetPixelColor(i+256,j,&Quad);}
//*********************************************************************// // 交换 m_pDibInit 与 m_pDibTest 指针CDib* pTmp = pDoc->m_pDibInit;pDoc->m_pDibInit = pDoc->m_pDibTest;pDoc->m_pDibTest = pTmp;// 设置脏标记pDoc->SetModifiedFlag(TRUE);// 更新视图pDoc->UpdateAllViews(NULL);
}

实现现象

将图片右移了256个像素点
在这里插入图片描述

二、图像缩放

1. 缩放原理

设原图像大小为宽度M、高度N,调整后宽度为k1×M、高度为k2×N,则:
Img.New(x,y) = Img.Old(x/k1, y/k2)
这样就可以实现图像的缩放

2. 实验代码

void CImageProcessingView::OnGeoResizing()
{// 实验 图像缩放//MessageBox("请在这里添加图像缩放的代码");// 获得当前文档对象CImageProcessingDoc* pDoc = GetDocument();// 判断图像是否已被加载if( pDoc->m_pDibInit->IsEmpty() ){MessageBox("图像未加载");return;}int width = pDoc->m_pDibInit->GetWidth();int height = pDoc->m_pDibInit->GetHeight();int bitCount = pDoc->m_pDibInit->GetBitCount();// 将 m_pDibInit 拷贝至 m_pDibTestpDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);// 考虑将图像放大两倍的情况 float nResizing = 0.6;//大于1则为放大,小于1则为缩小// 获得新的图像高度int newWidth = width*nResizing;int newHeight = height*nResizing;pDoc->m_pDibTest->SetWidthHeight(newWidth, newHeight);//***************************图像的放大与缩小***********////间隔采样int i=0;int j=0;RGBQUAD Quad1;for(i=0;i<newWidth;i++)for(j=0;j<newHeight;j++){Quad1=pDoc->m_pDibInit->GetPixelColor(i/nResizing,j/nResizing);pDoc->m_pDibTest->SetPixelColor(i,j,&Quad1);}// 交换 m_pDibInit 与 m_pDibTest 指针CDib* pTmp = pDoc->m_pDibInit;pDoc->m_pDibInit = pDoc->m_pDibTest;pDoc->m_pDibTest = pTmp; // 设置脏标记pDoc->SetModifiedFlag(TRUE);// 更新视图pDoc->UpdateAllViews(NULL);
}

实验现象

将图片变为原来的0.6倍
在这里插入图片描述

三、图像裁剪

裁剪原理

图像裁剪是从原始图像中选择或提取感兴趣的区域,以产生新的图像。这个过程可以通过调整图像的像素坐标来实现。以下是图像裁剪的基本原理:

  1. 选择裁剪区域: 首先,确定你希望保留的图像区域。这可以通过指定裁剪区域的坐标、宽度和高度来完成。裁剪区域通常以左上角和右下角的坐标、宽度和高度来定义。

  2. 调整坐标: 对于裁剪区域内的每个像素,调整其坐标以匹配裁剪后的图像。如果裁剪区域的左上角坐标是 ( x start , y start ) (x_{\text{start}}, y_{\text{start}}) (xstart,ystart),那么裁剪后的图像中的像素 ( i , j ) (i, j) (i,j)的新坐标是 ( i − x start , j − y start ) (i-x_{\text{start}}, j - y_{\text{start}}) (ixstart,jystart)

  3. 创建新图像: 使用裁剪后的坐标,从原始图像中提取像素值,并将它们组合成新的图像。新图像的宽度和高度将是裁剪区域的宽度和高度。

实验代码c++

void CImageProcessingView::OnGeoCut()
{// 实验 图像裁剪// 获得当前文档对象CImageProcessingDoc* pDoc = GetDocument();// 判断图像是否已被加载if( pDoc->m_pDibInit->IsEmpty() ){MessageBox("图像未加载");return;}// 将 m_pDibInit 拷贝至 m_pDibTestpDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);// 设置裁剪的起始坐标点int x1 = pDoc->m_pDibInit->m_lpBMIH->biWidth/4;int y1 = pDoc->m_pDibInit->m_lpBMIH->biHeight/3;// 设置裁剪的宽度与高度int cx = pDoc->m_pDibInit->m_lpBMIH->biWidth/2;int cy = pDoc->m_pDibInit->m_lpBMIH->biHeight/3;// 将 m_pDibTest 的宽度与高度 按照裁剪的要求进行设置pDoc->m_pDibTest->SetWidthHeight(cx, cy);// 复制像素点int i,j;RGBQUAD rgbQuad;for(i=0; i<cx; i++)for(j=0; j<cy; j++){rgbQuad = pDoc->m_pDibInit->GetPixelColor(i+x1, j+y1);pDoc->m_pDibTest->SetPixelColor(i, j, &rgbQuad);}// 交换 m_pDibInit 与 m_pDibTest 指针CDib* pTmp = pDoc->m_pDibInit;pDoc->m_pDibInit = pDoc->m_pDibTest;pDoc->m_pDibTest = pTmp; // 设置脏标记pDoc->SetModifiedFlag(TRUE);// 更新视图pDoc->UpdateAllViews(NULL);
}

实验现象

裁剪出中间的一部分:
在这里插入图片描述

四、图像对角线镜像

对角线原理

图像的对角镜像是指通过图像的对角线进行翻转,从而得到镜像效果。具体来说,对角镜像的原理是将图像中的每个像素与其对角位置上的像素进行交换。

对于一个二维图像,坐标为 ( i , j ) (i, j) (i,j) 的像素与坐标为 ( j , i ) (j, i) (j,i) 的像素进行交换。这个操作实际上是关于对角线翻转。如果图像的宽度和高度相等,对角镜像就是将图像沿着其主对角线翻转。

以下是一个简单的示例说明对角镜像的原理:

假设有一个3x3的图像:

1 2 3
4 5 6
7 8 9

对角线上的元素是 (1, 5, 9),将它们与对应的对角位置上的元素进行交换:

1 4 7
2 5 8
3 6 9

这就是对角线翻转后的图像。对于更大的图像,同样的原理适用。

在计算机图像处理中,对角线镜像通常涉及到图像的像素交换或者矩阵操作。这可以通过遍历图像的每个像素并进行交换操作来实现。

实验代码

void CImageProcessingView::OnDiagonalMirror()
{ // 实验 对角线镜像显示图像//MessageBox("请在这里添加图像对角线镜像的代码");// 可以参考:CImageProcessingView::OnGeoVerticalMirror()// 获得当前文档对象CImageProcessingDoc* pDoc = GetDocument();// 判断图像是否已被加载if( pDoc->m_pDibInit->IsEmpty() ){MessageBox("图像未加载");return;}int width = pDoc->m_pDibInit->GetWidth();int height = pDoc->m_pDibInit->GetHeight();int bitCount = pDoc->m_pDibInit->GetBitCount();if( width!=height ){MessageBox("图像长度与宽度不一致");return;}// 将 m_pDibInit 拷贝至 m_pDibTestpDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);
//*************************图像的对角镜像******************//int i,j;RGBQUAD quad;for(i=0;i<width;i++)for(j=0;j<height;j++){quad = pDoc->m_pDibInit->GetPixelColor(i, j);pDoc->m_pDibTest->SetPixelColor(j, i, &quad);  //将横竖坐标对换即可}// 交换 m_pDibInit 与 m_pDibTest 指针CDib* pTmp = pDoc->m_pDibInit;pDoc->m_pDibInit = pDoc->m_pDibTest;pDoc->m_pDibTest = pTmp; // 设置脏标记pDoc->SetModifiedFlag(TRUE);// 更新视图pDoc->UpdateAllViews(NULL);
}

实验现象

在这里插入图片描述

五、 任意大小图片旋转任意角度

原先的实验要求是实现宽和高相等的图片的旋转,但是后来B实验的要求是任意角度,就改写了代码,升级了一下

旋转原理

图像的旋转是通过应用旋转矩阵来实现的。旋转矩阵对应于二维平面上的坐标变换,其中旋转角度 (\theta) 决定了变换的角度。对于给定的坐标 ((X, Y)),应用旋转矩阵可以得到旋转后的坐标 ((X’, Y’))。

旋转矩阵如下所示:

[ X ′ Y ′ ] = [ cos ⁡ ( θ ) − sin ⁡ ( θ ) sin ⁡ ( θ ) cos ⁡ ( θ ) ] [ X Y ] \begin{bmatrix}X' \\Y'\end{bmatrix}=\begin{bmatrix}\cos(\theta) & -\sin(\theta) \\\sin(\theta) & \cos(\theta)\end{bmatrix}\begin{bmatrix}X \\Y\end{bmatrix} [XY]=[cos(θ)sin(θ)sin(θ)cos(θ)][XY]

对应的坐标变换公式是:

X ′ = X ⋅ cos ⁡ ( θ ) − Y ⋅ sin ⁡ ( θ ) X' = X \cdot \cos(\theta) - Y \cdot \sin(\theta) X=Xcos(θ)Ysin(θ)

Y ′ = X ⋅ sin ⁡ ( θ ) + Y ⋅ cos ⁡ ( θ ) Y' = X \cdot \sin(\theta) + Y \cdot \cos(\theta) Y=Xsin(θ)+Ycos(θ)

这个公式描述了绕原点进行旋转的情况。如果要围绕其他点旋转,则需要先将坐标平移到该点,执行旋转,然后再将坐标平移到原来的位置。

在计算机图像处理中,旋转通常涉及对图像的每个像素应用坐标变换,以实现整体图像的旋转效果。

实验代码

void CImageProcessingView::OnGeoRotation()
{// 实验 图像旋转//MessageBox("请在这里添加图像旋转的代码");// 获得当前文档对象CImageProcessingDoc* pDoc = GetDocument();// 判断图像是否已被加载if( pDoc->m_pDibInit->IsEmpty() ){MessageBox("图像未加载");return;}int width = pDoc->m_pDibInit->GetWidth();int height = pDoc->m_pDibInit->GetHeight();int bitCount = pDoc->m_pDibInit->GetBitCount();pDoc->m_pDibTest->CloneDib(pDoc->m_pDibInit);int newwidth = width * (sqrt(2) + 1);int newheight = height * (sqrt(2) + 1);pDoc->m_pDibTest->SetWidthHeight(newwidth,newheight); //重设大小为对角线长度double angle = M_PI / 2; //任意角度RGBQUAD quad;// 设置 pDoc->m_pDibTest 为全白图像int i, j;RGBQUAD rgbQuad1;rgbQuad1.rgbBlue = 255;rgbQuad1.rgbGreen = 255;rgbQuad1.rgbRed = 255;rgbQuad1.rgbReserved = 0;for (i = 0; i < newwidth; i++){for (j = 0; j < newheight; j++){pDoc->m_pDibTest->SetPixelColor(i, j, &rgbQuad1);}}for ( i = 0; i < width; i++)for ( j = 0; j < height; j++){quad = pDoc->m_pDibInit->GetPixelColor(i, j);int x = 0;x = -(i * cos(angle) + j * sin(angle));int y = 0;y = (i * sin(angle) + j * cos(angle));pDoc->m_pDibTest->SetPixelColor(x, y, &quad);} // 交换 m_pDibInit 与 m_pDibTest 指针CDib* pTmp = pDoc->m_pDibInit;pDoc->m_pDibInit = pDoc->m_pDibTest;pDoc->m_pDibTest = pTmp; // 设置脏标记pDoc->SetModifiedFlag(TRUE);// 更新视图pDoc->UpdateAllViews(NULL);
}

实验现象

逆时针旋转90°
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LOWORD, HIWORD, LOBYTE, HIBYTE的解释

文章目录 实验结论 实验 int 类型大小正常为4Byte 以小端序来看 0x12345678在内存中的存储为 0x78 0x56 0x34 0x120x78在低地址&#xff0c;0x12在高地址 程序输出 #include <stdio.h> #include <string.h> #include<windows.h>int main() {int a 0x12345…

创信短信API的无代码开发集成:电商平台、CRM和用户运营

无代码开发&#xff1a;集简云与创信短信API的连接 创信短信API的无代码开发集成&#xff0c;旨在为电商平台、CRM和用户运营提供便利。作为一款超级软件连接器&#xff0c;集简云可以在无需开发&#xff0c;无需代码知识的情况下&#xff0c;轻松连接创信短信与近千款软件系统…

​Unity Vuforia 新手(图片识别)教程,后续整理 实体识别 详细流程

文章目录 前言一、Vuforia是什么&#xff1f;二、Unity导入Vuforia1.去Unity - Windows – Asset Store&#xff0c;搜vuforia engine&#xff0c;添加到我的资源2.打开package Manager&#xff0c;导入到工程中即可3.或者在vuforia engine官网下载的Unity包导入4.检查是否导入…

Git相关: 拉取、git push提交 过程遇到的错误

目录 解决git push报错error: RPC failed; HTTP 413 curl 22 关于这个问题&#xff0c;其实千万别用gitlab,因为你怎么推送 也不可能把几G的文件推上去。 error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 se 解决git push报错error: RPC failed;…

夯实c语言基础

题干以下关于函数的叙述中正确的是&#xff08;  d &#xff09;。   A.函数调用必须传递实参   B.函数必须要有形參   C.函数必须要有返回值   D.函数形参的类型与返回值的类型无关 题干以下程序实现&#xff0c;打印任意奇数行菱形星塔&#xff0c;请填空。 void…

Python交易-通过Financial Modeling Prep (FMP)选择行业

介绍 在您的交易旅程中,无论您是在寻找理想的股票、板块还是指标,做出明智的决策对于您的成功至关重要。然而,收集和分析所需的大量数据可能相当艰巨。财务建模准备 (FMP) API的

vue3实现数据大屏内数据向上滚动,鼠标进入停止滚动 vue3+Vue3SeamlessScroll

1.效果图 2.npm下载依赖及main.js文件配置 npm install vue3-seamless-scroll --saveimport vue3SeamlessScroll from vue3-seamless-scroll;app.use(vue3SeamlessScroll) 3.html代码 <!-- scrollFlag为true时再渲染,vue3只要涉及到传值子页面需要加flag判断&#xff0c;否…

竞赛选题 深度学习疲劳检测 驾驶行为检测 - python opencv cnn

文章目录 0 前言1 课题背景2 相关技术2.1 Dlib人脸识别库2.2 疲劳检测算法2.3 YOLOV5算法 3 效果展示3.1 眨眼3.2 打哈欠3.3 使用手机检测3.4 抽烟检测3.5 喝水检测 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于深度学习加…

服务器常见问题排查(一)—cpu占用高、上下文频繁切换、频繁GC

一般而言cpu异常往往还是比较好定位的。原因包括业务逻辑问题(死循环)、频繁gc以及上下文切换过多。而最常见的往往是业务逻辑(或者框架逻辑)导致的&#xff0c;可以使用jstack来分析对应的堆栈情况。 使用jstack排查占用率问题 当使用jstack排查占用率问题时&#xff0c;可以…

淘宝账单导出的手工操作

文章目录 淘宝账单导出的手工操作概述笔记END 淘宝账单导出的手工操作 概述 日常的支付(JD, 淘宝, 1688), 最终都是用微信和支付宝来支付. 微信和支付宝是绑定的自己银行卡. JD绑定的也是自己的银行卡. 微信账单的导出, 已经记录了, 好使. 现在记录一下支付宝账单(只要是阿…

从真实案例出发,全方位解读 NebulaGraph 中的执行计划

本文整理自 NebulaGraph 核心开发 Yee 在直播《聊聊执行计划这件事》中的主题分享。分享视频参见 B站&#xff1a;https://www.bilibili.com/video/BV1Cu4y1h7gn/ 一条 Query 的一生 在开始正式地解读执行计划之前&#xff0c;我们先来了解在 NebulaGraph 中&#xff0c;一条…

【工艺库】SMIC数字后端工艺库

工艺库文件 Calibredigital文件夹apollolefprimetimesynopsys TD系列文件夹 本来是想找一个工艺库&#xff0c;想要其包含逻辑综合和SPICE Model相关的库文件&#xff0c;但是找了很久也没有直接找到想要的&#xff0c;主要原因还是自己对工艺库文件的构成不是很清楚&#xff0…

五年制专转本备考中如何进行有效的自我管理

时间管理 0 1 一天中的4个记忆黄金时间 清晨起床后&#xff0c;适合学习难以记忆的内容&#xff1b;8&#xff1a;00—10&#xff1a;00&#xff0c;适宜学习需要周密思考、分析判断的内容&#xff0c;是攻克难题的最佳时间&#xff1b;18&#xff1a;00后的两个小时&#x…

spring boot中使用Bean Validation做优雅的参数校验

一、Bean Validation简介 Bean Validation是Java定义的一套基于注解的数据校验规范&#xff0c;目前已经从JSR 303的1.0版本升级到JSR 349的1.1版本&#xff0c;再到JSR 380的2.0版本&#xff08;2.0完成于2017.08&#xff09;&#xff0c;目前最新稳定版2.0.2&#xff08;201…

计算机二级Office真题解析 excel减免税,订单,成绩

第一题 1.将“Excel 减免税.xlsx”文件另存为 excel.xlsx&#xff0c;最后提交该文件&#xff08;1 分&#xff09;。 2.将“对应代码.xlsx”文件中的 sheet1 工作表插入到 excel.xlsx 中&#xff0c;工作 表名重命名为“代码”&#xff08;3 分&#xff09;。 3.在"序号&…

2024年度“阳江市惠民保”正式发布!阳江市专属补充医疗保险全新升级

11月14日&#xff0c;2024年度“阳江市惠民保”暨百场义诊活动发布会在阳江市华邑酒店顺利举行。2024年度“阳江市惠民保”一年保费最低只要59元&#xff0c;最高可获得400万元的医疗保障。 阳江市人民政府、阳江市医疗保障局、阳江市农业农村局、阳江市金融工作局、国家金融监…

碳交易机制下考虑需求响应的综合能源系统优化运行(附带Matlab程序)

碳交易机制下考虑需求响应的综合能源系统优化运行&#xff08;附带Matlab程序&#xff09; 仿真平台&#xff1a;MATLABCPLEX 使用的是yalmipcplex求解器完成求解 资源地址&#xff1a; 碳交易机制下考虑需求响应的综合能源系统优化运行&#xff08;附带Matlab程序&#xff09…

Go常见数据结构的实现原理——map

&#xff08;一&#xff09;基础操作 版本&#xff1a;Go SDK 1.20.6 1、初始化 map分别支持字面量初始化和内置函数make()初始化。 字面量初始化&#xff1a; m : map[string] int {"apple": 2,"banana": 3,}使用内置函数make()初始化&#xff1a; m …

Spark SQL 每年的1月1日算当年的第一个自然周, 给出日期,计算是本年的第几周

一、问题 按每年的1月1日算当年的第一个自然周 (遇到跨年也不管&#xff0c;如果1月1日是周三&#xff0c;那么到1月5号&#xff08;周日&#xff09;算是本年的第一个自然周, 如果按周一是一周的第一天) 计算是本年的第几周&#xff0c;那么 spark sql 如何写 ? 二、分析 …

kubernetes集群编排——etcd

备份 从镜像中拷贝etcdctl二进制命令 [rootk8s1 ~]# docker run -it --rm reg.westos.org/k8s/etcd:3.5.6-0 sh 输入ctrlpq快捷键&#xff0c;把容器打入后台 获取容器id [rootk8s1 ~]# docker ps 从容器拷贝命令到本机 docker container cp c7e28b381f07:/usr/local/bin/etcdc…