描线。同样,垂直百页窗清除的实现与垂直百页窗的显示相似,不同的是将绘制
位图换成画矩形而已。在下面的例子中,我将图像的分成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;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;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); ………………………………… 本文上面的内容介绍了几种图像的特殊显示效果,代码在Windows2000和Visual C++6.0编程环境下编译通过,运行正常,处理达到了预期的效果。读者可以将上面介绍的显示图像的函数和处理思路结合起来,实现更多效果 VC数字图像处理编程讲座之五 第四节 BMP图像操作的补充篇 上一讲中我们介绍了图像特效显示操作的实现方法,如随机显示效果、马赛克效果、拉幕显示效果等,由于篇幅的限制,还有许多效果没有介绍;本期讲座将接着上一讲的内容,继续介绍一些图像特效显示效果。 另外,我们前面的学习都是针对现成的BMP图像,在实际工作学习中,绝大部分处理图像过程都是在一个系统环境中,也就是说需要和图像数据的获取设备直接打交道,一般情况下,计算机图像处理系统从系统层次上可分为高、中、低档三个层次,目前比较普及的是低档次的系统,该系统由CCD(摄像头)、图像采集卡、计算机三个部分组成,其结构简单,应用方便,效果也比较不错,得到的图像较清晰,所以目前在工程应用中采用的比较多。这就给开发人员带来一个现实的问题,如何使用图像采集卡呢?目前虽然各种编程资源中基于VC开发经验的文章不少,但是关于如何在VC开发平台上使用图像采集卡的文章的确没发现,笔者借这期讲座的宝贵机会,补充介绍一下如何在程序中编写自己的代码来操作图像采集卡,从而搭建一个完整的图像处理系统。希望通过这部分内容的学习,在读者的脑海里就可以建立一个完整的图像操作系统概念;同时也能够给目 前正需要利用图像采集卡开发自己的图像处理系统的朋友有所帮助。 1. 抖动图像 在上一节讲座中,我们讲到了如何实现图象的\雕刻\和\浮雕\效果,它们的实现思想是通过求取\没有处理过的相邻两个像素之间的差值\来实现的。如果没 有限制\以前没有处理过的两个像素之间的操作\,取而代之的是\处理以前已经操作过的像素\,那末就可以将一个像素的灰度值传递到与其相邻的若干像素。事实上,有时后我们必须通过上述的约定才能实现一些效果,如图像的抖动效果。例如,为了使图象看起来好象从左上角向右下角扫过,以产生运动的感觉,必须要反复拷贝左上方的那些像素的灰度值,逐步把它们融合在一起,看起来好象图像后边有一些颜色在逐渐的消失,这就是我们要讲的图象的抖动效果。下面给出 了该效果的实现代码: void CDibView::OnDouDongImage() //产生\抖动\效果图函数 { HANDLE data1handle;//用来存放图像数据的句柄; LPBITMAPINFOHEADER lpBi;//图像的信息头结构; CDibDoc *pDoc=GetDocument();//得到文挡指针; HDIB hdib;//用来存放图像数据的句柄; unsigned char *pData;//指向原始图像数据的指针; unsigned char *data;//指向处理后图像数据的指针; hdib=pDoc->m_hDIB;//拷贝存放已经读取的图像文件数据句柄; lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);//获取图像信息头; pData=(unsigned char*)FindDIBBits((LPSTR)lpBi); //FindDIBBits是我定义的一个函数,根据图像的结构得到位图的灰度值数据; pDoc->SetModifiedFlag(TRUE); //设置文档修改标志为\真\,为后续的修改存盘作准备; e=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight); //声明一个缓冲区用来暂存处理后 据; data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);//得到该缓冲区的指针; AfxGetApp()->BeginWaitCursor(); int i,j,buf; for( i=lpBi->biHeight; i>=2; i--)//从图像右下角开始对图像的各个像素进行\抖动\处理; for( j=lpBi->biWidth; j>=2; j--) { //抖动处理、从图像的右下角开始计算图像斜上方相邻像素的均值; a+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)+*(pData+(lpBi->biHeight-i+1)*WIDTHBYTES(lpBi->biWidt if(buf>255) buf=255;//限制像素点的灰度范围为0-255; if(buf<0)buf=0; *(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf; } for( j=0; j //重新写回原始图像的数据缓冲区; i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j); AfxGetApp()->EndWai pDoc->m_hDIB =hdib//将处理过的图像数据写回pDoc中的图像缓冲区; GlobalUnlock((HGLOBAL)hdib);//解锁、释放缓冲区; GlobalUnlock((HGLOBAL)data1handle); GlobalFree((HGLOBAL)hdib); GlobalFree((HGLOBAL)data1handle);