📄 geotrans.cpp
字号:
// ************************************************************************
// 文件名:GeoTrans.cpp
//
// 图像几何变换函数库:
//
// ZoomDIB() - 缩放位图
// Rotate() - 旋转位图
// Rectinication() - 空间较正图像
//
// ************************************************************************
#include "stdafx.h"
#include "DIP_System.h"
#include "GeoTrans.h"
#include "SpaceFilter.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CGeoTrans
CGeoTrans::CGeoTrans()
{
}
CGeoTrans::~CGeoTrans()
{
}
BEGIN_MESSAGE_MAP(CGeoTrans, CWnd)
//{{AFX_MSG_MAP(CGeoTrans)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CGeoTrans message handlers
/*************************************************************************
*
* 函数名称:
* ZoomDIB()
*
* 参数:
* HDIB hDIB - 待处理的DIB
* float fZoomRatio - 缩放比率
*
* 返回值:
* HDIB - 缩放后的DIB
*
* 说明:
* 该函数用来缩放DIB图像,返回处理后的DIB
*
************************************************************************/
HDIB CGeoTrans::ZoomDIB(HDIB hDIB, float fZoomRatio)
{
// 源图像的宽度和高度
LONG lWidth;
LONG lHeight;
// 缩放后图像的宽度和高度
LONG lNewWidth;
LONG lNewHeight;
// 指向源图像的指针
LPBYTE lpDIBBits;
// 指向DIB的指针
LPBYTE lpDIB;
// 缩放后新DIB句柄
HDIB hNewDIB;
// 指向缩放图像对应象素的指针
LPBYTE lpDst;
// 指向缩放图像的指针
LPBYTE lpNewDIB;
LPBYTE lpNewDIBBits;
// 指向BITMAPINFO结构的指针(Win3.0)
LPBITMAPINFOHEADER lpbmi;
// 指向BITMAPCOREINFO结构的指针
LPBITMAPCOREHEADER lpbmc;
// 循环变量(象素在新DIB中的坐标)
LONG i;
LONG j;
// 象素在源DIB中的坐标
LONG i0;
LONG j0;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到源DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是24-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 24)
{
// 提示用户
MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return NULL;
}
// 更改光标形状
BeginWaitCursor();
// 获取图像的宽度
lWidth = m_clsDIB.DIBWidth(lpDIB);
// 获取图像的高度
lHeight = m_clsDIB.DIBHeight(lpDIB);
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 计算缩放后的图像实际宽度
// 此处直接加0.5是由于强制类型转换时不四舍五入,而是直接截去小数部分
lNewWidth = (LONG) (lWidth * fZoomRatio + 0.5);
// 计算缩放后的图像高度
lNewHeight = (LONG) (lHeight * fZoomRatio + 0.5);
// 计算图像每行的字节数
LONG lNewLineBytes = WIDTHBYTES(lNewWidth * 24);
// 分配内存,以保存新DIB
hNewDIB = (HDIB) ::GlobalAlloc(GHND, lNewHeight * lNewLineBytes
+ *(LPDWORD)lpDIB + m_clsDIB.PaletteSize(lpDIB));
// 判断是否内存分配失败
if (hNewDIB == NULL)
{
// 分配内存失败
return NULL;
}
// 锁定内存
lpNewDIB = (LPBYTE)::GlobalLock((HGLOBAL) hNewDIB);
// 复制DIB信息头和调色板
memcpy(lpNewDIB, lpDIB, *(LPDWORD)lpDIB + m_clsDIB.PaletteSize(lpDIB));
// 找到新DIB象素起始位置
lpNewDIBBits = m_clsDIB.FindDIBBits(lpNewDIB);
// 获取指针
lpbmi = (LPBITMAPINFOHEADER)lpNewDIB;
lpbmc = (LPBITMAPCOREHEADER)lpNewDIB;
// 更新DIB中图像的高度和宽度
if (IS_WIN30_DIB(lpNewDIB))
{
// 对于Windows 3.0 DIB
lpbmi->biWidth = lNewWidth;
lpbmi->biHeight = lNewHeight;
}
else
{
// 对于其它格式的DIB
lpbmc->bcWidth = (unsigned short) lNewWidth;
lpbmc->bcHeight = (unsigned short) lNewHeight;
}
// 针对图像每行进行操作
for(i = 0; i < lNewHeight; i++)
{
// 针对图像每列进行操作
for(j = 0; j < lNewLineBytes; j++)
{
// 计算该象素在源DIB中的坐标
i0 = (LONG) (i / fZoomRatio);
j0 = (LONG) (j / (fZoomRatio * 3));
// 对应缩放前象素的红色分量
unsigned char R = *((unsigned char *)lpDIBBits + lLineBytes * i0 + 3 * j0);
// 复制象素
*((unsigned char *)lpNewDIBBits + lNewLineBytes * i + j) = R;
// 源、目的图像移到G分量
lpDst++; j++;
// 对应缩放前象素的绿色分量
unsigned char G = *((unsigned char *)lpDIBBits + lLineBytes * i0 + 3 * j0 +1);
// 复制象素
*((unsigned char *)lpNewDIBBits + lNewLineBytes * i + j) = G;
// 源、目的图像移到B分量
lpDst++; j++;
// 对应缩放前象素的蓝色分量
unsigned char B = *((unsigned char *)lpDIBBits + lLineBytes * i0 + 3 * j0 +2);
// 复制象素
*((unsigned char *)lpNewDIBBits + lNewLineBytes * i + j) = B;
}
}
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 恢复光标
EndWaitCursor();
// 返回
return hNewDIB;
}
/*************************************************************************
*
* 函数名称:
* Rotate()
*
* 参数:
* HDIB hDIB - 待处理的DIB
* int nAngle - 缩放比率
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数用来旋转DIB图像
*
************************************************************************/
void CGeoTrans::Rotate(HDIB hDIB, float fAngle)
{
#define PI 3.14159
// 循环变量
LONG i0;
LONG j0;
LONG i1;
LONG j1;
// 指向DIB的指针
LPBYTE lpDIB;
// 指向DIB象素指针
LPBYTE lpDIBBits;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是24-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 24)
{
// 提示用户
MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return;
}
// 更改光标形状
BeginWaitCursor();
// DIB的宽度
LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
// DIB的高度
LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 旋转角度的弧度
fAngle = (float)(fAngle * PI / 180);
// 角度的正余弦
float fSinAngle = (float)sin(fAngle);
float fCosAngle = (float)cos(fAngle);
// 不能用char,也不能用::strcpy()
unsigned char* m_temp;
m_temp=new unsigned char [lLineBytes * lHeight];
// 复制空白数据到中间缓存
for (i0 = 0; i0 < lLineBytes * lHeight; i0++)
m_temp[i0] = 255;
// 对各像素进行旋转处理
for (i0 = 0; i0 < lHeight; i0 ++)
{
for (j0 = 0; j0 < lWidth; j0 ++)
{
// 计算旋转后的坐标位置
j1 = (LONG)((j0 - lWidth / 2) * fCosAngle + (lHeight / 2 - i0) * fSinAngle + lWidth / 2 + 0.5);
i1 = (LONG)((j0 - lWidth / 2) * fSinAngle - (lHeight / 2 - i0) * fCosAngle + lHeight / 2 + 0.5);
// 将原始象素复制到目标位置
if (i1 >= 0 && i1 < lHeight && j1 >= 0 && j1 < lWidth)
{
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 1] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 1);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 2] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 2);
}
}
}
// 回存处理结果到DIB
for(i0 = 0; i0 < lLineBytes * lHeight; i0++)
*(lpDIBBits + i0) = m_temp[i0];
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
delete[] m_temp;
// 恢复光标
EndWaitCursor();
}
/*************************************************************************
*
* 函数名称:
* Rectinication()
*
* 参数:
* HDIB hDIB - 待处理的DIB
* int nAngle - 面倾斜角度
*
* 返回值:
* void - 无返回值
*
* 说明:
* 该函数用来在空间矫正DIB图像
*
************************************************************************/
void CGeoTrans::Rectinication(HDIB hDIB, float fAngle)
{
#define PI 3.14159
// 循环变量
LONG i0;
LONG j0;
LONG i1;
LONG j1;
// 指向DIB的指针
LPBYTE lpDIB;
// 指向DIB象素指针
LPBYTE lpDIBBits;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是24-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 24)
{
// 提示用户
MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return;
}
// 更改光标形状
BeginWaitCursor();
// DIB的宽度
LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
// DIB的高度
LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 旋转角度的弧度
fAngle = (float)(fAngle * PI / 180);
// 角度的正余弦
float fSinAngle = (float)sin(fAngle);
float fCosAngle = (float)cos(fAngle);
float fTgAngle = fSinAngle / fCosAngle;
// 不能用char,也不能用::strcpy()
unsigned char* m_temp;
m_temp = new unsigned char [lLineBytes * lHeight];
// 复制空白数据到中间缓存
for (i0 = 0; i0 < lLineBytes * lHeight; i0++)
m_temp[i0] = 255;
// 先对X方向进行矫正处理
for (i0 = 0; i0 < lHeight; i0 ++)
{
for (j0 = 0; j0 < lWidth; j0 ++)
{
// 计算校直后的坐标位置
j1 = (LONG)(lWidth - (lWidth - j0) / fCosAngle + 0.5f);
i1 = i0;
// 将原始象素复制到目标位置
if (i1 >= 0 && i1 < lHeight && j1 >= 0 && j1 < lWidth)
{
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 1] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 1);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 2] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 2);
}
}
}
// 回存处理结果到DIB
for(i0 = 0; i0 < lLineBytes * lHeight; i0++)
*(lpDIBBits + i0) = m_temp[i0];
// 调用中值滤波进行平滑处理
CSpaceFilter clsSpaceFilter;
clsSpaceFilter.MedianFilter(hDIB);
// 再对y方向进行矫正处理
for (i0 = 0; i0 < lHeight; i0 ++)
{
for (j0 = 0; j0 < lWidth; j0 ++)
{
// 计算校直后的坐标位置
j1 = j0;
if (i0 < lHeight / 2)
i1 = (LONG)(i0 - (lHeight / 2 - i0) * fSinAngle * (lWidth - j1) / lWidth + 0.5f);
else
i1 = (LONG)(i0 + (i0 - lHeight / 2) * fSinAngle * (lWidth - j1) / lWidth + 0.5f);
// 将原始象素复制到目标位置
if (i1 >= 0 && i1 < lHeight && j1 >= 0 && j1 < lWidth)
{
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 1] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 1);
m_temp[lLineBytes * (lHeight - i1 - 1) + j1 * 3 + 2] = *((unsigned char *)lpDIBBits + lLineBytes * (lHeight - i0 - 1) + j0 * 3 + 2);
}
}
}
// 回存处理结果到DIB
for(i0 = 0; i0 < lLineBytes * lHeight; i0++)
*(lpDIBBits + i0) = m_temp[i0];
// 调用中值滤波进行平滑处理
clsSpaceFilter.MedianFilter(hDIB);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 释放内存
delete[] m_temp;
// 恢复光标
EndWaitCursor();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -