获取垂直或水平线的图像算法

时间:2019-06-03 21:38:14

标签: java image image-processing pixel

我非常感谢您的所有努力,但很遗憾,他们没有回答问题。 我在上面说过bruteForce方法,我的问题是如何进一步优化它。 这是我的蛮力方法的回顾:

我希望能够获得图像中尽可能少的垂直和水平线。我的想法是得到最长的线(垂直或水平),然后再获得第二长的线,依此类推(我认为)可以解决该问题。

这些图像看起来将类似于8位图像,但是看起来更大,更详细: Mario 8Bit

到目前为止,我已经提出了对整个图像进行迭代,提取最长的行,进行存储并重新生成图像的方案,但是避免访问已经访问过的行。如果没有其他路线可供参观,它将停止。

由于这是蛮力的,所以花的时间比我需要的时间长。我正在寻找一种方法来优化整个方法,而不仅仅是代码内部的微小优化。

2 个答案:

答案 0 :(得分:0)

这是用于查找所有水平线的示例伪代码:

List lineList;

for(v : [0, imageHeight-1]) {
  int streakStart = 0;
  Color lastColor = colorAt(0, v);
  for(u : [1, imageWidth-1]) {
    Color currentColor = colorAt(u, v);
    if(currentColr != lastColor) {
      lineList.insert(Line(streakStart, u-1));
      streakStart = u;
      lastColor = currentColor;
    }
  }
  lineList.insert(streakStart, imageWidth-1);
}

您可以通过切换u和v来获得垂直线。

答案 1 :(得分:0)

从描述中看,您似乎正在寻找的行包含完全相同颜色且完全水平或垂直的像素。< / p>

我创建了一个示例,该示例在图像中生成了一堆随机的红线:

LinesInImage

蓝色突出显示已找到的行,绿色突出显示已找到的最长行。

通过简单的方法检测线条:

  • 遍历所有像素(x,y),直到找到具有线条颜色的像素
  • 检查附近像素。也就是说,检查当前像素的“北”,“南”,“东”和“西”像素与当前像素的颜色是否相同

    • 如果当前像素为红色,像素 west 为白色,像素 east 为红色,则开始<此时,水平> strong 行。这基本上是寻找这种模式:

      . ? .
      W R R
      . ? .
      
    • 如果当前像素为红色,像素 north 为白色,像素 south 为红色,则开始<此时,strong>垂直线。这基本上是寻找这种模式:

      . W .
      ? R ?
      . R .
      
  • 当检测到这样的行开始时,水平或垂直走动,直到找到该行的末尾,并存储结果行

  • 最后,按行长对行进行排序

请注意,这里有一些假设和特殊情况。尽管确实找到了合理的结果,但是当两条直线并排时,事情变得棘手。这么说:当您有这样的红色像素图案时...

. . . . .
. R R R .
. R R R .
. R R R .
. . . . .

那么严格来说,就不可能说这些是否是

  • 长度为3的三条水平线
  • 长度为3的三条垂直线
  • 3条长度为2的水平线和1条长度为3的垂直线
  • 或其他...

