有效的gif /图像颜色量化?

FTL*_*lph 5 java algorithm gif animated-gif quantization

所以我试图在我的Java应用程序中编码一些动画gif文件.我一直在使用在线发现的一些类/算法,但似乎没有一个工作得很好.

现在我正在使用这个量化类将图像的颜色减少到256:http://www.java2s.com/Code/Java/2D-Graphics-GUI/Anefficientcolorquantizationalgorithm.htm

问题是,它似乎并不是非常"聪明".

如果我传入的图像超过256种颜色,它确实会减少颜色数,但效果不是很好.(红色变成蓝色等 - 非常明显的错误就像这样).

您可以推荐使用Java中的颜色量化的其他算法/库吗?


注意:我知道在此算法中使用的Neuquant:http://www.java2s.com/Code/Java/2D-Graphics-GUI/AnimatedGifEncoder.htm

它非常慢并产生"eh"结果(帧之间的颜色闪烁).

Spe*_*tre 9

你可以谷歌搜索中位数,人口,k均值等其他算法.

我最近也需要这个,但也必须看起来很漂亮(我需要这个实时视频捕获)所以我设法做了这样的事情:

  1. 转换为15位rgb

    如果您已经有RGB,则可以跳过此步骤但应用shift /并匹配每个通道5位.您也可以使用5:6:5方案

  2. 做直方图

    15位rgb导致32768个条目,因此创建2个阵列

    • his[32768] 是像素数(直方图)
    • idx[32768] 是index =颜色值

    计数颜色可确保计数器在使用低位数或高分辨率时不会溢出

  3. 对数组进行重新排序,使得零位于his[]数组的末尾

    还计算非零条目his[]并调用它hists

  4. (索引)分类hist[],idx[]以便hist[]被命令下降;

  5. 创建N色调色板

    取颜色idx[i](i={ 0,1,2,3,...,hists-1 })并查看调色板中是否有相似的颜色.如果忽略此颜色(将其设置为最接近的颜色),否则将其添加到调色板.如果你达到N颜色停止

  6. 创建颜色映射

    因此,取每种颜色并在调色板中找到最接近的颜色(这可以在步骤5中部分完成)我称之为此表 recolor[32][32][32]

  7. 重新着色图像

这是C++源码:

BYTE db,*p;
AnsiString code;
int e,b,bits,adr;
int x0,x1,y0,y1,x,y,c;
DWORD ix,cc,cm,i0,i,mask;
union { DWORD dd; BYTE db[4]; } c0,c1;


    DWORD r,g,b; int a,aa,hists;
    DWORD his[32768];
    DWORD idx[32768];
    // 15bit histogram
    for (x=0;x<32768;x++) { his[x]=0; idx[x]=x; }
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        cc=pyx[y][x];
        cc=((cc>>3)&0x1F)|((cc>>6)&0x3E0)|((cc>>9)&0x7C00);
        if (his[cc]<0xFFFFFFFF) his[cc]++;
        }
    // remove zeroes
     for (x=0,y=0;y<32768;y++)
        {
        his[x]=his[y];
        idx[x]=idx[y];
        if (his[x]) x++;
        } hists=x;
    // sort by hist
    for (i=1;i;)
     for (i=0,x=0,y=1;y<hists;x++,y++)
      if (his[x]<his[y])
        {
        i=his[x]; his[x]=his[y]; his[y]=i;
        i=idx[x]; idx[x]=idx[y]; idx[y]=i; i=1;
        }
    // set lcolor color palete
    for (i0=0,x=0;x<hists;x++) // main colors
        {
        cc=idx[x];
        b= cc     &31;
        g=(cc>> 5)&31;
        r=(cc>>10)&31;
        c0.db[0]=b;
        c0.db[1]=g;
        c0.db[2]=r;
        c0.dd=(c0.dd<<3)&0x00F8F8F8;
        // skip if similar color already in lcolor[]
        for (a=0,i=0;i<i0;i++)
            {
            c1.dd=lcolor[i];
            aa=int(BYTE(c1.db[0]))-int(BYTE(c0.db[0])); if (aa<=0) aa=-aa; a =aa;
            aa=int(BYTE(c1.db[1]))-int(BYTE(c0.db[1])); if (aa<=0) aa=-aa; a+=aa;
            aa=int(BYTE(c1.db[2]))-int(BYTE(c0.db[2])); if (aa<=0) aa=-aa; a+=aa;
            if (a<=16) { a=1; break; } a=0; // *** treshold ***
            }
        if (a) recolor[r][g][b]=i;
        else{
            recolor[r][g][b]=i0;
            lcolor[i0]=c0.dd; i0++;
            if (i0>=DWORD(lcolors)) { x++; break; }
            }
        }   // i0 = new color table size
    for (;x<hists;x++)  // minor colors
        {
        cc=idx[x];
        b= cc     &31;
        g=(cc>> 5)&31;
        r=(cc>>10)&31;
        c0.db[0]=b;
        c0.db[1]=g;
        c0.db[2]=r;
        c0.dd=(c0.dd<<3)&0x00F8F8F8;
        // find closest color
        int dc=-1; DWORD ii=0;
        for (a=0,i=0;i<i0;i++)
            {
            c1.dd=lcolor[i];
            aa=int(BYTE(c1.db[0]))-int(BYTE(c0.db[0])); if (aa<=0) aa=-aa; a =aa;
            aa=int(BYTE(c1.db[1]))-int(BYTE(c0.db[1])); if (aa<=0) aa=-aa; a+=aa;
            aa=int(BYTE(c1.db[2]))-int(BYTE(c0.db[2])); if (aa<=0) aa=-aa; a+=aa;
            if ((dc<0)||(dc>a)) { dc=a; ii=i; }
            }
        recolor[r][g][b]=ii;
        }
