很多人都喜欢绘画技术之一是点画法(pointillism),这是一种绘画技术,其中将细小的不同颜色的点应用于图案中以形成图像。该技术依赖于观看者的眼睛和心灵将色斑混合到更广泛的色调范围内的能力。不同颜色的并置使它们更加生动,使整个图像更具活力。点画法是一种很棒的技术,但是要制作这些类型的画,您需要采取有条不紊且漫长的方法。作为计算机视觉开发人员,我对处理图像有很多了解,但是在绘画方面很糟糕。那么如何使用Python和OpenCV创建Pointillist绘画?
模拟绘画过程
绘画过程模拟分三个步骤完成:
1. 调色板创建
2. 行程大小和长度计算
3. 实际绘画
调色板创建
首先,我们需要确定哪些颜色将出现在“虚拟艺术家”的调色板中。我们需要选择与图像的颜色一致但又生动鲜明的一组颜色。
我们首先运行k均值以从图像中选择n = 20种主色。k均值的“对抗性”性质会产生不同的颜色,这些颜色集中在图像中最常见的颜色周围。
为了增加活力,我们通过添加kmeans选择的颜色的一些变化来增强调色板。我选择添加一个更加饱和的基础调色板版本,并在颜色中添加两个小的变化(±20色),并增加一点饱和度。
行程方向和长度计算
为了使最终结果更具动感,我们可以使用较小的不同颜色的笔触代替圆点。实际上,这是许多点画师绘画中使用的技术!我们希望笔触的方向与图像的内容一致,并使用更长的笔触来描绘边缘。因此,我们使用图像渐变来确定每个绘画笔触的长度和方向。
为了计算笔刷笔触的方向和长度,我们在x和y轴上采用Scharr图像导数,从而在图像上定义了矢量场。然后,我们使用高斯模糊对场进行平滑处理,以使最终的“绘画”更加连贯。
绘画过程
我们像一位真正的画家一样绘制最终结果,一次一击!对于每个笔划,我们必须决定:
1. 职位
2. 每个笔触的方向和长度
3. 使用哪种颜色的调色板
选择一个随机位置可能很诱人,但是这种方法的主要缺点是:我们不知道何时绘制了足够的笔触来填充整个图像。因此,我们通过在图像上均匀采样来创建笔划位置的列表,向每个位置添加一点随机噪声,然后对列表进行混洗以使笔划具有随机顺序。
<p> def randomized_grid(h, w, scale):</p>
<p> r = scale//2</p>
<p> grid = []</p>
<p> for i in range(0, h, scale):</p>
<p> for j in range(0, w, scale):</p>
<p> y = random.randint(-r, r) + i</p>
<p> x = random.randint(-r, r) + j</p>
<p> grid.append((y % h, x % w))</p>
<p> random.shuffle(grid)</p>
<p> return grid</p>
一旦我们使用图像梯度在图像上定义了矢量场,方向和长度就易于计算。
<p> angle = math.degrees(gradient.direction(y, x)) + 90</p>
<p> length = int(round(stroke_scale + stroke_scale *
math.sqrt(gradient.magnitude(y, x))))</p>
我们将渐变的方向旋转90度,因为我们希望笔触与图像边缘平行(图像渐变垂直于边缘)。根据图像梯度的大小(即强度)计算长度。这里stroke_scale是一个参数,用于指定笔划的全局比例,平方根用于使笔划更均匀。我们不想在笔画的长度上有太大的差异。
笔触颜色的选择可能是最困难的部分。我们希望随机获得漂亮的色彩并排,但是我们希望与原始照片保持一致。想法是从调色板中随机选择一种颜色,从而使与照片下方像素更相似的颜色被选择的可能性更大。使用颜色之间相似度的softmax函数确定概率。
代码
您可以在此处找到源代码。它与我在这里描述的算法相对应,但性能有所提高。该代码已注释,应该很容易理解。
|