但是,此MCVE中显示了建议的方法:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class FindLinesInImage {
    public static void main(String[] args) {

        int w = 100;
        int h = 100;

        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

        int numLines = 30;
        int lineRgb = Color.RED.getRGB();

        Random random = new Random(0);
        drawSomeLines(image, numLines, lineRgb, random);

        List<Line2D> lines = findLines(image, lineRgb);
        Comparator<Line2D> comparator = (line0, line1) -> {
            double length0 = line0.getP1().distance(line0.getP2());
            double length1 = line1.getP1().distance(line1.getP2());
            return Double.compare(length1, length0);
        };
        Collections.sort(lines, comparator);

        SwingUtilities.invokeLater(() -> createAndShowGui(image, lines));
    }

    private static void createAndShowGui(BufferedImage image, List<Line2D> lines) {
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        double scaling = 5.0;
        AffineTransform lineTransform = AffineTransform.getScaleInstance(scaling, scaling);
        lineTransform.translate(0.5, 0.5);
        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics gr) {
                super.paintComponent(gr);
                Graphics2D g = (Graphics2D) gr;
                AffineTransform oldAt = g.getTransform();
                g.scale(scaling, scaling);
                g.drawImage(image, 0, 0, null);
                g.setTransform(oldAt);
                g.setColor(new Color(0, 128, 0, 64));
                g.setStroke(new BasicStroke((float) (3 * scaling)));
                for (int i = 0; i < lines.size(); i++) {
                    Line2D line = lines.get(i);
                    g.draw(lineTransform.createTransformedShape(line));
                    g.setColor(new Color(0, 0, 255, 64));
                }

            };
        };
        f.getContentPane().add(panel);

        f.setSize(800, 800);
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static List<Line2D> findLines(BufferedImage image, int rgb) {
        List<Line2D> lines = new ArrayList<Line2D>();
        int w = image.getWidth();
        int h = image.getHeight();
        for (int y = 0; y < h; y++) {
            for (int x = 0; x < w; x++) {

                boolean atC = pixelHasColor(image, x, y, rgb);
                boolean atN = pixelHasColor(image, x, y - 1, rgb);
                boolean atS = pixelHasColor(image, x, y + 1, rgb);
                boolean atE = pixelHasColor(image, x + 1, y, rgb);
                boolean atW = pixelHasColor(image, x - 1, y, rgb);

                if (atC) {
                    if (atE && !atW) {
                        Line2D line = computeLine(image, x, y, 1, 0, rgb);
                        System.out.println("Line " + line.getP1() + " " + line.getP2());
                        lines.add(line);
                    }
                    if (atS && !atN) {
                        Line2D line = computeLine(image, x, y, 0, 1, rgb);
                        System.out.println("Line " + line.getP1() + " " + line.getP2());
                        lines.add(line);
                    }
                    if (!atS && !atN & !atW && !atE) {
                        Line2D line = new Line2D.Double(x, y, x, y);
                        lines.add(line);
                    }
                }
            }
        }
        return lines;
    }

    private static Line2D computeLine(BufferedImage image, int x, int y, int dx, int dy, int rgb) {
        int cx = x;
        int cy = y;
        while (pixelHasColor(image, cx, cy, rgb)) {
            cx += dx;
            cy += dy;
        }
        return new Line2D.Double(x, y, cx - dx, cy - dy);
    }

    private static boolean pixelHasColor(BufferedImage image, int x, int y, int rgb) {
        if (x < 0 || y < 0) {
            return false;
        }
        int w = image.getWidth();
        int h = image.getHeight();
        if (x >= w || y >= h) {
            return false;
        }
        return image.getRGB(x, y) == rgb;
    }

    private static void drawSomeLines(BufferedImage image, int n, int rgb, Random random) {
        int w = image.getWidth();
        int h = image.getHeight();
        Graphics2D g = image.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, w, h);
        g.setColor(new Color(rgb));
        for (int i = 0; i < n; i++) {
            int x0 = random.nextInt(w / 2) * 2;
            int y0 = random.nextInt(h / 2) * 2;
            int x1 = x0;
            int y1 = y0;
            boolean horizontal = random.nextBoolean();
            if (horizontal) {
                x1 = x0 + random.nextInt(w - x0);
            } else {
                y1 = y0 + random.nextInt(h - y0);
            }
            g.drawLine(x0, y0, x1, y1);
        }
        g.dispose();
    }

    private static void drawLine(BufferedImage image, int x0, int y0, int x1, int y1, int rgb) {
        Graphics2D g = image.createGraphics();
        g.setColor(new Color(rgb));
        g.drawLine(x0, y0, x1, y1);
        g.dispose();
    }

}