📄 geotrans.cpp
字号:
break;
case 24:
nMovedBits = 3;
break;
case 32:
nMovedBits = 4;
break;
}
//针对图像每行进行操作
for(y = 0; y < nNewHeight; y++)
{
//指向新图像第y行
//注意此处宽度和高度是新图像的宽度和高度
pNewTemp = pNewBits;
pNewTemp += (nNewHeight - 1 - y) * nNewWidthBytes;
//针对图像每列进行操作
for(x = 0; x < nNewWidth; x++)
{
//计算该像素在源图像中的坐标
int y0 = (long) (y / fYZoomRatio + 0.5);
int x0 = (long) (x / fXZoomRatio + 0.5);
//判断是否在源图范围内
if( (x0 >= 0) && (x0 < nOldWidth) &&
(y0 >= 0) && (y0 < nOldHeight))
{
//用双线性插值
if(bBilinear)
{
unsigned char *pTemp = Interpolation (nOldWidth, nOldHeight,
(float)x0, (float)y0,
nOldWidthBytes, nMovedBits, pOldBits);
//复制像素
memcpy(pNewTemp, pTemp, nMovedBits);
delete [] pTemp ;
}
else
{
//指向源图像第y0行,第x0个像素
//注意此处宽度和高度应该互换
pOldTemp = pOldBits;
pOldTemp += (nOldHeight - 1 - y0) * nOldWidthBytes;
pOldTemp += x0 * nMovedBits;
//复制像素
memcpy(pNewTemp, pOldTemp, nMovedBits);
}
}
pNewTemp += nMovedBits;
}
}
//将内存解锁和将不再使用的内存释放
::GlobalUnlock( m_pDibObject->GetDib() );
::GlobalFree( m_pDibObject->GetDib() );
::GlobalUnlock( hNewDib );
//将新图像设置为当前图像
m_pDibObject->SetDib( hNewDib );
m_pDibObject->ProcessImageHeader();
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//BOOL Rotate()
//----------------------------------------------------------------------
//基本功能:本函数对传入的CDibObject对象中的图像进行旋转操作。如果进行
// 此调整之前没有指定一个CDibObject对象指针,则必须在调整时加
// 以指定。
//----------------------------------------------------------------------
//参数说明:int iRotateAngle - 旋转的角度(0-360度)
// BOOL bBilinear - TRUE为双线性插值,FALSE为最邻近插值
// CDibObject *pDibObject, 默认为NULL
//----------------------------------------------------------------------
//返回:BOOL:成功返回TRUE,失败返回FALSE。
//----------------------------------------------------------------------
//注 意:该函数用来以图像中心为中心旋转图像,调用该函数会自动扩大图像
// 以显示所有的像素。函数中采用最邻近插值算法进行插值。
////////////////////////////////////////////////////////////////////////
BOOL CGeoTrans::Rotate(int nRotateAngle,
BOOL bBilinear,
CDibObject *pDibObject)
{
if( pDibObject != NULL ) m_pDibObject = pDibObject;
//无CDibObject对象, 返回FALSE
if( m_pDibObject == NULL ) return( FALSE );
//获得图像宽度和高度
int nOldWidth = m_pDibObject->GetWidth();
int nOldHeight = m_pDibObject->GetHeight();
//旋转角度(弧度)
float fRotateAngle;
//旋转角度的正弦和余弦值
float fSina, fCosa;
//源图四个角的坐标(以图像中心为坐标系原点)
float fSrcX1, fSrcY1;
float fSrcX2, fSrcY2;
float fSrcX3, fSrcY3;
float fSrcX4, fSrcY4;
//旋转后四个角的坐标(以图像中心为坐标系原点)
float fDstX1, fDstY1;
float fDstX2, fDstY2;
float fDstX3, fDstY3;
float fDstX4, fDstY4;
//两个中间常量
float f1,f2;
//将旋转角度从度转换到弧度
fRotateAngle = (float) RADIAN(nRotateAngle);
//计算旋转角度的正弦
fSina = (float) sin((double)fRotateAngle);
//计算旋转角度的余弦
fCosa = (float) cos((double)fRotateAngle);
//计算原图的四个角的坐标(以图像中心为坐标系原点)
fSrcX1 = (float) (- (nOldWidth - 1) / 2);
fSrcY1 = (float) ( (nOldHeight - 1) / 2);
fSrcX2 = (float) ( (nOldWidth - 1) / 2);
fSrcY2 = (float) ( (nOldHeight - 1) / 2);
fSrcX3 = (float) (- (nOldWidth - 1) / 2);
fSrcY3 = (float) (- (nOldHeight - 1) / 2);
fSrcX4 = (float) ( (nOldWidth - 1) / 2);
fSrcY4 = (float) (- (nOldHeight - 1) / 2);
//计算新图四个角的坐标(以图像中心为坐标系原点)
fDstX1 = fCosa * fSrcX1 + fSina * fSrcY1;
fDstY1 = -fSina * fSrcX1 + fCosa * fSrcY1;
fDstX2 = fCosa * fSrcX2 + fSina * fSrcY2;
fDstY2 = -fSina * fSrcX2 + fCosa * fSrcY2;
fDstX3 = fCosa * fSrcX3 + fSina * fSrcY3;
fDstY3 = -fSina * fSrcX3 + fCosa * fSrcY3;
fDstX4 = fCosa * fSrcX4 + fSina * fSrcY4;
fDstY4 = -fSina * fSrcX4 + fCosa * fSrcY4;
//计算旋转后的图像实际宽度
int nNewWidth = (long) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);
//计算旋转后的图像高度
int nNewHeight = (long) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5);
//两个常数
f1 = (float) (-0.5 * (nNewWidth - 1) * fCosa - 0.5 * (nNewHeight - 1) * fSina
+ 0.5 * (nOldWidth - 1));
f2 = (float) ( 0.5 * (nNewWidth - 1) * fSina - 0.5 * (nNewHeight - 1) * fCosa
+ 0.5 * (nOldHeight - 1));
//定义变量
unsigned char *pOldBuffer, *pNewBuffer;
unsigned char *pOldBits, *pNewBits;
unsigned char *pOldTemp, *pNewTemp;
BITMAPFILEHEADER *pOldBFH, *pNewBFH;
BITMAPINFOHEADER *pOldBIH, *pNewBIH;
RGBQUAD *pOldPalette, *pNewPalette;
int nOldWidthBytes, nNewWidthBytes, nNumColors, x, y;
//原图像指针
pOldBuffer = (unsigned char *)
m_pDibObject->GetDIBPointer( &nOldWidthBytes,
m_pDibObject->GetNumBits(),
&nNewWidthBytes, nNewWidth );
if( pOldBuffer == NULL ) return( FALSE );
//原图像文件头指针
pOldBFH = (BITMAPFILEHEADER *) pOldBuffer;
//原图像信息头指针
pOldBIH = (BITMAPINFOHEADER *)
&pOldBuffer[sizeof(BITMAPFILEHEADER)];
//原图像颜色数
nNumColors = m_pDibObject->GetNumColors();
//原图像调色板指针
pOldPalette = (RGBQUAD *) &pOldBuffer[sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)];
//原图像数据指针
pOldBits = (unsigned char *)
&pOldBuffer[sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)
+nNumColors*sizeof(RGBQUAD)];
DWORD dwNewSize;
HGLOBAL hNewDib;
//新图像大小(包括文件头、信息头、调色板和图像数据)
dwNewSize = (DWORD) nNumColors * sizeof( RGBQUAD ) +
sizeof( BITMAPFILEHEADER ) +
sizeof( BITMAPINFOHEADER ) +
nNewWidthBytes * nNewHeight;
//为新图像分配内存
hNewDib = ::GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT, dwNewSize );
if( hNewDib == NULL )
{
m_pDibObject->m_nLastError = IMAGELIB_MEMORY_ALLOCATION_ERROR;
::GlobalUnlock( m_pDibObject->GetDib() );
return( FALSE );
}
//新图像指针
pNewBuffer = (unsigned char *) ::GlobalLock( hNewDib );
if( pNewBuffer == NULL )
{
::GlobalFree( hNewDib );
m_pDibObject->m_nLastError = IMAGELIB_MEMORY_LOCK_ERROR;
::GlobalUnlock( m_pDibObject->GetDib() );
return( FALSE );
}
//新图像文件头指针
pNewBFH = (BITMAPFILEHEADER *) pNewBuffer;
//新图像信息头指针
pNewBIH = (BITMAPINFOHEADER *) &pNewBuffer[sizeof(BITMAPFILEHEADER)];
//新图像调色板指针
pNewPalette = (RGBQUAD *) &pNewBuffer[sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)];
//新图像数据指针
pNewBits = (unsigned char *) &pNewBuffer[sizeof(BITMAPFILEHEADER)
+sizeof(BITMAPINFOHEADER)
+nNumColors*sizeof(RGBQUAD)];
//用255(白色)填充新图像数据区
memset(pNewBits, (BYTE)255, nNewWidthBytes * nNewHeight );
//用原图像文件头数据填充新图像文件头
memcpy( pNewBFH, pOldBFH, sizeof(BITMAPFILEHEADER) );
//用原图像信息头数据填充新图像信息头
memcpy( pNewBIH, pOldBIH, sizeof(BITMAPINFOHEADER) );
//调整文件总字节数
pNewBFH->bfSize = dwNewSize;
//调整新图像的宽度和高度
pNewBIH->biWidth = nNewWidth;
pNewBIH->biHeight = nNewHeight;
//pNewBIH->biBitCount = nNewBitsPerPixel;
pNewBIH->biSizeImage = nNewWidthBytes * nNewHeight;
pNewBIH->biClrUsed = nNumColors;
pNewBFH->bfSize = sizeof( BITMAPFILEHEADER )
+ sizeof( BITMAPINFOHEADER )
+ nNumColors * sizeof( RGBQUAD )
+ pNewBIH->biSizeImage;
pNewBFH->bfOffBits = sizeof( BITMAPFILEHEADER )
+ sizeof( BITMAPINFOHEADER )
+ nNumColors * sizeof( RGBQUAD );
//用原图像调色板填充新图像调色板
if(nNumColors != 0)
memcpy( pNewPalette, pOldPalette, nNumColors*sizeof(RGBQUAD) );
//由图像位数确定的移动字节数
int nMovedBits = 1;
switch( m_pDibObject->GetNumBits() )
{
case 8:
nMovedBits = 1;
break;
case 16:
nMovedBits = 2;
break;
case 24:
nMovedBits = 3;
break;
case 32:
nMovedBits = 4;
break;
}
//针对图像每行进行操作
for(y = 0; y < nNewHeight; y++)
{
//指向新图像第y行
//注意此处宽度和高度是新图像的宽度和高度
pNewTemp = pNewBits;
pNewTemp += (nNewHeight - 1 - y) * nNewWidthBytes;
//针对图像每列进行操作
for(x = 0; x < nNewWidth; x++)
{
//计算该像素在源图像中的坐标
int y0 = (long) (-((float) x) * fSina + ((float) y)
* fCosa + f2 + 0.5);
int x0 = (long) ( ((float) x) * fCosa + ((float) y)
* fSina + f1 + 0.5);
//判断是否在源图范围内
if( (x0 >= 0) && (x0 < nOldWidth) &&
(y0 >= 0) && (y0 < nOldHeight))
{
//用双线性插值
if(bBilinear)
{
unsigned char *pTemp = Interpolation (nOldWidth, nOldHeight,
(float)x0, (float)y0,
nOldWidthBytes, nMovedBits, pOldBits);
//复制像素
memcpy(pNewTemp, pTemp, nMovedBits);
delete [] pTemp ;
}
else
{
//指向源图像第y0行,第x0个像素
//注意此处宽度和高度应该互换
pOldTemp = pOldBits;
pOldTemp += (nOldHeight - 1 - y0) * nOldWidthBytes;
pOldTemp += x0 * nMovedBits;
//复制像素
memcpy(pNewTemp, pOldTemp, nMovedBits);
}
}
pNewTemp += nMovedBits;
}
}
//将内存解锁和将不再使用的内存释放
::GlobalUnlock( m_pDibObject->GetDib() );
::GlobalFree( m_pDibObject->GetDib() );
::GlobalUnlock( hNewDib );
//将新图像设置为当前图像
m_pDibObject->SetDib( hNewDib );
m_pDibObject->ProcessImageHeader();
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//BOOL Interpolation()
//----------------------------------------------------------------------
//基本功能:本函数对传入的CDibObject对象中的图像进行旋转操作。如果进行
// 此调整之前没有指定一个CDibObject对象指针,则必须在调整时加
// 以指定。
//----------------------------------------------------------------------
//参数说明:int nWidth - 源图像宽度(像素数)
// int nHeight - 源图像高度(像素数)
// float x - 插值元素的x坐标
// float y - 插值元素的y坐标
// int nWidthBytes - 图像字节宽度
// int nMovedBits - 一次移动的字节数
// LPSTR lpDIBBits - 指向源DIB图像指针
//----------------------------------------------------------------------
//返 回:unsigned char - 返回插值计算结果。
//----------------------------------------------------------------------
//注 意:该函数利用双线性插值算法来估算像素值。对于超出图像范围的像素,
// 直接返回255。
////////////////////////////////////////////////////////////////////////
unsigned char *CGeoTrans::Interpolation(int nWidth,
int nHeight,
float x,
float y,
int nWidthBytes,
int nMovedBits,
unsigned char *pBits)
{
//四个最临近像素的坐标(x1, y1), (x2, y1), (x1, y2), (x2, y2)
long x1, x2;
long y1, y2;
//四个最临近像素值
unsigned char f1, f2, f3, f4;
//二个插值中间值
unsigned char f12, f34;
//定义一个值,当像素坐标相差小于改值时认为坐标相同
float EXP;
//直方图数据数组
unsigned char *pData = new unsigned char [nMovedBits];
int i;
//赋值
EXP = (float) 0.0001;
//计算四个最临近像素的坐标
x1 = (long) x;
x2 = x1 + 1;
y1 = (long) y;
y2 = y1 + 1;
//根据不同情况分别处理
if( (x < 0) || (x > nWidth - 1) || (y < 0) || (y > nHeight - 1))
{
for(i = 0; i < nMovedBits; i++)
{
pData[i] =(unsigned char) 255;
}
//要计算的点不在源图范围内,直接返回255。
return(pData);
}
else
{
if (fabs(x - nWidth + 1) <= EXP)
{
//要计算的点在图像右边缘上
if (fabs(y - nHeight + 1) <= EXP)
{
//要计算的点正好是图像最右下角那一个像素,直接返回该点像素值
for(i = 0; i < nMovedBits; i++)
{
pData[i] = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x1 * nMovedBits + i);
}
//返回插值结果
return(pData);
}
else
{
//在图像右边缘上且不是最后一点,直接一次插值即可
for(i = 0; i < nMovedBits; i++)
{
f1 = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x1 * nMovedBits + i);
f3 = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x2 * nMovedBits + i);
pData[i] =(unsigned char)(f1 + (y -y1) * (f3 - f1));
}
//返回插值结果
return(pData);
}
}
else if (fabs(y - nHeight + 1) <= EXP)
{
//要计算的点在图像下边缘上且不是最后一点,直接一次插值即可
for(i = 0; i < nMovedBits; i++)
{
f1 = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x1 * nMovedBits + i);
f2 = *(pBits + nWidthBytes * (nHeight - 1 - y2) + x1 * nMovedBits + i);
pData[i] =(unsigned char)(f1 + (x -x1) * (f2 - f1));
}
//返回插值结果
return(pData);
}
else
{
//计算四个最临近像素值
for(i = 0; i < nMovedBits; i++)
{
// 计算四个最临近象素值
f1 = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x1 * nMovedBits + i);
f2 = *(pBits + nWidthBytes * (nHeight - 1 - y2) + x1 * nMovedBits + i);
f3 = *(pBits + nWidthBytes * (nHeight - 1 - y1) + x2 * nMovedBits + i);
f4 = *(pBits + nWidthBytes * (nHeight - 1 - y2) + x2 * nMovedBits + i);
//插值1
f12 = (unsigned char)(f1 + (x - x1) * (f2 - f1));
//插值2
f34 = (unsigned char)(f3 + (x - x1) * (f4 - f3));
pData[i] = (unsigned char)(f12 + (y -y1) * (f34 - f12));
//char s[200];
//wsprintf(s,"pData[%d]=%d", i, pData[i]);
//AfxMessageBox(s);
}
//返回插值结果
return(pData);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -