我原本的想法是,设置一个3维数组,维数是R,G,B值,所以这个数组是这样的array[byte,byte,byte] of word但是问题是,函数不允许有那么大的参数。那好,我现在改成对每一个 r,g,b 值 除以10, 然后 floor,我的意思是忽略细微的颜色差别,结果数组就变成array[0..25,0..25,0..25] of word然后用Scanline取每一点的颜色,相应的改变数组里的值(就是在相应的维数那里加1而已)。这部分已经最大优化了,可以跳过。最后我还要再次检索一次那个三维数组,找到里面的最大值。再将维数提出来,变化一个颜色。这个值就是近似出现最多的那种颜色。这种方法我是创建了一个 thread 来做的,速度还可以接受。
只是效果不是太好,并不能找到最准确的值。而且,如果一张图象,背景都是近似白的,但是人物有很多暗色,结果得出来的还是类似黑色的值。我在网上也搜索了很久,找不到有什么可以参考的信息。所以来这里请教,请各位有自己想法的给点提示吧,谢谢!

解决方案 »

  1.   

    建议,用Scanline取得R,G,B的颜色,分别累积,然后再得到其平均值,转换成颜色
      

  2.   

    你的意思是有N点,就分别把 R,G,B 累加起来,然后每个值除以 N ,最后再组成得到那个颜色?这样不行的,多数得到都是一个类似黑色的值。我已经试过了。
      

  3.   

    array[byte,byte,byte] of word
    是可以的。大不了定义一个全局变量。从速度上考虑,除以10再floor速度会比较慢。
    建议采用移位操作。SHR会快很多。采用两个个变量,记录当前最多的一种颜色和当前最多的一种颜色的出现次数。
    这样可以减少最后的一次检索工作。背景都是近似白的,但是人物有很多暗色
    有可能出现次数最多的就是这种暗色呀?
      

  4.   

    array[byte,byte,byte] of word 无法出现在局部变量,已经超过64K,因为我不止只有这一个变量,除非像你说的定义为全局就可以。但是数组那么大,定义为全局很浪费哦。你说的那个定义两个变量,在读Scanline的过程中,我是一点一点的那样读,我最多只能保存,我怎么可能知道哪个颜色正在出现得最多呢?所以你说的方法我不是太理解。而我说的那种情况确实可以出现,在我测试过程中就有这么一张图片出现。比如一张雪地,某一个角落是人物,但基本上都是黑色。要知道,我是读近似值,是取 floor,如果有很多 030309 之类的值,就全部变成 黑色,十分集中; 而那一堆雪地,因为颜色分得很散;并不能保证近似后都变成白色。结果,这样一张图片本意上是取占大体的颜色素,不一定是白色啦,但是却很容易因为我的算法得到一个很暗的颜色。我曾经试过用 hashedstringlist 来保存每一点的颜色,最后再检索比较的时候,根本慢倒吐血。或许我还可以再强化一下我的算法,比如增加一倍,用 [50,50,50] 的数组来判断,或许结果会更准确。可是,这样真的好吗?
      

  5.   

    定义两个变量
    var
     a:array[..] of word;
     MaxCountColor:integer; MaxCount :integer;MaxCount :=0;
    MaxCountColor := 0;
    for i:=0 to ....
    begin
      a[r,g,b] := a[r,g,b] +1;
      if a[r,g,b] > MaxCount then
      begin
        MaxCountColor := r shl 16 + g shl 8 + b; 
        MaxCount := a[r,g,b]; //这就是最大数量的颜色和最大数量
      end;
      

  6.   

    >>背景都是近似白的,但是人物有很多暗色增加一倍不可能有更好的效果。
    减少一倍的效果可能更好一些。
    就是说,采用[8,8,8]的效果试试看。建议采用2的倍数,然后移位操作会快很多。上面的代码没有认真考虑,不过你应该能懂。
      

  7.   

    BTW:
    array[byte,byte,byte] of word;
    定义在局部变量或者作为函数的参数(要先用type定义类型)都可以。
    我在我的机器上测试通过。
      

  8.   

    那个局部变量的问题真奇怪。如果我 VAR ,是绝对不行,我也不知道为什么。即使我定义了一个全局的 
    type
      tflagArray = array [byte,byte,byte] of integer;然后在函数里 var 
      flags:tflagArray;还是会出错。我个人就一直觉得是不行的,即使可以,也不是一个好方法。因为所有函数入口出都会根据子变量的多少在 stack 上预留空间,如果定义一个那么的空间,对 stack 来说太危险,很容易 overflow。所以,还是算了。你的算法很不错。不过我改成了 [17,17,17], 代码也改成     for...
            r:=rgbtRed shr 4;
            b:=rgbtBlue shr 4;
            g:=rgbtGreen shr 4;
            inc(flags[r,g,b]);        if (flags[r,g,b]>MaxCount) then begin
              MaxCountColor := RGB(rgbtRed,rgbtGreen,rgbtBlue);
              MaxCount:=flags[r,g,b];
            end;这样的结果比较正常,而且最后的颜色也绝对是图片上的色。