如何通过vc编程实现对mbp图像的各种效果

如题所述

第1个回答  推荐于2016-01-30
经常看电视的朋友们不知注意到没有,最近的电视连续剧在每集片头或片尾部分都有显示一些特殊效果的图像,比如前一阵子中央一套放的《长征》、目前中央八套正在播放的《康熙王朝》,这些特效称为"图像的浮雕效果"和"图像的雕刻效果",经过这些特效处理后的图像增强了观众们的视觉效果,它们看上去仿佛是使用3D技术作的,这也是为什么这种技术那么流行的原因吧。其实,我们完全可以用一些简单的数字图像处理算法来实现这些看似复杂高深的显示效果。我们手头上的一些关于利用VC开发数字图像资料大都是讲解如何控制图像的每一行或每一列像素的显示时间或顺序来实现一些简单的图像显示效果,涉及到图像算法的文章很少,本文针对上述的这两种图像特效处理技术并加以引伸,讲解了一些实现图像特效算法,以一个标准的Lena灰度图像为原图,给出了处理后的效果图,同时给出了VC开发平台上的部分实现源代码。

  1."浮雕"图像

  "浮雕"图象效果是指图像的前景前向凸出背景。所谓的"浮雕"概念是指标绘图像上的一个像素和它左上方的那个像素之间差值的一种处理过程,为了使图像保持一定的亮度并呈现灰色,我在处理过程中为这个差值加了一个数值为128的常量。需要读者注意的是,当设置一个像素值的时候,它和它左上方的像素都要被用到,为了避免用到已经设置过的像素,应该从图像的右下方的像素开始处理,下面是实现的源代码:

void CDibView::OnFDImage() //产生"浮雕"效果图函数
{
 HANDLE data1handle;
 LPBITMAPINFOHEADER lpBi;
 CDibDoc *pDoc=GetDocument();
 HDIB hdib;
 unsigned char *hData;
 unsigned char *data;
 hdib=pDoc->GetHDIB();
 //我是如何打开图像文件并得到图像数据,请感兴趣的朋友参考
 //天极网上我的相关文章,那里有详细的论述,这里不再赘述。
 BeginWaitCursor();
 lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);
 hData=(unsigned char*)FindDIBBits((LPSTR)lpBi);
 pDoc->SetModifiedFlag(TRUE);
 data1handle=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--)
  {
   //"浮雕"处理
   buf=*(hData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)-*(hData+(lpBi->biHeight-i+1)*WIDTHBYTES(lpBi->biWidth*8)+j-1)+128;
   if(buf>255) buf=255;
   if(buf<0)buf=0;
   *(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf;
  }

  for( j=0; jbiHeight; j++)
   for( i=0; ibiWidth; i++)
    //重新写回原始图像的数据缓冲区
    *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j);
    AfxGetApp()->EndWaitCursor();
    GlobalUnlock((HGLOBAL)hdib);
    GlobalUnlock(data1handle);
    EndWaitCursor();
    Invalidate(TRUE);//显示图像
  }

2."雕刻"图像

  上面讲述了通过求一个像素和它左上方像素之间的差值并加上一个常数的方法生成"浮雕"效果的灰度图像,"雕刻"图像与之相反,它是通过取一个像素和它右下方的像素之间的差值并加上一个常数,这里我也取128,经过这样处理,就可以得到"雕刻"图像,这时候图像的前景凹陷进背景之中。同样需要读者注意的是为了避免重复使用处理过的图像像素,处理图像时要从图像的左上方的像素开始处理。实现代码如下:

void CDibView::OnDKImage()
{
 // TODO: Add your command handler code here
 HANDLE data1handle;
 LPBITMAPINFOHEADER lpBi;
 CDibDoc *pDoc=GetDocument();
 HDIB hdib;
 unsigned char *hData;
 unsigned char *data;
 hdib=pDoc->GetHDIB();
 BeginWaitCursor();
 lpBi=(LPBITMAPINFOHEADER)GlobalLock((HGLOBAL)hdib);
 hData=(unsigned char*)FindDIBBits((LPSTR)lpBi);
 pDoc->SetModifiedFlag(TRUE);
 data1handle=GlobalAlloc(GMEM_SHARE,WIDTHBYTES(lpBi->biWidth*8)*lpBi->biHeight);
 data=(unsigned char*)GlobalLock((HGLOBAL)data1handle);
 AfxGetApp()->BeginWaitCursor();
 int i,j,buf;
 //图像的"雕刻"处理
 for( i=0;i<=lpBi->biHeight-2; i++)
  for( j=0;j<=lpBi->biWidth-2; j++)
  {
   buf=*(hData+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)-*(hData+(lpBi->biHeight-i-1)*WIDTHBYTES(lpBi->biWidth*8)+j+1)+128;
   if(buf>255) buf=255;
   if(buf<0)buf=0;
   *(data+(lpBi->biHeight-i)*WIDTHBYTES(lpBi->biWidth*8)+j)=(BYTE)buf;
  }
 for( j=0; jbiHeight; j++)
 for( i=0; ibiWidth; i++)
  //重新将处理后的图像数据写入原始的图像缓冲区内
  *(hData+i*WIDTHBYTES(lpBi->biWidth*8)+j)=*(data+i*WIDTHBYTES(lpBi->biWidth*8)+j);
  AfxGetApp()->EndWaitCursor();
  GlobalUnlock((HGLOBAL)hdib);
  GlobalUnlock(data1handle);
  EndWaitCursor();
  Invalidate(TRUE);
 }

