在画布上找到最理想的位置来书写文字

Exo*_*cal 1 html javascript canvas

我正在开发一个项目,其中有一个画布,上面绘制了图像。我想要实现的目标是自动将此文本放置在画布上不会打扰图像内容的位置。

小例子:假设我有一张画布,上面画着一群人的图像。在这种情况下,我想将文本放置在没有面孔等的地方,这样文本就清晰可读,并且图像不会受到文本的干扰。

到目前为止,我在 JS 中编写了以下函数来将图像绘制到画布上:

    function drawStuff() {
            var slideBackground = new Image();
            slideBackground.src = "https://images.pexels.com/photos/50987/money-card-business-credit-card-50987.jpeg?w=940&h=650&auto=compress&cs=tinysrgb";
            slideBackground.onload = function() {
                canvasContext.imageSmoothingEnabled = false;
                canvasContext.drawImage(slideBackground, 0, 0, canvas.width, canvas.height);
            }
        }
Run Code Online (Sandbox Code Playgroud)

现在我的想法是检查每个像素,查看它具有什么十六进制颜色并检查仅包含该(或略有不同)六角形的空间,但我认为这不会很有效。

有没有更干净/更简单的解决方案?

谢谢。

小智 5

这不是一个完整的解决方案,但它显示了一些预先步骤,以便您可以开始将像素分组在一起。分组后,找到每组的边界并选择最适合应用程序的一组。

这里的步骤是:

  • 使用内置滤镜以灰度绘制原始图像
  • 将混合模式设置为difference并在顶部绘制模糊(后者也使用内置滤镜)。这将过滤掉往往(但并非总是)焦点感兴趣的高频区域。
  • 使用阈值迭代每个像素,以使用 32 位有符号数组标记最暗的像素
  • 可选择应用后模糊
  • 然后,您需要实现对像素区域进行分组的功能(请参阅主题斑点检测- 我相信Firefly 元启发式算法/ PSO也可以在这里使用;甚至在某种程度上行进方形(请参阅文章中的等值带))并计算边界从那里。
  • 提示:由于新元素的放置相对松散,因此可以以低分辨率处理图像。边界框可以放大到最终分辨率。

主意另一种方法(未经测试,只是一个想法)是使用边缘检测并将图片分割成单元格,例如 9 × 9 以补充三分法。计算每个单元格中的像素数,并使用不太拥挤(就像素计数而言)的区域或不太拥挤的单元格组。

例如,在您链接到的示例图像中,左上和左下组可能是放置其他元素的良好候选者(中心通常也是许多图像中的注意力中心,以及三分法则- 这可能是有用的信息以进一步协助选择位置)。当然还有面部识别、深度神经网络(用于形状检测)等等 - 这一切都取决于您希望它有多先进以及您愿意走多远!:)

下面的演示与可能性相比很简单,取决于浏览器对新过滤器属性的支持(Firefox、Chrome 至少应该做得很好)。这可以为您省去手动实现这些过滤器的麻烦,除非您想支持较旧的或不合格的浏览器 - 而且它们还具有性能优势。

对模糊半径和阈值的一些调整可能需要根据每个图像进行调整,或者在一系列图像上进行测试以找到“理想”值,但当然,我没有在这里这样做(即模糊半径和下面的阈值是完全任意的)。

var ctx = c.getContext("2d"), img = new Image;
img.onload = analyze; img.crossOrigin = "";
img.src = "//i.imgur.com/KCLeihX.jpg";

function analyze() {
  c.width = this.width;
  c.height = this.height;
  
  // draw original as grayscale
  ctx.filter = "grayscale(100%)";
  ctx.drawImage(this, 0, 0);
  
  // blur and grayscale for next draw as well as use difference blending mode
  ctx.filter = "blur(30px) grayscale(100%)";
  ctx.globalCompositeOperation = "difference";

  // draw again to produce difference
  ctx.drawImage(this, 0, 0);
  
  // mark pixels of interest
  var idata = ctx.getImageData(0, 0, c.width, c.height),
      data = new Uint32Array(idata.data.buffer),
      i = 0, len = data.length;
  
  while(i < len) {
    if ((data[i] & 0xff) < 5) data[i] = 0xff0000ff;
    i++
  }
  
  ctx.putImageData(idata, 0, 0);

  // analyze concentrations/blobs here, use the bigger one...
}
Run Code Online (Sandbox Code Playgroud)
body {margin:0} #c {width:100%;}
Run Code Online (Sandbox Code Playgroud)
<canvas id=c></canvas>
Run Code Online (Sandbox Code Playgroud)

为了清晰起见,上面的像素以红色显示,但通常您最终会得到黑白遮罩,如下图所示。

var ctx = c.getContext("2d"), img = new Image;
img.onload = analyze; img.crossOrigin = "";
img.src = "//i.stack.imgur.com/10dGm.jpg";

function analyze() {
  c.width = this.width;
  c.height = this.height;
  
  // draw original as grayscale
  ctx.filter = "grayscale(100%)";
  ctx.drawImage(this, 0, 0);
  
  // blur and grayscale for next draw as well as use difference blending mode
  ctx.filter = "blur(30px) grayscale(100%)";
  ctx.globalCompositeOperation = "difference";

  // draw again to produce difference
  ctx.drawImage(this, 0, 0);
  
  // mark pixels of interest
  var idata = ctx.getImageData(0, 0, c.width, c.height),
      data = new Uint32Array(idata.data.buffer),
      i = 0, len = data.length;
  
  while(i < len) {
    data[i] = ((data[i] & 0xff) < 5) ? -1 : 0xff000000;
    i++
  }
  
  ctx.putImageData(idata, 0, 0);

  // redraw with blur
  ctx.globalCompositeOperation = "source-over";
  ctx.filter = "blur(9px)";
  ctx.drawImage(c, 0, 0);

  // analyze concentrations/blobs here, use the bigger one...
}
Run Code Online (Sandbox Code Playgroud)
body {margin:0} #c {width:100%;}
Run Code Online (Sandbox Code Playgroud)
<canvas id=c></canvas>
Run Code Online (Sandbox Code Playgroud)

原来的:

原创-家庭

处理:

处理

任何非全黑的东西都可以包含在斑点+边界计算中。