实时绘制1像素厚的别名线

时间:2010-12-28 21:21:51

标签: algorithm graphics drawing paint

简要背景:我正在研究基于网络的绘图应用程序,我正在实现的工具之一是1像素厚的铅笔。该工具允许用户在画布上绘制1px别名行。

为了确定用户在画布上绘制的位置,将监视鼠标坐标。如果按住mouse1,光标所在的像素将会改变。基本上它就像Photoshop中的铅笔工具一样。

注意:Bresenham的算法不适用于这种情况。我的输入是实时提交的,所以我没有画一条从P0到P1的线,其中P0和P1之间的距离是很多像素。通常,P1是P0的邻居。

我遇到的问题是我生成的线条没有完全干净的1px重量。这是一个例子:

Line comparison

请注意,两条线都是手绘的,因此存在一些差异。有趣的是,Photoshop能够为我绘制的线条制作更清晰的1px表示。我的生产线看起来更脏的原因是:

Photoshop's line

My line

在我的应用程序中使用工具绘图时,红色像素被填充。在Photoshop中,红色像素未填充。这是有道理的,因为为了从给定像素移动到例如其东南方向邻居,东方或南方邻居都可能会被遗弃。光标很可能会将完全通过角落传递到东南邻居,避免绘制红色像素,但这通常不会发生。

所以,我留下的问题是Photoshop如何能够跳过我的线条中出现的红色像素。我唯一能想到的就是等到两个像素排队之后才能绘制其中任何一个,这样我就知道是否有一个“角落邻居”被传递过来。在这种情况下,我不会绘制两个像素中的第一个,因为它相当于我的图中的红色像素。如果用户绘制像素,将光标向南移动一个像素,然后向东移动一个像素,则存在不绘制预期像素的风险。应绘制两个像素,但算法会另外说明。

有什么想法吗? Photoshop如何处理这个问题?

3 个答案:

答案 0 :(得分:5)

两条线之间的差异基本上是Photoshop重新考虑在绘制像素n后绘制的n-1像素,如果它使用以下一个掩模给出正面,则擦除它:

 x 1 x       x 1 x
 1 o x   or  x o 1
 x x x       x x x

 x x x       x x x
 1 o x   or  x o 1
 x 1 x       x 1 x

x =不介意
o = n-1像素
1 =绘制像素n后标记的像素

或写成逻辑:

假设像素n-1位于[i,j],因此,在标记像素n之后,检查:

If ( (a[i-1,j  ]==1 && a[i  ,j-1]==1) ||
     (a[i-1,j  ]==1 && a[i  ,j+1]==1) ||
     (a[i  ,j-1]==1 && a[i+1,j  ]==1) ||
     (a[i  ,j+1]==1 && a[i+1,j  ]==1))
Then
     Unmark a[i,j];

你可能希望你的行延迟一个像素,只是为了不显示你的“消失”像素(虽然我怀疑它会在那个尺度上引人注目)。

alt text

答案 1 :(得分:3)

原创:看看Bresenham的线算法。它可以很容易地扩展平滑等。

编辑:关于问题和讨论的发展(特别是下面的评论),我想提出一些有趣的观点:Photoshop的铅笔工具也绘制了与“东方”非常相似的线条“和”东南“像素也是如此,如果鼠标移动相对较慢,从而为所有这些像素提供许多样本。一旦鼠标移动得更快,轨迹就不会为所有直接相邻的像素提供样本。结果将是所需的1像素粗线。总之,我们注意到:Photoshop的铅笔工具背后没有“魔力”;它似乎扫描更少的样本。有关详细信息,请参阅下面的讨论/评论。

答案 2 :(得分:0)

我猜你终于解决了你的问题(6年过去了......),但我只想说你的应用程序在这种特殊情况下似乎比Photoshop更好。虽然我认为我知道你的目标是什么(避免那些像素聚类),但是使用你的应用程序(尽管那些不需要的分组)可以更好地实现“恒定厚度”,而Photoshop制作的“香肠绳”图案可能更聪明,但没有所以宽度恒定,因此,不那么“真实”。这可能是由于十进制值的不同处理(舍入)和选择要填充或跳过的像素。但同样,这是一个古老的话题。