Существует ли правильный алгоритм определения цвета фона фигуры?

Для колледжа нам дали задание, в котором по изображению мы должны определить «цифры», их цвет и количество «пиксельных групп» внутри них. Позволь мне объяснить:

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

Цвет фона холста - пиксель в 0,0 (в данном случае, желтый)Цвет границы рисунка - черный (это может быть любой цвет, кроме цвета фона холста).Цвет фона рисунка - белый (он также может совпадать с цветом фона холста).Фигура может иметь только один цвет фона.На рисунке две группы пикселей. Один - это пул синих пикселей, а другой - пул красного с зеленым внутри. Как видите, не имеет значения цвет пикселей группы пикселей (он просто отличается от цвета фона рисунка). Важно то, что они находятся в контакте (даже по диагонали). Таким образом, несмотря на наличие двух разных цветов, такая группа в любом случае считается только одной.Как видите, граница может быть нерегулярной, как вы хотите. Он имеет только один цвет.Известно, что группа пикселей не будет касаться границы.Мне сказали, что цвета группы пикселей могут быть любыми, кроме цвета фона фигуры. Я предполагаю, что тогда он может быть таким же, как цвет границы фигуры (черный).

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

Вот и все. Я делаю это с Java.

Что я сделал так далеко

Итерация по каждому пикселю в матрицеЕсли я найду пиксель, отличный от цвета фона, я предположу, что он принадлежит границе рисунка. Я назову этот пиксельinitialPixel впредь.Обратите внимание, чтоinitialPixel на изображении, которое я указал, изображен черный пиксель в верхнем левом углу рисунка. Я специально сделал резкий разрез, чтобы проиллюстрировать это.Моя задача сейчас - найти цвет фона фигуры (в данном случае белый).

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

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

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

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

ЧТО МНЕ НУЖНО

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

Мне не нужен какой-либо код - мне просто трудно придумать правильный алгоритм для такого. Тот факт, что на границе могут быть такие странные нерегулярные линии, убивает меня.

Или даже лучше: я делал все это неправильно? Может быть, я не должен был сосредоточиться на этомinitialPixel вообще. Может быть, сработал бы другой метод? Есть ли какие-либо документы / примеры на подобные темы? Я понимаю, что есть много исследований по «компьютерному зрению» и тому подобное, но я не могу найти много об этой конкретной проблеме.

НЕКОТОРЫЙ КОД

Моя функция для извлечения вектора со всеми фигурами: * Примечание:Figure это просто класс, который содержит некоторые значения, такие как цвет фона и количество элементов.

public Figure[] getFiguresFromImage(Image image) {
    Figure[] tempFigures = new Figure[100];
    int numberOfFigures = 0;
    matrixOfImage = image.getMatrix();
    int imageBackgroundColor = matrixOfImage[0][0];
    int pixel = 0;

    for (int y = 0; y < matrixOfImage.length; ++y) {
        for (int x = 0; x < matrixOfImage[0].length; ++x) {
            pixel = matrixOfImage[y][x];
            if (!exploredPixels[y][x]) {
                // This pixel has not been evaluated yet
                if (pixel != imageBackgroundColor ) {
                    // This pixel is different than the background color
                    // Since it is a new pixel, I assume it is the initial pixel of a new figure
                    // Get the figure based on the initial pixel found
                    tempFigures[numberOfFigures] = retrieveFigure(y,x);
                    ++numberOfFigures;
                }
            }
        }   
    }

    // ** Do some work here after getting my figures **

    return null;
}

Тогда, понятно, функцияretrieveFigure(y,x) это то, что я не могу сделать.

Примечания:

В учебных целях я не должен использовать какие-либо внешние библиотеки.
 Andrew Thompson21 окт. 2012 г., 08:06
Видетьэтот ответ который сталэтот вопрос для одного подхода к поиску областей, где происходит цвет.
 DarthVader21 окт. 2012 г., 08:03
Как определить фон изображения и рассказать своей программе?
 Voldemort21 окт. 2012 г., 08:06
@DarthVader: Ах! Мне жаль. Цвет фона холста - пиксель при 0,0. И рисунок не коснется границы холста.
 DarthVader21 окт. 2012 г., 08:04
на твоей картинке? белый фон или желтый? я даже не могу сказать это. даже черный может быть фоном.

Ответы на вопрос(2)

Попробуйте этот код:

import java.util.Scanner;
import java.awt.image.BufferedImage;
import java.io.*;

import javax.imageio.ImageIO;

