RGB24转为灰度图本身并不难。基本方法就是计算象素的R、G、B分量的平均值(加起来除以3)。但是我想知道MMX指令能否帮助优化?初看完MMX指令的解释,觉得根本没法用在这个程序中。RGB24内存区是这样分布的:R1 G1 B1 R2 G2 B2 R3 G3 B3 ……。
现在要把它变成:(R1+G1+B1)/3 (R2+G2+B2)/3 (R3+G3+B3)/3 ……。这三个三个的,也没法用顺序分组,也没法用交错分组,也就更提不上一条加法指令计算多个象素了。何况还要除以3……。有没有高手能给我点提示或思路?谢谢!

解决方案 »

  1.   

    查表:
    char table[256*3];
    int i;
    for (i = 0; i < sizeof(table); i++) {
    table[i] = i/3;
    }
    ...
    for (i = 0; i < picture_pixels; i+= 2) {
    table(R[i]+G[i]+B[i]);
    table(R[i+1]+G[i+1]+B[i+1]);
    }
    1) 无须除法
    2) for里面2为单位处理,可以优化指令流水
      

  2.   

    不是很难,说说思路吧
    1. 每次从源内存,假设在 edi 读3个64位的数,放在mm1, mm2, mm3
       movq mm1, byte ptr [edi]
       movq mm2, byte ptr [edi+8]
       movq mm3, byte ptr [edi+16]
       那么mm1, mm2, mm3里存放的数据是:
       mm1: R1 G1 B1 R2 G2 B2 R3 G3
       mm2: B3 R4 G4 B4 R5 G5 B5 R6
       mm3: G6 B6 R7 G7 B7 R8 G8 B8
       取三个常量作为R的掩码:R_Mask1 = 0xFF0000FF0000FF00 
                              R_Mask2 = 0x00FF0000FF0000FF
                              R_Mask3 = 0x0000FF0000FF0000
       有没有注意到三个掩码正好交错,取 mm4 = (mm1 & R_Mask1) | (mm2 & R_Mask2) | (mm3 & R_Mask3)
       这时候 mm4 = R1 R4 R7 R2 R5 R8 R3 R6
       正好是8个像素的R值,同样可以得到
              mm5 = G6 G1 G4 G7 G2 G5 G8 G3
              mm6 = B3 B6 B1 B4 B7 B2 B5 B8
       关系就是依次左移8位
       
    2. 把 mm4 unpack到两个64位寄存器中,对mm5, mm6作同样操作,然后对齐数据(懒了,不写了,基本就是用psllq之类的移位操作)
       假设mm4 mm5 mm6都对齐了数据,比如
       mm4: R1 0 R4 0 R7 0 R2 0
       mm5: G1 0 G4 0 G7 0 G2 0
       mm6: B1 0 B4 0 B7 0 B2 03. 最后是加起来除3的操作,这里建议看一下这篇文章 http://blog.csdn.net/zyl910/archive/2006/05/22/749752.aspx
       把除法转换为加法和移位操作
                   
      

  3.   

    基本方法就是计算象素的R、G、B分量的平均值?错了吧,你用下面的灰度公式试试看就知道思路不正确。(我曾经犯同样错误)
    0.299 R +0.587 G+0.114B=graylevel
    这个是国际标准!
    MMX指令问题就算了吧。
      

  4.   

    0.299 R +0.587 G+0.114B=graylevel这个公式可不是随便乱写的,是基于光学、心理学的经验公式。不是哪个程序员造出来的
      

  5.   

    非常感谢楼上各位高手的回复,小弟一一受教。CounterHack:
    在发了这个帖子,又一时等不到回复时,一着急自己写想出你说的方法。所以看到你出的主意感到蛮亲切的呵呵~而且我觉得这个看似儿科的方法,其实在很多地方能够发挥意想不到的良好性能。攒一个!DRACULAX05:
    没想到这么蹩脚的错位计算,还能用这种单指令多数据的方式处理啊,你头脑真够灵活的。不过我还一时看不懂,复制下来慢慢研究!感觉MMX的指令的思路很另类啊。rover:
    你说的是求亮度的公式。当需要从图像中提取亮度时(比如RGB转YUV时),确实需要如你所说的运算,简单的除以3是不行的(否则转换后很多颜色无法区分了,比如纯红和纯蓝)。我最后的解决办法:我向公司算法部门的同事请教,一时没能拿到MMX版的程序,只是找到了一个能求亮度的,全整数运算的公式:
    CLIP255((( 77*R + 150*G +  29*B + 128) >>8)); // 其中“CLIP255”自己顾名思义吧我没有仔细对比,但是心想大概应该是对求Y公式中的小数因数通分之后,再把分母尽量做成“除以256”,然后获得的计算式。估计我猜得应该差不多呵呵。