【问题标题】:Java Partition Surface into Little SquaresJava 将表面分割成小方块
【发布时间】:2014-04-25 14:57:12
【问题描述】:

我想知道是否有任何算法可以做这样的事情:

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

类似于这个示例图:

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

我正在考虑是否有优化的方法来做到这一点。

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

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

提前非常感谢;)

【问题讨论】:

    标签: java image graphics rectangles partition


    【解决方案1】:

    这是一种解决方法。

    1. 创建图像的蒙版。 (我只是用 Photoshop)

    2. 窃取 AndrewThompson 的 Creating an Area from an Image 代码并用它来创建图像的 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&lt;Rectangle2D&gt;。只会添加该区域中包含的矩形,从而为您提供要绘制的最终矩形网格。在下面的示例中,我只是将矩形绘制为视觉对象。

      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);
                }
            }
        }
    }
    

    【讨论】:

    • 非常感谢您的回答,这对我有帮助;)
    【解决方案2】:

    您只是想用正方形填充它 - 还是用最佳数量的正方形填充它?

    第二种算法更难。

    首先,一次只浏览一个正方形大小的图像。如果该点的像素已填充,则扫描整个正方形,如果已全部填充,则绘制正方形。如果不是,则进入下一个点。

    即如果正方形是 10*10 像素:

    for (int x=0;x<width;x+=SQUARE_SIZE) {
        for (int y=0;y<height;y+=SQUARE_SIZE) {
           // Now check if you can put a valid square here, if so draw it
        }
    }
    

    【讨论】:

    • 感谢您的回复,您所说的最佳方格数是什么意思?给定正方形的特定宽度和高度,我想将表面划分为可能的最大正方形数
    • 正确放置方格可能意味着您可以放入不同的数字。例如,如果一个空间是 11 个单位宽,那么如果您从 0 或 1 开始,您可以容纳两个 5 个单位宽的方格,但是如果你从 2 开始,你只能装一个正方形。
    猜你喜欢
    • 1970-01-01
    • 2017-05-24
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多