(学习笔记4)BMP位图照片的几何变换

这次我主要在BMP位图照片的读取和显示的基础上,加上了对BMP位图照片的几何变换。

代码下载地址:http://download.csdn.net/detail/caicai_zju/9485779
在下面也陆续贴出了代码

几何变换包括以下几个操作:
平移
水平镜像
垂直镜像
缩放
旋转
其中,旋转包括:
顺时针旋转90°
逆时针旋转90°
旋转180°
任意角度旋转

对于每个功能操作如何实现,我在代码中附上注释,保证大家都可以看得懂。

step 1:完成如下图的任务,在菜单栏中显示我们所需要完成的功能操作按键。
(学习笔记4)BMP位图照片的几何变换_第1张图片

找到”资源视图“在Menu下有对应如下图。如果找不到资源视图,在vs2010菜单栏中有”视图“一项,在其中你会找到资源视图。
(学习笔记4)BMP位图照片的几何变换_第2张图片

接下来,我们对”几何变换“下的”平移“等依次进行修改ID。如下图所示:
”平移“的ID为:id_Move
”水平镜像“的ID为:id_HorizontalMirror
”垂直镜像“的ID为:id_VerticalMirror
”缩放“的ID为:id_Zoom
”顺时针旋转90°“的ID为:id_Clockwise90
”逆时针旋转90°“的ID为:id_Anticlockwise90
”旋转180°“的ID为:id_Rotate180
”任意角度旋转“的ID为:id_FreeRotate

如何找到右边的属性窗口,在”平移“上右键,会出现”属性“单击就可以看到。
(学习笔记4)BMP位图照片的几何变换_第3张图片

(学习笔记4)BMP位图照片的几何变换_第4张图片

step 2:”平移“、”缩放“、”任意角度旋转“,这3个操作还需要我们另外进行传入数值。或者说还需要输入参数。针对输入参数,我们需要有输入参数的界面。这一步就是设计输入参数的界面,具体如下图:

”平移“的参数输入界面设计步骤如下:
如下图,首先在”Dialog“右击选中”插入Dialog“,先插入一个Dialog
(学习笔记4)BMP位图照片的几何变换_第5张图片

接着,修改这个Dialog的ID,修改如下图所示:右键左边的红色方框,接着单击属性,在属性中修改,ps:所有的ID的修改都在属性中。
(学习笔记4)BMP位图照片的几何变换_第6张图片

接着我们从工具箱中拖入一个Group Box控件,如下图,
(学习笔记4)BMP位图照片的几何变换_第7张图片

红色方框中有”平移参数“,这个是怎么修改了,还是进入对应控件的属性窗口,在这个地方就是Group Box控件的属性窗口,然后修改Caption。Caption中的内容是什么,对应就显示什么。
(学习笔记4)BMP位图照片的几何变换_第8张图片

下图窗口的”平移参数输入界面也还是一个道理“,如下图所示:
(学习笔记4)BMP位图照片的几何变换_第9张图片

接下来,我们看Group Box中的4个控件分别是什么。如下图所示:
(学习笔记4)BMP位图照片的几何变换_第10张图片

下面两张截屏分别是修改对应Edit Control的ID:
(学习笔记4)BMP位图照片的几何变换_第11张图片

(学习笔记4)BMP位图照片的几何变换_第12张图片

下面两张截屏分别是修改对应”确定“与”取消“这两个BUTTON的ID:
(学习笔记4)BMP位图照片的几何变换_第13张图片

(学习笔记4)BMP位图照片的几何变换_第14张图片

OK,平移参数输入界面,到这一步就完全设计完成。接下来设计”缩放输入参数界面“,ps:不再想平移参数输入界面那么详细的图文说明了。

缩放参数输入界面 其实和平移参数输入界面是完全一样的,只不过Edit Control的ID,以及一些Caption需要修改,设计步骤如下图:

(学习笔记4)BMP位图照片的几何变换_第15张图片

(学习笔记4)BMP位图照片的几何变换_第16张图片

(学习笔记4)BMP位图照片的几何变换_第17张图片

”确定“和”取消“的ID命名与前面”平移参数输入界面“的命名一样。

旋转角度输入界面 它的设计步骤和前面两个的设计大同小异。设计步骤如下图:

(学习笔记4)BMP位图照片的几何变换_第18张图片

