You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用P5.js统计指定最小尺寸的黑点并获取其坐标

嘿,我完全懂你的困扰——现在的代码只能把所有符合阈值的黑像素混在一起算平均坐标,根本没法区分“单个像素噪点”和“真正达到最小尺寸的黑点区域”对吧?要解决这个问题,核心是要做连通区域检测(Blob Detection):把属于同一个黑点的像素分组,然后判断每个组的尺寸是否达标。

下面给你一套完整的解决方案,一步步帮你实现需求:

核心思路
  1. 给每个像素做“访问标记”,避免重复处理同一个区域
  2. 遍历每个像素,遇到未访问的黑像素时,用**广度优先搜索(BFS)**找出所有连通的黑像素,组成一个独立的黑点区域
  3. 计算每个区域的宽度和高度,过滤掉尺寸不达标的区域
  4. 统计符合要求的区域数量,还能获取每个区域的中心坐标
完整代码实现
let img;
// 可根据你的需求调整参数
const minWidth = 10;    // 黑点最小宽度
const minHeight = 10;   // 黑点最小高度
const threshold = 20;   // 黑像素的RGB阈值

function preload() {
  img = loadImage('your-image.png'); // 替换成你的图像路径
}

function setup() {
  createCanvas(img.width, img.height);
  image(img, 0, 0);
  loadPixels();
  detectValidBlackBlobs();
}

function detectValidBlackBlobs() {
  const d = pixelDensity();
  // 创建二维数组标记像素是否已被访问
  const visited = create2DArray(width, height);
  let validBlobCount = 0;
  const validBlobs = [];

  // 遍历画布所有像素
  for (let x = 0; x < width; x++) {
    for (let y = 0; y < height; y++) {
      // 找到未被访问的黑像素,启动BFS探索整个连通区域
      if (!visited[x][y] && isBlackPixel(x, y)) {
        const blobPixels = bfsExploreBlob(x, y, visited);
        // 计算当前区域的边界范围
        const [minX, maxX, minY, maxY] = calculateBlobBounds(blobPixels);
        const blobWidth = maxX - minX + 1;
        const blobHeight = maxY - minY + 1;

        // 过滤掉尺寸不达标的区域
        if (blobWidth >= minWidth && blobHeight >= minHeight) {
          validBlobCount++;
          const centerX = (minX + maxX) / 2;
          const centerY = (minY + maxY) / 2;
          validBlobs.push({ x: centerX, y: centerY, width: blobWidth, height: blobHeight });
          console.log(`找到有效黑点:中心(${centerX.toFixed(1)}, ${centerY.toFixed(1)}),尺寸${blobWidth}x${blobHeight}`);
        }
      }
    }
  }

  console.log(`满足最小尺寸要求的黑点总数:${validBlobCount}`);
  // 可选:给有效黑点画红色边界框,方便验证
  drawBlobBoundingBoxes(validBlobs);
}

// 判断单个像素是否为黑像素
function isBlackPixel(x, y) {
  const d = pixelDensity();
  const index = 4 * ((y * d) * width * d + (x * d));
  return pixels[index] <= threshold && pixels[index + 1] <= threshold && pixels[index + 2] <= threshold;
}

// 用BFS探索整个连通的黑像素区域
function bfsExploreBlob(startX, startY, visited) {
  const queue = [{ x: startX, y: startY }];
  visited[startX][startY] = true;
  const blobPixels = [];
  // 四方向连通(上下左右),如果需要对角线连通可以加上[1,1], [-1,-1]等方向
  const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];

  while (queue.length > 0) {
    const current = queue.shift();
    blobPixels.push(current);

    // 遍历四个方向的相邻像素
    for (const dir of directions) {
      const newX = current.x + dir[0];
      const newY = current.y + dir[1];
      // 检查坐标合法、未被访问、且是黑像素
      if (newX >= 0 && newX < width && newY >= 0 && newY < height
          && !visited[newX][newY] && isBlackPixel(newX, newY)) {
        visited[newX][newY] = true;
        queue.push({ x: newX, y: newY });
      }
    }
  }
  return blobPixels;
}

// 计算黑点区域的边界坐标
function calculateBlobBounds(blobPixels) {
  let minX = Infinity, maxX = -Infinity;
  let minY = Infinity, maxY = -Infinity;
  for (const p of blobPixels) {
    minX = Math.min(minX, p.x);
    maxX = Math.max(maxX, p.x);
    minY = Math.min(minY, p.y);
    maxY = Math.max(maxY, p.y);
  }
  return [minX, maxX, minY, maxY];
}

// 创建二维数组用于标记访问状态
function create2DArray(w, h) {
  const arr = new Array(w);
  for (let i = 0; i < w; i++) {
    arr[i] = new Array(h).fill(false);
  }
  return arr;
}

// 画出有效黑点的红色边界框
function drawBlobBoundingBoxes(blobs) {
  stroke(255, 0, 0);
  strokeWeight(2);
  noFill();
  rectMode(CORNERS);
  for (const blob of blobs) {
    const left = blob.x - blob.width / 2;
    const right = blob.x + blob.width / 2;
    const top = blob.y - blob.height / 2;
    const bottom = blob.y + blob.height / 2;
    rect(left, top, right, bottom);
  }
}
关键细节说明
  • 访问标记矩阵:确保每个像素只被处理一次,避免重复统计同一个黑点区域
  • BFS遍历:高效找出所有连通的黑像素,你可以根据需求改成八方向连通(加上对角线)
  • 尺寸过滤:通过计算区域的最小/最大坐标得到宽高,直接排除单个像素的噪点
  • 可视化验证:最后的drawBlobBoundingBoxes函数可以帮你直观看到检测结果是否正确

如果是处理实时视频流(比如摄像头输入),只需要把检测逻辑放到draw()函数里,并每次调用loadPixels()即可,不过建议根据性能情况适当缩小画布尺寸。

内容的提问来源于stack exchange,提问作者Clément Grondin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 13:17:46