zoukankan      html  css  js  c++  java
  • [转]J2ME开发中彩色转灰度算法的应用

          

    一、基础

    对于彩色转灰度,有一个很著名的心理学公式:

    Gray = R*0.299 + G*0.587 + B*0.114

    二、整数算法

    而实际应用时,希望避免低速的浮点运算,所以需要整数算法。

    注意到系数都是3位精度的没有,我们可以将它们缩放1000倍来实现整数运算算法:

    Gray = (R*299 + G*587 + B*114 + 500) / 1000

    RGB一般是8位精度,现在缩放1000倍,所以上面的运算是32位整型的运算。注意后面那个除法是整数除法,所以需要加上500来实现四舍五入。

    就是由于该算法需要32位运算,所以该公式的另一个变种很流行:

    Gray = (R*30 + G*59 + B*11 + 50) / 100

    但是,虽说上一个公式是32位整数运算,但是根据80x86体系的整数乘除指令的特点,是可以用16位整数乘除指令来运算的。而且现在32位早普及了(AMD64都出来了),所以推荐使用上一个公式。

    三、整数移位算法

    上面的整数算法已经很快了,但是有一点仍制约速度,就是最后的那个除法。移位比除法快多了,所以可以将系数缩放成 2的整数幂。

    习惯上使用16位精度,2的16次幂是65536,所以这样计算系数:

    0.299 * 65536 = 19595.26419595
     
    0.587 * 65536 + (0.264) = 38469.632 + 0.264 = 38469.89638469
     
    0.114 * 65536 + (0.896) = 7471.104 + 0.896 = 7472

    可能很多人看见了,我所使用的舍入方式不是四舍五入。四舍五入会有较大的误差,应该将以前的计算结果的误差一起计算进去,舍入方式是去尾法:

    写成表达式是:

    Gray = (R*19595 + G*38469 + B*7472) >> 16

    2至20位精度的系数:

    Gray = (R*1 + G*2 + B*1) >> 2
     
    Gray = (R*2 + G*5 + B*1) >> 3
     
    Gray = (R*4 + G*10 + B*2) >> 4
     
    Gray = (R*9 + G*19 + B*4) >> 5
     
    Gray = (R*19 + G*37 + B*8) >> 6
     
    Gray = (R*38 + G*75 + B*15) >> 7
     
    Gray = (R*76 + G*150 + B*30) >> 8
     
    Gray = (R*153 + G*300 + B*59) >> 9
     
    Gray = (R*306 + G*601 + B*117) >> 10
     
    Gray = (R*612 + G*1202 + B*234) >> 11
     
    Gray = (R*1224 + G*2405 + B*467) >> 12
     
    Gray = (R*2449 + G*4809 + B*934) >> 13
     
    Gray = (R*4898 + G*9618 + B*1868) >> 14
     
    Gray = (R*9797 + G*19235 + B*3736) >> 15
     
    Gray = (R*19595 + G*38469 + B*7472) >> 16
     
    Gray = (R*39190 + G*76939 + B*14943) >> 17
     
    Gray = (R*78381 + G*153878 + B*29885) >> 18
     
    Gray = (R*156762 + G*307757 + B*59769) >> 19
     
    Gray = (R*313524 + G*615514 + B*119538) >> 20

    仔细观察上面的表格,这些精度实际上是一样的:3与4、7与8、10与11、13与14、19与20

    所以16位运算下最好的计算公式是使用7位精度,比先前那个系数缩放100倍的精度高,而且速度快:

    Gray = (R*38 + G*75 + B*15) >> 7

    其实最有意思的还是那个2位精度的,完全可以移位优化:

    Gray = (R + (WORD)G<<1 + B) >> 2

    由于误差很大,所以做图像处理绝不用该公式(最常用的是16位精度)。但对于游戏编程,场景经常变化,用户一般不可能观察到颜色的细微差别,所以最常用的是2位精度。

    public static int[] Turngrey(Image image) {
        int rgx[];
        rgx = new int[image.getWidth() * image.getHeight()];
        image.getRGB(rgx, 0, image.getWidth(), 0, 0, image.getWidth(),
                     image.getHeight()); //获得图片的ARGB值
        int r, g, b;
        for (int j = 0; j < rgx.length; j++) {
            r = (rgx[j] & 0x00ff0000) >> 16;
            g = (rgx[j] & 0x0000ff00) >> 8;
            b = rgx[j] & 0x000000ff;
            if ((rgx[j] == 0x00FFFFFF)) {
                continue;
            }
            r = g;
            b = g;
     
            rgx[j] = ((r << 16) | (g << 8) | b) | 0xff000000;
        }
        return rgx;
    }

    以上是别人写的算法,我把这个算法用到游戏中处理角色死亡的画面,整个屏幕变灰,刷新也变慢,这个效果是很COOL的~~

    在我的项目中我自己写了个函数,一便于我的游戏引擎调度:

    /**
     * @todo 灰度处理
     */
    public static int[] Turngrey(Image image) {
        int rgx[];
        rgx = new int[image.getWidth() * image.getHeight()];
        image.getRGB(rgx, 0, image.getWidth(), 0, 0, image.getWidth(),
                     image.getHeight()); //获得图片的ARGB值
        int r, g, b;
        for (int j = 0; j < rgx.length; j++) {
            r = (rgx[j] & 0x00ff0000) >> 16;
            g = (rgx[j] & 0x0000ff00) >> 8;
            b = rgx[j] & 0x000000ff;
            if ((rgx[j] == 0x00FFFFFF)) {
                continue;
            }
            r = g;
            b = g;
     
            //r = g*3/10;
            //r = (g << 1 + r) >> 3 + (g << 1 + r);
            //b = g * 6 / 10;
            //b = ((g << 1) << 1 + (g << 1)) >> 3 + ((g << 1) << 1 + (g << 1));
     
            //g = g >> 3 + g;
     
            rgx[j] = ((r << 16) | (g << 8) | b) | 0xff000000;
        }
        return rgx;
    }

    游戏中的效果在下面(当然引擎可以随时控制颜色恢复彩色):

     


     

  • 相关阅读:
    cinder支持nfs快照
    浏览器输入URL到返回页面的全过程
    按需制作最小的本地yum源
    创建可执行bin安装文件
    RPCVersionCapError: Requested message version, 4.17 is incompatible. It needs to be equal in major version and less than or equal in minor version as the specified version cap 4.11.
    惠普IPMI登陆不上
    Linux进程状态——top,ps中看到进程状态D,S,Z的含义
    openstack-neutron基本的网络类型以及分析
    openstack octavia的实现与分析(二)原理,架构与基本流程
    flask上下文流程图
  • 原文地址:https://www.cnblogs.com/jacktu/p/1490892.html
Copyright © 2011-2022 走看看