Lena原图
"雕刻"效果图
 "浮雕"效果图

用VC实现小型矢量图形系统的开发
大家学习了VC的MFC的一些基础知识后,如果能用VC开发一个比较实用的软件,对熟悉VC各方面编程和面向对象的软件设计和开发都是很有帮助的。

  本文旨在通过对一个作者自己开发的小型矢量图形系统全面讲述而达到让读者了解一个小软件从设计到实现的阶段的解决的问题。同时也从界面和功能上对MFC和Windows系统功能的挖掘,同样,对于学习计算机图形学的读者,也可以看到本文有很多对图形学算法和实现的有益探讨。

  一. 功能和界面设计

  首先,让大家对一个本软件功能的大概了解。当你着手开发一个软件时,首先要解决的当然是本软件的功能(软件工程常称作用例,具体概念可以参考有关资料,不妨简单理解为用户使用它能完成哪些工作)。由于写这篇文章时,本软件已经具有比较完整的原型。我们可以结合它的界面(图1)来介绍软件设计的过程。

       

  可以看到,本软件是实现了一个绘图功能的子集。最初就确定了开发环境为VC6.0,界面采用IE风格。在使用上为了给用户最大的便利,采用了三种工具条(普通文件、打印操作等标准工具,对图形对象属性设置的工具条式对话框,带文字说明的大按钮式可浮动或任意船坞- Dock定位的绘图工具条)。

  操作上采用左键点击建立图形对象起始点,移动动态调整图形大小和位置(随手画采用按住左键拖动的方式,再次点击左键确定位置,右键取消操作,双击确定(结束)多步图形对象(如多边形)的绘制。在功能设计方面基本符合一般图形软件的惯例,但出于作者的便利和保护鼠标的考虑,整个功能体现了基本无需按住左键拖动的思想。这也是很容易让人接受的,因为即便习惯拖动的用户拖动时也会产生位置调整,只是释放后还是出于拖动状态,再次点击或双击才最终确定。

  功能上选择了画线、框、圆、多边形、立体、文字、曲线、填充以及删除的功能,根据是否填充和光照又增加了几个类别,填充方式根据图形学的概念提供了两种方式(以后介绍)。根据对图形属性取了线宽、线型(很容易实现简单的线型,由于想加入更多的特性,作者先没有具体实现它,以后作者会提到它的实现,读者有兴趣可以试着实现)、边框色、填充色和字体几个属性。当然,这些功能在面向对象的方法中都是可以很方便扩展的(如画椭圆,选取对象,对象的位移和旋转操作,根据填充算法实现同色选取,即Photoshop等软件的魔棒功能等),对于橡皮擦功能可以很简单的实现特定工具或告诉用户如何实现此功能(即用背景色利用已有功能绘图)。

  内部实现上,要求单独记录各图形的关键属性(如位置、色彩等,这些是矢量图区别于位图的特点)。由于各对象可以形成对象链表,因此,也要求实现多步撤消(Undo)和重做(Redo)的功能,这往往是用户所十分期待的功能(Window自带的画笔附件程序在这点上就很欠缺)。

二. 对象设计

  面向对象的程序设计方法都支持三种基本的活动:识别对象和类,描述对象和类之间的关系,以及通过描述每个类的功能定义对象的行为。

  首先介绍一下对象(Object)和类(Class)的区别,类是同类对象数据凸δ艿拿枋龊褪迪郑–++中用Class关键字定义的是类),对象是类的在内存中的具体形态(用类名声明或用new操作生成的是对象变量),一般称对象为类的实例(Instance)。

  对于图形对象的对象设计由于它们的较强的相关性,往往在很多面向对象编程书都提到过,故相信读者识别对象和类不会很困难。但是,要充分利用继承和多态的特性来描述对象和类之间的关系,以及通过描述每个类的功能定义还是要具体问题具体分析的。本回答被提问者和网友采纳
相似回答