Как разделить изображение на два с Java

Я задаюсь вопросом, существует ли "умный" способ разделить изображение на основе определенных функций.

Изображения 300x57, черный и белый (на самом деле шкала полутонов, но большинство цветов является или черным или белым), это состоит из двух основных функций (давайте назовем их блобами), разделенный черным пространством, каждый блоб немного варьируется по ширине и высота, положение блобов также варьируется, блобы НИКОГДА не накладываются!

Вот то, как что "смотрит" изображение:

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

Получающееся разделение было бы чем-то вроде этого:

------------     -------------
----WWW-----     ----WWWWW----
---WWWWWWW--     --WWWWWW-----
-----WWWW---     ----WWW------
------------     -------------

Шаги, которые я планирую сделать для разделения изображения:

  1. Отсканируйте изображение от одной стороны до другого.
  2. Определите края блобов.
  3. Возьмите расстояние между двумя внутренними краями.
  4. Разделите изображение в середину внутреннего расстояния.
  5. Сохраните эти два образа как отдельные файлы.

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

У меня нет опыта в обработке изображения, таким образом, я не знаю то, что является эффективным способом сделать это. Я в настоящее время использую BufferedImage, получая ширину/высоту, выполняя итерации по каждому пикселю, и т.д. Нет никакого неверного решения для моей проблемы, но я ищу более эффективный (меньше кода + быстрее). Я также изучал java.awt. Графика...

Я ценил бы, если я получаю некоторое представление для более эффективных способов сделать эту задачу. Я хочу придерживаться встроенных библиотек Java, также - действительно ли BufferedImage или Graphics2D самая эффективная вещь использовать в этом случае?

Править: Вот код после чтения предложений:

public void splitAndSaveImage( BufferedImage image ) throws IOException
{
    // Process image ------------------------------------------         
    int height = image.getHeight();
    int width = image.getWidth();
    boolean edgeDetected = false;
    double averageColor = 0;
    int threshold = -10;
    int rightEdge = 0;
    int leftEdge = 0;
    int middle = 0;

    // Scan the image and determine the edges of the blobs.
    for(int w = 0; w < width; ++w)
    {               
        for(int h = 0; h < height; ++h)
        {
            averageColor += image.getRGB(w, h);
        }

        averageColor = Math.round(averageColor/(double)height);

        if( averageColor /*!=-1*/< threshold && !edgeDetected )
        {
            // Detected the beginning of the right blob
            edgeDetected = true;
            rightEdge = w;
        }else if( averageColor >= threshold && edgeDetected )
        {
            // Detected the end of the left blob
            edgeDetected = false;
            leftEdge = leftEdge==0? w:leftEdge;
        }

        averageColor = 0;
    }

    // Split the image at the middle of the inside distance.
    middle = (leftEdge + rightEdge)/2;

    // Crop the image
    BufferedImage leftImage = image.getSubimage(0, 0, middle, height);

    BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height);

    // Save the image
    // Save to file -------------------------------------------
    ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg"));

    ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg"));
}
5
задан Kiril 30 January 2010 в 00:16
поделиться

4 ответа

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

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

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

COL AVG:

---wwWWwww-----wWWWWww---

В зависимости от того, насколько пустым пространство (важное значение пикселя) между двумя каплями, вы можете установить свое пороговое значение довольно низкое. Если есть немного шума, он должен быть немного выше.

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

5
ответ дан 14 December 2019 в 04:38
поделиться

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

Приложение: Учитывая предпочтение для избежания внешних зависимостей, BufferedImage - хороший выбор. Как только вы определите края, метод Mething () удобно. Вы можете использовать один из методов Raster GetPixels () , эффективно в свертке. Imageio может написать результаты.

1
ответ дан 14 December 2019 в 04:38
поделиться

Я не думаю, что есть какие-либо причина делать что-либо, кроме сканирования каждой строки и остановиться, когда вы получили белый-> черный-> белый переход (не нужно сканировать всю строку !). Если вы можете сделать любую предположение о том, что у вас есть , сможем немного усовершенствовать его, выбирая отправную точку в середине изображения, а затем поиск влево и прямо оттуда. Но я серьезно сомневаюсь, что это стоило бы усилий.

Также нет необходимости сначала запускать алгоритм обнаружения краев на изображении. Просто сканируйте строки!

Редактировать: Г-н Берна указал, что это не будет работать с вогнутыми объектами.

1
ответ дан 14 December 2019 в 04:38
поделиться

Имеет ли значение промежуток между каплями? Если вам не нужно балансировать белое пространство, потребуется меньше усилий, чтобы просто найти вертикальную белую линию между каплями. Убедитесь, что на центральной вертикальной линии есть только белые пиксели. Если средняя линия имеет черный пиксель, просканируйте влево и вправо, чтобы найти первую строку, содержащую только белые пиксели. Чтобы проверить наличие ситуаций, когда оба пятна находятся по одну сторону от центра, отсканируйте горизонтальную линию на наличие черно-белых-черных интервалов. Если выбранная вертикальная линия находится в пределах белого интервала, окруженного черными интервалами, вы знаете, что с каждой стороны разбитого изображения есть по крайней мере по одной капле.

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

-------------------------
----WWW----WWWWWWWWWW----
---WWWWWWW----WWWWWW-----
-----WWWWWWWW---WWW------
-------------------------

Но вопрос, кажется, указывает на то, что такая ситуация невозможна. Если причина этого разделения изображения требует обработки каждого изображения, вам понадобится метод возврата. Вам не понадобится запасной метод, если крайние случаи могут быть отклонены. Как только сканирование обнаружит, что изображение выходит за допустимые пределы, вы можете прекратить проверку изображения. Например, если вертикальная полностью белая линия не может быть найдена в центральной трети изображения, вы можете отклонить изображение. Или вы можете просто использовать этот метод в качестве оптимизации, выполнив эту проверку только на двух строках, чтобы найти и разделить правильно сформированные изображения, а затем передать плохо сформированные изображения более тщательному алгоритму.

1
ответ дан 14 December 2019 в 04:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: