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

如何在Libgdx或Java中查找Pixmap内指定颜色的边界矩形

查找Pixmap指定颜色边界矩形的代码问题与修正

问题概述

你尝试基于Stack Exchange上的思路,将其转换为Java(LibGDX)代码来查找Pixmap中指定颜色的所有边界矩形,但现有代码存在多处逻辑错误,无法正确实现需求。

现有代码的核心问题

  • getBoundingRectangle逻辑完全失效:方法中color.equals(compare)的compare变量从未更新为当前扫描的像素颜色,始终是初始空值,导致无法正确收集同颜色点;同时arrayMax方法未定义,代码无法编译。
  • 区域归属判断错误:用扩大2像素的矩形来判断点是否属于已有区域,这种方式完全不符合连通区域的判断逻辑,会导致大量误判(将不连通的区域归为同一矩形)或漏判(将连通区域拆分为多个矩形)。
  • 扫描逻辑不完整:仅从第一个点的下一行开始扫描到maxX,无法覆盖所有同颜色的连通区域,遗漏大量像素。
  • 颜色比较精度问题:使用Color.equals进行精确比较,而Pixmap的像素颜色可能因存储格式导致精度损失,应该直接比较像素的整数值更可靠。

修正后的实现方案

采用连通区域遍历+极值记录的方式,先标记已访问的像素,对每个未访问的目标颜色像素,用BFS遍历整个连通区域,同时记录区域的最小/最大X、Y坐标,最终生成边界矩形。

import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Queue;

public class Magik {
    // 存储最终的边界矩形列表
    private final Array<Rectangle> bounds = new Array<>();
    // 标记已处理的像素,避免重复遍历
    private boolean[][] visited;
    // 目标颜色的打包整数值,用于快速比较
    private int targetColorInt;
    private Pixmap pixmap;

    public Array<Rectangle> getBounds(Pixmap pixmap, Color targetColor) {
        this.pixmap = pixmap;
        this.targetColorInt = Color.rgba8888(targetColor);
        this.visited = new boolean[pixmap.getWidth()][pixmap.getHeight()];
        bounds.clear();

        // 遍历所有像素
        for (int y = 0; y < pixmap.getHeight(); y++) {
            for (int x = 0; x < pixmap.getWidth(); x++) {
                // 如果当前像素是目标颜色且未被访问过
                if (!visited[x][y] && pixmap.getPixel(x, y) == targetColorInt) {
                    // 遍历整个连通区域,计算边界矩形
                    Rectangle rect = calculateBoundingRectForRegion(x, y);
                    bounds.add(rect);
                }
            }
        }

        // 打印结果(可选)
        System.out.println("检测到的边界矩形:");
        for (Rectangle rect : bounds) {
            System.out.println(rect);
        }

        return bounds;
    }

    /**
     * 从(x,y)开始,用BFS遍历所有连通的目标颜色像素,计算最小包围矩形
     */
    private Rectangle calculateBoundingRectForRegion(int startX, int startY) {
        Queue<int[]> queue = new Queue<>();
        queue.add(new int[]{startX, startY});
        visited[startX][startY] = true;

        // 初始化区域极值
        int minX = startX;
        int maxX = startX;
        int minY = startY;
        int maxY = startY;

        // 四个方向:上、下、左、右(如果需要8连通可以增加斜向)
        int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

        while (!queue.isEmpty()) {
            int[] pos = queue.removeFirst();
            int x = pos[0];
            int y = pos[1];

            // 更新区域极值
            minX = Math.min(minX, x);
            maxX = Math.max(maxX, x);
            minY = Math.min(minY, y);
            maxY = Math.max(maxY, y);

            // 遍历四个相邻像素
            for (int[] dir : directions) {
                int newX = x + dir[0];
                int newY = y + dir[1];
                // 检查坐标是否在Pixmap范围内,且未被访问,且是目标颜色
                if (isValidCoordinate(newX, newY) && !visited[newX][newY] && pixmap.getPixel(newX, newY) == targetColorInt) {
                    visited[newX][newY] = true;
                    queue.add(new int[]{newX, newY});
                }
            }
        }

        // 生成边界矩形:x=minX, y=minY, width=maxX-minX+1, height=maxY-minY+1
        return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
    }

    /**
     * 检查坐标是否在Pixmap的有效范围内
     */
    private boolean isValidCoordinate(int x, int y) {
        return x >= 0 && x < pixmap.getWidth() && y >= 0 && y < pixmap.getHeight();
    }
}

关键优化说明

  • 高效颜色比较:用Color.rgba8888(targetColor)将目标颜色转换为和Pixmap.getPixel()一致的RGBA8888整数值,避免浮点精度问题,比较更快。
  • 连通区域遍历:使用BFS(广度优先搜索)遍历所有连通的目标颜色像素,确保不会遗漏任何属于同一区域的像素。
  • 极值记录:遍历区域时直接记录min/max X/Y,不需要收集所有点,节省内存且效率更高。
  • 已访问标记:避免重复处理同一像素,确保每个区域只被计算一次。

内容的提问来源于stack exchange,提问作者WASD123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 07:06:32