抖动
今天我有时间来做这件事,所以这里是结果。你没有提供你的绘图机颜色板,所以我从你的结果图像中提取了它,但你可以使用任何颜色板。抖动背后的思想很简单:我们的感知将区域上的颜色集成起来,而不是看单个像素,因此必须使用一些颜色差异积累器,该积累器记录已渲染和应该被渲染的内容之间的颜色差异,并将其添加到下一个像素…
这样,区域内大致具有相同的颜色,但实际使用的只有离散数量的颜色。如何更新此信息的形式会影响结果,导致抖动分支出许多方法。最简单直接的方法是:
以下是你的输入图像(我把它们放在一起):
这里是你的源图像的结果:
左上角的颜色方块只是我使用的调色板(从你的图像中提取出来的)。
以下是我用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]
的union
,用于简单的通道访问。
List<>
是我的模板(动态数组/列表)
List<int> a
与int a[]
相同。add(b)
将b添加到列表末尾num
是列表中项目的数量现在为了避免过多的点(为了您的绘图仪的使用寿命),您可以使用不同的线条样式等,但这需要大量的试验/错误...例如,您可以计算某个区域中使用特定颜色的次数,并从该比率使用不同的填充模式(基于线条)。您需要在图像质量、渲染速度/耐久性之间进行选择...
如果没有更多关于您的绘图仪能力(速度、工具更换方法、颜色组合行为)的信息,很难决定最佳形成控制流的方法。我打赌您手动更改颜色,因此您将一次渲染每种颜色。因此,提取所有使用第一个工具颜色的像素,将相邻像素合并为线条/曲线并进行渲染...然后移动到下一个工具颜色...