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

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

类似于此示例图:

 

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

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

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

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

在此先感谢;)

最佳答案

这是解决问题的一种方法。


创建图像的遮罩。 (我刚用过Photoshop)


窃取AndrewThompson的Creating an Area from an Image代码,并使用它创建图像的Area

Area imageArea = getOutline(Color.BLACK, imageMask);

为整个图像创建一个网格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);
    }
}

拥有网格后,您可以遍历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);
            }
        }
    }
}

08-25 22:08