我有一个这样的绘图仪:image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

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

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

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

一些初步结果:

image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

最佳答案

抖动

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

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

  • 将颜色累加器重置为零
  • 处理所有像素
  • 将每个像素的颜色添加到累加器
  • 在您的调色板中找到最接近的匹配结果
  • 渲染选定的调色板颜色
  • 从累加器中减去选定的调色板颜色

  • 这是您的输入图像(我将它们放在一起):

    image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

    这是您的来源的结果图像:

    image-processing - 将 BMP 图像转换为绘图仪的指令集?-LMLPHP

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

    这里的代码( 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 位像素格式,因此每 channel 8 位)
  • clear(DWORD c) 用颜色填充图像 c
  • color 只是 unionDWORD ddBYTE db[4] ,用于简单的 channel 访问。
    List<> 是我的模板(动态数组/列表>
  • List<int> aint a[] 相同。
  • add(b) 在列表末尾添加 b
  • num 是列表中的项目数

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

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

    关于image-processing - 将 BMP 图像转换为绘图仪的指令集?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36674210/

    10-10 00:59
    查看更多