(学习笔记4)BMP位图照片的几何变换_第19张图片

step 3:
首先我们定义几何变换这个类,GeometryTrans.h和GeometryTrans.cpp代码如下:
(学习笔记4)BMP位图照片的几何变换_第20张图片

// GeometryTrans.h: interface for the GeometryTrans class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_GEOMETRYTRANS_H__02D0603E_60BD_4147_9F76_2CF74447F2F6__INCLUDED_)
#define AFX_GEOMETRYTRANS_H__02D0603E_60BD_4147_9F76_2CF74447F2F6__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "ImageDib.h"

class GeometryTrans : public ImageDib  
{
public:
    //输出图像每像素位数
    int m_nBitCountOut;

    //输出图像位图数据指针
    unsigned char * m_pImgDataOut;

    //输出图像颜色表
    LPRGBQUAD m_lpColorTableOut;
private:
    //输出图像的宽
    int m_imgWidthOut;

    //输出图像的高
    int m_imgHeightOut;

    //输出图像颜色表长度
    int m_nColorTableLengthOut;

public:
    //构造函数
    GeometryTrans();

    //带参数的构造函数
    GeometryTrans(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData);

    //析构函数
    ~GeometryTrans();

    //以像素为单位返回输出图像的宽和高
    CSize GetDimensions();

    //平移
    void Move(int offsetX, int offsetY);

    //缩放
    void Zoom(float ratioX, float ratioY);//缩放

    //水平镜像
    void MirrorHorTrans();

    //垂直镜像
    void MirrorVerTrans();

    //顺时针旋转90度
    void Clockwise90();

    //逆时针旋转90度
    void Anticlockwise90();

    //旋转180
    void Rotate180();

    //0-360度之间任意角度旋转 
    void Rotate(int angle);//angle旋转角度
};

#endif // !defined(AFX_GEOMETRYTRANS_H__02D0603E_60BD_4147_9F76_2CF74447F2F6__INCLUDED_)

(学习笔记4)BMP位图照片的几何变换_第21张图片

// GeometryTrans.cpp: implementation of the GeometryTrans class.
//
//

#include "stdafx.h"
#include "demo1.h"
#include "GeometryTrans.h"
#include "math.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//

GeometryTrans::GeometryTrans()
{

    m_pImgDataOut=NULL;//输出图像位图数据指针为空
    m_lpColorTableOut=NULL;//输出图像颜色表指针为空
    m_nColorTableLengthOut=0;//输出图像颜色表长度为0
    m_nBitCountOut=0;//输出图像每像素位数为0  
    m_imgWidthOut=0;//输出图像的宽为0
    m_imgHeightOut=0;//输出图像的高为0 
}

/***********************************************************************
* 函数名称: GeometryTrans()
* 函数参数: CSize size -图像大小(宽、高)
*            int nBitCount  -每像素所占位数
*            LPRGBQUAD lpColorTable  -颜色表指针
*            unsigned char *pImgData  -位图数据指针
* 返回值:   无
* 说明:本函数为带参数的构造函数,给定位图的大小、每像素位数、颜色表
*      及位图数据,调用ImgDib()对基类成员初始化,并初始化派生类的
*      数据成员
***********************************************************************/
GeometryTrans::GeometryTrans(CSize size, int nBitCount, LPRGBQUAD lpColorTable,
                             unsigned char *pImgData):
ImageDib(size, nBitCount, lpColorTable, pImgData)
{   
    //输出图像每像素位数与输入图像相同
    m_nBitCountOut=m_nBitCount;

    //输出图像颜色表长度
    m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

    //输出图像颜色表与输入图像相同
    if(m_nColorTableLengthOut){
        //分配颜色表缓冲区,进行颜色表拷贝
        m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
        memcpy(m_lpColorTableOut,m_lpColorTable, sizeof(RGBQUAD)*m_nColorTableLengthOut);
    }
    else// 彩色图像没有颜色表
         m_lpColorTableOut=NULL;

    //输出图像指针为空
    m_pImgDataOut=NULL;

    //输出图像宽和高置0
    m_imgWidthOut=0;
    m_imgHeightOut=0;
}

