[图像处理]图像的几何变换

1、图像的平移变换

设dx为水平偏移,dy为垂直偏移,则平移变换公式为:

x = x0 + dx

y = y0 + dy

在代码实现的问题上由于图像在内存中倒放,当垂直偏移为10时,应该使图像向下方移动10但是图像倒放所以会向上移动10解决方法就是从下往上取值,先取(height-1-j)详细情况如下:

void jiheBianHuan::PingYi(int m_Xmove,int m_Ymove)
{
	LPBYTE lpSrc;
	LPBYTE p_data;
	LPBYTE lpDst;
	LPBYTE temp;
	int i, j;
	LONG width, height;
	LONG perLineBytes;
	p_data = getData();
	width = getWidth();
	height = getHeight();
	if (m_pBitmapInfoHeader->biBitCount < 9)//灰度图要保证每行的字节数是4的倍数,除以32是因为4个字节是32位,为了获知这一行总共有几个4字节
	{					//width是以像素为单位所以每个像素点的字节数为width*8为了将不满足的部分装满32位所以又加了31
		perLineBytes = (((width * 8) + 31) / 32 * 4);
		temp = new BYTE[perLineBytes*height];
		lpDst = (LPBYTE)temp;
		memset(lpDst, (BYTE)255, perLineBytes*height);
		for ( i = 0; i < width; i++)
		{
			for (j = 0; j < height; j++)
			{
				lpSrc = (LPBYTE)p_data + perLineBytes*(height - 1 - j) + i;//数据在内存中是倒放,先求出来数据所在位置的高度,即所在行的上一行,再加宽度i
				int i0, j0;						  //如果按照width*j+i的算法移动图像那么就会使垂直方向往上方移动
				//以下是重要代码
				i0 = i + m_Xmove;
				j0 = j + m_Ymove;
				if (i0 < width&&i0 >= 0 && j0 < height&&j0 >= 0)
				{
					lpDst = (LPBYTE)temp + perLineBytes*(height - 1 - j0) + i0;
					*lpDst = *lpSrc;
				}
				else
				{
					*lpDst = 255;
				}
			}
		}
		memcpy(p_data, temp, perLineBytes*height);
		delete temp;
	}

2、图像的镜像变换

设图像的宽度为width,则水平镜像为:{x = width -1 -x0}

垂直镜像为:{y=height-1-y0}

	if (m_pBitmapInfoHeader->biBitCount < 9)
	{
		perLineBytes = (((width * 8) + 31) / 32 * 4);
		temp = new BYTE[perLineBytes*height];
		lpDst = temp;
		for (i = 0; i < width; i++)
		{
			for (j = 0; j < height; j++)
			{
				lpSrc = (LPBYTE)p_data + perLineBytes*(height - 1 - j) + i;
				int i0, j0;
				//以下是重要代码
				i0 = perLineBytes - i;
				j0 = j;
				if (i0 < width&&i0 >= 0 && j0 < height&&j0 >= 0)
				{
					lpDst = (LPBYTE)temp + perLineBytes*(height - 1 - j0) + i0;
					*lpDst = *lpSrc;
				}
				else
				{
					*lpDst = 255;
				}
			}
		}
		memcpy(p_data, temp, perLineBytes*height);
		delete temp;
	}

3、图像的缩放处理

图像缩放是用的是向后映射法,先计算出新图像的大小,newWidth和newHeight。水平缩放系数为sx垂直缩放系数为sy。则有以下关系:

newwidth = sx * width 

newheight = sy * height

最重要的代码如下:

int x = (int)(1/sx+0.5)
int y = (int)(1/sy+0.5) 

这样就能够找到合适的缩放前的点,将这个点的像素值付给缩放后的点,这是一种方法为最近邻插法。还有一种为双线性插值法。

4、图像的旋转变换

图像的旋转变换涉及到的数学问题较多大致分为以下三个部分:

1.将输入图像坐标系转为数学坐标系,由于计算机的坐标系在左上角所以先转为数学坐标系

2.通过数学坐标系计算指定像素旋转后的坐标:

x0=rcosθ y0=rsinθ 转为 x =rcos(θ-α)  y=rsin(θ-α)

3.由旋转坐标系再转回输出坐标系

经过一系列的矩阵运算之后可以得到两个常量,和x,y的旋转公式,具体看代码:

angle = (double)RADIAN(angle);
	//原图像坐标
	int srcX1, srcX2, srcX3, srcX4;
	int srcY1, srcY2, srcY3, srcY4;
	srcX1 = 0; srcX2 = width-1; srcX3 = 0; srcX4 = width-1;
	srcY1 = 0; srcY2 = 0; srcY3 = height-1; srcY4 = height-1;
	//新图像坐标
	double tranX1, tranX2, tranX3, tranX4;
	double tranY1, tranY2, tranY3, tranY4;
	//坐标计算
	double Fsin = sin(angle);
	double Fcos = cos(angle);
	//新坐标赋值
	tranX1 = srcX1*Fcos + srcY1*Fsin;
	tranY1 = -srcX1*Fsin + srcY1*Fcos;
	tranX2 = srcX2*Fcos + srcY2*Fsin;
	tranY2 = -srcX2*Fsin + srcY2*Fcos;
	tranX3 = srcX3*Fcos + srcY3*Fsin;
	tranY3 = -srcX3*Fsin + srcY3*Fcos;
	tranX4 = srcX4*Fcos + srcY4*Fsin;
	tranY4 = -srcX4*Fsin + srcY4*Fcos;
	//新图像的长度与宽度
	UINT newWidth = (UINT)(max(fabs(tranX1 - tranX4), fabs(tranX2 - tranX3)) + 1.5); //加1.5是为了取整数防止数值丢失
	UINT newHeight = (UINT)(max(fabs(tranY1 - tranY4), fabs(tranY2 - tranY3)) + 1.5);
	//两个常亮的值
	double num1 = -0.5*newWidth*Fcos - 0.5*newHeight*Fsin + 0.5*width;
	double num2 = 0.5*newWidth*Fsin - 0.5*newHeight*Fcos + 0.5*height;
	temp = new BYTE[newWidth*newHeight];
	lpDst = temp;
	memset(temp,(BYTE)255, newWidth*newHeight);
	if(m_pBitmapInfoHeader->biBitCount<9)
	{
		
		for(int j=0;j<newHeight;j++)
			for (int i = 0; i < newWidth; i++)
			{
				lpDst = (LPBYTE)temp + newWidth*j + i;
				int x0 = (int)i*Fcos + j*Fsin + num1+0.5;
				int y0 = (int)-i*Fsin + j*Fcos + num2+0.5;
				if (x0 < width&&x0 >= 0 && y0 < height&&y0 >= 0)
				{
					lpSrc = (LPBYTE)p_data + width*y0 + x0;
					*lpDst = *lpSrc;
				}
			}
	}
	this->m_pData = temp;
	m_pBitmapInfoHeader->biHeight = newHeight;
	m_pBitmapInfoHeader->biWidth = newWidth;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值