2012-10-21 15 views
7

Na studia dostaliśmy zadanie, w którym, biorąc pod uwagę obraz, musimy zidentyfikować "liczby", ich kolor i ilość "grup pikseli" wewnątrz nich. Pozwól mi wyjaśnić:Czy istnieje odpowiedni algorytm do wykrywania koloru tła figury?

enter image description here

Obraz powyżej ma jedno postać (w obrazie może być wiele figury, ale zapomnijmy o tym na razie).

  • kolor tła płótna jest piksel na 0,0 (w tym przypadku, żółty)
  • kolor obramowania rysunku czarna (może to być jakikolwiek inny kolor niż płótna kolor tła).
  • Kolor tła figurki jest biały (może również być taki sam, jak kolor tła płótna).
  • Rysunek może mieć tylko jeden kolor tła.
  • Na rysunku są dwie grupy pikseli. Jedna to pula niebieskich pikseli, a druga to pula czerwieni z odrobiną zieleni w środku. Jak widać, nie ma znaczenia kolor pikseli w pikselach (jest po prostu inny niż kolor tła postaci). Liczy się to, że mają kontakt (nawet po przekątnej). Tak więc pomimo dwóch różnych kolorów, taka grupa jest mimo wszystko uważana za jedną.
  • Jak widać, granica może być tak nieregularna, jak chcesz. Ma jednak tylko jeden kolor.
  • Wiadomo, że grupa pikseli nie dotknie granicy.
  • Powiedziano mi, że kolory grupy pikseli mogą być dowolne z wyjątkiem koloru tła postaci. Zakładam, że wtedy może być taki sam, jak kolor ramki (czarny).

Otrzymaliśmy klasę zdolną do robienia zdjęć i przekształcania ich w macierz (każdy element jest liczbą całkowitą reprezentującą kolor piksela).

I to wszystko. Robię to z Javą.

Co zrobiłem SO FAR

  • iterację każdego piksela na matrycy
  • Jeśli znajdę piksel, który jest inny od koloru tła, będę zakładać, że należący do granicy Figura. Nazwę ten piksel initialPixel od teraz.
  • Należy zauważyć, że initialPixel na podanym obrazie to czarny piksel w lewym górnym rogu figury. Ostro naciąłem go, aby to zilustrować.
  • Moją misją jest teraz znalezienie koloru tła figury (w tym przypadku białego).

Ale mam dużo problemów, aby znaleźć taki kolor tła (biały). Jest to najbliżej sposób ja, który pracował w niektórych przypadkach - ale nie z tym obrazem:

  • Ponieważ znam kolor obramowania, mogę znaleźć pierwszą inny kolor, który jest do południowo z initialPixel.Brzmiało to jak dobry pomysł - czasami działało, ale nie działałoby to z dostarczonym obrazem: w tym przypadku zmieni kolor na żółty, ponieważ initialPixel jest dość oddalony od zawartości figury.

Zakładając, że znalazłem kolor tła postaci (biały), moim następnym zadaniem byłoby uświadomienie sobie, że istnieją dwie grupy pikseli na rysunku. Ten wydaje się łatwiejsze:

  • Od teraz wiem koloru tła rysunku za (biały), mogę spróbować iteracja każdego piksela w rysunku, a jeśli znajdę taki, który nie należy do granicy i nie jest częścią z tła postaci, mogę już powiedzieć, że jest jedna grupa pikseli. Mogę rozpocząć funkcję rekursywną, aby znaleźć wszystkie piksele związane z taką grupą i "oznaczyć ją", aby w przyszłości iteracje całkowicie ignorować takie piksele.

co muszę

Tak, mój problem jest o tym, jak znaleźć kolor rysunku w tle (należy pamiętać, to może być takie samo jak cały obraz w kolorze tła - na razie to żółte, ale może też być biały) w oparciu o to, co opisałem wcześniej.

Nie potrzebuję żadnego kodu - po prostu mam problem z przemyśleniem odpowiedniego algorytmu. Fakt, że granica może mieć tak dziwne, nieregularne linie, zabija mnie.

Albo jeszcze lepiej: czy przez cały czas robiłem źle? Może w ogóle nie powinienem koncentrować się na tym initialPixel. Może działałby inny rodzaj początkowej metody? Czy są jakieś dokumenty/przykłady dotyczące takich tematów? Zdaję sobie sprawę, że istnieje wiele badań nad "wizją komputerową" i takimi, ale nie mogę znaleźć wiele na temat tego konkretnego problemu.

jakiś kod

Moja funkcja do pobrania wektorowych z wszystkich figur: * Uwaga: Figure jest właśnie klasa, która zawiera pewne wartości, takich jak kolor tła i liczby elementów.

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

Następnie wyraźnie, funkcja retrieveFigure(y,x) to co mam jest w stanie to zrobić.

