请教算法:如何得到一张图片中出现最多的一种颜色呢?

anggogo 2004-04-30 01:25:13
我原本的想法是,设置一个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 来做的,速度还可以接受。
只是效果不是太好,并不能找到最准确的值。

而且,如果一张图象,背景都是近似白的,但是人物有很多暗色,结果得出来的还是类似黑色的值。

我在网上也搜索了很久,找不到有什么可以参考的信息。所以来这里请教,请各位有自己想法的给点提示吧,谢谢!
...全文
558 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
anggogo 2004-04-30
  • 打赏
  • 举报
回复
你的意思是有N点,就分别把 R,G,B 累加起来,然后每个值除以 N ,最后再组成得到那个颜色?

这样不行的,多数得到都是一个类似黑色的值。我已经试过了。
xzhifei 2004-04-30
  • 打赏
  • 举报
回复
建议,用Scanline取得R,G,B的颜色,分别累积,然后再得到其平均值,转换成颜色
anggogo 2004-04-30
  • 打赏
  • 举报
回复
那个局部变量的问题真奇怪。

如果我 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;

这样的结果比较正常,而且最后的颜色也绝对是图片上的色。
windindance 2004-04-30
  • 打赏
  • 举报
回复
BTW:
array[byte,byte,byte] of word;
定义在局部变量或者作为函数的参数(要先用type定义类型)都可以。
我在我的机器上测试通过。
windindance 2004-04-30
  • 打赏
  • 举报
回复
>>背景都是近似白的,但是人物有很多暗色

增加一倍不可能有更好的效果。
减少一倍的效果可能更好一些。
就是说,采用[8,8,8]的效果试试看。

建议采用2的倍数,然后移位操作会快很多。

上面的代码没有认真考虑,不过你应该能懂。
windindance 2004-04-30
  • 打赏
  • 举报
回复
定义两个变量
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;
anggogo 2004-04-30
  • 打赏
  • 举报
回复
array[byte,byte,byte] of word 无法出现在局部变量,已经超过64K,因为我不止只有这一个变量,除非像你说的定义为全局就可以。但是数组那么大,定义为全局很浪费哦。

你说的那个定义两个变量,在读Scanline的过程中,我是一点一点的那样读,我最多只能保存,我怎么可能知道哪个颜色正在出现得最多呢?所以你说的方法我不是太理解。

而我说的那种情况确实可以出现,在我测试过程中就有这么一张图片出现。

比如一张雪地,某一个角落是人物,但基本上都是黑色。要知道,我是读近似值,是取 floor,如果有很多 030309 之类的值,就全部变成 黑色,十分集中; 而那一堆雪地,因为颜色分得很散;并不能保证近似后都变成白色。结果,这样一张图片本意上是取占大体的颜色素,不一定是白色啦,但是却很容易因为我的算法得到一个很暗的颜色。

我曾经试过用 hashedstringlist 来保存每一点的颜色,最后再检索比较的时候,根本慢倒吐血。或许我还可以再强化一下我的算法,比如增加一倍,用 [50,50,50] 的数组来判断,或许结果会更准确。可是,这样真的好吗?
windindance 2004-04-30
  • 打赏
  • 举报
回复
array[byte,byte,byte] of word
是可以的。大不了定义一个全局变量。

从速度上考虑,除以10再floor速度会比较慢。
建议采用移位操作。SHR会快很多。

采用两个个变量,记录当前最多的一种颜色和当前最多的一种颜色的出现次数。
这样可以减少最后的一次检索工作。

背景都是近似白的,但是人物有很多暗色
有可能出现次数最多的就是这种暗色呀?

1,185

社区成员

发帖
与我相关
我的任务
社区描述
Delphi GAME,图形处理/多媒体
社区管理员
  • GAME,图形处理/多媒体社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