??xml version="1.0" encoding="utf-8" standalone="yes"?> 大多数实时网l游戏,?server 的时间和 client 的时间校对一致是可以带来许多其他pȝ设计上的便利的。这里说的对Ӟq去调?client ?os 中的旉Q而是?game client 内部的逻辑旉调整?server 一致即可?/p> 一个粗略的ҎҎ可以是这LQclient 发一个数据包l?serverQ里面记录下发送时刅Rserver 收到后,立刻l这个数据包d一个server 当前时刻信息Qƈ发还l?client 。因为大部分情况下,game server 不会立刻处理q个包,所以,可以在处理时再加一个时刅R两者相减,client 可以得包在 server 内部耽搁旉?/p> client 收到 server 发还的对时包Ӟ因ؓ他可以取出当初发送时自己附加的时M息,q知道当前时刻,也就可以出q个数据包来回的行程旉。这里,我们假定数据包来回时间相同,那么?server 通知的时_加上行程旉的一半,则可以将 client 旉?server 旉校对一致?/p> q个q程?udp 协议做比?tcp 协议来的好。因?tcp 协议可能因ؓ丢包重发引v教大误差Q?udp 则是自己控制Q这个误差要的多。只是,现在|络游戏?tcp 协议实现要比 udp 有优势的多,我们也不必ؓҎ另v一套协议走 udp ?/p> 一般的解决Ҏ用多ơ校对就可以了。因为,如果双方旉快慢一致的情况下,Ҏ包在|络上行E时间越短,׃定表明误差越。这个误差是不会过包来回时间的一半的。我们一旦在Ҏq程中得C个很的行程旉Qƈ在我们游戏逻辑的时间误差允许范围内Q就不需要再校对了?/p> 或者校对多ơ,发现|络比较E_Q虽然网速很慢)Q也可以认ؓ校对准确。这U情况下Q潜在的旉误差可能比较大。好在,一般,我们在时间敏感的包上都会携带旉戟뀂当双方旉校对误差很小的时候,client 发过来的旉x不应该早?server 真实时刻的。(当时间校对准后Qserver 收到的包上的旉戛_上数据包单行旉Q应该等?server 当前时刻Q?/p> 一?server 发现 client 的包“提前”收到了,只有一U解释:当初校对旉时糟p的|络状态带来了很多的时间误差,而现在的|络状态要明显优于那个时候。这Ӟserver 应该勒o client 重新Ҏ。同理,client 发现 server 的数据包“提前”到达Q也可以d?server 重新Ҏ?/p> 一个良好的Ҏ协议的设定,在协议上避免 client 旉作弊Q比如加速器Q或者减速器Q是可行的。这里不讨论也不分析更高U的利用游戏逻辑L间作弊的方式Q我们给数据包打上时间戳的主要目的也非防止时间作弊?/p> 校对旉的一般用途是用来实现更流畅的战斗pȝ和位|同步。因Z依赖|络传输的统一旉参照标准可以使游戏看h更ؓ实时?/p> 首先谈谈位置同步?/p> 好的位置同步一定要考虑|络延迟的媄响,所以,单把 entity 的坐标广播到 clients 不是一个好的方案。我们应该同步的是一个运动矢量以及时间信息。既Q无论是 client q是 server Q发出和收到的信息都应该是每?entity 在某个时ȝ位置和运动方向。这P接收方可以根据收到的时刻Q估出 entity 的真实位|。对?server 一方的处理Q只要要?client 按一个频?一般来说战斗时 10Hz 卛_Q而非战斗状态或 player 不改变运动状态时可以更低) l它发送位|信息。server 可以在网l状态不好的情况下依据最q收到的包估出现在 player 位置。?client 发出的每?player 位置信息Q都应该?server 信QQ用来去修正上次的估倹{?server 要做的只是抽查,或交l另一个模块去校验数据包的合法性(防止作弊Q?/p> ?server 端,每个 entity 的位|按 10Hz 的频率做Lq动卛_?/p> client 因ؓ涉及昄问题Q玩家希望看到的?entity 的连l运动,所以处理v来麻烦一炏Vserver 发过来的位置同步信息也可能因为网lgq晚收到。client 同样Ҏ最q收到的包做估算Q但是再收到的包和之前已l收到的信息估算l果不同的时候,应该做的是运动方向和速度的修正,可能的让下ơ的估算更准?/p> 关于战斗指o同步Q我希望是给所有战斗指令都加上冷却旉和引导时_q正?wow 的设计。这P信Q client 的时间戳Q就可以得到 client 准确的指令下达时间。引导时_或者是公共冷却旉Q可以充当网lgq时间的~冲。当然我们现在的设计会更复杂一些,q里不再列出。对于距L感的技能,例如q程d和范围魔法,我们的设计是有一个模p的 miss 判定公式Q解册边界的判定问题?/p> q里Q?server Ҏȝ标的位置做估的时候,可以不按上次发出包的q动方向d位置估计Q而选择用最有利于被d者的q动方向来做。这P可以减少|络状况差的玩家的劣ѝ?/p> 对于 PVE 的战斗,甚至可以做更多的取舍Q达到游戏流畅的效果。比如一个网l状态差的玩家去?npcQ他d npc 的时刻,npc 是处于攻击范围之内的。但是由于网lgq,数据包被 server 收到的时候,npc 已经d。这个时?server 可以?client 的逻辑来将 npc 拉会原来的坐标?/p> 虽然Q这样做Q可能会引v其他玩家Q旁观者) client 上表现的不同。但是,|络游戏很多情况下是不需要严格同步的。在不媄响主要游戏逻辑的情况下Qplayer 的手感更为重要?/p> 在FPU中,却存在着三种q算_ֺQsingle precision(24bits)Qdouble precision(53bits)(一般应用程序启动时的精?Qdouble extended precision(64bitsQ很用)。FPU的默认精度是53bits的double precision。D3D的CreateDevice函数会将FPU的运精度改?4bits。除非指定了D3DCREATE_FPU_PRESERVE参数Q否则不能你的应用程序Q点精度也会降低?br style="LINE-HEIGHT: 20px"> 悲剧的是你不能确认dx或者其他程序是否给你切换回来,感觉有些dx版本有bugQ即使设|D3DCREATE_FPU_PRESERVE也不会切换回来。这是我们需要手动切?br style="LINE-HEIGHT: 20px"> unsigned int uiFloat; ....... pd前面的两文章写的内容太单了Q本文对我理解的GDI+做一个综qͼ不再涉及代码l节?br> 全局变换通过Graphics.Transform指定Q其cd为Matrix。GDI+中的矩阵?x3点矩阵Q可以通过MatrixcȝҎ和属性来修改全局变换Q也可以通过GraphicscM的TranslateTransform{方法来讑֮。页面变换通过GraphicscȝPageUnit和PageScale来设定坐标单位和~放倍数?/font> Point, Size, Rectangle是GDI+中常用的度量cdQƈ且都h对应的floatcd。Color则代表了32位A8R8G8B8的颜艌Ӏ这一些都是基本的值类型,在实际用的时候,要牢记其值类型的特征Q类似o.Size.Width = 100的代码是没有作用的,因ؓ.Width = 100是作用在了o.Sizeq回的时变量上了,对于o的状态没有Q何媄响?/font> GraphicsPathQRegion, Image则是GDI+中的一些资源性的cdQ在使用完成后要快Dispose。GraphicsPath是一pdq箋的线Q包含直U和曲线。Region则表C封闭的一个区域,q个区域的边界可以由GraphicsPath来描q。Image表示一个图形,其中表现像素l成的位囄zcMؓBitmapQ表现失量绘图指令组成的囑Ş的派生类为Metafile。计机屏幕最擅长展现两维的数据,因此Rectangle视ؓ最单的一URegionQƈ且应用面也非常广泛,计算包含整个Region的Rectangle也是非常常见的一U操作?/font> Brush用来填充一个RegionQ填充时可以使用单色填充Q可以用纹理(囄Q填充,也可以用线型填充和渐变填充Q?NET中封充的GDI+提供了SolidBrushQTextureBrushQHatchBrushQLinearGradientBrush和PathGradientBrushcRBrush也是需要及时Dispose的,对于SolidBrushQ可使用SystemBrushes和Brushes中的静态属性,获取预定义的Brush对表Q免去Dispose的麻烦?/font> Pen是用来画U的QGDI+的线是有宽度的,也就有其内部区域Q因此GDI+中的Pen需要一个Brush实例来构造。同样SystemPens和Pens中提供了预定义的单色Pen实例?/font> 此外Font对象用来实现GDI+中不同字体的输出QGraphicscL供了一个MeasureStringҎ计算一D字W串l制出来时占据的区域大小?/font> GraphicscL供了一pdDraw...ҎQ用特定的Pen来绘制一定的形状QFill...pd则用特定的Brush来填充指定区域?/font> Graphics的Clip属性通过一个Regioncȝ实例指定GDI+有效l制区域Q这是一个基信息QGraphics的属性ClipBoundsQIsClipEmptyQIsVisibleClipEmptyQVisibleClipBounds均基于Clip属性,q且为只ȝ?/font> CompositingQualityQInterpolationModeQPixelOffsetModeQSmoothingModeQTextRenderingHint用来控制l制输出质量Q质量越高,速度慢。CompositingMode用来启用Alpha BlendQTextContrast控制文本输出时的Gamma|RenderingOrigin用来控制8bit/16bit色深时的色彩拌动和Hatch Brush的v始点?br> 1. BMP文gl成 计算机彩色显C器昄色彩的原理与彩色电视ZP都是采用RQ?span>RedQ?span>GQ?span>GreenQ?span>BQ?span>BlueQ相加色的原理Q通过发射ZU不同强度的电子束,使屏q内侧覆盖的U、绿、蓝光材料发光而生色彩。这U色彩的表示ҎUCؓRGB色彩I间表示Q它也是多媒体计机技术中用得最多的一U色彩空间表C方法)?/span> 调用模型 利用面向对象思想多态?调用方保存着被调用方的基接口指针(一般称gؓ 钩子),调用方直接调用接口指针里面方?Ҏ具体实现逻辑?/p>
该接口的zcd?C意? 为系l功能设计,需要处理网l事件数据SocketEventQ数据库事g数据DatabaseEventQ定时器事g数据TimerEvent{,为此建立数据队列?/p>
务QueueService,为每一队列建立多个子线EQueueServiceThread处理。数据队列服务提供添加事件数据方法AddToQueueQ设|数据队列服务钩 子SetQueueServiceSinkQ让数据队列服务钩子QueueServiceSink做具体逻辑事g数据处理?br>C意? 理接口,外部处理接口具体׃ơ开发用户实现。示意图: 事g数据设计 功能模块划分 数据队列服务QueueService模块设计 基本设计概念 建立一个内存链表,保存事g数据Q对外部提供Ҏ往链表d事g数据q知U程Q同时启动多个处理线E,从数据链表里获取事g数据Q执行外部钩子方法进行处?U程事g通知采用完成端口技? cM接口设计 接口设计 本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/dotnet90/archive/2009/05/05/4152401.aspx
]]>
一步一步的调试Q发现经常出现指针异常的变量L在调用autorelease后一会就莫名其妙再用的时候就抛异常。狠下心Q在它的析构函数里面断点+Log输出信息。发现对象被释放了。一时也很迷p,因ؓ对象只是
autorelease,q没有真正释放,是谁D它释攄Q?br style="word-wrap: break-word; " />
然后去看了CCAutoreleasePool的源码,发现存在Cocos2d-X的内存管理在多线E的情况下存在如下问?br style="word-wrap: break-word; " />
如图Qthread 1和thread 2是独立的两个U程Q它们之间存在CPU分配的交叉集Q我们在time 1的时候push一个autorelease的自动释放池Q在该线E的末尾Q即time 3的时候pop它。同理在thread 2的线E里面,在time 2的时候push一个自动释放池Q在time 4的时候释攑֮Q即Pop.
此时我们假设在thread 2分配得到CPU的时候有一个对象obj自动释放Q即obj-autorelease().那么在time 3的时候会发生是么事情呢?
{案很简单,是obj在time 3的时候就被释放了Q而我们期望它在time 4的时候才释放。所以就D我上面说的,在多U程下面Qcocos2d-x的autorelease变量会发生莫名其妙的指针异常?/strong>
解决办法Q?/strong>在PoolManagerl每个线E根据pthread_t的线Eid生成一个CCArray的stack的嵌套管理自动释放池。源码如?br style="word-wrap: break-word; " />所以我在Push的时候根据当前线E的pthread_t的线Eid生成一个CCArray的stack来存储该U程对应的Autoreleasepool的嵌套对?br style="word-wrap: break-word; " />源码如下
转自Q?a >http://www.ityran.com/thread-3364-1-1.html
]]>
许多人开始跑步就是因为减肥,跑步实减肥的最好运动方式,跑步每分钟比起其他运动燃烧更多的卡\里?nbsp;
2.防止你的骨骼Q肌肉退化?nbsp;
我们的骨骼是和你的n体需求相互协调的。长期坐在显C器前的我们让我们的骨骼来脆弱。而长期的Q经常的q动会你的骨骼保持健康。更q一步说是防止我们w体内部老化的更快。经常的高强度锻|例如跑步Q被证明可以促进Z荷尔蒙的生长Q荷蒙是那些名hZ看v来更q轻而持l注的药剂?nbsp;
3.抉|疄
跑步可以降低得中风和乌癌的风险。经常的跑步已经成ؓȝ寚w些容易引发或在已l处在早期的骨质疏松Q糖病Q高血压病人的ȝ?nbsp;
4.l持q提高M的n体水q?nbsp;
跑步是是Z可以采取的最好的ȝw体的运动。它可以提高胆固?降低血液凝块的危险Q锻g?0%的经常处于闲|状态的肺。跑步还可以通过增加你的淋巴l胞来增Z的免疫力?nbsp;
5.让你更加自信?nbsp;
慢跑像其他一些单动一P它可以增Z的自信心。跑步让你完成一ơ又一ơ的试Q让你变得更强大Q更加肯定自己。他让你真实的越q某个山峎ͼI过某个障碍.在意识到你的w体已经更加强壮Q更加有用,你会得到被赋予力量和自由的感觉。自信更是那些通过跑步成功的减肥ƈ得到自己心中理想w材的跑步者的宝贵财富?nbsp;
6.放松自己Q减d力?nbsp;
慢跑可以转移聂注意力Q沐在路旁的风景中Q你的烦g定会消失D尽?nbsp;
长跑适合那些正处在一堆头|gh的烦心事的h。还有比在两个小时的长跑中,清理的的头脑、舒~自q经更好的主意了吗?nbsp;
如果你此时觉得异常压抑,何不快跑一下呢Q之后你会一个好的心情?nbsp;
7.著名?#8220;跑步者高C?#8221;
包括释放压力Q慢跑被证明提高你的心态。跑步,特别在户外和旅行?会w体释放一U物质让你生一U幸愉悦感Q跑步者高C验)或者就是快乐的感觉。跑步已l被采用了多q来ȝ临床抑郁症,上瘾{。更的压力Q更的压抑Q更的疲劳Q更的混ؕQ经q一D|间的l常跑步Q病人很快就有了变化。跑步让他们有了注意的对象,让他们看C除了他们消极的状态和沉h的事务,q有一些美好的东西的存在?nbsp;
8.ȝ你的头脑?nbsp;
像对你的w体有所帮助一P跑步同样对你的头脑很有帮助。通过在跑步中克服一pd的障,你学会了专注和决?在经历那些你几乎要放弃的长跑或其他项目后你会发现Q你在跑步过E中产生的意志和体魄的增你在其他斚w有着同样的专注和军_?nbsp;
9.增强合作_?nbsp;
又是一个非常值得d的好处。这点好处或许让很多人感到惊奇,因ؓZ认ؓ跑步不可能得到这U益处,仅仅׃跑步是单动。但是跑步确实有时涉及到互相合作。旅行跑步,特别是在那些路况不好的地方,需要极大的合作意识。这些\面经怼有一?障碍如石头、灌木让跑步q行的很困难?nbsp;
10.随时随地Q简单?nbsp;
不是很多的运动可以在M地方Q几乎不需要设备的。我敢肯定古代希腊h会争辩说甚至是鞋子和衣服也不需要。今天,我们只是需要一双好点的跑步鞋然后就可以出发了。从市中心到郊区,整个世界的地方等待你的探索。经常出差吗Q你的旅行箱里肯定会有空间来装你的运动鞋的。这个世界就是你的健w房Q去再次发现它吧?nbsp;
Here are some tips for how to make running a practice:
Be consistent in your running program. Plan your weekly workout schedule and stick to it. This will teach you persistence.
Know which focuses you'll use during every run. This will teach you planning and mindfulness, and improve your mind/body connection.
Constantly practice relaxing your muscles. This will help to relieve tension and train you to relax no matter what activity you're doing.
At the end of your run, spend a few minutes doing an "end-of-run review." Ask yourself how well you did with keeping your focuses, how your body felt during the run. What did you come away with that will help your next run? Then, the next time you go out for a run, you'll have something to work on that you brought forward from your last run. In this way you'll build a healthy, growing and sustainable running program.
转自Q?a >http://www.douban.com/group/topic/20749798/
]]>
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&g_pd3dDevice)))
{
return FALSE;
}
q是 CreateDevice 函数修改了系l的点q算_ֺQ只要加?D3DCREATE_FPU_PRESERVE 选项卛_解决Q修改后的代码如下:
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_FPU_PRESERVE,
&d3dpp,
&g_pd3dDevice)))
{
return FALSE;
}
参考资料:
http://topameng.spaces.live.com/Blog/cns!F962D4854A8233D!396.entry?wa=wsignin1.0&sa=56810441
D3DCREATE_FPU_PRESERVE
_controlfp_s(&uiFloat, 0, 0);
_controlfp_s(0, _PC_53, MCW_PC); //切换到double_ֺ
_controlfp_s(0, uiFloat, MCW_PC); //切换到原来的_ֺ
]]>
GDI+中共有三U坐标,全局坐标、页面坐标和讑֤坐标。在GDI+的绘图调用中Q传入的坐标位于全局坐标内,全局坐标l由全局变换转换到页面坐标,面坐标再通过面变换计算备坐标?/font>
q些内容对之后的Minesweeper内容_了,如果有问题,Ƣ迎在评Z提出?/font>
]]>
四大囑փ库的使用感受:OpenCV/FreeImage/CImg/CxImage
对OpenCV的印象:功能十分的强大,而且支持目前先进的图像处理技术,体系十分完善Q操作手册很详细Q手册首先给大家补计机视觉的知识,几乎늛了近10q内的主算法;然后图像格式和矩阵q算Q然后将各个法的实现函数。我用它来做了一个Harris角点器和Canny边缘器Qdp了一个小ӞW一ơ用OpenCVQ。而且该库昄囑փ极其方便Q两句话可以。但该库g不大E_Q对32F?6S?U的图像数据支持上bug重重。我用cvFilter2D函数q行U性o波,屡屡出错Q后来一查原来是大bug。后来用cvmGet来取矩阵元素也是频繁出错Q仔l检查了N遍确保程序没问题之后在yahoogroup上找到答案:仍然是bug。。。但好歹该库是开攄Q所以自己可以修改;而且支持CVS。另外该库用的是IPL矩阵库,速度奇快~~
对CxImage考察的印象:该开发包完全开放源代码Q图像封装ؓ一个类Q功能极为强大,与Windows、MFC支持极好Q支持图像的多种操作Q线性o波、中值o波、直方图操作、旋转羃放、区域选取、阈值处理、膨胀腐蚀、alpha混合{等Q,支持从文件、内存或者win32api定义的位囑֛像格式中d囑փQ支持将囑փ昄在Q意窗口,功能可谓很强大了Q而且对像素的操作很方便,另外q有一个界面很强的demoQ可以直接在上面q行二次开发,推荐使用Q?br>~点Q里面的子库很多Q用h可能较麻烦;而且感觉速度E慢Q不如后面提到的freeimage
但功能真的十分强大啊Q?br>
CImgQ就一?h文g所以用h很简明,但感觉功能上不如CxImage。可以与CxImage配合使用Q因为CImg提供了基于lapack的矩阵运函数和完善的线性o波卷U函敎ͼ同时CImg做像素运还是很方便的。另外,独有Displaycd以方便的实现各种昄Q包括显C图像、打字、画U等{。还有,该库有个Z光流的多度囑փ配准例子Q很?br>
FreeImageQC语言的体p,大量使用指针q算速度可以保证Q内含先q的多种插值算法。另外独有的支持meta exif信息的读取。该库最大的特点是比较l,只把重点攑֜对各U格式图像的d写入支持上,没有昄部分Q实际编E的时候还是需要调用API函数q行昄
OpenCV 参考手?/div>
深度囑փ理解
http://blog.csdn.net/thirdapple/category/117113.aspx
一个边~识别算法代?br>http://www.moon-soft.com/download/soft/2157.htm
|友评论
本站|友
旉Q?008-03-15 23:58:05 IP地址Q?19.225.53.?/td>
CImg 是一个用C++~写的开源数字图像处理库?br>
作者介l?br>
作者David TschumperléQ?nbsp;之前是法国La Rochelle大学的一名教授,现受雇于CNRS 囑փl。据说作者从1998q写博士论文时就开始写q个库。作者主:http://www.greyc.ensicaen.fr/~dtschump/ Q里面有更多关于作者本人的消息?br>
库的特点
q个库与一般的cd最大的不同点在于,不像其他的图像处理类库,CImg所有的代码都包含在一个文件中QCImg.hQ。库的设计用了C++模板技术,支持多种数据cdQ且库的设计机器单明了。库包含了这几个模块Q首先是CImgc,q是库的MQ基本上Z囑փ的操作都在这个类里实C。第二个是CImgDisplayc,该类用于昄处理后的囑փ。我们在用c++处理囑փӞL要花好多功夫在图像的昄上,CImgDisplay的设计就是ؓ解决q个问题而写的。有了它Q我们可以像用Matlab一h便的昄囑փ。第三个重要的类是CImgList该类主要为处理序列图像?br>
该库q有一个特Ҏ可移植性,同时支持Windows和linuxQFreeBSD{等?br>
该库支持多种囑փ格式的读取与保存Q不q个为,除了bmp文g外,d其他文g旉是先用ImageMagic的convertE序转换格式在读取,所以速度很慢。读取bmp文g很快?br>
如何使用
在该库发布的下蝲文g中包含了很多演示E序。要使用它,首先下载下来的CImg.h文g拯C的编译器搜烦的include文g夹中Q然后在源代码写上:
#include "CImg.h"
using namespace cimg_library;
p么简单,你就可以使用所有的库函数?br>
下面是作者给的一个例子:
#include "CImg.h"
using namespace cimg_library;
int main() {
CImg<unsigned char> image("lena.jpg"), visu(500,400,1,3,0);
const unsigned char red[] = { 255,0,0 }, green[] = { 0,255,0 }, blue[] = { 0,0,255 };
image.blur(2.5);
CImgDisplay main_disp(image,"Click a point"), draw_disp(visu,"Intensity profile");
while (!main_disp.is_closed && !draw_disp.is_closed) {
main_disp.wait();
if (main_disp.button && main_disp.mouse_y>=0) {
const int y = main_disp.mouse_y;
visu.fill(0).draw_graph(image.get_crop(0,y,0,0,image.dimx()-1,y,0,0),red,1,255,0);
visu.draw_graph(image.get_crop(0,y,0,1,image.dimx()-1,y,0,1),green,1,255,0);
visu.draw_graph(image.get_crop(0,y,0,2,image.dimx()-1,y,0,2),blue,1,255,0).display(draw_disp);
}
}
return 0;
}
你可以直接将上面的源代码保存C?cpp文g然后~译查看效果。当Ӟ在项目所在文件夹中必d含有囄lena.jpg?br>
技术支?br>
该库有非常详l的文档说明随源代码一起发布。http://cimg.sourceforge.net/index.shtml q是sourceforge上该目的主,有论坛,我觉得作者非常认真负责,l常在上面ؓ|友解答问题Q详l细致?br>
]]>
高斯qx 高斯模糊 高斯滤L器:http://blog.csdn.net/hhygcy/archive/2009/07/07/4329056.aspx
对Photoshop高斯模糊滤镜的算法ȝ Q?a >http://www.cnblogs.com/hoodlum1980/archive/2008/03/03/1088567.html
]]>
BMP文g由文件头、位图信息头、颜色信息和囑Ş数据四部分组成。文件头主要包含文g的大、文件类型、图像数据偏L件头的长度等信息Q位图信息头包含图象的尺怿息、图像用几个比特数值来表示一个像素、图像是否压~、图像所用的颜色数等信息。颜色信息包含图像所用到的颜色表Q显C图像时需用到q个颜色表来生成调色板,但如果图像ؓ真彩Ԍ既图像的每个像素?4个比Ҏ表示Q文件中没有这一块信息,也就不需要操作调色板。文件中的数据块表示囑փ的相应的像素|需要注意的是:囑փ的像素值在文g中的存放序Z左到叻I从下CQ也是_在BMP文g中首先存攄是图像的最后一行像素,最后才存储囑փ的第一行像素,但对与同一行的像素Q则是按照先左边后右边的的顺序存储的Q另外一个需要读者朋友关注的l节是:文g存储囑փ的每一行像素值时Q如果存储该行像素值所占的字节Cؓ4的倍数Q则正常存储Q否则,需要在后端?Q凑?的倍数?
2. BMP文g?
BMP文g头数据结构含有BMP文g的类型、文件大和位图起始位置{信息。其l构定义如下:
2 {
3 WORD bfType; // 位图文g的类型,必须?#8220;BM”
4 DWORD bfSize; // 位图文g的大,以字节ؓ单位
5 WORD bfReserved1; // 位图文g保留字,必须?
6 WORD bfReserved2; // 位图文g保留字,必须?
7 DWORD bfOffBits; // 位图数据的v始位|,以相对于位图文g头的偏移量表C,以字节ؓ单位
8 } BITMAPFILEHEADERQ该l构占据14个字节?nbsp;
3. 位图信息?
BMP位图信息头数据用于说明位囄寸{信息。其l构如下Q?br>
2 DWORD biSize; // 本结构所占用字节?/span>
3 LONG biWidth; // 位图的宽度,以像素ؓ单位
4 LONG biHeight; // 位图的高度,以像素ؓ单位
5 WORD biPlanes; // 目标讑֤的^面数不清Q必Mؓ1
6 WORD biBitCount// 每个像素所需的位敎ͼ必须?(双色), 4(16?Q?(256??4(真彩?之一
7 DWORD biCompression; // 位图压羃cdQ必L 0(不压~?,1(BI_RLE8压羃cd)?(BI_RLE4压羃cd)之一
8 DWORD biSizeImage; // 位图的大,以字节ؓ单位
9 LONG biXPelsPerMeter; // 位图水^分L率,每米像素?/span>
10 LONG biYPelsPerMeter; // 位图垂直分L率,每米像素?/span>
11 DWORD biClrUsed;// 位图实际使用的颜色表中的颜色?/span>
12 DWORD biClrImportant;// 位图昄q程中重要的颜色?/span>
13 } BITMAPINFOHEADERQ该l构占据40个字节?nbsp;
注意Q对于BMP文g格式Q在处理单色囑փ和真彩色囑փ的时候,无论图象数据多么庞大Q都不对图象数据q行M压羃处理Q一般情况下Q如果位N用压~格式,那么16色图像采用RLE4压羃法Q?56色图像采用RLE8压羃法?br>
4. 颜色?
颜色表用于说明位图中的颜Ԍ它有若干个表,每一个表Ҏ一个RGBQUADcd的结构,定义一U颜艌ӀRGBQUADl构的定义如?
2 BYTErgbBlue;// 蓝色的亮?D围ؓ0-255)
3 BYTErgbGreen; // l色的亮?D围ؓ0-255)
4 BYTErgbRed; // U色的亮?D围ؓ0-255)
5 BYTErgbReserved;// 保留Q必Mؓ0
6 } RGBQUAD;
颜色表中RGBQUADl构数据的个数由BITMAPINFOHEADER 中的biBitCountҎ定Q当biBitCount=1,4,8Ӟ分别?,16,256个颜色表,当biBitCount=24Ӟ囑փ为真彩色Q图像中每个像素的颜色用三个字节表示Q分别对应R、G、B|囑փ文g没有颜色表项。位图信息头和颜色表l成位图信息QBITMAPINFOl构定义如下:
2 typedef struct tagBITMAPINFO {
3 BITMAPINFOHEADER bmiHeader; // 位图信息?/span>
4 RGBQUAD bmiColors[1]; // 颜色?/span>
5 } BITMAPINFO;
注意QRGBQUAD数据l构中,增加了一个保留字DrgbReservedQ它不代表Q何颜Ԍ必须取固定的gؓ“0”Q同ӞRGBQUADl构中定义的颜色gQ红艌Ӏ绿色和蓝色的排列顺序与一般真彩色囑փ文g的颜色数据排列顺序恰好相反,既:若某个位图中的一个像素点的颜色的描述?#8220;00Q?0QffQ?0”Q则表示该点为红Ԍ而不是蓝艌Ӏ?br>
5. 位图数据
位图数据记录了位囄每一个像素值或该对应像素的颜色表的索引|囑փ记录序是在扫描行内是从左到?扫描行之间是从下C。这U格式我们又UCؓBottom_Up位图Q当然与之相对的q有Up_Down形式的位图,它的记录序是从上到下的Q对于这UŞ式的位图Q也不存在压~Ş式。位囄一个像素值所占的字节敎ͼ当biBitCount=1Ӟ8个像素占1个字节;当biBitCount=4Ӟ2个像素占1个字节;当biBitCount=8Ӟ1个像素占1个字节;当biBitCount=24?1个像素占3个字节,此时囑փ为真彩色囑փ。当囑փ不是为真彩色Ӟ囑փ文g中包含颜色表Q位囄数据表示对应像素点在颜色表中相应的烦引|当ؓ真彩色时Q每一个像素用三个字节表示囑փ相应像素点彩色|每个字节分别对应R、G、B分量的|q时候图像文件中没有颜色表。上面我已经讲过了,Windows规定囑փ文g中一个扫描行所占的字节数必L4的倍数(即以字ؓ单位),不的以0填充Q图像文件中一个扫描行所占的字节数计方法:
2
3 或?br> 4 DataSizePerLine= (biWidth* biBitCount+31)/32 * 4Q?/span>// 一个扫描行所占的字节?nbsp;
5
6 (如果biBitCount == 8 ?4)
7
8 DataSizePerLine= (biWidth* 3+3)/4*4Q?/span>// 一个扫描行所占的字节?nbsp;
9
10 ?br>11
12 DataSizePerLine= (biWidth*1+3)/4*4Q?/span>// 一个扫描行所占的字节?nbsp;
13
位图数据的大按下式计算(不压~情况下)Q?br>
DataSize= DataSizePerLine* biHeight?
上述是BMP文g格式的说明,搞清楚了以上的结构,可以正的操作囑փ文gQ对它进行读或写操作了?br>
]]>
Ҏ三基色原理,L一U色?span>F都可以用不同分量?span>R?span>G?span>B三色相加混合而成?/span>
F = r [ R ] + g [ G ] + b [ B ]
其中Q?span>r?span>g?span>b分别Z参与混合的系数。当三基色分量都?span>0Q最弱)时合ؓ黑色光;而当三基色分量都?span>kQ最强)时合ؓ白色光。调?span>r?span>g?span>b三个pL的|可以混合Z于黑色光和白色光之间的各U各L色光?/span>
那么YUV又从何而来呢?在现代彩色电视系l中Q通常采用三管彩色摄像机或彩色CCD摄像行摄像,然后把摄得的彩色囑փ信号l分艌Ӏ分别放大校正后得到RGBQ再l过矩阵变换电\得到亮度信号Y和两个色差信?span>RQ?span>YQ即UQ?span>BQ?span>YQ即VQ,最后发送端亮度和色差三个信号分别q行~码Q用同一信道发送出厅R这U色彩的表示Ҏ是所谓的YUV色彩I间表示?/span>
采用YUV色彩I间的重要性是它的亮度信号Y和色度信?span>U?span>V是分ȝ。如果只?span>Y信号分量而没?span>U?span>V分量Q那么这栯C的囑փ是黑白灰度囑փ。彩色电视采?span>YUVI间正是Z用亮度信?span>Y解决彩色电视Z黑白电视机的兼容问题Q黑白电视Z能接收彩色电视信受?/span>
YUV?span>RGB怺转换的公式如下(RGB取D围均?span>0-255Q:
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
?span>DirectShow中,常见?span>RGB格式?span>RGB1?span>RGB4?span>RGB8?span>RGB565?span>RGB555?span>RGB24?span>RGB32?span>ARGB32{;常见?span>YUV格式?span>YUY2?span>YUYV?span>YVYU?span>UYVY?span>AYUV?span>Y41P?span>Y411?span>Y211?span>IF09?span>IYUV?span>YV12?span>YVU9?span>YUV411?span>YUV420{。作频媒体类型的辅助说明cdQ?span>SubtypeQ,它们对应?span>GUID见表2.3?/span>
?span>2.3 常见?span>RGB?span>YUV格式
GUID 格式描述
MEDIASUBTYPE_RGB1 2Ԍ每个像素?span>1位表C,需要调色板
MEDIASUBTYPE_RGB4 16Ԍ每个像素?span>4位表C,需要调色板
MEDIASUBTYPE_RGB8 256Ԍ每个像素?span>8位表C,需要调色板
MEDIASUBTYPE_RGB565 每个像素?span>16位表C,RGB分量分别使用5位?span>6位?span>5?/span>
MEDIASUBTYPE_RGB555 每个像素?span>16位表C,RGB分量都?span>5位(剩下?span>1位不用)
MEDIASUBTYPE_RGB24 每个像素?span>24位表C,RGB分量各?span>8?/span>
MEDIASUBTYPE_RGB32 每个像素?span>32位表C,RGB分量各?span>8位(剩下?span>8位不用)
MEDIASUBTYPE_ARGB32 每个像素?span>32位表C,RGB分量各?span>8位(剩下?span>8位用于表C?span>Alpha通道|
MEDIASUBTYPE_YUY2 YUY2格式Q以4:2:2方式打包
MEDIASUBTYPE_YUYV YUYV格式Q实际格式与YUY2相同Q?/span>
MEDIASUBTYPE_YVYU YVYU格式Q以4:2:2方式打包
MEDIASUBTYPE_UYVY UYVY格式Q以4:2:2方式打包
MEDIASUBTYPE_AYUV ?span>Alpha通道?span>4:4:4 YUV格式
MEDIASUBTYPE_Y41P Y41P格式Q以4:1:1方式打包
MEDIASUBTYPE_Y411 Y411格式Q实际格式与Y41P相同Q?/span>
MEDIASUBTYPE_Y211 Y211格式
MEDIASUBTYPE_IF09 IF09格式
MEDIASUBTYPE_IYUV IYUV格式
MEDIASUBTYPE_YV12 YV12格式
MEDIASUBTYPE_YVU9 YVU9格式
下面分别介绍各种RGB格式?/span>
RGB1?span>RGB4?span>RGB8都是调色板类型的RGB格式Q在描述q些媒体cd的格式细节时Q通常会在BITMAPINFOHEADER数据l构后面跟着一个调色板Q定义一pd颜色Q。它们的囑փ数据q不是真正的颜色|而是当前像素颜色值在调色板中的烦引。以RGB1Q?span>2色位图)ZQ比如它的调色板中定义的两种颜色gơؓ0x000000Q黑Ԍ?span>0xFFFFFFQ白ԌQ那么图像数?span>001101010111…Q每个像素用1位表C)表示对应各像素的颜色为:黑黑白白黑白黑白黑白白白…?/span>
RGB565使用16位表CZ个像素,q?span>16位中?span>5位用?span>RQ?span>6位用?span>GQ?span>5位用?span>B。程序中通常使用一个字Q?span>WORDQ一个字{于两个字节Q来操作一个像素。当d一个像素后Q这个字的各个位意义如下Q?/span>
高字?span> 低字?/span>
R R R R R G G G G G G B B B B B
可以l合使用屏蔽字和UM操作来得?span>RGB各分量的|
#define RGB565_MASK_RED 0xF800
#define RGB565_MASK_GREEN 0x07E0
#define RGB565_MASK_BLUE 0x001F
R = (wPixel & RGB565_MASK_RED) >> 11; // 取D?span>0-31
G = (wPixel & RGB565_MASK_GREEN) >> 5; // 取D?span>0-63
B = wPixel & RGB565_MASK_BLUE; // 取D?span>0-31
RGB555是另一U?span>16位的RGB格式Q?span>RGB分量都用5位表C(剩下?span>1位不用)。用一个字d一个像素后Q这个字的各个位意义如下Q?/span>
高字?span> 低字?/span>
X R R R R G G G G G B B B B B Q?span>X表示不用Q可以忽略)
可以l合使用屏蔽字和UM操作来得?span>RGB各分量的|
#define RGB555_MASK_RED 0x7C00
#define RGB555_MASK_GREEN 0x03E0
#define RGB555_MASK_BLUE 0x001F
R = (wPixel & RGB555_MASK_RED) >> 10; // 取D?span>0-31
G = (wPixel & RGB555_MASK_GREEN) >> 5; // 取D?span>0-31
B = wPixel & RGB555_MASK_BLUE; // 取D?span>0-31
RGB24使用24位来表示一个像素,RGB分量都用8位表C,取D围ؓ0-255。注意在内存?span>RGB各分量的排列序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据l构来操作一个像素,它的定义为:
typedef struct tagRGBTRIPLE {
BYTE rgbtBlue; // 蓝色分量
BYTE rgbtGreen; // l色分量
BYTE rgbtRed; // U色分量
} RGBTRIPLE;
RGB32使用32位来表示一个像素,RGB分量各用?span>8位,剩下?span>8位用?span>Alpha通道或者不用。(ARGB32是?span>Alpha通道?span>RGB32。)注意在内存中RGB各分量的排列序为:BGRA BGRA BGRA…。通常可以使用RGBQUAD数据l构来操作一个像素,它的定义为:
typedef struct tagRGBQUAD {
BYTE rgbBlue; // 蓝色分量
BYTE rgbGreen; // l色分量
BYTE rgbRed; // U色分量
BYTE rgbReserved; // 保留字节Q用?span>Alpha通道或忽略)
} RGBQUAD;
下面介绍各种YUV格式?span>YUV格式通常有两大类Q打包(packedQ格式和q面Q?span>planarQ格式。前者将YUV分量存放在同一个数l中Q通常是几个相ȝ像素l成一个宏像素Q?span>macro-pixelQ;而后者用三个数l分开存放YUV三个分量Q就像是一个三l^面一栗表2.3中的YUY2?span>Y211都是打包格式Q?span>IF09?span>YVU9都是q面格式。(注意Q在介绍各种具体格式ӞYUV各分量都会带有下标,?span>Y0?span>U0?span>V0表示W一个像素的YUV分量Q?span>Y1?span>U1?span>V1表示W二个像素的YUV分量Q以此类推。)
YUY2Q和YUYVQ格式ؓ每个像素保留Y分量Q?span>UV分量在水qx向上每两个像素采样一ơ。一个宏像素?span>4个字节,实际表示2个像素。(4:2:2的意思ؓ一个宏像素中有4?span>Y分量?span>2?span>U分量?span>2?span>V分量。)囑փ数据?span>YUV分量排列序如下Q?/span>
Y0 U0 Y1 V0 Y2 U2 Y3 V2 …
YVYU格式?span>YUY2cMQ只是图像数据中YUV分量的排列顺序有所不同Q?/span>
Y0 V0 Y1 U0 Y2 V2 Y3 U2 …
UYVY格式?span>YUY2cMQ只是图像数据中YUV分量的排列顺序有所不同Q?/span>
U0 Y0 V0 Y1 U2 Y2 V2 Y3 …
AYUV格式带有一?span>Alpha通道Qƈ且ؓ每个像素都提?span>YUV分量Q图像数据格式如下:
A0 Y0 U0 V0 A1 Y1 U1 V1 …
Y41PQ和Y411Q格式ؓ每个像素保留Y分量Q?span>UV分量在水qx向上?span>4个像素采样一ơ。一个宏像素?span>12个字节,实际表示8个像素。图像数据中YUV分量排列序如下Q?/span>
U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y8 …
Y211格式在水qx向上Y分量?span>2个像素采样一ơ,?span>UV分量?span>4个像素采样一ơ。一个宏像素?span>4个字节,实际表示4个像素。图像数据中YUV分量排列序如下Q?/span>
Y0 U0 Y2 V0 Y4 U4 Y6 V4 …
YVU9格式为每个像素都提取Y分量Q而在UV分量的提取时Q首先将囑փ分成若干?span>4 x 4的宏块,然后每个宏块提取一?span>U分量和一?span>V分量。图像数据存储时Q首先是整幅囑փ?span>Y分量数组Q然后就跟着U分量数组Q以?span>V分量数组?span>IF09格式?span>YVU9cM?/span>
IYUV格式为每个像素都提取Y分量Q而在UV分量的提取时Q首先将囑փ分成若干?span>2 x 2的宏块,然后每个宏块提取一?span>U分量和一?span>V分量?span>YV12格式?span>IYUVcM?/span>
YUV411?span>YUV420格式多见?span>DV数据中,前者用?span>NTSCӞ后者用?span>PAL制?span>YUV411为每个像素都提取Y分量Q?span>UV分量在水qx向上?span>4个像素采样一ơ?span>YUV420qV分量采样?span>0Q而是?span>YUV411相比Q在水^方向上提高一倍色差采样频率,在垂直方向上?span>U/V间隔的方式减一半色差采栗?/span>
]]>
基本设计概念和处理流E?/p>
Z事g驱动的数据处理模?/p>
再者,Ҏ|络,数据库等特定功能Q构建网l,数据库等理服务Q实现数据队列服务钩子QueueServiceSinkҎQ调度事件数据执行外部处
框架体系设计
]]>
世界变换
世界变换是物体顶点坐标从模型I间转换C界空间。在模型I间里,点位置坐标依据模型的本地坐标系的原点而定Q在世界I间里,所有模型的点q一个原点,即世界坐标系原点。事实上Q世界变换就是将一个模型从本地I间重新定位C界空间内。从模型I间C界空间的转换实际上就是对模型q行q移、旋转、羃放以及它们的Ll合变换?/p>
使用三维模型制作软gQ例?dmaxQ制作三l模型时Q首先需要ؓ模型讑֮一个坐标系Q模型上的顶点坐标就是设定的模型自n坐标pM的坐标,q个坐标pM是上面提到的本地坐标系或模型空间?/p>
1、世界变换矩?/strong>
在处理三l图像的应用E序中,可用世界变换完成一个物体(切的说是一个坐标或一pd坐标Q的q移、旋转和~放。当然也可以完成q三U变换的Ll合。具体的Ҏ是通过下式Q?/p>
Q意一点P(x, y, z)转换到p'(x', y', z')Q上式也可以表示Z下Ş式:
p'(x', y', z') = P(x, y, z) . Mworld
Mworld是世界变换矩阵。也是它实C物体的^UR旋转、羃攑֒它们的复合变换。在定义好世界变换矩阵后Q调用函数IDirect3DDevice9::SetTransform()q指定第一个参CؓD3DTS_WORLDQ第二个参数为相应的世界变换矩阵卛_?/p>
2、^U?/strong>
可以通过下式Q也是下面的^Ud换矩阵)Q?/p>
点Qx, y, zQ沿x、y和z轴分别移动Tx、Ty、TzQ到另一点(x'Qy'Qz'Q。很昄Q只要得Cq个q移矩阵Q^Ud作就可以完成?/p>
为方便v见,D3DX扩展函数库d3dx9.lib提供了函数D3DXMatrixTranslation()Q用它可以很方便地生成一个^UM界矩c该函数的声明如?
Builds a matrix using the specified offsets.
D3DXMATRIX * D3DXMatrixTranslation(
D3DXMATRIX * pOut,
FLOAT x,
FLOAT y,
FLOAT z
);
Pointer to a D3DXMATRIX structure that contains a translated transformation matrix.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMATRIXTranslation can be used as a parameter for another function.
3、旋?/strong>
与^Uȝ|使用下面的四阶矩阵可以将点(x, y, zQ绕x轴旋?#952;角,到新点(x', y', z'Q?
ly轴旋?#952;角时的矩阵ؓQ?/p>
lz轴旋?#952;角时的矩阵ؓQ?/p>
θ指旋转角度,单位是弧度,具体是指沿着旋{轴的指向Q即正方向)向坐标原点看去顺指针旋{q的角度?/p>
同样可以使用D3DX扩展函数库d3dx9.lib提供的函数D3DXMatrixRotationX()、D3DXMatrixRotationY()和D3DXMatrixRotationZ()方便地创建旋转矩阵,q三个函数的声明如下Q因声明cMQ只列出D3DXMatrixRotationX()的用说?
Builds a matrix that rotates around the x-axis.
D3DXMATRIX * D3DXMatrixRotationX(
D3DXMATRIX * pOut,
FLOAT Angle
);
Pointer to a D3DXMATRIX structure rotated around the x-axis.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixRotationX function can be used as a parameter for another function.
4、羃?/strong>
使用下面的四阶矩阵可以将点(x, y, zQ在x、y、z轴上各羃放Sx、Sy、SzQ到另一点(x', y', z'Q?/p>
同样Q可以用Direct3D扩展实用库中的函数D3DXMatrixScaling()来生成羃攄阵,该函数的声明如下Q?/p>
Builds a matrix that scales along the x-axis, the y-axis, and the z-axis.
D3DXMATRIX * D3DXMatrixScaling(
D3DXMATRIX * pOut,
FLOAT sx,
FLOAT sy,
FLOAT sz
);
Pointer to the scaling transformation D3DXMATRIX.
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixScaling function can be used as a parameter for another function.
5、矩阵连接与复合变换
在大多数情况下,Direct3D中的物体需要进行的世界变换不止一个,而往往是多个世界变换的l合Q这时可以用矩阵连接来实现q种复合变换。因为矩늚一个优Ҏ通过矩阵的相乘,两个或更多矩阵的作用合q在一起实现。ؓ了先后实C个模型的旋{和移动,不需要用两个矩阵,可以旋转矩阵和q移矩阵怹得到一个复合矩阵以实现所有功能。这个过E叫做矩阵连接(matrix concatentionQ,可以用下面的公式表示Q?/p>
C = M1 * M2 * ... * Mn-1 * Mn
在这个公式里QC是实现复合变换的复合矩阵Q从M1到Mn是只能实现某一U世界变换的单独矩阵Qindividual matricesQ。大多数情况下是两到三个矩阵q接Q但q个数量没有限制?/p>
使用函数D3DXMatrixMultiply() 可完成矩늚乘法Q该函数的说明如下:
Determines the product of two matrices.
D3DXMATRIX * D3DXMatrixMultiply(
D3DXMATRIX * pOut,
CONST D3DXMATRIX * pM1,
CONST D3DXMATRIX * pM2
);
Pointer to a D3DXMATRIX structure that is the product of two matrices.
The result represents the transformation M1 followed by the transformation M2 (Out = M1 * M2).
The return value for this function is the same value returned in the pOut parameter. In this way, the D3DXMatrixMultiply function can be used as a parameter for another function.
矩阵pOut表示最l的复合变换Q也是先进行矩阵pM1表示的变换,然后又进行矩阵pM2表示的变换?/p>
在矩늚乘法中,序是很关键的。无创徏什么样的世界变换矩阵,C从左到右的原则才能确保实现想要的效果Q也是_一个复合矩늚视觉效果是按从左到右的顺序各单独矩阵视觉效果的组合?/font>假设一个物体先ly轴旋转,然后把它Ud到场景内的另一个位|。ؓ实现q个效果Q首先创Z个旋转矩阵RyQ然后乘以一个^Uȝ阵TwQ?/p>
W = Ry * Tw 在这个公式里QRy表示ly轴的旋{矩阵QTw实现世界坐标pd的一ơ^UR?font color=#800000>矩阵的乘法不满交换律?/font>如果这两个矩阵以相反的序怹Q效果是先^U,然后旋{?/p>
Q.囑փ的逆反处理法
逆反处理的算法如下:
设rQgQb分别为源囑փ像素fQiQjQ的U,l,蓝分量|rrQggQbb分别为处理后像素gQiQjQ的U,l,蓝分量倹{则
rr=255-r
gg=255-g
bb=255-b
Q?囑փ的^滑处?/p>
法如下Q?br>qx处理是指源囑փ的每一个像素的颜色值由其相邻n*n个像素的q_值来代替?br>例如Q对?*3炚w而言Q设原图像某像素的gؓfQiQjQ,qx处理后该像素的gؓgQiQjQ,则:
g(i,j)=(f(i,j)+f(i-1,j)+f(i+1,j)+f(i-1,j-1)+f(i,j-1)+f(i+1,j-1)+
f(i-1,j+1)+f(i,j+1)+f(i+1,j+1))/9
注意Q该法不能qx囑փ边界的像素?/p>
Q? 图象的霓虹处?/p>
法Q?br>对于3*3炚wQ首先计原图象像素f(i,j)的红Q绿Q蓝分量与相同行fQi+1QjQ及同列f(i,j+1)盔R象素的梯度,卛_的^方之和的qx根,然后梯度g为处理后的象素g(i,j)的红Q绿Q蓝分量倹{?br>设r1,g1,b1分别为原图象象素f(i,j)的红Q绿Q蓝分量|r2,g2,b2分别为相同行盔R象素f(i+1,j)的红Q绿Q蓝分量|r3,g3,b3分别为同列相邻象素f(i,j+1)的红Q绿Q蓝分量|rr,gg,bb为处理后象素g(i,j)的红Q绿Q蓝分量|则:
rr1=(r1-r2)^2 rr2=(r1-r3)^2
gg1=(g1-g2)^2 gg2=(g1-g3)^2
bb1=(b1-b2)^2 bb2(b1-b3)^2
rr=2*(rr1+rr2)^0.5
gg=2*(gg1+gg2)^0.5
bb=2*(bb1+bb2)^0.5
Q?图象的锐化处?/p>
锐化处理的算法:
计算原图像像素f(i,j)的像素g该像素与盔R像素f(i-1,j-1)像素g差的l对值得癑ֈ比之和,作ؓ处理后图像像素g(i,j)的像素倹{例如,设r1,g1,b1分别为f(i,j)的红、绿、蓝分量|r2,g2,b2分别为f(i-1,j-1)的红、绿、蓝分量|rr,gg,bb分别为g(i,j)的红、绿、蓝分量|则:
rr=r1+0.25*abs(r1-r2)
gg=g1+0.25*abs(g1-g2)
bb=b1+0.25*abs(b1-b2)
Q? 囑փ的Q雕处?/p>
法Q?br>位图囑փ的Q雕处理的法是:
g(i,j)=f(i,j)-f(i-1,j)+常数
式中Qg(i,j)为处理后囑փ的像素|f(i,j)为原囑փ的像素|f(i-1,j)为前一个相d素的倹{常C般取128Q即
rr=r1-r2+128
gg=g1-g2+128
bb=b1-b2+128
式中Qr1,g1,b1分别为原囑փ的像素f(i,j)的红、绿、蓝分量|r2,g2,b2分别为前一个相d素f(i-1,j)的红、绿、蓝分量|rr,gg,bb,分别为处理后囑փ的像素g(i,j)的红、绿、蓝分量?
Q?囑փ的镶嵌处?/p>
镶嵌处理法如下Q?br>镶嵌处理后的囑փ每一矩阵内的所有像素值都取此矩阵内原囑փ各像素g和的q_倹{例如,对于3*3的子域:
g(i,j)=(f(i,j)+f(i-1,j)+f(i+1,j)+f(i-1,j-1)+f(i+1,j-1)+f(i-1,j+1)+f(i,j+1)+f(i+1,j+1))/9
则取Q?br>g(i-1,j)=g(i,j)
g(i+1,j)=g(i,j)
gQi,j-1Q?g(i,j)
g(i,j+1)=g(i,j)
g(i,j+1)=g(i,j)
g(i-1,j-1)=g(i,j)
g(i-1,j+1)=g(i,j)
g(i+1,j-1)=g(i,j)
g(i+1,j+1)=g(i,j)
Q?囑փ的灰度处?/p>
彩色囑փ灰度处理的算法如下:
c=tuxing.GetPixel(i,j)
r=c.R
g=c.G
b=c.B
rr=g(r 64)*64
gg=(g 64)*64
bb=(b 64)*64
Q?囑փ~小处理
以坐标原点ؓ中心Q将囑փ个像素坐标的X分量和Y分量分别乘以SxQSyQ则可囑փq行整体攑֤和羃。这Ӟ
X'=X*Sx
Y'=Y*Sy
当Sx=SyӞ作相似变?
当Sx!=SyӞ产生变Ş?/p>
Q?囑փ的^Ud?/p>
囑փ的^Ud换是图形上的点Qx,y)在x方向Q水qx向)和y方向Q垂直方向)
分别Uddx和dy,则变换后?x',y')坐标gؓQ?br>x'=x+dx
y'=y+dy
Q0.囑փ的旋转变?/p>
二维囑փ的旋转变换是以原点ؓ中心Q将点(x,yQ旋转a角度而得到新的坐标(x',y'Q的变换UCؓ旋{变换。其数学表达式ؓQ?br>x'=x*cosa-y*sina
y'=x*sina+y*cosa
Q1.二维囑փ的对U变?/p>
二维囑փ对称变换有以下几U情?
1.以x轴ؓ对称得对U变换?br>以x轴ؓ对称得点(x,y)的对U点(x',y')坐标为:
x'=x
y'=-y
2.以y轴ؓ对称得对U变换?br>以y轴ؓ对称的点Qx,yQ的对称?x',y')坐标为:
x'=-x
y'=y
3.以原点ؓ对称的对U变换?br>以原点ؓ对称得点Qx,yQ的对称点(x',y'Q坐标ؓQ?br>x'=-x
y'=-y
对图像的每一个像素依据二l图形几何变换公式进行计后Q在q行囑փ昄Q则可得到图像的几何变换?/p>
本文来自CSDN博客Q{载请标明出处Q?a >http://blog.csdn.net/alin0725/archive/2007/03/28/1543860.aspx
因问得h多了Q有时我也思烦和研I一下,ȝ找了个方法可以实玎ͼ虽然同专业的囑փ软gQ如PhotoShopQ文字描Ҏ果相比差Zh意,但可以凑合凑合,作ؓ研究心得Q将代码贴在q里备查?/p>
在《GDI+ 在DelphiE序的应?-- 可调节的文字阴媄Ҏ》一文的内容的基上,Ҏ字阴影效果代码进行了改进和扩充,扩充的功能有2点:一是由原来只能产生黑色阴媄扩充ZQ意颜色阴影;二是可以寚wp行扩展。有了这2个功能,利用阴媄效果也就可以q行文字描边了,推而广之,也可实现囑փ的描辏V下面是具体的代码内容:
// 备䆾囑փ。Data: GDI+位图数据Q?2位ARGB格式; Dest: 备䆾目标; Color: 阴媄颜色
procedure BackImage(Data: TBitmapData; Dest: Pointer; Color: TARGB);
asm
push esi
push edi
mov esi, [eax + 16] // esi = Data.Scan0
mov edi, edx // esi = Dest
mov edx, ecx // edx = Color & 0xffffff
and edx, 0FFFFFFh
mov ecx, [eax] // ecx = Data.Height * Data.Width
imul ecx, [eax + 4]
cld
@Loop: // for (; ecx >= 0; ecx --)
or [esi], edx
movsd // *edi++ = *esi++ & 0xff000000 | edx
loop @Loop
pop edi
pop esi
end;
// 扩展。Data: GDI+位图数据Q?2位ARGB格式; Source: 复制的源
// ExpMatrix: L矩阵; MatrixSizeQ矩阵大?
procedure MakeExpand(Data: TBitmapData; Source, ExpMatrix: Pointer;
MatrixSize: LongWord);
var
Radius, mSize, rSize: LongWord;
x, y: LongWord;
Width, Height: Integer;
Matrix: Pointer;
Stride: LongWord;
asm
push esi
push edi
push ebx
mov esi, edx // esi = Source
mov edi, [eax + 16] // edi = Data.Scan0 + 3 (Alpha byte)
add edi, 3
add ecx, 3
mov Matrix, ecx // Matrix = ExpMatrix + 3 (Alpha byte)
mov ecx, MatrixSize
mov edx, ecx
dec ecx
mov ebx, [eax]
sub ebx, ecx
mov Width, ebx // Width = Data.Width - (MatrixSize - 1)
mov ebx, [eax + 4]
sub ebx, ecx
mov Height, ebx // Height = Data.Height - (MatrixSize - 1)
shr ecx, 1
mov Radius, ecx // Radius = MatrixSize / 2
mov eax, [eax + 8]
mov Stride, eax
mov mSize, eax
shl edx, 2
sub mSize, edx // mSize = Data.Stride - MatrixSize * 4
add eax, 4
imul eax, ecx
add eax, 3
add esi, eax // esi = esi + (Data.Stride * Radius + Radius * 4 + 3)
shl ecx, 3
mov rSize, ecx // rSize = Radius * 2 * 4
mov y, 0 // for (y = 0; y < Height; y ++)
@yLoop: // {
mov x, 0 // for (x = 0; x < Width; x ++)
@xLoop: // {
test [esi], 0ffh // if (*esi != 0)
jz @NextPixel // {
test [esi - 4], 0ffh
jz @001
test [esi + 4], 0ffh
jz @001
mov ebx, Stride
test [esi + ebx], 0ffh
jz @001
neg ebx
test [esi + ebx], 0ffh
jnz @NextPixel
@001:
push edi // Save(edi)
mov ebx, Matrix // ebx = Matrix
mov edx, MatrixSize // for (I = 0; I < MatrixSize; I ++)
@Loop3: // {
mov ecx, MatrixSize // for (J = 0; J <= MatrixSize; J ++)
@Loop4: // {
mov al, [ebx] // *edi = max(*ebx, *edi)
cmp al, [edi]
jb @002
mov [edi], al
@002:
add edi, 4 // edi += 4
add ebx, 4 // ebx += 4
loop @Loop4 // }
add edi, mSize // edi += mSize
dec edx
jnz @Loop3 // }
pop edi // Reset(edi)
@NextPixel: // }
add edi, 4 // edi += 4
add esi, 4 // esi += 4
inc x
mov eax, x
cmp eax, Width
jl @xLoop // }
add esi, rSize
add edi, rSize
inc y
mov eax, y
cmp eax, Height
jl @yLoop // }
pop ebx
pop edi
pop esi
end;
procedure GdipShadow(Data: TBitmapData; Buf: Pointer; Radius: LongWord);
var
Gauss: array of Integer;
Q: Double;
x, y, n, z: Integer;
p: PInteger;
begin
// Ҏ半径计算高斯模糊矩阵
Q := Radius / 2;
if Q = 0 then Q := 0.1;
n := Radius shl 1 + 1;
SetLength(Gauss, n * n);
p := @Gauss[0];
z := 0;
for x := -Radius to Radius do
for y := -Radius to Radius do
begin
p^ := Round(Exp(-(x * x + y * y) / (2.0 * Q * Q)) / (2.0 * PI * Q * Q) * 1000.0);
Inc(z, p^);
Inc(p);
end;
MakeShadow(Data, Buf, Gauss, n, z);
end;
procedure GdipBorder(Data: TBitmapData; Buf: Pointer; Expand: LongWord; Color: TARGB);
var
bmp: TGpBitmap;
bg: TGpGraphics;
Data1: TBitmapData;
Size: Integer;
begin
Size := Expand shl 1 + 1;
bmp := TGpBitmap.Create(Size, Size, pf32bppARGB);
bg := TGpGraphics.Create(bmp);
try
// 刉一个直?SizeQ消除锯齿后的圆作ؓ描边Q或扩展Q的位图ȝ
bg.SmoothingMode := smAntiAlias;
bg.PixelOffsetMode := pmHalf;
bg.FillEllipse(Brushs[Color], 0, 0, Size, Size);
Data1 := bmp.LockBits(GpRect(0, 0, Size, Size), [imRead], pf32bppARGB);
try
// 用位囄W扩展图?
MakeExpand(Data, Buf, Data1.Scan0, Size);
finally
bmp.UnlockBits(Data1);
end;
finally
bg.Free;
bmp.Free;
end;
end;
procedure DrawShadow(const g: TGpGraphics; const Bitmap: TGpBitmap;
const layoutRect: TGpRectF; ShadowSize, Distance: LongWord;
Angle: Single; Color: TARGB; Expand: LongWord);
var
dr, sr: TGpRectF;
Data: TBitmapData;
Buf: Pointer;
SaveScan0: Pointer;
begin
Data := Bitmap.LockBits(GpRect(0, 0, Bitmap.Width, Bitmap.Height),
[imRead, imWrite], pf32bppARGB);
GetMem(Buf, Data.Height * Data.Stride);
try
BackImage(Data, Buf, Color);
if Expand > ShadowSize then
Expand := ShadowSize;
if Expand <> 0 then // 处理文字阴媄扩展
if Expand <> ShadowSize then
begin
SaveScan0 := Data.Scan0;
Data.Scan0 := Buf;
GdipBorder(Data, SaveScan0, Expand, Color);
Data.Scan0 := SaveScan0;
end else
GdipBorder(Data, Buf, Expand, Color);
if Expand <> ShadowSize then // 处理文字阴媄效果
GdipShadow(Data, Buf, ShadowSize - Expand);
finally
FreeMem(Buf);
Bitmap.UnlockBits(Data);
end;
sr := GpRect(0.0, 0.0, Data.Width, Data.Height);
// sr := GpRect(0.0, 0.0, layoutRect.Width + ShadowSize * 2 + 2,
// layoutRect.Height + ShadowSize * 2 + 2);
dr := GpRect(layoutRect.Point, sr.Size);
// Ҏ角度计算阴媄位图在目标画布的偏移?
Offset(dr, Cos(PI * Angle / 180) * Distance - ShadowSize - 1,
Sin(PI * Angle / 180) * Distance - ShadowSize - 1);
// 输出阴媄位图到目标画?
g.DrawImage(Bitmap, dr, sr.X, sr.Y, sr.Width, sr.Height, utPixel);
end;
// 计算q输出文字阴影效?
// g: 文字输出的画? str要输出的文字; font: 字体; layoutRect: 限定的文字输?
// ShadowSize: 阴媄大小; Distance: 阴媄距离;
// Angle: 阴媄输出角度(左边q处ؓ0度。顺旉方向)
// ShadowAlpha: 阴媄文字的不透明? format: 文字输出格式
procedure DrawShadowString(const g: TGpGraphics; const str: WideString;
const font: TGpFont; const layoutRect: TGpRectF;
ShadowSize, Distance: LongWord; Angle: Single = 60;
Color: TARGB = $C0000000; Expand: LongWord = 0;
const format: TGpStringFormat = nil); overload;
var
Bmp: TGpBitmap;
Bg: TGpGraphics;
begin
// 建立透明?2位ARGB阴媄位图Q大ؓlayoutRectѝ宽?+ ShadowSize * 2 + 2
Bmp := TGpBitmap.Create(Round(layoutRect.Width + 0.5) + ShadowSize shl 1 + 2,
Round(layoutRect.Height + 0.5) + ShadowSize shl 1 + 2,
pf32bppARGB);
Bg := TGpGraphics.Create(Bmp);
try
Bg.TextRenderingHint := thAntiAlias;
// 以Color不透明度的黑色dQ在ShadowSize + 1处输出文字到位图d?
// 方便黑色以外的阴影颜色替换(直接用Color画,模糊处理后很隄Q?
Bg.DrawString(str, font, Brushs[Color and $FF000000],
GpRect(ShadowSize + 1, ShadowSize + 1,
layoutRect.Width, layoutRect.Height), format);
DrawShadow(g, Bmp, layoutRect, ShadowSize, Distance, Angle, Color, Expand);
finally
Bg.Free;
Bmp.Free;
end;
end;
// 计算q输出文字阴影效果,除以输出点origin替代上面布局矩Ş外,其他参数同上
procedure DrawShadowString(const g: TGpGraphics; const str: WideString;
const font: TGpFont; const origin: TGpPointF;
ShadowSize, Distance: LongWord; Angle: Single = 60;
Color: TARGB = $C0000000; Expand: LongWord = 0;
const format: TGpStringFormat = nil); overload;
begin
DrawShadowString(g, str, font, g.MeasureString(str, font, origin, format),
ShadowSize, Distance, Angle, Color, Expand, format);
end;
上面代码中MakeShadowq程的代码在《GDI+ 在DelphiE序的应?-- 可调节的文字阴媄Ҏ》一文中Q本文没有脓出。由于代码中已经有了较详l的注释Q故不再解释。下面脓出测试代码:
procedure TextPaint(g: TGpGraphics);
var
brush: TGpLinearGradientBrush;
font: TGpFont;
fontFamily: TGpFontFamily;
r: TGpRect;
begin
fontFamily := TGpFontFamily.Create({'Times New Roman'}'华文行楷');
font := TGpFont.Create(fontFamily, 55, [fsBold], utPixel);
r := GpRect(Form1.PaintBox1.ClientRect);
brush := TGpLinearGradientBrush.Create(r, kcBlue, kcAliceBlue, 90);
g.FillRectangle(Brush, r);
DrawShadowString(g, '文字阴媄Ҏ', font, GpPoint(10, r.Height / 3), 5, 10, 60, $C0000000, 1);
DrawShadowString(g, '文字阴媄Ҏ', font, GpPoint(10, r.Height / 3), 1, 0, 60, $FFFF0000, 1);
// DrawShadowString(g, '文字阴媄Ҏ', font, GpPoint(10, r.Height / 3), 5, 12, 60, $C0000000, 1);
// DrawShadowString(g, '文字阴媄Ҏ', font, GpPoint(10, r.Height / 3), 2, 3, 60, $FFc00000, 1);
g.TextRenderingHint := thAntiAlias;
g.DrawString('文字阴媄Ҏ', font, Brushs.White, 10, r.Height / 3);
font.Free;
fontFamily.Free;
Brush.Free;
end;
以下是测试代码效果图Q图一和图二都是文字描边(1个像素的ҎQ加阴媄效果Q其中图一没进行阴影扩展,即上面的15行的代码最后一个参Cؓ0Q图二是加了1个像素的阴媄扩展效果Q上qC码的“正宗”输出Q:
图一
图二
利用改进的阴影效果,不仅可实现文字描边,也可昄cM立体文字的效果(改变昄距离Q,上面试代码中,被注释的2句代码输出效果如下:
图三
至于囑փ的描边,g没有文字的描Ҏ果好Q究其原因,主要是图像的轮廓看v来好像是圆润qx的,其实有很多半影锯齿,在Photoshop中,通过先选区后描边,可能寚w区边缘作了处理Q所以效果相当好Q专业的软gQ肯定有很好的算法)。下面是我对一张小囄作的描边处理代码和输出效果图Q?/p>
// 囑փ描边
// g: 文字输出的画? Image: 囑փ; x, y: 囑փ输出原点
// BorderWidth: ȝҎ宽度; Color: Ҏ颜色;
// Expand: Ҏ扩散大小; Attributes: 囑փ昄属?
procedure DrawImageBorder(const g: TGpGraphics; const Image: TGpImage;
x, y: Single; BorderWidth: LongWord; Color: TARGB = kcWhite;
Expand: LongWord = 0; const Attributes: TGpImageAttributes = nil);
var
Bmp: TGpBitmap;
Bg: TGpGraphics;
ColorMatrix: TColorMatrix;
Attr: TGpImageAttributes;
layoutRect: TGpRectF;
begin
Bmp := TGpBitmap.Create(Image.Width + BorderWidth shl 1 + 2,
Image.Height + BorderWidth shl 1 + 2,
pf32bppARGB);
Bg := TGpGraphics.Create(Bmp);
Attr := Attributes;
if Attr = nil then
Attr := TGpImageAttributes.Create;
try
FillChar(ColorMatrix, Sizeof(TColorMatrix), 0);
ColorMatrix[3, 3] := 1;
ColorMatrix[4, 4] := 1;
// 利用颜色矩阵图像输Zؓ黑色Q以便边框颜色替?
Attr.SetColorMatrix(ColorMatrix);
layoutRect := GpRect(x, y, Image.Width, Image.Height);
Bg.DrawImage(Image,
GpRect(BorderWidth + 1, BorderWidth + 1, layoutRect.Width, layoutRect.Height),
0, 0, layoutRect.Width, layoutRect.Height, utPixel, Attr);
DrawShadow(g, Bmp, layoutRect, BorderWidth, 0, 0, Color, BorderWidth - Expand);
finally
if Attributes <> nil then
Attr.ClearColorMatrix
else
Attr.Free;
Bg.Free;
Bmp.Free;
end;
end;
procedure ImagePaint(g: TGpGraphics);
var
brush: TGpLinearGradientBrush;
r: TGpRect;
Image: TGpImage;
Attributes: TGpImageAttributes;
begin
r := GpRect(Form1.PaintBox1.ClientRect);
brush := TGpLinearGradientBrush.Create(r, kcBlue, kcAliceBlue, 90);
g.FillRectangle(Brush, r);
Image := TGpImage.Create('..\..\Media\Watermark.bmp');
// d?
g.TranslateTransform(20, r.Height / 3);
g.DrawImage(Image, 0, 0, Image.Width, Image.Height);
// 讄囑փ透明?
Attributes := TGpImageAttributes.Create;
Attributes.SetColorKey($ff00ff00, $ff00ff00);
// ?个像素的描边?
g.TranslateTransform(Image.Width + 20, 0);
DrawImageBorder(g, Image, 0, 0, 2, kcWhite, 0, Attributes);
g.DrawImage(Image, GpRect(0.0, 0, Image.Width, Image.Height),
0.0, 0.0, Image.Width, Image.Height, utPixel, Attributes);
// ?个像素的描边图,其中扩散3像素
g.TranslateTransform(Image.Width + 20, 0);
DrawImageBorder(g, Image, 0, 0, 5, kcWhite, 3, Attributes);
g.DrawImage(Image, GpRect(0.0, 0, Image.Width, Image.Height),
0.0, 0.0, Image.Width, Image.Height, utPixel, Attributes);
Attributes.Free;
Brush.Free;
Image.Free;
end;
囑֛
上面的效果图中,左边是原图,中间?个像素的描边图,双?个像素的描边图,其中?像素的模p扩散。从图中可以看出Q我?ff00ff00为透明色处理图像四个角后,在中间和双的描边图中,q是很明昄看到四个角有很E的绿Ԍ正是q个原因Q在中间囄圆角描边有明昄锯?/p>
最后作几点说明Q?/p>
1、本文纯属业余学习和研究的心得,q什么正宗的法Q?/p>
2、因为本文代码是学习时即兴写的,q优化代码Q而且是以q程形式出现的,有兴的朋友可以自己q行优化改进Q写成类或者元件更好(׃法和功能都不是很完善,所以我没写成类的Ş式)Q?/p>
3、例子中的GDI+版本pL己改写的Q与|上通的版本不完全兼容,如需使用本版本,请参照《GDI+ for VCL基础 -- GDI+ ?VCL 》一文的下蝲地址QƈL意后面的修改说明?/p>
4、如有好的徏议,h信:maozefa@hotmail.com
更新(2008-8-5 12:50)Q在MakeExpandq程中,是按图象逐点用位囄W矩阵填充的Q每个像素点都要q行矩阵大小的操作,最的1像素扩展的矩阵大ؓ3 * 3Q可见扩展速度是不大理想的。今天对代码作了一点修改,Ҏ个象素点都进行了判断Q如果是边界像素Q则作画W矩阵填充,否则直接跌Q这样一来,速度应该提高不少Q没作测试,增加的代码用U色标出Q有兴趣者可以测试)?/p>
原作者相x章:
GDI+ 在DelphiE序的应?-- 可调节的文字阴媄Ҏ
GDI+在DelphiE序的应?– Photoshop色相/饱和?明度功能