javascript - 在 JS 中使用像素操作 (WebImage) 填充未知的不对称多边形

标签 javascript polygon webimage

最近,我一直在尝试创建代码来用颜色填充任何形状的多边形。我已经能够正确填充只有一种边框尺寸的线条的形状,尽管我发现自己无法做更多的事情。问题在于代码不知道何时考虑大于其预期的形状垂直或水平边框的像素线。我将从左到右遍历形状的每个像素,并通过检查 alpha 值是否为 0 来检查是否有任何像素具有任何形式的颜色。一旦它发现一个像素的 alpha 值不是 0,它就会向前移动一个像素,然后使用偶/奇技术来确定该点是否在多边形的内部(它会形成一条无限线)向右并确定与彩色线的碰撞次数是否为奇数,如果是,则该点位于多边形内部)。一般来说,我们将单个单独的像素视为一条线,并且将多于一个像素的水平线视为两条线,因为水平线经常成为或不成为边框的一部分。假设以下场景:

enter image description here

这里,红点是我们开始测试的点(像素)。如果我们不认为中间的水平线是两个点(如红线和 x 所示),我们将只有两个交点,因此不会填充像素,尽管事实上我们肯定会这样做想要填充该像素。然而,如前所述,这会在不同的场景中带来另一个问题:

enter image description here

在这种情况下,如果我们确实将超过一个像素的水平线算作两条单独的线,那么我们最终不会填充任何边框比预期厚度更厚的区域。供您引用,处理此问题的函数如下:

//imgData is essentially a WebImage object (explained more below) and r, g, and b are the color values for the fill color
function fillWithColor(imgData, r, g, b) {
  //Boolean determining whether we should color the given pixel(s) or not
  var doColor = false;
  //Booleans determining whether the last pixel found in the entire image was colored
  var blackLast = false;
  //Booleans determining whether the last 1 or 2 pixels found after a given pixel were colored
  var foundBlackPrev, foundBlackPrev2 = false;
  //The number of colored pixels found
  var blackCount = 0;
      
  //Loop through the entire canvas
  for(var y = 0; y < imgData.height; y += IMG_SCALE) {
    for(var x = 0; x < imgData.width; x += IMG_SCALE) {
      //Test if given pixel is colored
      if(getAlpha(imgData, x, y) != 0) {
        //If the last pixel was black, begin coloring
        if(!blackLast) {
          blackLast = true;
          doColor = true;
        }
      } else {
        //If the current pixel is not colored, but the last one was, find all colored lines to the right
        if(blackLast){
          for(var i = x; i < imgData.width; i += IMG_SCALE) {
            //If the pixel is colored...
            if(getAlpha(imgData, i, y) != 0) {
              //If no colored pixel was found before, add to the count
              if(!foundBlackPrev){
                blackCount++;
                foundBlackPrev = true;
              } else {
                //Otherwise, at least 2 colored pixels have been found in a row
                foundBlackPrev2 = true;
              }
            } else { 
              //If two or more colored pixels were found in a row, add to the count
              if(foundBlackPrev2) {
                blackCount++;
              }
              //Reset the booleans
              foundBlackPrev2 = foundBlackPrev = false;
            }
          }
        }
            
        //If the count is odd, we start coloring
        if(blackCount & 1) {
          blackCount = 0;
          doColor = true;
        } else {
          //If the last pixel in the entire image was black, we stop coloring
          if(blackLast) {
            doColor = false;
          }
        }
          
        //Reset the boolean
        blackLast = false;
        //If we are to be coloring the pixel, color it
        if(doColor) {
          //Color the pixel
          for(var j = 0; j < IMG_SCALE; j++) {
            for(var k = 0; k < IMG_SCALE; k++) {
              //This is the same as calling setRed, setGreen, setBlue and setAlpha functions from the WebImage API all at once (parameters in order are WebImage object equivalent, x position of pixel, y position of pixel, red value, green value, blue value, and alpha value)
              setRGB(imgData, x + j, y + k, r, g, b, 255);
            }
          }
        }
      }
    }
  }
  //Update the image (essentially the same as removing all elements from the given area and calling add on the image)
  clearCanvas();
  putImageData(imgData, 0, 0, imgData.width, imgData.height);
  //Return the modified data
  return imgData;
}

哪里...

imgData是给定区域中所有像素的集合(本质上是一个WebImage对象)

IMG_SCALE 是图像放大的整数值(这也为我们提供了像素的比例)。在此示例中,它等于 4,因为图像放大到 192x256(从 48x64)。这意味着您在图像中看到的每个“像素”实际上都是由 4x4 的相同颜色像素 block 组成。

所以,我在这里真正寻找的是一种方法来确定在另一个之后出现的给定彩色像素是否是水平边框的一部分,或者它是否只是包含垂直边框厚度的另一 block 。此外,如果我对这个问题的处理方法通常是错误的,我将非常感谢任何关于如何更有效地做到这一点的建议。谢谢。

最佳答案

我理解这个问题,并且我认为如果您在这里改变策略,您会做得更好。我们知道以下内容:

  • 起点位于形状内部
  • 应该为形状内的每个像素填充颜色

因此,我们总是可以将当前点的邻居插入要处理的队列中,并小心避免对相同的点进行两次处理,这样可以遍历所有有用的像素并将它们包含到着色计划中。以下功能未经测试。

function fillColor(pattern, startingPoint, color, boundaryColor) {
    let visitQueue = [];
    let output = {};
    if (startingPoint.x - 1 >= 0) visitQueue.push({startingPoint.x - 1, startingPoint.y});
    if (startingPoint.x + 1 < pattern.width) visitQueue.push({startingPoint.x + 1, startingPoint.y});
    if (startingPoint.y + 1 < pattern.height) visitQueue.push({startingPoint.x, startingPoint.y + 1});
    if (startingPoint.y - 1 >= 0) visitQueue.push({startingPoint.x, startingPoint.y - 1});
    let visited = {};
    while (visitQueue.length > 0) {
        let point = visitQueue[0];
        visitQueue.shift();
        if ((!visited[point.x]) || (visited[point.x].indexOf(point.y) < 0)) {
            if (!visited[point.x]) visited[point.x] = [];
            visited[point.x].push(point.y);
            if (isBlank(pattern, point)) { //you need to implement isBlank
                if (!output[point.x]) output[point.x] = [];
                output[point.x].push(point.y);
                if (point.x + 1 < pattern.width) visitQueue.push({point.x + 1, point.y});
                if (point.x - 1 >= 0) visitQueue.push({point.x - 1, point.y});
                if (point.y + 1 < pattern.height) visitQueue.push({point.x, point.y + 1});
                if (point.y - 1 >= 0) visitQueue.push({point.x, point.y - 1})
            }
        }
    }
    return output;
}

关于javascript - 在 JS 中使用像素操作 (WebImage) 填充未知的不对称多边形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70229866/

相关文章:

javascript - 使用带有快速服务器的文件

algorithm - 如何以编程方式找到多边形的方向?

javascript - Divs 占据整个页面

javascript - Canvas.toDataURL() 问题。还有其他选择吗?

r - sp::over()用于多边形分析中的点

python - 在散点图中,在 matplotlib 中围绕数据点绘制平滑多边形

asp.net - 在上传到 Azure Blob 存储之前调整图像大小

web - 检测网页图像中的图形区域

javascript - jquery .click() 事件的奇怪行为