65.9K
CodeProject 正在变化。 阅读更多。
Home

基于密度的数字图像重采样方法及示例:仿古马赛克

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2022年4月8日

BSD

2分钟阅读

viewsIcon

8946

downloadIcon

210

一种非常简单的从数字图像中重采样点并将其绘制成仿古马赛克、点(点彩)和Voronoi单元的方法。

frmMain01

引言

在本文中,我将介绍一种新的且非常简单的从数字图像中重采样点并将其绘制成看起来像仿古马赛克、点(点彩)和Voronoi单元的方法。该方法基于计算基于密度的核大小,然后进行采样并消除由圆形核跨越的剩余邻居点。

在继续之前,我强烈建议您查看“参考文献”部分中的文章。

通常解释一种方法及其逻辑背景是从展示我们想要做什么开始
第一步是获取重采样点,第二步是使用这些采样点绘制我们想要的东西。

输入图像 采样点
input image sampled points
仿古马赛克 点(点彩)
fake antique mosaics dots (stippling)
Voronoi单元 点(描边)
voronoi cells dots (stroke)

方法

从技术上讲,数字图像的重采样被称为“空间采样”。在实践中使用了许多采样方法,例如规则网格、不规则网格、六边形网格、三角形网格、泊松盘采样、随机采样、准随机采样等。其中一些采样方法与统计分布有密切关系。主要目标是在数学上和艺术风格化上获得平衡的分布(即采样点)。在这里,我将解释另一种基于密度的采样方法。对于数字图像,我们认为“密度”是图像的亮度(即像素的灰度级)。

步骤

Step 1 这是输入图像及其像素。

让我们按照以下步骤扫描图像中的所有像素。
Step 2 1. 将图像转换为灰度。
Step 3 2. 获取每个像素的灰度值。
Step 4 3. 基于这些灰度值(即密度)计算圆形核半径。
Step 5 4. 消除圆形核(窗口)中剩余的邻居像素。
Step 6, result 5. 结果,我们得到一个重采样像素和其他白色像素。

如果我们对每个像素重复这些步骤,我们将得到所有重采样像素。所以,第一步完成了。

之后,我们将基于这些采样像素的颜色和之前计算的相关半径值绘制一些形状。这些步骤更容易,不需要解释。

现在,请以轻松的心情再次查看上面的图像。

代码

计算核半径的公式是我自己所有权的一个计算公式。

kernelRadius := (256 div density) - (gray div density); 

典型的参数值是密度为20,阈值为192。

Using the Code

用核心亮点代码开始!

type
  TCDots = record
    Cx, Cy: integer;
    CRadius: integer;
    CColor: TColor;
  end;

var
  dots: array of TCDots;  
  ...
  ...
  SetLength(dots, nSize);
  ...
  ...
  for y:=0 to H-1 do
  begin
    for x:=0 to W-1 do
    begin
      c := imgWork.Canvas.Pixels[x, y];

      r := GetRValue(c);
      g := GetGValue(c);
      b := GetBValue(c);

      gray := trunc(r * 0.2989 + g * 0.5866 + b * 0.1145 + 0.5);

      //////////////////////////////////////////////////////////////

      // (c) Copyright AG 2022. ademgunes@yahoo.com
      // Not allowed to use for commercial apps without permissions.

      kernelRadius := (256 div density) - (gray div density); // copyrighted

      if chkFixedDensity.Checked then
        kernelRadius := 16 - (gray div 32);  // trivial

      //////////////////////////////////////////////////////////////

      if (kernelRadius < 5) then kernelRadius := 5;
      radii2 := kernelRadius * kernelRadius;

      if (gray > threshold) then
      begin
        c1 := clWhite;
        imgWork.Canvas.Pixels[x, y] := c1;
        continue;
      end;

      // stippling
      for ky:=-kernelRadius to +kernelRadius do
      begin
        yy := y + ky;
        if (yy < 0) then yy := 0; if (yy > H-1) then yy := H-1;

        for kx:=-kernelRadius to +kernelRadius do
        begin
          xx := x + kx;
          if (xx < 0) then xx := 0; if (xx > W-1) then xx := W-1;

          if ( (ky = 0) and (kx = 0) ) then
            c1 := c 
          else
            c1 := clWhite;

          if (kx*kx + ky*ky < radii2) then
          begin
            imgWork.Canvas.Pixels[xx, yy] := c1;

            if (c1 <> clWhite) then
            with dots[nCount] do
            begin
              Cx := xx;
              Cy := yy;
              CRadius := kernelRadius;
              CColor := c1;
            end;
          end; // if 
        end; // kx
      end; // ky
      ...
    end; // x
    ...
  end; // y  
  ...

注意:为了简单起见,我在这里使用了Canvas.Pixels[..],但是为了优化速度,请不要在实际应用中使用Canvas.Pixels[..]

结论和关注点

说实话,没什么可讨论的。为了避免更复杂和昂贵的方法,请跟随我。:)

参考文献

  1. 文章:加权Voronoi点彩
  2. 文章:泊松盘样本集的样本消除
  3. StippleGen:Windell Oskay 在 Processing 中加权 Voronoi 点彩和 TSP 路径
  4. Mike Bostock 的 Voronoi 点彩
  5. Selim Tezel 的 Voronoi:收缩圆算法
  6. 书籍:基于图像和视频的艺术风格化

历史

  • 2022年4月7日:初始版本
基于密度的数字图像重采样方法及示例:仿古马赛克 - CodeProject - 代码之家
© . All rights reserved.