为了账号安全,请及时绑定邮箱和手机立即绑定

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

/ 猿问

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

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

http://img3.sycdn.imooc.com/5d8dbd230001bcab06200358.jpg

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

作为绘画工具,将使用带有油漆的刷子。这意味着绘图仪绘图线不会太细,而且会相对较短。

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

一些初步结果:

http://img1.sycdn.imooc.com/5d8dbd4200017dba04250318.jpg

http://img1.sycdn.imooc.com/5d8dbd42000166e403450230.jpg

http://img4.sycdn.imooc.com/5d8dbd420001f19b05610374.jpg


查看完整描述

2 回答

?
慕仰1329654

抖动

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

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

  1. 将颜色累加器重置为零

  2. 处理所有像素

    1. 为每个像素将其颜色添加到累加器

    2. 在您的调色板中找到最匹配的结果

    3. 渲染选定的调色板颜色

    4. 从累加器中减去选定的调色板颜色

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

//img2.sycdn.imooc.com/5d8dbd5a0001fe4e10240400.jpg

以下是您来源的结果图片:

//img1.sycdn.imooc.com/5d8dbd5d0001531c10240400.jpg

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

这里的代码(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 dd和BYTE db[4]简单的信道接入。


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


List<int> a与相同int a[]。

add(b) 在列表末尾添加b

num 是列表中的项目数

现在,为了避免过多的点(为了绘图仪的使用寿命),您可以改用其他线条图案等,但这需要大量的尝试/错误...例如,您可以计算某个区域使用一种颜色的次数。然后从该比例使用不同的填充方式(基于线条)。您需要在图像质量和渲染/耐用性之间进行选择...


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


查看完整回答
反对 回复 2019-09-27
?
烙印99

Spektre,非常感谢,非常好的回答。我没有提供太多有目的的初始信息。我本来想像头脑风暴会议这样的事情来收集新的想法。在这里,您可以看到有关到目前为止我如何解决问题的方式的更多详细信息:github.com/TodorBalabanov/EllipsesImageApproximator 

查看完整回答
反对 回复 2019-09-27

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信