xxb 发表于 2007-8-14 09:36:00

将RGB值转换为灰度值的简单算法

<font face="Tahoma" size="2"> 使场景或精灵以灰度的形式显示,这是一般游戏制作中常常用到的效果,如:战棋游戏中当一个角色被使用过后,通常就会变成灰色,代表本回合已不能行动了;《仙剑》中回忆彩蝶的部分是用整屏的灰色来表现的?(记的不太清楚,太久了^_^);还有很多很多例子……<br/>  将RGB值转换为灰度的过程应该是在程序中实现的(至少我是这么认为的)。其实这是非常简单的,基本原理就是将一个点的RGB值分开来求和,然后除以3,把得到的值再分别付给RGB,用公式表示如下:</font>
        <p><span class="p1"><font face="Tahoma" size="2">R = G = B = 0.3R + 0.6G + 0.1B; //第二版改正后的公式<br/>//第一版中的错误公式是 R = G = B = ( R + G + B ) / 3;</font></span></p><p><span class="p1"><font face="Tahoma" size="2">  在实际编程应用中又可分为8位、16位和24位三种情况,下面进行一一介绍:<br/>  一、首先说最简单的24位点的转换,24位点的RGB均匀分布,所以分离和合成都较为简单,代码如下:</font></span></p><p><span class="p1"><font face="Tahoma" size="2"><br/></font><font face="宋体" color="#99ccff" size="2">//=======24位转换============<br/>int gMask=0x00ff00; //绿色掩码<br/>int bMask=0x0000ff; //兰色掩码</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">int RGB24toGray(int sour)<br/>{<br/>&nbsp;&nbsp;&nbsp; int r,g,b,t; //临时变量</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">&nbsp;&nbsp;&nbsp; r=(sour&gt;&gt;16);<br/>&nbsp;&nbsp;&nbsp; g=(sour &amp; gMask) &gt;&gt;8;<br/>&nbsp;&nbsp;&nbsp; b=sour &amp; bMask;<br/>&nbsp;&nbsp;&nbsp; t=(r*3+g*6+b)/10; //第二版改正的地方</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">&nbsp;&nbsp;&nbsp; return (t&lt;&lt;16)|(t&lt;&lt;8)|t;<br/>}</font></span></p><p><span class="p1"><font face="Tahoma" size="2">  二、16位点的转换要麻烦一些,因其涉及到555和565两种色码格式,所以在转换前需要我们进行一些初始工作:</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">//=======16位转换============<br/>BYTE RMove, GMove; //R和G移动到最低位需要的步数</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">//初始化数据,本函数在游戏初始时执行,仅执行一次<br/>void Init()<br/>{<br/>&nbsp;&nbsp;&nbsp; if( Is555 ) //555模式 0rrrrrgggggbbbbb<br/>&nbsp;&nbsp;&nbsp; {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RMove=10;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GMove=5;<br/>&nbsp;&nbsp;&nbsp; }<br/>&nbsp;&nbsp;&nbsp; else //565模式 rrrrrggggggbbbbb<br/>&nbsp;&nbsp;&nbsp; {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RMove=11;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GMove=6;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*注意:为什么这里GMove=6,因为565模式下G值有6位,如果用一个6位值和两个5位值相加除以3,得到的结果可能使5位溢出,所以我们要多移动一位即除以2*/<br/>&nbsp;&nbsp;&nbsp; }<br/>}</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">//16位点转换<br/>WORD RGB16toGray(WORD sour)<br/>{<br/>&nbsp;&nbsp;&nbsp; WORD t;<br/>&nbsp;&nbsp;&nbsp; WORD r, g, b;<br/>&nbsp;&nbsp;&nbsp; r= sour &gt;&gt; RMove;<br/>&nbsp;&nbsp;&nbsp; g= (GMask &amp; sour) &gt;&gt; GMove;<br/>&nbsp;&nbsp;&nbsp; b= BMask &amp; sour;<br/>&nbsp;&nbsp;&nbsp; t = (r*3+b*6+g)/10; //第二版改正的地方<br/>&nbsp;&nbsp;&nbsp; return (t&lt;&lt;RMove)|(t&lt;&lt;GMove)|t;<br/>}</font></span></p><p><span class="p1"><font face="Tahoma" size="2">  三、8位点的转换和上面两种有比较大的差异,因为它的颜色是由调色板决定的,我们只有通过改变调色板来进行转换,先用lpDDPal-&gt;GetEntries()获得调色板,然后分别转换需要的调色板值,完成后用lpDDPal-&gt;SetEntries()更新即可,程序如下:</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">//===========8位转换(注:本函数只适用于全屏转换)===========<br/>void RGB8_to_Gray()<br/>{<br/>&nbsp;&nbsp;&nbsp; int t; //临时变量<br/>&nbsp;&nbsp;&nbsp; LPPALETTEENTRY Pal = (LPPALETTEENTRY) LocalAlloc( LPTR, sizeof( PALETTEENTRY ) * 256 );</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">&nbsp;&nbsp;&nbsp; //获取调色板<br/>&nbsp;&nbsp;&nbsp; lpDDPal-&gt;GetEntries(0,0,256,Pal);</font></span></p><p><span class="p1"><font face="宋体" color="#99ccff" size="2">&nbsp;&nbsp;&nbsp; //转换<br/>&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;256; i++)<br/>&nbsp;&nbsp;&nbsp; {<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; t=( Pal.peRed * 3 + Pal.peGreen *6 + Pal.peBlue ) / 10; //第二版改正的地方<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Pal.peRed=Pal.peGreen=Pal.peBlue=t;<br/>&nbsp;&nbsp;&nbsp; }<br/><br/>&nbsp;&nbsp;&nbsp; //更新调色板<br/>&nbsp;&nbsp;&nbsp; lpDDPal-&gt;SetEntries(0,0,256,Pe);<br/>}</font></span></p><p><span class="p1"><font face="Tahoma" size="2">  上面代码中16位转换已经过测试,而其余两种尚未测试,如果各位发现有问题请及时指正。另:我曾试图用汇编对16转换进行优化,但由于本人的汇编功底实在过于拙劣,经汇编改写后的代码效率不但没有提高,反而有小幅下降,所以如果有人对其16位转换进行优化后,请务必发给在下一份,不胜感激!</font></span><font face="Tahoma" size="2"><br/></font></p>
页: [1]
查看完整版本: 将RGB值转换为灰度值的简单算法