Java 将表面分割成小方块

2024-01-12

我想知道是否有任何算法可以执行以下操作:

给定一个特定的表面,它将其分成相同大小的更小的矩形。

像这个示例图一样:

灰色区域是表面,红色方块是分区本身。

我在想是否有一种优化的方法来做到这一点。

一个非常糟糕的方法是在所有像素中进行 for 循环,并检查该特定点是否有矩形,如果没有,将创建一个矩形,依此类推。

也许有人知道已经完成的算法?或者更好的解决方案?

预先非常感谢;)


这是一种解决方法。

  1. 创建图像的蒙版。 (我刚用过Photoshop)

  2. 窃取安德鲁·汤普森的代码从图像创建区域 https://stackoverflow.com/q/7218309/2587435并用它来创建一个Area的图像。

    Area imageArea = getOutline(Color.BLACK, imageMask);
    
  3. 创建网格Rectangle2D整个图像的对象。

    Rectangle2D[][] grid = new Rectangle2D[rows][cols];
    for (int i = 0; i < grid.length; i++) {
        int y = i * CELL_SIZE;
        for (int j = 0; j < grid[i].length; j++) {
            int x = j * CELL_SIZE;
            grid[i][j] = new Rectangle2D.Double(x, y, cellSize, cellSize);
        }
    }
    
  4. 一旦你有了网格,你就可以遍历Rectangle2D对象并检查是否Area.contains每个人Rectangle2D在网格中,您可以将其添加到List<Rectangle2D>。只会添加该区域中包含的矩形,从而为您提供最终要绘制的矩形网格。在下面的示例中,我只是将矩形绘制为视觉效果。

    for (Rectangle2D[] rects : imageGrid) {
        for (Rectangle2D rect : rects) {
            if (imageArea.contains(rect)) {
                g2.drawRect((int) rect.getX(), (int) rect.getY(),
                        (int) rect.getWidth(), (int) rect.getHeight());
            }
        }
    }
    

完整示例

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class SquaresInArea extends JPanel {

    private static final int CELL_SIZE = 30;

    BufferedImage image;
    BufferedImage imageMask;
    Area imageArea;
    Rectangle2D[][] imageGrid;

    public SquaresInArea() {
        try {
            image = ImageIO.read(getClass().getResource("/resources/floorplan.png"));
            imageMask = ImageIO.read(getClass().getResource("/resources/floorplan-black.png"));
        } catch (IOException ex) {
            Logger.getLogger(SquaresInArea.class.getName()).log(Level.SEVERE, null, ex);
        }
        imageArea = getOutline(Color.BLACK, imageMask);
        imageGrid = createGrid();
    }

    private Rectangle2D[][] createGrid() {
        int width = image.getWidth();
        int height = image.getHeight();
        int rows = height / CELL_SIZE;
        int cols = width / CELL_SIZE;
        Rectangle2D[][] grid = new Rectangle2D[rows][cols];
        for (int i = 0; i < grid.length; i++) {
            int y = i * CELL_SIZE;
            for (int j = 0; j < grid[i].length; j++) {
                int x = j * CELL_SIZE;
                grid[i][j] = new Rectangle2D.Double(x, y, CELL_SIZE, CELL_SIZE);
            }
        }
        return grid;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.drawImage(image, 0, 0, this);
        g2.setColor(Color.YELLOW);
        g2.setStroke(new BasicStroke(3f));
        for (Rectangle2D[] rects : imageGrid) {
            for (Rectangle2D rect : rects) {
                if (imageArea.contains(rect)) {
                    g2.drawRect((int) rect.getX(), (int) rect.getY(),
                            (int) rect.getWidth(), (int) rect.getHeight());
                }
            }
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return image == null ? new Dimension(300, 300)
                : new Dimension(image.getWidth(), image.getHeight());

    }

    private Area getOutline(Color target, BufferedImage bi) {
        // construct the GeneralPath
        GeneralPath gp = new GeneralPath();

        boolean cont = false;
        int targetRGB = target.getRGB();
        for (int xx = 0; xx < bi.getWidth(); xx++) {
            for (int yy = 0; yy < bi.getHeight(); yy++) {
                if (bi.getRGB(xx, yy) == targetRGB) {
                    if (cont) {
                        gp.lineTo(xx, yy);
                        gp.lineTo(xx, yy + 1);
                        gp.lineTo(xx + 1, yy + 1);
                        gp.lineTo(xx + 1, yy);
                        gp.lineTo(xx, yy);
                    } else {
                        gp.moveTo(xx, yy);
                    }
                    cont = true;
                } else {
                    cont = false;
                }
            }
            cont = false;
        }
        gp.closePath();

        // construct the Area from the GP & return it
        return new Area(gp);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new SquaresInArea());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

为了清楚起见,这是另一个视图

private final BasicStroke thin = new BasicStroke(1f);
private final BasicStroke thick = new BasicStroke(4f);

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D) g;
    g2.drawImage(image, 0, 0, this);
    for (Rectangle2D[] rects : imageGrid) {
        for (Rectangle2D rect : rects) {
            if (imageArea.contains(rect)) {
                g2.setStroke(thick);
                g2.setColor(Color.GREEN);
                g2.draw(rect);
            } else {
                g2.setStroke(thin);
                g2.setColor(Color.RED);
                g2.draw(rect);
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 将表面分割成小方块 的相关文章

随机推荐