将BMP图像转换为绘图仪的指令集?

时间:2016-04-17 08:18:29

标签: image-processing colors vectorization reduction

我有一个像这样的绘图仪:PloterXY device.

我必须实现的任务是将24位BMP转换为该绘图仪的指令集。在绘图仪中,我可以改变16种常见颜色。我面临的第一个复杂性是颜色减少。我面临的第二个复杂性是如何将像素转换为一组绘图指令。

将使用带油漆的绘图工具刷。这意味着绘图仪绘制线不会那么小,而且它们会相对较短。

请建议可用于解决此图像数据转换问题的算法?

一些初步结果:

Flower 1 - colors reduction.

Flower 2 - colors reduction.

Flower 3 - colors reduction.

1 个答案:

答案 0 :(得分:5)

<强>抖动

嗯,今天我有一些时间,所以这里结果。您没有提供绘图仪调色板,因此我从生成的图像中提取它,但您可以使用任何颜色。抖动背后的想法很简单我们的感知是在区域上集成颜色而不是单个像素,所以你必须使用一些颜色差异的累加器,而不是渲染的内容和应该渲染的内容,并将其添加到下一个像素......

这样,该区域具有大致相同的颜色,但实际上只使用离散数量的颜色。如何更新此信息的形式可以将结果分支抖动与许多方法区分开来。简单明了就是:

  1. 将颜色累加器重置为零
  2. 处理所有像素
    1. 为每个像素添加其颜色到累加器
    2. 在调色板中找到最接近的匹配结果
    3. 渲染选定的调色板
    4. 从累加器
    5. 中减去所选的调色板颜色
  3. 这是你的输入图片(我把它们放在一起):

    input

    此处为您的来源的结果图片:

    result

    左上角的颜色方块只是我使用的调色板(从图像中提取)。

    这里代码( C ++ )我这样做:

    picture pic0,pic1,pic2;
        // pic0 - source img
        // pic1 - source pal
        // pic2 - output img
    int x,y,i,j,d,d0,e;
    int r,g,b,r0,g0,b0;
    color c;
    List<color> pal;
    // resize output to source image size clear with black
    pic2=pic0; pic2.clear(0);
    // create distinct colors pal[] list from palette image
    for (y=0;y<pic1.ys;y++)
     for (x=0;x<pic1.xs;x++)
        {
        c=pic1.p[y][x];
        for (i=0;i<pal.num;i++) if (pal[i].dd==c.dd) { i=-1; break; }
        if (i>=0) pal.add(c);
        }
    // dithering
    r0=0; g0=0; b0=0;   // no leftovers
    for (y=0;y<pic0.ys;y++)
     for (x=0;x<pic0.xs;x++)
        {
        // get source pixel color
        c=pic0.p[y][x];
        // add to leftovers
        r0+=WORD(c.db[picture::_r]);
        g0+=WORD(c.db[picture::_g]);
        b0+=WORD(c.db[picture::_b]);
        // find closest color from pal[]
        for (i=0,j=-1;i<pal.num;i++)
            {
            c=pal[i];
            r=WORD(c.db[picture::_r]);
            g=WORD(c.db[picture::_g]);
            b=WORD(c.db[picture::_b]);
            e=(r-r0); e*=e; d =e;
            e=(g-g0); e*=e; d+=e;
            e=(b-b0); e*=e; d+=e;
            if ((j<0)||(d0>d)) { d0=d; j=i; }
            }
        // get selected palette color
        c=pal[j];
        // sub from leftovers
        r0-=WORD(c.db[picture::_r]);
        g0-=WORD(c.db[picture::_g]);
        b0-=WORD(c.db[picture::_b]);
        // copy to destination image
        pic2.p[y][x]=c;
        }
    // render found palette pal[] (visual check/debug)
    x=0; y=0; r=16; g=pic2.xs/r; if (g>pal.num) g=pal.num;
    for (y=0;y<r;y++)
     for (i=0;i<g;i++)
      for (c=pal[i],x=0;x<r;x++)
       pic2.p[y][x+(i*r)]=c;
    

    其中picture是我的图片类,所以这里有一些成员:

    • xs,ys决议
    • color p[ys][xs]直接像素访问(32位像素格式,每通道8位)
    • clear(DWORD c)使用颜色c
    • 填充图片

    color只是union DWORD ddBYTE db[4],用于简单频道访问。

    List<>是我的模板(动态数组/列表&gt;

    • List<int> aint a[]相同。
    • add(b)在列表末尾添加b
    • num是列表中的项目数

    现在为了避免过多的点(为了你的绘图仪的生命周期),你可以使用不同的线条图案等,但这需要大量的试验/错误...例如你可以计算使用颜色的次数在某些区域,从该比例使用不同的填充模式(基于线条)。您需要在图像质量和渲染速度/耐久性之间做出选择......

    如果没有关于绘图仪功能(速度,换刀方法,颜色组合行为)的更多信息,很难确定形成控制流的最佳方法。我敢打赌你手动改变颜色,这样你就可以一次渲染每种颜色。因此,使用第一个工具的颜色将相邻像素的所有像素提取到线条/曲线并渲染...然后移动到下一个工具颜色......