class Analyzer{
    private int pixdata[][];
    private int rgbdata[][];
    private BufferedImage image;
    int background_color;
    int border_color;
    int imagebg_color;
    private void populateRGB(){
        rgbdata = new int[image.getWidth()][image.getHeight()];
        for(int i = 0; i < image.getWidth(); i++){
            for(int j = 0; j < image.getHeight(); j++){
                rgbdata[i][j] = image.getRGB(i, j);
            }
        }
        int howmanydone = 0;
        int prevcolor,newcolor;
        prevcolor = rgbdata[0][0];

        /*
        for(int i = 0; i < image.getWidth(); i++){
           for(int j = 0; j < image.getHeight(); j++){
              System.out.print(rgbdata[i][j]);
           }
           System.out.println("");
        }*/
        for(int i = 0; i < image.getWidth(); i++){
            for(int j = 0; j < image.getHeight(); j++){
                newcolor = rgbdata[i][j];
                if((howmanydone == 0) && (newcolor != prevcolor)){
                    background_color = prevcolor;
                    border_color = newcolor;
                    prevcolor = newcolor;
                    howmanydone = 1;
                }
                if((newcolor != prevcolor) && (howmanydone == 1)){
                    imagebg_color = newcolor;
                }
            }
        }
    }
    public Analyzer(){ background_color = 0; border_color = 0; imagebg_color = 0;}
    public int background(){ return background_color; }
    public int border() { return border_color;}
    public int imagebg() {return imagebg_color;}
    public int analyze(String filename,String what) throws IOException{
        image = ImageIO.read(new File(filename));
        pixdata = new int[image.getHeight()][image.getWidth()];
        populateRGB();
        if(what.equals("background"))return background();
        if(what.equals("border"))return border();
        if(what.equals("image-background"))return imagebg();
        else return 0;
    }
}
public class ImageAnalyze{
    public static void main(String[] args){
        Analyzer an = new Analyzer();
        String imageName;

        Scanner scan = new Scanner(System.in);
        System.out.print("Enter image name:");
        imageName = scan.nextLine();
        try{
        int a = an.analyze(imageName,"border");//"border","image-background","background" will get you different colors
        System.out.printf("Color bg: %x",a);

        }catch(Exception e){
           System.out.println(e.getMessage());
        }
    }
}

возвращенный цвет - формат ARGB. Вам нужно будет извлечь R, G и B из него.

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

 Voldemort21 окт. 2012 г., 08:26
Я не могу игнорировать желтый, потому что также возможно, что фоновый цвет фигуры действительно желтый (фоновый рисунок фигуры и фоновый холст могут быть одинаковыми - в этом случае это не так, но это возможно). так или иначе).
 Aniket Inge21 окт. 2012 г., 08:24
Вы можете игнорировать определенный цвет (прозрачный), (в данном случае желтый). Определите, что такое граница (черный в данном случае)
 Voldemort21 окт. 2012 г., 08:22
Как, начиная с начальной позиции Пикселя, а затем идти по диагонали вниз-вправо? Но если я это сделаю, есть вероятность (вероятно, на изображении, которое я предоставил), что результат будет желтым, а не ожидаемым белым. Потому что в этом случае initialPixel находится так далеко, что, если вы уйдете по диагонали вниз вправо, вполне вероятно, что вы нажмете желтый вместо белого. Если нет, то просто представьте, что черная рамка немного больше.
Решение Вопроса

графикгде есть один узел («компонент» в этом ответе) для каждой области, заполненной цветом.

Вот один из способов реализации этого подхода:

Пометить все пиксели как не посещенные.

Для каждого пикселя, если он не посещен, выполнитезаливка алгоритм на нем. Во время заливки отметьте каждый подключенный пиксель как посещенный.

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

Найдите компонент, пиксели которого расположены рядом с компонентом цвета фона - это граница вашей фигуры. Обратите внимание, что вы можете найти компонент цвета фона, найдя компонент с 0,0 пикселем.

Теперь найдите компоненты с пикселями, смежными с недавно найденным компонентом 'figure border'. Таких компонентов будет два - выберите тот, который не является фоном (то есть не имеет 0,0 пикселя). Это фон вашей фигуры.

Чтобы найти группы пикселей, просто посчитайте количество компонентов с пикселями, смежными с компонентом фона рисунка (игнорируя, конечно, компонент границы рисунка)

Преимущества этого подхода:

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

Чтобы убедиться, что вы понимаете, как могут работать итерации компонентов и их соседей, вот пример реализации псевдокода для шага 5:

List<Component> allComponents; // created in step 2
Component background; // found in step 3 (this is the component with the 0,0 pixel)
Component figureBorder; // found in step 4
List<Component> pixelGroups = new List<Component>(); // list of pixel groups

for each Component c in allComponents:
    if c == background:
        continue;
    for each Pixel pixel in c.pixelList:
        for each Pixel neighbor in pixel.neighbors:
            if neighbor.getComponent() == figureBorder:
                c.isPixelGroup = true;

int numPixelGroups = 0;
for each Component c in allComponents:
    if (c.isPixelGroup)
        numPixelGroups++;
 Voldemort01 нояб. 2012 г., 02:46
В конце я понял, что это работает с твоей идеей. Благодарю.
 Cam01 нояб. 2012 г., 05:12
@ Омега: Приятно слышать - извините, я пропустил ваш комментарий выше!
 Voldemort23 окт. 2012 г., 01:19
Спасибо, это звучит как отличная идея, и теперь я нахожусь в процессе ее испытания. Я дам вам знать, как идут дела :). У меня есть вопрос о шаге 5: что делать, если мне нужно узнать, сколько групп пикселей делаетопределенная фигура есть? Я имею в виду, что, по-видимому, ваш пример найдет все группы пикселей во всем изображении, но мне, возможно, придется сказать: «Есть фигура зеленого цвета с двумя группами, а другая фигура зеленого цвета с 5 группами»

Ваш ответ на вопрос