/***********************************************************************
* 函数名称:  ~GeometryTrans()
* 说明:析构函数,释放资源
***********************************************************************/
GeometryTrans::~GeometryTrans()
{
    //释放输出图像位图数据缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //释放输出图像颜色表
    if(m_lpColorTableOut!=NULL){
        delete []m_lpColorTableOut;
        m_lpColorTableOut=NULL;
    }
}


/***********************************************************************
* 函数名称: GetDimensions()
* 函数参数: 无
* 返回值:   图像的尺寸,用CSize类型表达
* 说明:返回输出图像的宽和高
***********************************************************************/
CSize GeometryTrans::GetDimensions()
{
    return CSize(m_imgWidthOut, m_imgHeightOut);
}

/***********************************************************************
* 函数名称:Move()
* 函数参数:int Xmove  -水平方向的平移量,以像素为单位
*           int Ymove  -垂直方向的平移量,以像素为单位
* 说明:当给定水平、垂直方向的位移量后,可实现对图像的平移操作,
        函数不改变图像的大小,超出图像的部分用黑色填充。
***********************************************************************/
void GeometryTrans::Move(int Xmove, int Ymove)
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输出图像的宽和高
    m_imgWidthOut=m_imgWidth;
    m_imgHeightOut=m_imgHeight;

    //每行像素字节数,输出图像与输入图像相等
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

    //置黑色
    memset(m_pImgDataOut,0,lineByte*m_imgHeight);

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //平移运算
    for(i=0;ifor(j=0;j//输出的点在输入图像范围内
            if(i-Ymove>=0&&i-Ymove=0&&j-Xmovefor(k=0;k/***********************************************************************
* 函数名称: MirrorHorTrans()
* 说明:对图像水平镜像
***********************************************************************/
void GeometryTrans::MirrorHorTrans()
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输出图像的宽和高
    m_imgWidthOut=m_imgWidth;
    m_imgHeightOut=m_imgHeight;

    //每行像素字节数,输出图像与输入图像相等
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //水平镜像
    for(i=0;ifor(j=0;jfor(k=0;k1-j)*pixelByte+k);
        }
    }
}

/***********************************************************************
* 函数名称: MirrorVerTrans()
* 说明:对图像垂直镜像
***********************************************************************/
void GeometryTrans::MirrorVerTrans()
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输出图像的宽和高
    m_imgWidthOut=m_imgWidth;
    m_imgHeightOut=m_imgHeight;

    //每行像素字节数,输出图像与输入图像相等
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //垂直镜像
    for(i=0;ifor(j=0;jfor(k=0;k1-i)*lineByte+j*pixelByte+k);
        }
    }
}

/***********************************************************************
* 函数名称: Clockwise90()
* 说明:对图像顺时针旋转90度
***********************************************************************/
void GeometryTrans::Clockwise90()
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输入图像每行像素字节数
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //输出图像的宽和高
    m_imgWidthOut=m_imgHeight;
    m_imgHeightOut=m_imgWidth;

    //输出图像每行像素字节数
    int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //顺时针90度
    for(i=0;ifor(j=0;jfor(k=0;k1-i)*pixelByte+k);
        }
    }
}


/***********************************************************************
* 函数名称: Anticlockwise90()
* 说明:对图像逆时针旋转90度
***********************************************************************/
void GeometryTrans::Anticlockwise90()
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输入图像每行像素字节数
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //输出图像的宽和高
    m_imgWidthOut=m_imgHeight;
    m_imgHeightOut=m_imgWidth;

    //输出图像每行像素字节数
    int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //逆时针90度
    for(i=0;ifor(j=0;jfor(k=0;k1-j)*lineByte+i*pixelByte+k);
        }
    }
}

/***********************************************************************
* 函数名称:Rotate180()
* 说明:对图像旋转180度
***********************************************************************/
void GeometryTrans::Rotate180()
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输出图像的宽和高
    m_imgWidthOut=m_imgWidth;
    m_imgHeightOut=m_imgHeight;

    //每行像素字节数,输出图像与输入图像相等
    int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

    //循环变量,图像坐标
    int i,j;

    //循环变量,像素的每个通道
    int k;

    //每像素字节数,输出图像与输入图像相等
    int pixelByte=m_nBitCountOut/8;

    //旋转180度
    for(i=0;ifor(j=0;jfor(k=0;k1-i)*lineByte+(m_imgWidth-1-j)*pixelByte+k);
        }
    }
}


