将BMP图像转换为绘图仪的指令集?
我有一个这样的绘图仪:
我必须执行的任务是将24位BMP转换为该绘图仪的一组指令。 在绘图仪中,我可以改变16种常见的颜色。 我面临的第一个复杂性就是颜色的减less。 我面对的第二个复杂性是如何将像素转换成绘图指令集。
因为使用油漆的绘画工具刷将被使用。 这意味着绘图机的绘制线不会太小,而且会比较短。
请提出可以用来解决这个图像数据转换问题的algorithm?
一些初步结果:
抖动
那么今天我得到了一些这样的结果。 你没有提供你的绘图仪调色板,所以我从你的结果图像中提取,但你可以使用任何。 抖动背后的想法很简单,我们的理解是将颜色集中在区域而不是单个像素上,所以您必须使用渲染的颜色差异累加器和应该渲染的颜色差异,并将其添加到下一个像素中。
这样,该区域具有大致相同的颜色,但实际上仅使用离散数量的颜色。 如何更新此信息的forms可以将分支抖动的结果与许多方法区分开来。 简单明了的是这样的:
- 将颜色累加器重置为零
- 处理所有像素
- 为每个像素添加颜色到累加器
- 在调色板中find最接近的匹配结果
- 渲染选定的调色板颜色
- 从累加器中减去选定的调色板颜色
在这里你的input图像(我把它们放在一起):
这里的结果图像为您的来源:
左上angular的颜色方块就是我用过的调色板(从图像中提取)。
这里代码( 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
只是DWORD dd
和BYTE db[4]
的简单通道访问的联合。
List<>
是我的模板(dynamic数组/列表)
-
List<int> a
与int a[]
相同。 -
add(b)
在列表的末尾添加b - 数量是列表中的项目数量
现在为了避免太多的点(为了你的绘图仪的寿命),你可以使用不同的线条模式等,但是这需要大量的试验/错误…例如,你可以计算某个区域使用了多less次颜色并从这个比例使用不同的填充模式(基于线)。 您需要在图像质量和渲染速度/耐久性之间进行select…
如果没有关于绘图仪function(速度,换刀方法,颜色组合行为)的更多信息,很难确定形成控制stream的最佳方法。 我敢打赌,你手动改变颜色,所以你会一次呈现每种颜色。 因此,提取所有像素与第一个工具的颜色合并相邻像素线/曲线和渲染…然后移动到下一个工具颜色…