Uwagi:

  • w celach edukacyjnych, nie należy używać żadnych zewnętrznych bibliotek.
+0

jak u zdefiniować tło obrazu i powie do twojego programu? – DarthVader

+0

na Twoim zdjęciu? jest białe lub żółte? Nie mogę nawet tego powiedzieć. nawet czerń może być tłem. – DarthVader

+0

@DarthVader: Ah! Przepraszam. Kolor tła płótna to piksel o wartości 0,0. I figura nie dotknie granicy płótna. – Voldemort

Odpowiedz

4

Dobrym sposobem na rozwiązanie tego problemu jest potraktowanie obrazu jako graph, gdzie jest jeden węzeł ("komponent" w tej odpowiedzi) dla każdego wypełnionego kolorem obszaru.

Oto jeden ze sposobów realizacji tego podejścia:

  1. Mark wszystkie piksele jak nieodwiedzonych.
  2. Dla każdego piksela, jeśli piksel jest nieodwiedzany, wykonaj na nim algorytm flood fill. Podczas wypełniania powodzi zaznacz każdy podłączony piksel jako odwiedzony.

    Teraz powinieneś mieć listę stałych obszarach kolorów w obrazie (lub „składniki”), więc po prostu trzeba dowiedzieć się, w jaki sposób są one ze sobą połączone:

  3. Znajdź element, który ma pikseli sąsiaduje ze składnikiem koloru tła - to jest twoja granica figur. Zauważ, że możesz znaleźć komponent koloru tła, znajdując komponent o wartości 0,0 pikseli.

  4. Teraz znajdź komponenty z pikselami w sąsiedztwie nowo znalezionego komponentu "obramowania rysunku". Będą dwa takie komponenty - wybierz ten, który nie jest tłem (tzn. Nie ma 0,0 piksela). To jest twoje tło postaci.

  5. wyszukiwanie grup pikseli, wystarczy zliczyć ilość składników z pikseli sąsiadujących z komponentu postać tła (pomijając oczywiście składnik postać granicy)

Zalety takiego podejścia:

  • działa w czasie O (# pikseli).
  • łatwe do zrozumienia i wdrożenia.
  • nie przyjmuje koloru tła i koloru tła rysunku są różne.

Aby upewnić się, że rozumiesz jak iteracja składników i ich sąsiedzi mogą pracować, oto implementacja przykład pseudokod dla Krok 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++; 
+0

Dzięki, to brzmi jak świetny pomysł, a teraz jestem w trakcie wypróbowywania go. Dam ci znać, jak to wszystko idzie :). Mam jednak pytanie dotyczące kroku 5: co zrobić, jeśli muszę się dowiedzieć, ile grup pikseli ma * pewna liczba * ma? Chodzi mi o to, że twój przykład znajdzie wszystkie grupy pikseli na całym obrazie, ale być może muszę powiedzieć: "Kolor ma postać zieloną z 2 grupami, a jest inny kolor postaci zielony z 5 grupami" – Voldemort

+0

Na koniec dostałem działa z twoim pomysłem. Dzięki. – Voldemort

+0

@Omega: Wspaniale to słyszeć - przepraszam, że przegapiłem twój komentarz powyżej! – Cam

1

Spróbuj ten kod:

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

kolor zwrócony jest w formacie ARGB. Będziesz musiał wyodrębnić z niego R, G i B.

W tym kodzie występuje błąd. Praca nad implementacją przy użyciu maszyny Finite State. w pierwszym stanie znajdujesz się wewnątrz obrazu, stąd 0,0 jest kolorem tła, a kiedy jest zmiana, zmiana jest kolorem obramowania, wtedy trzeci stan pojawia się, gdy wewnątrz obrazu + wewnątrz obramowania i koloru zmiany.

+0

Od początku, od pozycji początkowejPixel, a następnie po przekątnej w dół w prawo? Ale jeśli to zrobię, istnieje szansa (prawdopodobnie na obrazie, który podałem), że wynik będzie żółty zamiast oczekiwanego białego. Ponieważ w takim przypadku początkowy piksel jest tak daleko, że jeśli pójdziesz ukośnie w prawo, wydaje się możliwe, że uderzysz w żółty zamiast białego. Jeśli nie, to wyobraź sobie, że ta czarna granica jest nieco większa. – Voldemort

+0

Możesz zignorować określony kolor (przezroczysty), (w tym przypadku żółty).Określ granicę (w tym przypadku czarny) –

+0

Nie mogę zignorować żółtego, ponieważ możliwe jest również, że kolor tła postaci jest rzeczywiście również żółty (tło postaci i kolory tła na płótnie mogą być takie same - w tym przypadku nie są, bit i tak jest możliwe). – Voldemort

Powiązane problemy