/*************************************************************************
 * 函数名称: Zoom()
 * 参数:   float ratioX  -宽度缩放量
 *         float ratioY  -高度缩放量
 * 返回值: 无
 * 说明:   根据指定的大小和指定的插值方式,对原图像进行缩放,缩放后的结果存放
 *          在m_pImgDataOut缓冲区中,该函数同时适合于彩色和灰度图像
 ************************************************************************/

void GeometryTrans::Zoom(float ratioX, float ratioY)
{

    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //输出图像的宽和高
    m_imgWidthOut=int(m_imgWidth*ratioX+0.5) ;
    m_imgHeightOut=int(m_imgHeight*ratioY+0.5); 

    //输入图像每行像素字节数
    int lineByteIn=(m_imgWidth*m_nBitCount/8+3)/4*4;

    //输出图像每行像素字节数
    int lineByteOut=(m_imgWidthOut*m_nBitCount/8+3)/4*4;

    //申请缓冲区,存放输出结果
    m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];

    //每像素字节数,输入图像与输出图像相同
    int pixelByte=m_nBitCount/8;

    //输出图像在输入图像中待插值的位置坐标
    int coordinateX, coordinateY;

    //循环变量,输出图像的坐标
    int i, j;

    //循环变量,像素的每个通道
    int k;

    //近邻插值
    for(i=0; i< m_imgHeightOut; i++){
        for(j=0; j//输出图像坐标为(j,i)的像素映射到原图中的坐标值,即插值位置
            coordinateX=j/ratioX+0.5;
            coordinateY=i/ratioY+0.5;

            //若插值位置在输入图像范围内,则近邻插值
            if(0<=coordinateX&&coordinateX=0&&coordinateYfor(k=0;kelse //若不在输入图像范围内,则置255  
            {
                for(k=0;k255;
            }

        }
    }


}


/*************************************************************************
 * 函数名称:  Rotate()
 * 参数:   int angle  -旋转角度
 * 说明:   根据指定旋转角度,调用近邻插值旋转函数对原图像进行旋转,
 *         旋转结果输出至m_pImgDataOut缓冲区中,该函数同时适合于彩色和灰度图像
 ************************************************************************/
void GeometryTrans::Rotate(int angle)
{
    //释放旧的输出图像缓冲区
    if(m_pImgDataOut!=NULL){
        delete []m_pImgDataOut;
        m_pImgDataOut=NULL;
    }

    //每像素所占字节数,输入图像与输出图像相同
    int pixelByte=m_nBitCount/8;

    // 输入图像每行像素所占字节数
    int lineByte=(m_imgWidth*pixelByte+3)/4*4;

    // 旋转角度(弧度), 将旋转角度从度转换到弧度
    float   fRotateAngle= 2*3.1415926*angle/360;

    // 输入图像四个角的坐标,以图像中心为坐标系原点
    float   fSrcX1,fSrcY1,fSrcX2,fSrcY2,fSrcX3,fSrcY3,fSrcX4,fSrcY4;

    // 旋转后四个角的坐标,以图像中心为坐标系原点
    float   fDstX1,fDstY1,fDstX2,fDstY2,fDstX3,fDstY3,fDstX4,fDstY4;

    // 计算旋转角度的正弦
    float fSina = (float) sin((double)fRotateAngle);

    // 计算旋转角度的余弦
    float fCosa = (float) cos((double)fRotateAngle);

    // 计算原图的四个角的坐标,以图像中心为坐标系原点
    fSrcX1 = (float) (- (m_imgWidth  - 1) / 2);
    fSrcY1 = (float) (  (m_imgHeight - 1) / 2);
    fSrcX2 = (float) (  (m_imgWidth  - 1) / 2);
    fSrcY2 = (float) (  (m_imgHeight - 1) / 2);
    fSrcX3 = (float) (- (m_imgWidth  - 1) / 2);
    fSrcY3 = (float) (- (m_imgHeight - 1) / 2);
    fSrcX4 = (float) (  (m_imgWidth  - 1) / 2);
    fSrcY4 = (float) (- (m_imgHeight - 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;

    // 旋转后输出图像宽度
    m_imgWidthOut  = (LONG) ( max( fabs(fDstX4 - fDstX1), fabs(fDstX3 - fDstX2) ) + 0.5);

    // 旋转后输出图像高度
    m_imgHeightOut = (LONG) ( max( fabs(fDstY4 - fDstY1), fabs(fDstY3 - fDstY2) ) + 0.5);

    // 旋转后输出图像每行的字节数
    int lineByteOut=(m_imgWidthOut*pixelByte+3)/4*4;

    //分配缓冲区,存放旋转结果
    m_pImgDataOut = new unsigned char[lineByteOut*m_imgHeightOut];

    // 两个常数,这样不用以后每次都计算了
    float f1 = (float) (-0.5 * (m_imgWidthOut - 1) * fCosa 
                        + 0.5 * (m_imgHeightOut - 1) * fSina + 0.5 * (m_imgWidth  - 1));
    float f2 = (float) (-0.5 * (m_imgWidthOut - 1) * fSina 
                        - 0.5 * (m_imgHeightOut - 1) * fCosa + 0.5 * (m_imgHeight - 1));

    // 循环变量,输出图像坐标
    int i, j;

    //循环变量,像素的每个通道
    int k;

    //输出图像在输入图像中待插值的位置坐标,必须浮点型
    int coordinateX, coordinateY;

    // 最近邻插值旋转
    for(i = 0; i < m_imgHeightOut; i++)
    {
        for(j = 0; j < m_imgWidthOut; j++)
        {

            // 输出图像像素(j,i)映射到输入图像的坐标,近邻插值取整数
            coordinateX = (int)(j * fCosa - i * fSina + f1 + 0.5);
            coordinateY = (int)(j * fSina + i * fCosa + f2 + 0.5);

            // 判断是否在输入图像范围内
            if( (coordinateX >= 0) && (coordinateX < m_imgWidth) && (coordinateY >= 0) 
                && (coordinateY < m_imgHeight))
            {
                //将图像每个通道的数据进行分别插值,彩色图像pixelByte为3,
                //灰度图像pixelByte为1
                for(k=0; kelse
            {
                // 对于不在原图中的像素,赋值为255
                for(k = 0; k < pixelByte; k++)
                    *(m_pImgDataOut+i*lineByteOut+j*pixelByte+k) = 255;
            }

        }

    }

}



”平移“窗口
GeometryMoveDlg.h代码如下:
(学习笔记4)BMP位图照片的几何变换_第22张图片

/////////////////////////////////////////////////////////////////////////////
// GeometryMoveDlg dialog

class GeometryMoveDlg : public CDialog
{
// Construction
public:
    GeometryMoveDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
    //{{AFX_DATA(GeometryMoveDlg)
    enum { IDD = IDD_DIALOG_Move };
    int     m_Xmove;
    int     m_Ymove;
    //}}AFX_DATA


// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(GeometryMoveDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(GeometryMoveDlg)
        // NOTE: the ClassWizard will add member functions here
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
public:
    //afx_msg void OnBnClickedOk();
};

GeometryMoveDlg.cpp代码如下:
(学习笔记4)BMP位图照片的几何变换_第23张图片

/////////////////////////////////////////////////////////////////////////////
// GeometryMoveDlg dialog
// GeometryMoveDlg.cpp : implementation file
//

#include "stdafx.h"
#include "demo1.h"
#include "GeometryMoveDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

GeometryMoveDlg::GeometryMoveDlg(CWnd* pParent /*=NULL*/)
    : CDialog(GeometryMoveDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(GeometryMoveDlg)
    m_Xmove = 0;
    m_Ymove = 0;
    //}}AFX_DATA_INIT
}


void GeometryMoveDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(GeometryMoveDlg)
    DDX_Text(pDX, IDC_Edit_Xmove, m_Xmove);
    DDX_Text(pDX, IDC_Edit_Ymove, m_Ymove);
    //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(GeometryMoveDlg, CDialog)
    //{{AFX_MSG_MAP(GeometryMoveDlg)
        // NOTE: the ClassWizard will add message map macros here
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// GeometryMoveDlg message handlers


”缩放“窗口:

Zoomdlg.h代码如下:

#if !defined(AFX_ZOOMDLG_H__F466623C_B72C_4E57_A4A3_0DBEE2E271D3__INCLUDED_)
#define AFX_ZOOMDLG_H__F466623C_B72C_4E57_A4A3_0DBEE2E271D3__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// Zoomdlg.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// Zoomdlg dialog

class Zoomdlg : public CDialog
{
// Construction
public:
    Zoomdlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
    //{{AFX_DATA(Zoomdlg)
    enum { IDD = IDD_DIALOG_Zoom };
    float   m_XstrechRatio;
    float   m_YstrechRatio;
    //}}AFX_DATA


// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(Zoomdlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(Zoomdlg)
        // NOTE: the ClassWizard will add member functions here
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_ZOOMDLG_H__F466623C_B72C_4E57_A4A3_0DBEE2E271D3__INCLUDED_)

Zoomdlg.cpp代码如下:

// Zoomdlg.cpp : implementation file
//

#include "stdafx.h"
#include "demo1.h"
#include "Zoomdlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// Zoomdlg dialog


Zoomdlg::Zoomdlg(CWnd* pParent /*=NULL*/)
    : CDialog(Zoomdlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(Zoomdlg)
    m_XstrechRatio = 0.0f;
    m_YstrechRatio = 0.0f;
    //}}AFX_DATA_INIT
}


void Zoomdlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(Zoomdlg)
    DDX_Text(pDX, IDC_EDIT_strechW, m_XstrechRatio);
    DDX_Text(pDX, IDC_EDIT_strechH, m_YstrechRatio);
    //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(Zoomdlg, CDialog)
    //{{AFX_MSG_MAP(Zoomdlg)
        // NOTE: the ClassWizard will add message map macros here
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// Zoomdlg message handlers

”旋转任意角度“:

RotateDlg.h的代码如下:

#if !defined(AFX_ROTATEDLG_H__D9DBC9A7_DCF5_4698_B372_9D23993695E5__INCLUDED_)
#define AFX_ROTATEDLG_H__D9DBC9A7_DCF5_4698_B372_9D23993695E5__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// RotateDlg.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// RotateDlg dialog

class RotateDlg : public CDialog
{
// Construction
public:
    RotateDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
    //{{AFX_DATA(RotateDlg)
    enum { IDD = IDD_DIALOG_Rotate };
    int     m_RotateAngle;
    //}}AFX_DATA


// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(RotateDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(RotateDlg)
        // NOTE: the ClassWizard will add member functions here
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_ROTATEDLG_H__D9DBC9A7_DCF5_4698_B372_9D23993695E5__INCLUDED_)

RotateDlg.cpp的代码如下:

// RotateDlg.cpp : implementation file
//

#include "stdafx.h"
#include "demo1.h"
#include "RotateDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// RotateDlg dialog


RotateDlg::RotateDlg(CWnd* pParent /*=NULL*/)
    : CDialog(RotateDlg::IDD, pParent)
{
    //{{AFX_DATA_INIT(RotateDlg)
    m_RotateAngle = 0;
    //}}AFX_DATA_INIT
}


void RotateDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(RotateDlg)
    DDX_Text(pDX, IDC_EDIT_Rotate, m_RotateAngle);
    //}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(RotateDlg, CDialog)
    //{{AFX_MSG_MAP(RotateDlg)
        // NOTE: the ClassWizard will add message map macros here
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// RotateDlg message handlers

为什么这三个功能的实现需要这样去写,因为我绘制了3个窗口用来获取输入数据的。

接下来,将生成消息映射函数加上,加在demo1View.h中,如下图:

(学习笔记4)BMP位图照片的几何变换_第24张图片

    afx_msg void OnMove();
    afx_msg void OnHorizontalMirror();
    afx_msg void OnVerticalMirror();
    afx_msg void OnZoom();
    afx_msg void OnClockwise90();
    afx_msg void OnAnticlockwise90();
    afx_msg void OnRotate180();
    afx_msg void OnFreeRotate();

添加菜单的命令消息与消息处理代码绑在一起,通俗的去说就是”平移“这个ID的对应实现”平移“的OnMove函数捆绑一起,放在demo1View.cpp中,如下图:
(学习笔记4)BMP位图照片的几何变换_第25张图片

    ON_COMMAND(id_Move, OnMove)
    ON_COMMAND(id_HorizontalMirror, OnHorizontalMirror)
    ON_COMMAND(id_VerticalMirror, OnVerticalMirror)
    ON_COMMAND(id_Zoom, OnZoom)
    ON_COMMAND(id_Clockwise90, OnClockwise90)
    ON_COMMAND(id_Anticlockwise90, OnAnticlockwise90)
    ON_COMMAND(id_Rotate180, OnRotate180)
    ON_COMMAND(id_FreeRotate, OnFreeRotate)

消息处理程序的代码如下,直接放在demo1View.cpp最后面中:
(学习笔记4)BMP位图照片的几何变换_第26张图片

// Cdemo1View 消息处理程序
/

void Cdemo1View::OnMove() 
{
    // TODO: Add your command handler code here
    Cdemo1Doc *pDoc = GetDocument();
    ImageDib *pDib = pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8 && pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //平移参数设置对话框
    GeometryMoveDlg dlgPara;
    if(dlgPara.DoModal()== IDOK)
    {
        //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
        GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
            pDib->m_lpColorTable, pDib->m_pImgData);

        //将dlgPara.m_Xmove, dlgPara.m_Ymove作为平移量,对图像平移
        geoTrans.Move(dlgPara.m_Xmove, dlgPara.m_Ymove);


/*  */  //新建视图窗口,多文档显示变换结果
        CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
        pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
        Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
        Cdemo1Doc* pDocNew=pView->GetDocument();
        ImageDib *dibNew=pDocNew->m_dib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        pView->OnInitialUpdate();       
        pDocNew->SetModifiedFlag(TRUE);
        pDocNew->UpdateAllViews(pView);
        Invalidate();

//      单文档显示变换结果
/*
        CClientDC dc(this);
        ImageDib *dibNew = new ImageDib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),
            geoTrans.m_nBitCountOut,geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        dibNew->Draw(&dc,CPoint(0,0),dibNew->GetDimensions());
        pDib->Draw(&dc,CPoint(dibNew->GetDimensions().cx,0),pDib->GetDimensions());
 */
/*
        pDib->ReplaceDib(geoTrans.GetDimensions(),
            geoTrans.m_nBitCountOut,geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        Invalidate();
*/
    }   
}

void Cdemo1View::OnHorizontalMirror() 
{
    //获取文档类中m_dib的指针,访问当前DIB数据
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
    GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
        pDib->m_lpColorTable, pDib->m_pImgData);

    //水平镜像
    geoTrans.MirrorHorTrans();
   //显示变换结果
        CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
        pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
        Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
        Cdemo1Doc* pDocNew=pView->GetDocument();
        ImageDib *dibNew=pDocNew->m_dib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        pView->OnInitialUpdate();       
        pDocNew->SetModifiedFlag(TRUE);
        pDocNew->UpdateAllViews(pView);
        Invalidate();

}

void Cdemo1View::OnVerticalMirror() 
{
    //获取文档类中m_dib的指针,访问当前DIB数据
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
    GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
        pDib->m_lpColorTable, pDib->m_pImgData);

    //垂直镜像
    geoTrans.MirrorVerTrans();
   //显示变换结果
        CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
        pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
        Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
        Cdemo1Doc* pDocNew=pView->GetDocument();
        ImageDib *dibNew=pDocNew->m_dib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        pView->OnInitialUpdate();       
        pDocNew->SetModifiedFlag(TRUE);
        pDocNew->UpdateAllViews(pView);
        Invalidate();
}

void Cdemo1View::OnZoom() 
{
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0, L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //原图像尺寸
    CSize oldImgSize=pDib->GetDimensions();

    //缩放参数设置对话框
    Zoomdlg dlgPara;

    if(dlgPara.DoModal()==IDOK){
        //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
        GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
            pDib->m_lpColorTable, pDib->m_pImgData);

        //根据指定的缩放比例对对原图像进行缩放缩放
        geoTrans.Zoom(dlgPara.m_XstrechRatio,dlgPara.m_YstrechRatio);   

        //新建视图窗口,显示处理结果
        CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
        pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
        Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
        Cdemo1Doc* pDocNew=pView->GetDocument();
        ImageDib *dibNew=pDocNew->m_dib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,
            geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        pView->OnInitialUpdate();
        pDocNew->SetModifiedFlag(TRUE);
        pDocNew->UpdateAllViews(pView);
        Invalidate();
    }
}

void Cdemo1View::OnClockwise90() 
{
    //获取文档类中m_dib的指针,访问当前DIB数据
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0, L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
    GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
        pDib->m_lpColorTable, pDib->m_pImgData);

    //顺时针90度
    geoTrans.Clockwise90();

    //新建视图窗口,显示变换结果
    CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
    pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
    Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
    Cdemo1Doc* pDocNew=pView->GetDocument();
    ImageDib *dibNew=pDocNew->m_dib;
    dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,
        geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
    pView->OnInitialUpdate();
    pDocNew->SetModifiedFlag(TRUE);
    pDocNew->UpdateAllViews(pView);
    Invalidate();
}

void Cdemo1View::OnAnticlockwise90() 
{
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
    GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
        pDib->m_lpColorTable, pDib->m_pImgData);

    //逆时针90度
    geoTrans.Anticlockwise90();

    //新建视图窗口,显示变换结果
    CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
    pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
    Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
    Cdemo1Doc* pDocNew=pView->GetDocument();
    ImageDib *dibNew=pDocNew->m_dib;
    dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,
        geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
    pView->OnInitialUpdate();
    pDocNew->SetModifiedFlag(TRUE);
    pDocNew->UpdateAllViews(pView);
    Invalidate();
}

