y1 = (x-xcenter) sinθ+ (y- ycenter) cosθ+ ycenter;
与图像的镜像变换相类似,下一步就是把原图中的(x,y)处象素的灰度值读入新缓冲区的(x1,y1)点处。注意在新缓冲区中与原图没有对应的象素点的值用白色或指定的灰度代替。
二、图像的分块显示和清除
1. 图像的扫描显示和清除
扫描显示图像是最基本的特效显示方法,它表现为图像一行行(或一列列)地显示出来或从屏幕上清除掉,有种大戏院种的拉幕效果。根据扫描的方向的不同,可以分为上、下、左、右、水平平分和垂直平分等六种扫描。这里以向下移动为例,分别介绍显示和清除的实现。其余的扫描效果可以依次类推。向下扫描显示的实现方法是:从图像的底部开始将图像一行一行的复制到目标区域的顶部。每复制一行后,复制的行数便要增加一行,并加上一些延迟;向下移动清除的实现方法是图像向下移动显示,并在显示区域的上部画不断增高的矩形。
1)扫描显示的代码:
CdibView::OnImageDownScan() {
CDibDoc *pDoc=GetDocument(); HDIB hdib;
CClientDC pDC(this);
hdib=pDoc->m_hDIB;//获取图像数据句柄;
BITMAPINFOHEADER *lpDIBHdr;//位图信息头结构指针; BYTE *lpDIBBits;//指向位图像素灰度值的指针;
HDC hDC=pDC.GetSafeHdc();//获取当前设备上下文的句柄;
lpDIBHdr=( BITMAPINFOHEADER *)GlobalLock(hdib);//得到图像的位图头信息; lpDIBBits=(BYTE*)lpDIBHdr+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);//获取指向图像像素值;
SetStretchBltMode(hDC,COLORONCOLOR); //显示图像;
for(int i=0;ibiHeight;i++)
{ //每次循环显示图象的\到\行数据;
SetDIBitsToDevice (hDC,0,0,lpDIBHdr->biWidth, lpDIBHdr->biHeight, 0, 0,0, i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS );
DelayTime(50);//延迟;
}
GlobalUnlock(hdib); return; }
2)清除代码:
.......................................//由于篇幅的限制,省略了与上面的相同代码
Cbrush brush(crWhite);//定义一个\白色\的刷子; Cbrush *oldbrush=pDC->SelectObject(&brush); for(int i=0;i < lpDIBHdr->biHeight ;i++)
{//每次循环将目标区域中的\到\行刷成\白色\;
pDC->Rectangle(0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight); DelayTime(50); }
.......................................
2. 百页窗效果
所谓百页窗显示效果,就如同关闭和开启百页窗一样,图像被分为一条条或一列列地分别显示或清除掉,根据显示时以行或列为单位可以将该效果分为垂直或水平两种方式。以垂直百页窗为例来说明如何实现这种特效显示。实现垂直百页窗显示时,需要将图像垂直等分为n部分由上向下扫描显示,其中每一部分包括m个条、这个n可以根据具体应用时的需要来决定、m既为图像的高度除n。扫描显示时,依照差值进行扫描显示,即第k次显示k-1、k*m-1、...k*n -1条扫描线。同样,垂直百页窗清除的实现与垂直百页窗的显示相似,不同的是将绘制位图换成画矩形而已。在下面的例子中,我将图像的分成8份。
....................................... int m=8;
int n=lpDIBHdr->biHeight/m;//图像的高度能够整除8; for(int l=1;l<=m;l++) for(int k=0;k
{ //每次循环依次显示图像中的k-1、k*m-1、...k*n-1行; StretchDIBits (hDC,0,4*k+l-1,lpDIBHdr->biWidth,1, 0, lpDIBHdr->biHeight-4*k-l+1,lpDIBHdr->biWidth,1, lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS,
SRCCOPY);//juanlianxiaoguo
DelayTime(50); }
.......................................
3.栅条显示特效
栅条特效是移动特效的复杂组合,可以分为垂直栅条和水平栅条两类。它的基本思想是将图像分为垂直或水平的的小条,奇数条向上或向左显示/清除,偶数条向下或向右显示/清除。当然也可以规定进行相反的方向显示/清除。下面的代码是实现垂直栅条的例子:
....................................... int m=8;
for(int i=0;i<=lpDIBHdr->biHeight;i++) for(int j=0;j<=lpDIBHdr->biWidth;j+=m) {//向下显示偶数条;
StretchDIBits (hDC,j,0,m,i,j,lpDIBHdr->biHeight-i, m,i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS,
SRCCOPY);//juanlianxiaoguo j=j+m;
//向上显示奇数条;
StretchDIBits (hDC,j,lpDIBHdr->biHeight-i,m,i,j,0, m,i,
lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS, SRCCOPY);// DelayTime(20);
}.......................................
4.马赛克效果
马赛克显示是指图像被分成许多的小块,它们以随机的次序显示出来,直到图像显示完毕。实现马赛克的效果主要解决的问题是如何定义显示随机序列的小方块,这个问题的解决可以在定义过小方块的基础上,用一个数组来记录各个方块的左上角的坐标的位置。显示图像过程中,产生一个随机数来挑选即将显示的小方块,显示后将该方块的位置坐标从数组中剔除。清除过程与之相仿。剔除显示过的方块的位置坐标的方法是将该数组中的最后的一个点的坐标拷贝到当前位置,然后删除数组中的最后点的坐标,经过实现发现这样处理有时显示的图像是不完整的,分析其原因是生成随机数的过程有舍入溢出误差。读者可以采用其它的办法解决这个问题,例如可以生成固定的随机数组或采用一个动态的数组来跟踪未显示的图像方块的坐标等方法。
....................................... int m,n;
int RectSize=60;//方块的宽、高尺寸为60个像素;
if(lpDIBHdr->biWidth%RectSize!=0)//得到图像水平方块的个数; m= lpDIBHdr->biWidth/RectSize+1; else
m= lpDIBHdr->biWidth/RectSize;
if(lpDIBHdr->biHeight%RectSize!=0)//得到图像垂直方块的个数; n= lpDIBHdr->biHeight/RectSize+1; else
n=lpDIBHdr->biHeight/RectSize;
POINT *point=new POINT[n*m];//申请一个数组用来记录各个方块的左上角的坐标;
POINT point1; for(int a=0;a for(int b=0;b {
point1.x=a*RectSize; point1.y=b*RectSize; *(point+a*b+b)=point1; }
//开始随机的显示各个小方块;
double fMax=RAND_MAX;//定义Rand()函数的最大值; for(int k=m*n-1;k>=0;k--) {
int c=(int)((double)(m*n)*rand()/fMax); int mx=point[c].x; int my=point[c].y;
//显示对应的图像的小块;
StretchDIBits (hDC,mx,my,RectSize,RectSize, mx,lpDIBHdr->biHeight-my,RectSize,RectSize, lpDIBBits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS, SRCCOPY);
point[c].x=point[k].x; point[c].y=point[k].y; DelayTime(50); }
.......................................
5.图像的淡入淡出效果
图像的淡入淡出的显示效果被广泛的应用在多媒体娱乐软件中,是一种特别重要的特效显示方法。淡入就是将显示图像的目标区域由本色逐渐过度的图像中的各个像素点的颜色;淡出就是由显示的图像逐渐过度到目标区域的本色。实现图像的淡入淡出有两种办法:一是均匀的改变图像的调色板中的颜色索引值;另
一种方法是改变图像像素的灰度值。第一种方法实现起来比较繁琐,第二种方法就比较简单。下面是我们采用第二种方法实现图像淡入效果的代码:
....................................... //申请一个与图像缓冲区相同大小的内存;
hdibcopy=(HDIB)GlobalAlloc(GMEM_SHARE,lpDIBHdr->biWidth*lpDIBHdr->biHeight);
lpbits=(BYTE*)GlobalLock(hdibcopy); //将缓冲区的数据初始化;
for(int k=0;kbiWidth*lpDIBHdr->biHeight;k++) {
*(lpbits+k)=(BYTE)255; }
//显示最初的图像为\白色\
StretchDIBits (hDC,0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight,0,0, lpDIBHdr->biWidth,lpDIBHdr->biHeight, lpbits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS, SRCCOPY);
//布尔变量end用来标志何时淡入处理结束; BOOL end=false; while(!end) { int a=0;
for(int k=0;kbiWidth*lpDIBHdr->biHeight;k++) {
//判断是否待显示的像素的灰度值已经小于原始图像对应点的灰度值,如是则计数;
if(*(lpbits+k)<*(lpDIBBits+k)) a++;
else//否则对应点的灰度值继续减少; *(lpbits+k)-=(BYTE)10; }
//显示处理后的图像数据lpbits;
StretchDIBits (hDC,0,0,lpDIBHdr->biWidth,lpDIBHdr->biHeight,0,0, lpDIBHdr->biWidth,lpDIBHdr->biHeight, lpbits,(LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS, SRCCOPY);
//如果所有的点的灰度值的都小于或等于原始图像的像素点的灰度值,则认为图像的淡入处理结束。
if(a==lpDIBHdr->biWidth*lpDIBHdr->biHeight) end=true; DelayTime(50);
.......................................