Нахождение белого прямоугольника на изображении - PullRequest
0 голосов
/ 15 февраля 2012

Я пытаюсь найти белый прямоугольник на изображении.Размер прямоугольника фиксирован.Это то, к чему я уже пришел:

BufferedImage bImage = bufferedImage;
int height = bufferedImage.getHeight(); //~1100px
int width = bufferedImage.getWidth(); //~1600px
int neededWidth = width / 2; 
int neededHeight = 150;
int x = 0;
int y = 0;
boolean breaker = false;
boolean found = false;
int rgb = 0xFF00FF00;
int fx, fy;

fx = fy = 0;
JavaLogger.log.info("width, height: " + w + ", " + h);
while ((x != (width / 2) || y != (height - neededHeight)) && found == false) {
for (int i = y; i - y < neededHeight + 1; i++) {
    for (int j = x; j - x < neededWidth + 1; j++) { //Vareetu buut, ka +1 vajadziigs
        //JavaLogger.log.info("x,y: " + j + ", " + i);
        long pixel = bImage.getRGB(j, i);
        if (pixel != colorWhite && pixel != -1) {
            //bImage.setRGB(j, i, rgb);
            //JavaLogger.log.info("x,y: " + (j+x) + ", " + (i+y));
            breaker = true;
            break;

        } else {
            //bImage.setRGB(j, i, 0xFFFFFF00);
        }
        //printPixelARGB(pixel);
        if ((i - y == neededHeight-10) && j - x == neededWidth-10) {
            JavaLogger.log.info("width, height: " + x + ", " + y + "," + j + ", " + i);
            fx = j;
            fy = i;
            found = true;
            breaker = true;
            break;
        }
    }
    if (breaker) {
        breaker = false;
        break;
    }

}

if (x < (width / 2)) {
    x++;
} else {
    if (y < (height - neededHeight)) {
        y++;
        x = 0;
    } else {
        break;
    }
  }
//JavaLogger.log.info("width, height: " + x + ", " + y);
}

if (found == true) {

    for (int i = y; i < fy; i++) {
        for (int j = x; j < fx; j++) {
            bImage.setRGB(j, i, 0xFF00FF3F);
        }

    }

}
JavaLogger.log.info("width, height: " + w + ", " + h);

Это работает нормально, если нужный мне прямоугольник близок к началу (0;0), но по мере удаления от него производительность падаетдовольно сильно.Мне интересно, есть ли что-то, что можно сделать?

Например, этот поиск занял почти 8 секунд, что довольно много.One of searches Я думаю, что это можно сделать более эффективно.Может быть, поиск какой-нибудь кляксы?Читайте об этом, но я не знаю, как его применить.

Кроме того, я новичок в Java и обработке изображений, поэтому любая помощь приветствуется.

Ответы [ 3 ]

1 голос
/ 15 февраля 2012

Это очень грубо, но успешно находит все белые пиксели на изображении, можно сделать дополнительную проверку, чтобы убедиться, что это нужный размер, и все есть, но есть основы.

PS:Я не проверял с вашим изображением.r и this.rc - размер изображения, p и this.px - размер внутреннего прямоугольника

public static void main(String[] args) {
    JFrame frame = new JFrame();
    final int r = 100;
    final int p = 10;

    NewJPanel pan = new NewJPanel(r, p, new A() {
        @Override
        public void doImage(BufferedImage i) {
            int o = 0;

            for (int j = 0; j < i.getWidth() - p; j++) {
                for (int k = 0; k < i.getHeight() - p; k++) {

                    PixelGrabber pix2 = new PixelGrabber(
                            i, j, k, p, p, false);
                    try {
                        pix2.grabPixels();
                    } catch (InterruptedException ex) {}

                    int pixelColor = pix2.getColorModel()
                            .getRGB(pix2.getPixels());

                    Color c = new Color(pixelColor);
                    if (c.equals(Color.WHITE)) {
                        System.out.println("Found at : x:" + j + ",y:" + k);
                    }

                }
            }
        }
    });

    frame.getContentPane().add(pan);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(500, 500);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
}

private interface A {
    void doImage(BufferedImage i);
}

private static class NewJPanel extends JPanel {
    private static final long serialVersionUID = -5348356640373105209L;

    private BufferedImage image = null;
    private int px;
    private int rc;
    private A a;

    public NewJPanel(int r, int p, A a) {
        this.px = p;
        this.rc = r;
        this.a = a;
    }

    public BufferedImage getImage() {
        return image;
    }

    @Override public void paint(Graphics g) {
        super.paint(g);

        image = new BufferedImage(this.rc, this.rc,
                BufferedImage.TYPE_INT_ARGB);
        java.awt.Graphics2D g2 = image.createGraphics();

        g2.setColor(Color.BLACK);
        g2.fillRect(0, 0, this.rc, this.rc);
        g2.setColor(Color.WHITE);
        g2.fillRect(
                new Random().nextInt(this.rc - this.px),
                new Random().nextInt(this.rc - this.px),
                this.px, this.px);

        g.drawImage(image, this.rc, this.rc, this);
        this.a.doImage(this.image);
    }
}
0 голосов
/ 15 февраля 2012

То, что вы спрашиваете, может быть решено операцией, известной как «эрозия» Эрозия заменяет каждый пиксель самым темным из всех пикселей в прямоугольнике запрошенного размера в этом месте (верхний левый угол). Здесь самое темное означает, что небелое заменяет белое.

Результатом эрозии является изображение со столбцами W-1 и строками H-1 меньше. Любой белый пиксель в нем соответствует решению.

В счастливом случае прямоугольной формы эрозия - это отдельная операция. Это означает, что вы можете размывать сначала, используя форму горизонтального сегмента, а затем форму вертикального сегмента на выходе первой эрозии. Для размера перегруппировки W x H это заменяет операции W * H на W + H, что значительно экономит.

В удачном случае с бинарным изображением (не белым или белым) эрозия по сегменту может быть выполнена чрезвычайно эффективно: в каждой строке независимо найдите все смежные серии белых пикселей и поверните W-1 вправо те к небелым. Сделайте то же самое для всех столбцов, укоротив белые полосы на H-1 пикселей.

Пример: найти все прямоугольники 3х2:

####....####
##.....#..##
#..######...
.....###....

После эрозии 3х1:

####..####
##...#####
#########.
...#####..

После эрозии 1x2:

####.#####
##########
#########.

Этот алгоритм требует постоянного времени на пиксель (независимо от размера прямоугольника). Правильно выполненный, должен занять несколько миллисекунд.

0 голосов
/ 15 февраля 2012

Я не эксперт, но я не думаю, что проблема в коде - вам нужно изменить свой алгоритм. Я бы начал с рекурсивного поиска одного белого пикселя на 2d-плоскости, что-то вроде:

findWhitePixel (квадрат) { посмотрите на пиксель в середине 'квадрата' - если он белый, верните его, иначе: findWhitePixel (верхняя правая четверть квадрата) findWhitePixel (верхняя левая четверть квадрата) findWhitePixel (нижняя правая четверть квадрата) findWhitePixel (нижняя левая четверть квадрата) }

после того, как вы найдете белый пиксель, попробуйте пройти вверх, вниз, влево и вправо от него, чтобы найти границы на вашей фигуре. если дано, что могут быть только прямоугольники - все готово. если могут быть другие фигуры (треугольники, круги и т. д.), вам понадобится некоторая проверка здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...