void Cdemo1View::OnRotate180() 
{
    //获取文档类中m_dib的指针,访问当前DIB数据
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8&&pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }

    //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
    GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
        pDib->m_lpColorTable, pDib->m_pImgData);

    //旋转180度
    geoTrans.Rotate180();

    //新建视图窗口,显示变换结果
    CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
    pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
    Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
    Cdemo1Doc* pDocNew=pView->GetDocument();
    ImageDib *dibNew=pDocNew->m_dib;
    dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,
        geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
    pView->OnInitialUpdate();
    pDocNew->SetModifiedFlag(TRUE);
    pDocNew->UpdateAllViews(pView);
    Invalidate();
}

void Cdemo1View::OnFreeRotate() 
{
    Cdemo1Doc *pDoc=GetDocument();
    ImageDib *pDib=pDoc->m_dib;

    //只处理灰度和彩色图像
    if(pDib->m_nBitCount!=8 && pDib->m_nBitCount!=24){
        ::MessageBox(0,L"只处理灰度和彩色图像",MB_OK,0);
        return ;
    }
    //旋转参数设置对话框
    RotateDlg dlgPara;
    if(dlgPara.DoModal() == IDOK){
        //定义GeometryTrans类的对象geoTrans,用当前DIB对其初始化
        GeometryTrans geoTrans(pDib->GetDimensions(),pDib->m_nBitCount,
            pDib->m_lpColorTable, pDib->m_pImgData);

        //调用Rotate函数进行图像旋转,将角度和插值方式参数传进函数
        geoTrans.Rotate(dlgPara.m_RotateAngle);

        //新建视图窗口,显示处理结果
        CMainFrame* pFrame = (CMainFrame *)(AfxGetApp()->m_pMainWnd);
        pFrame->SendMessage(WM_COMMAND, ID_FILE_NEW);
        Cdemo1View* pView=(Cdemo1View*)pFrame->MDIGetActive()->GetActiveView();
        Cdemo1Doc* pDocNew=pView->GetDocument();
        ImageDib *dibNew=pDocNew->m_dib;
        dibNew->ReplaceDib(geoTrans.GetDimensions(),geoTrans.m_nBitCountOut,
            geoTrans.m_lpColorTable, geoTrans.m_pImgDataOut);
        pView->OnInitialUpdate();
        pDocNew->SetModifiedFlag(TRUE);
        pDocNew->UpdateAllViews(pView);
        Invalidate();
    }
}

最后一步,进行运行测试:
平移测试,如下图所示:
(学习笔记4)BMP位图照片的几何变换_第27张图片

(学习笔记4)BMP位图照片的几何变换_第28张图片

水平镜像测试,如下图所示:
(学习笔记4)BMP位图照片的几何变换_第29张图片

旋转任意角度测试,如下图所示:
(学习笔记4)BMP位图照片的几何变换_第30张图片

(学习笔记4)BMP位图照片的几何变换_第31张图片

学习笔记4 由于时间匆忙,好多东西没解释,不懂的百度一下。
学习笔记5 将会对BMP位图照片进行灰度变换。

你可能感兴趣的:(图像处理与模式识别)