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

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

获取源工程可访问gitee可在此工程的基础上进行学习。

实验内容

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_pDibTest
 pDoc->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_pDibTest
 pDoc->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_pDibTest
 pDoc->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_pDibTest
 pDoc->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°
在这里插入图片描述

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
以下是一个简单的计算机图形学平移旋转缩放实验 C 程序的完整代码,仅供参考: ```c #include <graphics.h> #include <conio.h> #include <math.h> #define PI 3.14159265 void draw_rect(int x1, int y1, int x2, int y2) { rectangle(x1, y1, x2, y2); } void rotate_rect(int x1, int y1, int x2, int y2, int angle) { int midx = (x1 + x2) / 2; int midy = (y1 + y2) / 2; double radian = angle * PI / 180.0; int new_x1 = round((x1 - midx) * cos(radian) - (y1 - midy) * sin(radian)) + midx; int new_y1 = round((x1 - midx) * sin(radian) + (y1 - midy) * cos(radian)) + midy; int new_x2 = round((x2 - midx) * cos(radian) - (y2 - midy) * sin(radian)) + midx; int new_y2 = round((x2 - midx) * sin(radian) + (y2 - midy) * cos(radian)) + midy; draw_rect(new_x1, new_y1, new_x2, new_y2); } void scale_rect(int x1, int y1, int x2, int y2, double scale) { int midx = (x1 + x2) / 2; int midy = (y1 + y2) / 2; int new_x1 = round(x1 * scale + midx * (1 - scale)); int new_y1 = round(y1 * scale + midy * (1 - scale)); int new_x2 = round(x2 * scale + midx * (1 - scale)); int new_y2 = round(y2 * scale + midy * (1 - scale)); draw_rect(new_x1, new_y1, new_x2, new_y2); } void translate_rect(int x1, int y1, int x2, int y2, int dx, int dy) { draw_rect(x1 + dx, y1 + dy, x2 + dx, y2 + dy); } int main() { int gd = DETECT, gm; initgraph(&gd, &gm, ""); draw_rect(100, 100, 200, 200); // 绘制矩形 delay(2000); // 延迟 2 秒 cleardevice(); // 清屏 rotate_rect(100, 100, 200, 200, 45); // 旋转 45 度 delay(2000); cleardevice(); scale_rect(100, 100, 200, 200, 0.5); // 缩小一半 delay(2000); cleardevice(); translate_rect(100, 100, 200, 200, 50, 50); // 平移 50 个单位 getch(); closegraph(); return 0; } ``` 在此代码中,draw\_rect、rotate\_rect、scale\_rect 和 translate\_rect 分别代表绘制矩形、旋转矩形、缩放矩形和平移矩形的函数。在 main 函数中,我们依次调用这些函数进行绘制、变换和清屏等操作。注意,在使用旋转和缩放函数时,需要先计算出变换后的坐标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

写的什么石山代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值