Run Code Online (Sandbox Code Playgroud)

所有者图像类包含:

// image data
Graphics::TBitmap *bmp,*bmp0,*bmp1; // actual and restore to 32bit frames,and 8bit input conversion frame
int xs,ys;                      // resolution
int *py;                        // interlace table
DWORD **pyx,**pyx0;             // ScanLine[] of bmp,bmp0
BYTE  **pyx1;

// colors (colors are computed from color_bits)
DWORD gcolor[256];              //hdr
DWORD lcolor[256];              //img
BYTE  recolor[32][32][32];      //encode reduce color table
int scolors,scolor_bits;        //hdr screen color depth
int gcolors,gcolor_bits;        //hdr global pallete
int lcolors,lcolor_bits;        //img/hdr local palette
Run Code Online (Sandbox Code Playgroud)
  • pyx[],bmp包含源32位图像
  • pyx1[],bmp1是用于编码临时8位图像

这是重新着色的方式:

    // recolor to lcolors
    for (y=0;y<ys;y++)
     for (x=0;x<xs;x++)
        {
        int r,g,b;
        c0.dd=(pyx[y][x]>>3)&0x001F1F1F;
        b=c0.db[0];
        g=c0.db[1];
        r=c0.db[2];
        i=recolor[r][g][b];
//      pyx [y][x]=lcolor[i];   // 32 bit output (visual)
        pyx1[y][x]=i;           // 8  bit output (encoding)
        }
Run Code Online (Sandbox Code Playgroud)

这里有一些输出示例:

这是VCL/GDI色彩还原,我的方法和原始图像之间的比较)

GDI对比这个算法

上部是调色板绘图(原始图像包含中间图像的调色板)

这里真彩照片:

原始照片

并减少到256种颜色:

减少颜色

这需要约185ms来编码成GIF(包括颜色减少).我对结果非常满意,但你可以看到图像不一样.重新着色后绿草簇有点不同(面积/强度较小?)

[笔记]

代码尚未优化,因此它应该是一种使其更快的方法.您可以通过以下方式提高编码速度:

  1. 降低最大编码字典大小
  2. 使用索引表进行字典或三种结构加速搜索
  3. 可以更改直方图冒泡排序,以更快地排序算法(但这部分代码远非关键)
  4. 编码序列你可以使用单个调色板(如果场景没有太多的颜色变化)
  5. 如果你想要更高的速度,那么创建静态调色板并使用抖动代替所有这些

这里是一个RT捕获视频的例子(源是50fps,所以我降低分辨率以匹配速度):

捕获示例


cMi*_*nor 2

你可以使用Gif89Encoder

这个用于编码 GIF 的 Java 类库比任何其他免费 Java GIF 编码器涵盖了更多的扩展 GIF89a 功能集,包括动画和嵌入式文本注释。

http://imagej.nih.gov/ij/

Java 的动画 GIF 库

我使用了 Java 的 Animated GIF 库,效果很好