Möglichkeiten, ein Bild schnell auszuwerten

ankmanu

Bekanntes Mitglied
Hi@all,

ich bin gerade dabei, ein webcambild auszuwerten, indem ich auf diesem Bild nach gelben Bereichen suche, dieser Bereich aber zwischen 4 grünen Eckpunkten sein muss!

Bisheriger Ablauf:
-Webcambild wird gespeichert und dann in ein BufferedImage umgewandelt
-Es wird mit der Funktion
Java:
xyz.getRGB(a,b);
die Farbe des Pixels mit den Koordinaten a und b ausgelesen.
-Es werden ALLE Pixel ausgelesen.
-Wenn ein Pixel zwischen einem bestimmten Bereich von Farbwerten liegt, dann wird es in eine Arraylist gespeichert.
Der Bereich ist zum Beispiel so definiert:
Java:
 Color c = new Color(rgb);
        
        if(c.getRed()>0 && c.getRed()<=20 && c.getGreen()>200 && c.getGreen()<=255 && c.getBlue()>=0 && c.getBlue()<=20){
...
}

-Da es auf dem Bild vier grüne "Häufungen" (Bereiche, die grün sind) gibt, werden von den gefundenen grünen Pixeln alle gelöscht, die ähnliche x-Koordinaten/y-Koordinaten haben (x+-20, y+-20).
-Es ergeben sich vier grüne Pixel.
-Nun wird die Auswertung wiederholt, nur das NICHT ALLE Pixel ausgelesen werden, sondern NUR die, die zwischen den 4 Eckpunkten liegen (und es wird NICHT nach GRÜNEN, sondern nach GELBEN Pixeln gesucht).

-Schließlich wird aus den gelben Pixeln ein Schwerpunkt errechnet, sodass sich ein gelbes Pixel mit x und y-Koordinaten ergibt.
-Es wird von dem Wert der x-Koordinate des gelben Pixels der Wert des linken (ob oberen oder unteren ist egal)Eckpunkts abgezogen.
-Bei der y-Koordinate geschieht genau das selbe.

Durch diese Auswertung habe ich immer den richtigen x-Wert(und y-Wert) des Schwerpunkts, und eben NUR zwischen den 4 grünen Punkten.

______________________________________________________________________
Das ganze klappt schon ganz gut, allerdings sind in meinem Code einige Fehler enthalten(das Programm hängt sich auf, weil es immer keine Pixel mit den entsprechenden Farbwerten findet*!).

*auch wenn:
Java:
c.getRed()>0 && c.getRed()<=255 && c.getGreen()>0 && c.getGreen()<=255 && c.getBlue()>=0 && c.getBlue()<=255
, was eigentlich heißt, das ALLE Pixel erscheinen müssten!


Bevor ich euch den ganzen Code poste, möchte ich fragen, ob das ganze nicht viel einfacher zu realisieren wäre??
Denn so ist das SEHR zeitintensiv, allein eine Auswertung nur aller 30-ten Pixel dauert eine halbe Minute!!!

Wäre es einfacher(und schneller), wenn ich das Bild in ein binäres wandle, und dann 0 für irgendeine Farbe steht, und 1 in der ersten Auswertung für grün, in der zweiten für gelb??

oder gibt es noch andere Möglichkeiten?

Und wenn, WIE geht das dann?? (das mit dem Binären Bild kann ich auch nicht:( )

Vielen Dank im Vorraus für eure Antworten
manu
 

Marco13

Top Contributor
"Ich weiß, dass ich nichts weiß".

(Und jetzt noch ein Zitat von Dieter Nuhr, dann dürfte ich eigentlich nichts mehr schreiben :D )

Aber zumindest weiß ich, dass sowas beliebig aufwändig sein kann. In Computer Vision, Feature Detection und Markerless Tracking wurden schon etliche Millionen Euro und etliche Jahre Forschung von sehr cleveren Leuten gesteckt, und trotzdem kann ein Computer noch keinen Autoreifen von einem verbrannten Donut unterscheiden, weil eben beides schwarz und rund ist und in der Mitte ein Loch hat :D

Was du mit getRGB und Pixeln usw. beschreibst klingt SEHR low-level. Es wäre gut, zu wissen, ob man irgendwelche Annahmen treffen kann. Wenn es um eine Webcam geht, dann kann wahrscheinlich mal die Beleuchtung sch...lecht sein, vielleicht das Bild verschwommen, und, was nicht ganz unwichtig ist: Das zu erkennende Objekt kann größer oder kleiner oder beliebig gedreht sein. Allerdings scheinst du das auch nicht zu berücksichtigen: Wenn die "Grünen Häufungen" einen Radius von 20 Pixeln haben, kann man schonmal davon ausgehen, dass das gesamte Objekt nicht nur 40 Pixel groß ist. Außerdem ist es wohl nicht gedreht, sonst wäre es eine Raute, und es gäbe keine "linke obere" Ecke....

Ohne dich beunruhigen zu wollen: Ich gehe (mit meinem Halbwissen) davon aus, dass es nicht möglich ist, allein durch "Pi-mal-Daumen"-Pixelgeschätze eine zuverlässigen Erkennung hinzubekommen. Wenn ich jetzt vor diesem Problem stehen würde, würde ich (mich fragen, wie ich dazu komme :shock: ;) aber) vermutlich erstmal eine Kantenerkennung machen (Stichwort "Sobel-Filter"), daraus dann Linien erstellen (Stichwort "Hough-Transform"), dann schauen, ob ich 4 Linien finde, bei denen jeweils EINE mindestens(!) ZWEI andere schneidet, und dann vielleicht noch prüfen, ob bei den Schnittpunkten im Bild "viele" Grüne Pixel liegen oder auf jeweils einer Seite dieser Linie zwischen zwei Schnittpunkte "viele" gelbe Pixel liegen... Wissend, dass das nur ein hemdsärmeliger, auf Halbwissen aufbauender Ansatz wäre, und es da sicher noch viel robustere (aber eben auch vieeel kompliziertere) Ansätze gibt...

Wenn es wirklich auf Pixelzählen und Abstandschätzen basieren soll, wäre ein bißchen Code und vielleicht ein Beispielbild sicher nicht verkehrt, aber wie viel Zeit man dann in die Lösung investieren kann, kann man so kaum sagen...
 

ankmanu

Bekanntes Mitglied
danke schon mal für die interessante Antwort,

kannst du mir mal ein Beispiel geben zu dem Sobel-Filter etc., dass ich weiß, wie das geht?
:)

Aber grundsätzlich müsste es doch möglich sein, industrieroboter können das auch schon, mom vielleicht find ich gleich ein Video....

Viele Grüße
manu
 

ice-breaker

Top Contributor
Also das ist bei weitem keine fertige Lösung, aber eine Idee:
In der Uni haben wir mal versimpelt die Erkennung eines Fußballs auf einem Bild (robocup ;)) als Hausaufgabe machen müssen, da wurde dann mit dem HSV-Farbraum das Bild ausgewertet und es blieben nur Farben in dem Bild, die in etwa mit der des Balles übereinstimmten, übrig.

Wenn man dies einmal auf das Bild anwenden würde, um die gelben Bereiche zu suchen, und einmal um die grünen Bereiche zu finden und dann sich beide Bilder anschaut, kann man vllt den Bereich der Gelbauswertung begrenzen.

Edit: Industrieroboter müssen aber nicht mit Bilderkennung arbeiten, da wird wahrscheinlich eher auf Lichtschranken gesetzt.
 

ankmanu

Bekanntes Mitglied
danke für die schnelle Antwort, das ist sogar eine sehr gute Idee, aber wie kann ich das mit Java realisieren??

Ich hab noch keine Idee, wie das gehen soll...

Gruß
manu
 

Marco13

Top Contributor
OK, mal mögliche (grundsätzlich) andere Ansätze außen vor gelassen - wenn ich das richtig verstanden habe, willst/wolltest du ursprünglich sowas machen wie
- Finde 4 Punkte, jeweils irgendeinen Punkt in den grünen Bereichen
- Berechne den Schwerpunkt des eingeschlossenen Bereiches

Die Zwischenschritte (und z.B. an welcher Stelle das "gelb" denn nun eine Rolle spielt) müßtest du ggf. noch erläutern. Und vielleicht auch, welche Annahmen man über das Bild treffen kann...
 

ankmanu

Bekanntes Mitglied
Also:

Auf dem Bild ist eine Fläche zu sehen, die an den vier Ecken grün gekennzeichnet ist.
Auf dieser Fläche ist irgendwo nun eine gelbe Tonne (also auf dem Bild ein gelber Kreis...).

Es soll die Position der Tonne (gelber Kreis) bestimmt werden, aber abhängig von der Fläche...

Da die vier grünen Ecken auf dem Bild größer als 1 Pixel sind, müssten eben alle Pixel von dem Eckpunkt zusammengefasst werden, sodass vier "Eckpixel" entstehen.

Nun soll in der Fläche (zwischen den 4 punkten)eben der gelbe Kreis gesucht werden und dessen Position gefunden werden.

Die Koordinaten des Kreises (bzw. des Kreisschwerpunktes) sollen schließlich ausgegeben werden.

Vielen Dank im Vorraus

manu
 

ankmanu

Bekanntes Mitglied
Also, noch einmal allgemein wie das Bild aussieht:

-Grundsätzlich schwarz(allerdings nicht durchgängig, es sind schwarze Platten, die allerdings Löcher haben).
-Der Großteil des Bildes ist mit einer Fläche bedeckt(diese ist zur Zeit auch schwarz, kann aber auch rot gemacht werden, wenn es einen Nutzen hat)(aber nicht gelb :( , denn sonst würde man die gelbe Tonne/Kreis nicht erkennen)
-Die Ecken der Fläche sind grün gekennzeichnet (jeder Eckpunkt 1,5 x 1,5 cm grün)
-auf der Fläche steht die gelbe Tonne. Da die Webcam darüber befestigt ist, sieht Sie diese als gelben Kreis(Radius des Kreises = 1,5cm --> Durchmesser 3cm )

Ich weiß nicht ob die cm Angaben was bringen, allerdings hab ich sie mal angegeben, um so ein Verhältnis klarzumachen. Die Fläche ist ca. 1m x 25cm groß. Sie ist ganz von der Webcam sichtbar(die Webcam befindet sich ca. 1,5meter über der Fläche)

@gerdgerdgerd:
ich verstehe das mit dem Colormodel nicht ganz, kannst du mir das nochmal erklären?

Hauptsache ist, das die ganze Auswertung relativ schnell geht!(unter 20 sekunden wär nett:) )
Natürlich sollte Sie auch relativ genau sein ... (aber auf 1cm genau würde reichen.)

Viele Grüße
manu
 

gerdgerdgerd

Aktives Mitglied
Java:
ColorModel model = image.getColorModel();

WritableRaster raster = image.getRaster();

for(int i=0; i<image.getWidth(); i++){
  for(int j=0; j<image.getHeight(); j++){
    Object dataElement= raster.getDataElements(i, j, null);
    int rgbValue = model.getRGB(dataElement); 
  }
}

theoretisch kannst du jetzt den erhaltenen rgb wert mit deinen gelbwerten vergleichen. besser wäre natürlich noch ein epsilon um einen farbbereich um den epsilon wert abzudecken, d.h. alle gelblichen farbe:
int gelb = 16776960;
hier kannst du die farbwerte genauer berechnen:
RGB Int Calculator
 

ankmanu

Bekanntes Mitglied
danke, doch ich verstehe die ganze Konstruktion noch nicht.
Meinst du mit vergleichen sowas:
Java:
ColorModel model = image.getColorModel();
int rgbgelb = 16776960;
int zähler = 1;  
int sumx = 0;
int sumy = 0;
int xspunkt = 0;
int yspunkt = 0;
 
WritableRaster raster = image.getRaster();
 
for(int i=0; i<image.getWidth(); i++){
  for(int j=0; j<image.getHeight(); j++){
    Object dataElement= raster.getDataElements(i, j, null);
    int rgbValue = model.getRGB(dataElement); 
if(rgbValue <= rgbgelb+1000 && rgbValue >= rgbgelb-1000){
/**i und j wert speichern... */
zähler++;
sumx = sumx+x;
sumy = sumy+y;
}}}
int zählermain = zähler - 1;
//Berechnung des Schwerpunktes...
xspunkt = sumx/zählermain;
yspunkt = sumy/zählermain;
System.out.println("Der Schwerpunkt P hat folgende Koordinaten: P("+xspunkt+"/"+yspunkt+")\n");
Gruß
manu
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Deine Antwort wird sein: "So funktioniert das bei mir nicht, weil ... [hier irgendwelche Gründe, warum es nicht funktioniert, die auf Annahmen oder Randbedingungen zurückzuführen sind, die du nicht genannt hast]"

Jedenfalls dauert das bisher ein paar Millisekunden.

Java:
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;


class CircleFinder
{
    public static void main(String args[]) throws Exception
    {
        BufferedImage image = ImageIO.read(new File("circleImage.png"));
        findCircle(image);
    }

    private static void findCircle(BufferedImage image)
    {
        float cornerHue = 0.33f;
        float circleHue = 0.16f;
        float threshold = 0.05f;

        int w = image.getWidth();
        int h = image.getHeight();

        BufferedImage cornersImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
        findAreas(image, cornerHue, threshold, cornersImage);

        List<Point> cornerCenters = computeAreaCenters(cornersImage);
        System.out.println("Corner centers "+cornerCenters);



        BufferedImage circleImage = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
        findAreas(image, circleHue, threshold, circleImage);
        List<Point> circleCenters = computeAreaCenters(circleImage);
        System.out.println("Circle centers "+circleCenters);


        JFrame f = null;
        f = new JFrame("Corners");
        f.getContentPane().add(new JLabel(new ImageIcon(cornersImage)));
        f.pack();
        f.setVisible(true);

        f = new JFrame("Circle");
        f.getContentPane().add(new JLabel(new ImageIcon(circleImage)));
        f.pack();
        f.setVisible(true);


    }

    private static void findAreas(BufferedImage image, float hue, float threshold, BufferedImage resultImage)
    {
        float hsb[] = new float[3];
        int w = image.getWidth();
        int h = image.getHeight();
        for (int x=0; x<w; x++)
        {
            for (int y=0; y<h; y++)
            {
                int rgb = image.getRGB(x,y);
                int r = (rgb >> 16) & 0xFF;
                int g = (rgb >>  8) & 0xFF;
                int b = (rgb >>  0) & 0xFF;
                hsb = Color.RGBtoHSB(r,g,b,hsb);

                if (Math.abs(hsb[0]-hue) < threshold)
                {
                    resultImage.setRGB(x,y,Color.WHITE.getRGB());
                }
                else
                {
                    resultImage.setRGB(x,y,Color.BLACK.getRGB());
                }
            }
        }
    }

    private static List<Point> computeAreaCenters(BufferedImage image)
    {
        List<Set<Point>> areas = new ArrayList<Set<Point>>();
        int w = image.getWidth();
        int h = image.getHeight();
        for (int x=0; x<w; x++)
        {
            for (int y=0; y<h; y++)
            {
                Point p = new Point(x,y);
                int rgb = image.getRGB(x,y);
                //System.out.println("rgb at "+x+" "+y+" is "+rgb);

                if (rgb == Color.WHITE.getRGB())
                {
                    Set<Point> currentFilled = new HashSet<Point>();
                    floodFill(image, x, y, currentFilled);
                    //System.out.println("floodFill at "+x+" "+y+" brought "+currentFilled);
                    areas.add(currentFilled);
                }
            }
        }

        List<Point> centers = new ArrayList<Point>();
        for (Set<Point> area : areas)
        {
            centers.add(computeCenter(area));
        }
        return centers;
    }

    private static Point computeCenter(Set<Point> points)
    {
        long cx = 0;
        long cy = 0;
        for (Point p : points)
        {
            cx += p.x;
            cy += p.y;
        }
        int x = (int)(cx/points.size());
        int y = (int)(cy/points.size());
        return new Point(x, y);
    }



    private static void floodFill(BufferedImage image, int x, int y, Set<Point> currentFilled)
    {
        List<Point> stack = new ArrayList<Point>();
        Point point = new Point(x,y);
        stack.add(point);

        int w = image.getWidth();
        int h = image.getHeight();
        while(stack.size() != 0)
        {
            Point p = stack.get(stack.size()-1);
            stack.remove(stack.size()-1);

            x = p.x;
            y = p.y;
            int rgb = image.getRGB(x, y);

            if (rgb == Color.WHITE.getRGB())
            {
                //System.out.println("rgb at "+p+" is "+rgb+" stack "+stack);

                currentFilled.add(p);
                image.setRGB(p.x, p.y, Color.BLUE.getRGB());

                Point p0 = new Point(x-1,y);
                Point p1 = new Point(x,  y-1);
                Point p2 = new Point(x+1,y);
                Point p3 = new Point(x,  y+1);
                Point p4 = new Point(x-1,y-1);
                Point p5 = new Point(x+1,y-1);
                Point p6 = new Point(x-1,y+1);
                Point p7 = new Point(x+1,y+1);

                if (x>0            && !currentFilled.contains(p0)) stack.add(p0);
                if (y>0            && !currentFilled.contains(p1)) stack.add(p1);
                if (x<w-1          && !currentFilled.contains(p2)) stack.add(p2);
                if (y<h-1          && !currentFilled.contains(p3)) stack.add(p3);
                if (x>0   && y>0   && !currentFilled.contains(p4)) stack.add(p4);
                if (x<w-1 && y>0   && !currentFilled.contains(p5)) stack.add(p5);
                if (x>0   && y<h-1 && !currentFilled.contains(p6)) stack.add(p6);
                if (x<w-1 && y<h-1 && !currentFilled.contains(p7)) stack.add(p7);
            }
        }
    }

}
 

ankmanu

Bekanntes Mitglied
Sorry, das ich das Thema noch mal aufgemacht hab, aber ich bin noch ein blutiger Java-Anfänger und verstehe vieles noch nicht.

Ich verstehe noch nicht mals mehr das obige Programm komplett... :(
Kann man die float Zahlen (z.B. 0.33f) auch als rgb angeben(z.B: r = 255, g = 255, b = 70)??
Und was ist bei dir eigentlich das threshold (die schwelle)??

Kannst du mir das bitte noch einmal erklären?

Ich weiß desweiteren nicht, wie ich das anstellen soll:
es soll nur EINE Mitte des Gegenstands geben, in dem bisherigen Programm kommen jetzt oft mehrere Punkte raus :(
Kann man das irgendwie zusammenfassen? (also alle gelben Punkte >> einem Schwerpunkt) (Ich glaube das ist bei dir auch drin, aber das klappt noch nicht so richtig.. )

Und der gelbe Punkt soll dann als einzelner Wert gespeichert werden, bisher kommt ja sowas raus : "java.awt.point[x=123, y=123]"
Geht das auch anders??(Das da steht: "x=123, y=123")

Und der x- und y-wert des gegenstands (des gelben oder circles) soll in abhängigheit der grünen angegeben werden!
(man muss also folgendes machen: x_gegenstand_echt = x_gegenstand_bisher - linker_Eckpunkt der Fläche)
Beim y-Wert genauso...

Sorry für die vielen(wahrscheinlich sehr einfach zu beantwortenden und idiotischen) Fragen.

Viele Grüße und schon mal vielen Dank
manu
 

Marco13

Top Contributor
Ich verstehe noch nicht mals mehr das obige Programm komplett... :(
Das Risiko besteht immer, bei Programmen, die man nicht selbst geschrieben hat. Und manchmal sogar bei eigenen :D

Kann man die float Zahlen (z.B. 0.33f) auch als rgb angeben(z.B: r = 255, g = 255, b = 70)??
Und was ist bei dir eigentlich das threshold (die schwelle)??

Kannst du mir das bitte noch einmal erklären?


Das zeigt zumindest schonmal, dass du den Link von ice-breaker nicht berücksichtigt hast. Diese Zahlen sind der/die/das "Hue" - der Farbton. Wenn man sich mal ein Bild von einer Kugel ansieht
lit_sphere.png

dann sieht man, dass die an der glänzenden Stelle "fast weiß" (zumindest sehr hell) ist, und in anderen bereichen praktisch schwarz. Man kommt mit RGB-Farben nicht weit, wenn
Diese Farbe und
Diese Farbe und
Diese Farbe und
Diese Farbe und
Diese Farbe und
Diese Farbe und
Diese Farbe und
alle als "grün" (und damit Teil der grünen Kugel) angesehen werden sollen. In RGB unterscheiden sich diese Farben teilweise dramatisch. In HSV haben sie alle ungefähr(!) ein Hue von 0.33 - vielleicht ein bißchen mehr, vielleicht ein bißchen weniger. Dieses "mehr oder weniger" ist genau der Threshold :D Also: Wenn eine Farbe einen Hue von 0.33 (+/- 0.05) hat, dann ist sie "Grünlich".


Meine Kristallkugel ist zwar gut genug, dass ich vorher schon sagen konnte, dass du sagen wirst, dass das Programm bei dir nicht funktioniert, aber nicht so gut, dass ich genau wüßte, was du eigentlich willst (abgesehen von einer Lösung, mit wenig Arbeit). Du hast dein Problem nicht genau beschrieben, und selbst wenn du das getan hättest (also die Aufgabenstellung und Beispielbilder hier gepostet hättest) könntest du nicht erwarten, dass jemand die perfekte Universallösung hinschreibt.

Das Programm gibt die Punkte raus, die es als mögliche Mittelpunkte der grünen "Ecken" findet (Corner Centers), und ggf. einen Punkt, der die Mitte des gelben Gegenstandes sein könnte (Circle Center). Das Programm sollte nur zeigen, dass man, wenn man ein bißchen mit HSV und Binärbildern rumrechnet, drumrumkommt irgendwelche ArrayLists mit Color-Objekten anzulegen, in denen man dann mit irgendwelchen Radien und RGB-Vergleichen Positionen rät. Das Programm war nur in der Mittagspause schnell hingeschrieben, und sicher alles andere als "gut". Du kannst es als Basis für eigene Lösungen verwenden, dich davon "inspirieren" lassen, oder weiter deine eigenen Ansätze verfolgen - das steht dir alles frei (einschließlich der Option, Code, Beispielbilder und Rahmenbedingungen zu posten, und präzsiere Fragen zu stellen...)

Wenn du nicht weißt (und keine Möglichkeit siehst, herauszufinden) wie man einen Point als "x=12, y=23" ausgeben kann, oder wie man zwei Punkte voneinander abzieht, solltest du weiter unten anfangen.
System.out.println("x="+point.x+", y="+point.y);
Point difference = new Point(p0.x-p1.x, p0.y-p1.y);
 

ankmanu

Bekanntes Mitglied
Ok, danke, ich werde versuchen mich selbst durchzuschlagen(allerdings fehlen mir eben sehr viele Kenntnisse...)

Noch mal ne Erklärung:
Das Programm greift auf ne Webcam zu und macht ein Bild(das klappt schon)
Als Beispiel folgendes Bild(ist keins von der Webcam, allerdings wird es da anschaulich):



Nun soll das Programm die vier grünen Eckflächen erkennen und diese dann zu vier Eckpunkten zusammenfassen.
(Es werden zum Beispiel alle grünen Punkt in ein Array gespeichert und dann alle gelöscht, die eine den x und y wert (+- 40) des ersten erkannten haben.) Dann bleiben 4 Punkte übrig.

Danach wird wieder das Bild durchsucht, diesmal nach gelben Punkten. Alle gelben Punkte werden nun auch wieder zu einem gelben "Schwerpunkt" zusammengefasst. (z.B. xschwerpunkt= 123, yschwerpunkt= 123; )
Nun muss der schwerpunkt abhängig von den grünen Eckpunkten berechnet werden(also
Java:
x_gelb_echt = xschwerpunkt - x_linker_grüner_eckpunkt;
y_gelb_echt = yschwerpunkt - y_linker_grüner_eckpunkt;

Dieser Punkt soll dann ausgegeben werden. (So wie in dem Beispielprogramm ist das natürlich schön, dass ein Bild erzeugt wird, wo man die erkannte Fläche sieht)

_________________________________________________
Ich weiß nur leider nicht wo ich anfangen soll, denn das obige Programm ist für mich so unübersichtlich(das heißt nur das ich es nicht verstehe) und ich weiß nicht wie und wo ich es verändern muss :(

Wäre schön wenn mir nochmal jemand eine Anregung geben könnte

Viele Grüße
manu
 

Marco13

Top Contributor
Falls das "schwer Verständlich" sich auf das gepostete bezog, ein paar Kommentare
Java:
    // Das "hue" gibt den Farbton vor (z.B. 0.33 für grün oder 0.15 für gelb). Der Threshold
    // besagt, wie stark der Farbton im Bild vom gegebenen abweichen darf, um noch als
    // dazugehörig erkannt zu werden. Das 'image' ist das Eingabebild. In das 'resultImage'
    // werden mit WHITE die Pixel gemalt, die zu den jeweiligen Farbbereichen gehören
    private static void findAreas(BufferedImage image, float hue, float threshold, BufferedImage resultImage)

    // Berechnet die Schwerpunkte aller WEISSEN Bereiche im gegebenen Bild
    private static List<Point> computeAreaCenters(BufferedImage image)

    // Berechnet den Schwerpunkt einer gegebenen Menge von Punkten
    private static Point computeCenter(Set<Point> points)

    // Füllt im gegebenen Bild einen WEISSEN Bereich, angefangen bei x,y. 
    // Der Bereich wird mit blauen Pixeln gefüllt, und die Menge aller
    // Pixel, die vorher weiß waren, werden in 'currentFilled' gespeichert
    private static void floodFill(BufferedImage image, int x, int y, Set<Point> currentFilled)

Das sind die "Bausteine", die man braucht, um auf EINE (SEHR einfache!) Art ungefähr das zu machen, was du angeduetet hast. Im Eingabebild werden erst alle grünen Bereiche gefunden, und dann die Schwerpunkte dieser Bereiche berechnet. Das gleiche dann mit dem gelben Bereich. Und wie man diese Punkte jetzt miteinander verrechnen soll, musst du wissen.

Was kommt denn raus, wenn du das Programm auf das gepostete Bild losläßt?
 

ankmanu

Bekanntes Mitglied
Hi, danke schon mal für deine erklärungen :)
So wirds mir schon viel verständlicher

Das Programm gibt dann folgendes aus:



Ich will z.B. noch folgendes einbauen:
-die grünen(und gelben) Flächen sollen nur ausgegeben werden, wenn sie größer als z.B.20x20 Pixel ist. (Damit eben nicht so kleine "Fitzelchen" als Fläche erkannt werden)

Wo muss das dann in den Code??
Bei
Java:
 List<Point> centers = new ArrayList<Point>();
        for (Set<Point> area : areas)
        {
            /** Hier?? */
            centers.add(computeCenter(area));
        }
        return centers;
Und wenn ja, wie? Mit
Java:
if(area.getlength() >= 20 && area.getWidth() >= 20){centers.add(computeCenter(area));}
??
Viele Grüße
manu
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Hast du, um diese "Fitzelchen" wegzukriegen, mal versucht, den "Threshold" kleiner zu machen? (Könnte helfen, muss es aber nicht...). Man könnte ja jetzt noch ein k-Means oder so drauf loslassen, aber das wäre eben aufwändiger. Die Erfahrung zeigt, dass es für jedes Problem eine Lösung gibt, die einfach, elegant ... und falsch ist. Oder anders formuliert: Wenn man für ein kompliziertes Problem (Objekterkennung) glaubt, eine einfache Lösung (Pixelzählen) gefunden zu haben, ist es nur eine Frage der Zeit (und der Rahmendbedingungen) bis eine Probleminstanz auftritt, die mit dem einfachen Lösungsansatz nicht funktioniert.

Wie sehen diese "Fitzelchen" denn im Originalbild aus?
 

ankmanu

Bekanntes Mitglied
naja die "fitzelchen " siehst du ja auf dem obigen Bild...
Eigentlich sind es einfach 4 grüne flächen(mit paint gemalt) und trotzdem findet das Programm daneben noch andere "grüne " flächen.

Mit kleinerem threshold wird es etwas weniger, aber nicht wirklich "gut".
Man müsste eben eine Bedingung einbauen, dass die Koordinaten nur verwendet werden, wenn die erkannte Fläche z.B. größer als 20x20 pixel ist.
Aber wie geht das??

Viele Grüße
manu
 

Marco13

Top Contributor
Aus dem Bild, das du weiter oben gepostet hast, kann eigentlich nicht das entstehen, was du weiter darunter gepostet hast. Das sieht wenn überhaupt dann nach übertrieben starker JPG-Kompression aus, aber wenn du nicht weißt, wo die "Fitzelchen" herkommen, weißt du auch nicht, ob du eine Größenbeschränkung von 20x20 oder 21x21 verwenden must. Trotzdem steht dir das frei: Diese Liste mit den "currentFilled" Pixeln beschreibt eine Zusammenhängende Fläche, deren Größe man ausrechnen kann.
Code:
private boolean isLargerThan(List<Point> area, int sizeX, sizeY)
{
    // Trivial
}
 

ankmanu

Bekanntes Mitglied
Das stimmt, das Bild zum letzten Post war dieses:

Allerdings wundere ich mich, waum neben den grünen und gelben Flächen des Bildes so "Fitzelchen" entstehen, denn dort ist das Bild doch eindeutig schwarz (oder ist das wegen dem float??)

Entschuldigung das ich dauernd frage, aber wie kann ich denn verwirklichen, dass wirklich NUR 4 grüne und NUR 1 gelbe Flächen gefunden werden, damit es am Ende wirklich NUR 4 grüne Schwerpunkte und NUR 1 gelben Schwerpunkt gibt??

Muss man das mit nem Array machen, also so:
Java:
int[] greencorners = new int[3];   //Array der WIRKLICHEN 4 Eckpunkte 
// In dem Array allppoints sind alle gefundenen grünen Punkte gespeichert
...
int counter = 0;
int i = 0;
for(i=0; i<=allpoints.getLengh(); i++){
//Wenn der aktuelle Punkt der erste gefundene Punkt +- 40 ist, dann zum array hinzufügen
if(allpoints[i] > allpoints[1] - 40 || allpoints[i] < allpoints[1] + 40) {
greencorners[counter] = allppoints[i];
counter++;
}}
Allerdings stimmt das mit dem allpoints[1] ja nicht, da der erste gefundene grüne Punkt ja nicht unbedingt der von einem Eckpunkt sein muss. Und außerdem gibt es ja 4 Eckpunkte!

Aber wie kann ich das (wenn das überhaupt ansatzweise stimmt) zum Richtigen verändern?
Und wo müsste ich diesen Code dann einfügen?

Viele Grüße
manu
 

Marco13

Top Contributor
Allerdings wundere ich mich, waum neben den grünen und gelben Flächen des Bildes so "Fitzelchen" entstehen, denn dort ist das Bild doch eindeutig schwarz (oder ist das wegen dem float??)

Im Anhang siehst du das, was rauskommt, wenn man bei dem Bild, das du gepostet hast, mit GIMP die Helligkeit und den Kontrast auf's Maximum stellt. Wie ich schon sagte
Das sieht wenn überhaupt dann nach übertrieben starker JPG-Kompression aus

Ob die nun "übertrieben" ist oder nicht, sei mal dahingestellt. Jedenfalls wäre ein erster Ansatz, das Kriterium bei "findAreas" entsprechend anzupassen. Vorher war das
Code:
if (Math.abs(hsb[0]-hue) < threshold)
Dort könnte man stattdessen sowas machen wie
Code:
if (Math.abs(hsb[0]-hue) < threshold && hsb[1] > 0.5f && hsb[2] > 0.25f)
Das Programm sollte eine grundsätzliche Möglichkeit zeigen, den Prozess in Teilschritte zu zerlegen, die man getrennt anpassen kann. Es hängt von der Kamera und dem genauen Bild ab, wann ein Pixel denn nun "Grün" ist und wann nicht. Beim Testbild funktioniert das so jedenfalls. Ob es beim Webcambild funktioniert, weiß ich nicht. Ich weiß ja nicht, wie das aussieht *räusper*.



Entschuldigung das ich dauernd frage, aber wie kann ich denn verwirklichen, dass wirklich NUR 4 grüne und NUR 1 gelbe Flächen gefunden werden, damit es am Ende wirklich NUR 4 grüne Schwerpunkte und NUR 1 gelben Schwerpunkt gibt??

Für Fragen ist so ein Forum da. Eine Möglichkeit, das (bei dem Testbild!) zu erreichen, steht oben. Falls ich genervt wirke, dann liegt das daran, dass du anscheinend zu wenig... involviert und engagiert bist, sowas selbst rauszufinden.

Was du immer mit der Größe der Bereiche hast, leuchtet mit nicht ein. Wann wird aus einem "Fitzel" ein "Eckpunktsbereich"? Das einzige, was mir spontan einfallen würde, um dort einen Hauch von Robustheit reinzubringen, wäre ein k-Means-Clustering. Zum Glück weiß man in diesem Fall zumindest schon, dass k=4 bzw. k=1 sein müßte.
 

Anhänge

  • epxu-3_2.png
    epxu-3_2.png
    8 KB · Aufrufe: 35
G

Guest2

Gast
Moin,

um mich dem hier auch mal anzuschließen:

Ob es beim Webcambild funktioniert, weiß ich nicht. Ich weiß ja nicht, wie das aussieht *räusper*

ankmanu, könntest Du nicht eines der original Bilder aus der Webcam posten? Oder besser noch, einen ganzen Satz an Beispielbildern? Du kannst den Algorithmus monatelang an synthetischen Bildern optimieren, aber sobald das erste reale Bild aus der Webcam kommt, wirst Du wieder ganz von vorne anfangen.

Computer Vision ist zwar nicht meine Hausdisziplin, aber ich hätte Lust zu spielen. :D

Gruß,
Fancy
 

ankmanu

Bekanntes Mitglied
Ja, doch das dauert noch ein paar Tage ( :( )

Der Grund:
Ich habe eine Webcam, die auf meinem alten PC funktioniert hat, und mit der ich gearbeitet habe.
Doch jetzt habe ich einen neuen PC, der mit dem Betriebssystem Windows 7 ausgestattet ist. Leider war das eine Webcam für 10 € bei mediamarkt, und für diese ist kein Treiber für Windows 7 vorhanden :(

Deshalb muss ich mir eine neue bestellen(hab ich noch nicht gemacht).
(Empfehlungen werden gerne angenommen ...)

Viele Grüße
manu
 

agentone

Bekanntes Mitglied
Vielleicht solltest du dein mit Paint gemachtes Bild mal als Bitmap (.bmp) speichern.
Dann siehst du keine "Fitzelchen" mehr!

dort ist das Bild doch eindeutig schwarz
Windows XP:
- Geh auf Destop
- rechtsklick
- "Eigenschaften"
- "Einstellungen"
Unter "Farbqualität" steht da bei mir "32 Bit", das heißt:
8 Bit Rot, 8 Bit Grün, 8 Bit Blau, 8 Bit Alpha.
Und wenn man dann Alpha mal außen vor lässt, hast du dann genau 2^24=16.777.216 verschiedene Farben. Erzähl mir also nicht, du kannst RGB(0,0,0) von RGB(0,0,1) mit bloßem Auge unterscheiden.

Aber sorry, war nicht böße gemeint. :)
Ich fand das Wort "eindeutig" nur unpassend gewählt.
 
G

Guest2

Gast
Besser wäre es aber vermutlich sein synthetisches Bild weiter zu verschlechtern. Das was aus der Webcam rauskommt wird ja auch nie und nimmer schwarz sein, genauso wenig wie das grün grün und das gelb gelb sein wird. Außerdem noch Verzerrungen durch Linse, Licht und Schatten, Artefakte und andere Störobjekte.

Mit ein bissel Glück sieht der Spaß dann doch schon so ähnlich aus:

green.png


(Und das ist dann imho sogar noch fernab jeglichen worst cases ;))

Gruß,
Fancy
 

agentone

Bekanntes Mitglied
Also mit dem folgenden Programm und dem Bild vom letzten Post konnte ich das im Anhang angehängte Bild berechnen:

Java:
import javax.imageio.*;
import java.awt.*;
import java.awt.image.*;
import java.io.File;
import javax.swing.*;

public class ImageTest
{
  public static final String FILE="paint2.jpg";
  
  public static final int SCHWELLE=20;

  public static void main(String args[])
  {
    try
    {
      BufferedImage image=ImageIO.read(new File(FILE));

      int width=image.getWidth();
      int height=image.getHeight();
      
      BufferedImage output=new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
      Graphics g=output.getGraphics();
      g.setColor(Color.WHITE);
      g.fillRect(0,0,width,height);
      g.setColor(Color.BLACK);
      
      for(int x=0; x<width; x++)
      {
        for(int y=0; y<height; y++)
        {
          Color c=new Color(image.getRGB(x,y));

          for(int i=x-1; i<=x+1; i++)
          {
            for(int j=y-1; j<=y+1; j++)
            {
              if(!(i==0 && j==0))
              {
                Color n=getColor(image,i,j);
                if(n!=null)
                {
                  if(difference(c,n)>=SCHWELLE)
                  {
                    g.drawRect(x,y,1,1);
                  }
                }
              }
            }
          }
        }
      }
      
      JFrame frame=new JFrame("Image Output");
      JLabel label=new JLabel(new ImageIcon(output));
      frame.getContentPane().add(label);
      frame.pack();
      frame.setVisible(true);
      
      ImageIO.write(output,"jpg",new File("output.jpg"));
      
      System.out.println("fertig");
    }
    catch(Exception e)
    {
      System.out.println(e);
    }
  }
  
  public static Color getColor(BufferedImage image, int x, int y)
  {
    if(x>0 && x<image.getWidth() && y>0 && y<image.getHeight())
    {
      return new Color(image.getRGB(x,y));
    }
    else
    {
      return null;
    }
  }
  
  public static int difference(Color ca, Color cb)
  {
    int r=Math.abs(ca.getRed()-cb.getRed());
    int g=Math.abs(ca.getGreen()-cb.getGreen());
    int b=Math.abs(ca.getBlue()-cb.getBlue());
    return (r+g+b)/3;
  }
}

Zugegeben, das Programm hat nicht wirklich was mit dem Thread hier zu tun, bringt aber auch für die anderen Bilder in diesem Thread ganz vernünftige Ergebnisse.
Es berechnet nämlich eigentlich die "markanten" Ränder von Objekten in Bildern.
Einfach FILE anpassen und ein bisschen an der SCHWELLE rumdrehen, dann kann z. B. auch das 2. Bild im Anhang entstehen, welches im Original auch in diesem Thread irgendwo ist.
 

Anhänge

  • output.jpg
    output.jpg
    26,9 KB · Aufrufe: 31
  • output2.jpg
    output2.jpg
    3,8 KB · Aufrufe: 27
Zuletzt bearbeitet:

Marco13

Top Contributor
Wie schon angedeutet: Diese SCHWELLE und der RGB-Vergleich sind ziemlich heikel. Angenommen SCHWELLE ist 20, dann würden die Farben im Bild im Anhang als "gleich" (zur ersten) angesehen werden, obwohl einige davon "eindeutig rötlich" und andere "eindeutig grünlich" (und eine GANZ eindeutig grau ;) ) sind...

Für verrauschte Bilder könnte man sich dann sowieso noch überlegen, ob man vorher einen Weichzeichner drüberlaufen läßt, aber das wäre ja im Idealfall nur ein weiterer Schritt in der (ansonsten gleichen) Verarbeitungspipeline....
 

Anhänge

  • Bild2.png
    Bild2.png
    209 Bytes · Aufrufe: 66

ankmanu

Bekanntes Mitglied
Das Programm von agentone sieht ja auch schon super aus. (Hätt ich nie hingekriegt :( )
Mal sehn ob ich da was draus machen kann( schwerpunkt berechnung hinzu, ...).

Ich versuch euch so bald wie möglich ein paar "echte" Webcambilder zu posten, dauert allerdings leider noch ein paar Tage.

Und hat jemand eine Idee wie man bei agentones Programm zwischen den rechteckigen Flächen und dem Kreis unterscheiden kann?

Viele Grüße und und vielen Dank dass ihr mir so super helft :)

manu
 

Janus

Bekanntes Mitglied
Zur Unterscheidung von Rechtecken und Kreisen ist Kompaktheit ein recht gutes Maß, wobei Kompaktheit hier als Verhältnis von Fläche zu Umfang definiert ist. Je kompakter, desto Kreis.
 

ankmanu

Bekanntes Mitglied
Hi @ all
So:
Bilder sind jetzt da (eine ganze Bildserie, mit unterschiedlichen Positionen des Gegenstandes und unterschiedlicher Belichtung)













Allerdings ist die Qualität der Bilder meines Erachtens sehr schlecht :(
Außerdem ist der Gegenstand gelb gekennzeichnet, aber die Holzplatte auf der die ganze Fläche befestigt ist hat fast die selbe Farbe, kann man das dann noch gut unterscheiden?

Oder sollte ich den Gegenstand lieber blau oder auch grün markieren?

Viele Grüße
manu
 
G

Gast2

Gast
*muhaha*

das Semester hast Du wohl in den Sand gesetzt ... da sind ja noch nicht mal die Lichtverhältnisse konstant ... das siehst Du schön wie sich die Farbe des Vierecks in den letzten beiden Bilder deutlich von den anderen unterscheidet

ich weiß das ich faul bin...

dann wird es Zeit das Du das änderst

Nachtrag

Allerdings ist die Qualität der Bilder meines Erachtens sehr schlecht :(
nein - eher real (wenn man mal von der JPG-Kompression absieht) ... mit solchen Bilder darf ich arbeiten

Außerdem ist der Gegenstand gelb gekennzeichnet, aber die Holzplatte auf der die ganze Fläche befestigt ist hat fast die selbe Farbe, kann man das dann noch gut unterscheiden?
irgendwie sieht die Tischplatte auf dem Bild deutlich dunkler aus

Oder sollte ich den Gegenstand lieber blau oder auch grün markieren?
wozu ?! ... solange Du alles mit den Augen trennen kannst, kannst Du es auch im Bild trennen ... wenn Du den Punkt auch grün machst wie die Vierecke wirst Du sie im Programm schwerer unterscheiden können
 
Zuletzt bearbeitet von einem Moderator:

noobadix

Bekanntes Mitglied
Hallo,

wenn ich mich da mal einmischen darf, ob meiner völligen Erfahrungslosigkeit auf dem Gebiet und diesem Problem im Besonderen. Hab da Ideen:

1. Farbfolie vor die Kamera setzen, eine neongelbe beispielsweise.
2. Neonfarbe Gelb für die Tonne verwenden
3. Kontraste der Bilder hoch-/runterfahren
4. Mit geringerer Auflösung aufnehmen
5. LED-Belichtung benutzen und Reflektionen (also Lacke etc.) minimieren

Könnte/Darf das helfen?
 
Zuletzt bearbeitet:

ankmanu

Bekanntes Mitglied
Das ist sogar eine sehr gute Idee !!

Einziges Problem: Es kann nur eine Farbe "erkannt" werden, dass heißt z.B. nur neongelb für den Gegenstand.
Allerdings müssen die Eckpunkte ja auch noch erkannt werden, da die Koordinaten des Gegenstands in Abhängigkeit der Fläche zwischen den 4 Eckpunkten angegeben werden soll.

Zitat: ankmanu

Beitrag anzeigen



Außerdem ist der Gegenstand gelb gekennzeichnet, aber die Holzplatte auf der die ganze Fläche befestigt ist hat fast die selbe Farbe, kann man das dann noch gut unterscheiden?


irgendwie sieht die Tischplatte auf dem Bild deutlich dunkler aus
naja es gibt mehrere schwarze Platten(da sind kleine Löcher drin). Aber diese sind auf einer Holzplatte montiert. Zwischen den schwarzen Platten ist ein kleiner Abstand, und da die Holzplatte auch "fast gelb" ist, sieht sie der Farbe des Gegenstands sehr ähnlich.

Viele Grüße
manu
 

noobadix

Bekanntes Mitglied
Wenn die Kamera fixiert ist, wozu brauchst du die Eckpunkte überhaupt? Ansonsten mach doch die Eckdinger auch gelb, dann brauchste wie weiter oben schon gesagt nur noch die Formen unterscheiden.
 
Zuletzt bearbeitet:

ankmanu

Bekanntes Mitglied
Also die Kamera ist zwar fixiert, allerdings soll das ganze Konstrukt einmal mitgenommen werden und dazu muss ich die Kamera wieder abmontieren.
Ich gehe davon aus, dass die Kamera beim Wiederanbringen nicht 100-%ig am selben Ort über der Fläche ist (also Pixel 1/1 nicht wieder 1/1)und deshalb wäre das mit den Eckpunkten sinnvoll. Diese müssten dann ja nur alle auf dem Bild zu sehen sein und schon wird der richtige Wert ausgegeben. :)

Aber vielleicht ist es wirklich einfacher nur nach gelben Flächen zu suchen. Wäre jedenfalls super wenn das erstmal klappen würde. :)

Viele Grüße
manu
 

ankmanu

Bekanntes Mitglied
nochmal als nachtrag:

Wäre es einfacher, ein solches invertiertes/neoneffekt Bild auszuwerten:



Logischerweise nicht oder?
(nur mal als versuch)

Viele Grüße
manu
 

noobadix

Bekanntes Mitglied
Die Farbe der relevanten Bereiche muss auf dem Bild einmalig sein, am besten so, dass du beim Iterieren über die Pixel nur eine if-Abfrage pro Durchlauf hast, so sparst du Zeit. Die if-Prüfung, die du anfangs gepostet hast, ist ja ziemlich zeitintensiv.
 

Marco13

Top Contributor
@mogel: Du Motivationskünstler! :D

@Topic: Aber ja, wie schon gesagt wurde: Solange man nichts über das Bild weiß, und die Lichtverhältnisse so unterschiedlich sein können usw. wird das schwierig. Das gelbe Objekt liegt manchmal auf diesen Gitterlinien, und die haben (im Bild) praktisch die gleiche Farbe wie das Objekt. (Weiß - bei zu hoher Belichtung ;) ).

Ich wollte hier im Forum ja schon immer mal ein Spiel veröffentlichen. Hier ist also mein Spiel. Es trägt den Titel "Bilderkennungsschwellwertsuche":
Java:
import java.util.*;
import java.util.List;
import java.awt.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.imageio.*;
import java.io.*;


class CircleFinder extends JFrame
{
    public static void main(String args[]) throws Exception
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                try
                {
                    BufferedImage image = ImageIO.read(new File("circleImage04.jpg"));
                    new CircleFinder(image).setVisible(true);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }

    private BufferedImage image;
    private BufferedImage resultImage;
    private float hsbMin[] = new float[]{ 0.0f, 0.0f, 0.0f };
    private float hsbMax[] = new float[]{ 1.0f, 1.0f, 1.0f };

    public CircleFinder(BufferedImage image)
    {
        this.image = image;
        int w = image.getWidth();
        int h = image.getHeight();

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

        getContentPane().setLayout(new BorderLayout());
        getContentPane().add(new JLabel(new ImageIcon(resultImage)), BorderLayout.CENTER);

        JPanel p = new JPanel(new GridLayout(0,2));

        p.add(new JLabel("Hue"));
        p.add(new JLabel(""));
        p.add(new JLabel("min"));
        p.add(createSlider(hsbMin, 0, 0));
        p.add(new JLabel("max"));
        p.add(createSlider(hsbMax, 0, 255));

        p.add(new JLabel("Sat"));
        p.add(new JLabel(""));
        p.add(new JLabel("min"));
        p.add(createSlider(hsbMin, 1, 0));
        p.add(new JLabel("max"));
        p.add(createSlider(hsbMax, 1, 255));

        p.add(new JLabel("Br"));
        p.add(new JLabel(""));
        p.add(new JLabel("min"));
        p.add(createSlider(hsbMin, 2, 0));
        p.add(new JLabel("max"));
        p.add(createSlider(hsbMax, 2, 255));

        getContentPane().add(p, BorderLayout.EAST);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        pack();
    }

    private JSlider createSlider(final float array[], final int index, int value)
    {
        final JSlider s = new JSlider(0,255,value);
        s.addChangeListener(new ChangeListener()
        {
            public void stateChanged(ChangeEvent e)
            {
                array[index] = s.getValue() / 255.0f;
                System.out.println("min "+Arrays.toString(hsbMin));
                System.out.println("max "+Arrays.toString(hsbMax));
                findAreas();
                repaint();
            }
        });
        return s;
    }



    private void findAreas()
    {
        float hsb[] = new float[3];
        int w = image.getWidth();
        int h = image.getHeight();
        for (int x=0; x<w; x++)
        {
            for (int y=0; y<h; y++)
            {
                int rgb = image.getRGB(x,y);
                int r = (rgb >> 16) & 0xFF;
                int g = (rgb >>  8) & 0xFF;
                int b = (rgb >>  0) & 0xFF;
                hsb = Color.RGBtoHSB(r,g,b,hsb);

                if (hsb[0]>hsbMin[0] && hsb[0]<hsbMax[0] &&
                    hsb[1]>hsbMin[1] && hsb[1]<hsbMax[1] &&
                    hsb[2]>hsbMin[2] && hsb[2]<hsbMax[2]
                    )
                {
                    resultImage.setRGB(x,y,Color.WHITE.getRGB());
                }
                else
                {
                    resultImage.setRGB(x,y,Color.BLACK.getRGB());
                }
            }
        }
    }

}
(Das kannst du dir auch gerne nach "RGB" umschreiben, und schauen, ob du damit weiterkommst :D)

Mal im ernst: Bei einigen Bildern kann man die Slider so einstellen, dass man die Eck-Ecke erkennen kann, aber mit den gleichen Einstellungen kriegt man bei einem der überbelichteten Bilder halt nur eine Weiße Fäche :autsch:

Zusammenfassend würde ich sagen, dass man in diese Aufgabe in dieser Form RICHTIG (RICHTIG) viel Arbeit stecken könnte. Nichts für jemanden der (im unproduktiven Sinne) faul ist ;) Ich bin kein Bildverarbeitungsexperte, aber bezweifle, dass man diese Aufgabe rein Pixelbasiert (d.h. ohne Kantenerkennung, Hough-Tansform & Co) überhaupt lösen kann. Vielleicht würde man mit genauerer Kameraklibrierung, weniger veränderlichen Lichtverhältnissen, deutlichen Farben, weniger Störungen (Glanzeffekte usw), und mit geschickter Vorverarbeitung (Histogrammabgleich oder was es da nicht alles gibt) irgendwie auf einen grünen Zweig kommen, aber... sicher nicht, indem man schaut ob in irgendeiner Arraylist erst 19 oder schon 20 Pixel liegen...
(So viel zum Thema "Motivationskünstler" :D aber ist nur meine subjektiv-unfundierte Einschätzung...)
 

ankmanu

Bekanntes Mitglied
Ja das stimmt, die gepostete if-abfrage(von mir) war sehr zeitintensiv :( (bis zu 30 sekunden...)

Ich hab die Fläche jetzt komplett schwarz, das heißt es ist wirklich grün und gelb zu unterscheiden.
Bilder kann ich grade leider nicht posten (morgen müsst ichs schaffen)

Wenn noch jemand Ideen hat: Bin froh wenn ihr sie postet :)

Viele Grüße
manu
 

Marco13

Top Contributor
Eine komplett einfarbige (und vielleicht auch weniger glänzende) Fläche wäre schonmal was. Wenn das Objekt selbst dann noch eine "eindeutigere" ("grellere") Farbe hätte (sowas wie dieses Verkehrshütchen-Neonorange oder so...), könnte es vielleicht sogar reichen nur nach dieser spezifischen Farbe zu suchen... Evtl. braucht man dann nichtmal die Ecken und die ganzen anderen aufwändigen Sachen...
 

noobadix

Bekanntes Mitglied
Genial wäre es, wenn die Farbe der relev. Bereiche die einzige im Bild wäre, deren r,g oder b wert höher als 250 oder so ist, kenne mich da im Speziellen nicht so aus, denn dann bräucht's pro Durchlauf nur noch n kompaktes if( farbe>wert). Die immergleichen Lichtverhältnisse ließen sich doch erreichen, wenn das Ding in nem Kasten wär und mit LED's beleuchtet würde, irgendwo hab ich mal aufgeschnappt, dass LED's die wahre Farben verraten. Evtl. sollte noch irgendwas streuendes, Milchglas z.B., vor die LED's gesetzt werden.
 
Zuletzt bearbeitet:

ankmanu

Bekanntes Mitglied
jo dann versuche ich eben alles mit farben auszufüllen, bis auf den Gegenstand, den markiere ich dann weiß (r = 255, g= 255, b=255).

Morgen post ich dann des Bild....

Gruß
manu
 

ankmanu

Bekanntes Mitglied
So, Bilder sind jetzt da:




Dieses Bild ist absichtlich mit überhöhter Belichtung aufgenommen: (als Test, aber ich denke, dass man dort den Gegenstand nicht erkennen kann :( )


Die Bilder sind jetzt hauptsächlich schwarz, und nur die Eckpunkte und der Gegenstand sind "farbig" (also nicht schwarz, obwohl schwarz auch eine Farbe ist :D )

EDIT: So, ich hab jetzt mal das erste der obigen Bilder mit den Werten:
Java:
 float cornerHue = 0.50f;
        float circleHue = 0.13f;
        float threshold = 0.03f;
ausgewertet, und es kommt folgendes raus:


Man sieht, dass die Eckpunkte relativ gut erkannt werden! (Nur den Wert für den Gegenstand müsste man noch anpassen... (oder man markiert den gegenstand z.B.ROT, um das mit der Belichtung zu vermeiden))

Doch wie kann man noch folgendes einbauen:
Es sollen nur Flächen größer als x mal y Pixel als Eckpunkte erkannt werden? Dann könnte man nämlich die kleinen Fitzelchen komplett vermeiden(denn zurzeit hat mir das Programm z.B 6 Ecken ausgegeben :-D )
Viele Grüße
manu
 
Zuletzt bearbeitet:
Ähnliche Java Themen
  Titel Forum Antworten Datum
E Java Programm mit Clients erweitern - Möglichkeiten? Allgemeine Java-Themen 2
J Videokonferenz mittel Java ? Welche Möglichkeiten habe ich ? Allgemeine Java-Themen 2
J Anzahl von Möglichkeiten zur Verteilung von Kugeln in Behälter Allgemeine Java-Themen 3
D HTMLUnit Möglichkeiten? Allgemeine Java-Themen 3
S Einschätzen der Möglichkeiten Allgemeine Java-Themen 5
G Möglichkeiten aufliste - Wie? Allgemeine Java-Themen 25
T Möglichkeiten der Kommunikatin zwischen Plugins in Ecl. RCP Allgemeine Java-Themen 3
B Möglichkeiten ein Java Programm auf einem Server auszuführen Allgemeine Java-Themen 30
I Welche Möglichkeiten bietet Java um Records in Dateien zu sp Allgemeine Java-Themen 10
G Alle Möglichkeiten n Elemente Anzuordnen. Allgemeine Java-Themen 13
J Funktion alle Möglichkeiten berücksichtigen Allgemeine Java-Themen 5
F SuppressWarnings("xxx") - welche Möglichkeiten gib Allgemeine Java-Themen 4
G möglichkeiten java? Allgemeine Java-Themen 4
berserkerdq2 Habe ein svg bild, kann ich das zu svg koordinaten umrechnen, damit ich den Umriss zeichnen kann? Wenn ja wie? Allgemeine Java-Themen 1
berserkerdq2 Wenn ich einfach eine GIF in den Scenebuilder als Bild reinpacke, wird das dann asl Gif angezeigt Allgemeine Java-Themen 1
OnDemand Prüfen ob Bild defekt ist Allgemeine Java-Themen 4
Y Bild in JPanel setzen Allgemeine Java-Themen 2
Kirby.exe Bild im Zentrum spiegeln Allgemeine Java-Themen 14
I Apache POI Bild in Word ersetzen Allgemeine Java-Themen 15
OnDemand Bild prüfen ob defekt Allgemeine Java-Themen 3
L Input/Output Kassenzettel lesen aus einem Bild Allgemeine Java-Themen 2
K Bild in einem anderen Bild suchen Allgemeine Java-Themen 12
R Compiler-Fehler Bild per E-Mail versenden Allgemeine Java-Themen 3
M Java- Bild gewissen Anzahl von Sekunden anzeigen?! Allgemeine Java-Themen 4
RalleYTN 2D-Grafik Bild mit bilinearer Interpolation skalieren Allgemeine Java-Themen 31
RalleYTN 2D-Grafik Bild ohne AWT, Swing und JavaFX rotieren Allgemeine Java-Themen 12
S Telefonbuch mit Bild Allgemeine Java-Themen 4
A 2D-Grafik Text in ein Bild schreiben Allgemeine Java-Themen 11
Tacofan GIF-Bild wird "zerstört" Allgemeine Java-Themen 3
B Bild aus Jar kann nach Export nicht mehr gefunden werden Allgemeine Java-Themen 13
T Neuen Kanal in Bild (TIFF) einfügen à la Photoshop Allgemeine Java-Themen 2
Z Zahlen aus Bild auslesen Allgemeine Java-Themen 1
X Bild -> lokale Variable -> DB -> lokale Variable Allgemeine Java-Themen 3
E 3D Objekte in 2D Bild finden Allgemeine Java-Themen 5
R HtmlUnit: Canvas als Bild speichern Allgemeine Java-Themen 0
E am häufigsten vorkommenden Farben aus einem Bild Allgemeine Java-Themen 5
S Bild in Raster Allgemeine Java-Themen 1
S Bild in Frame Allgemeine Java-Themen 0
F Punkte in einem Bild finden Allgemeine Java-Themen 10
A Bild aufteilen für getData Allgemeine Java-Themen 3
P Wie füge ich ein Bild in die GUI ein? Allgemeine Java-Themen 7
F ImageJ: Linien und Schnittpunkte in Bild Allgemeine Java-Themen 1
A mit getClassLoader Bild laden Allgemeine Java-Themen 8
E Bild abspeichern Allgemeine Java-Themen 5
D Face.com - Gesicht im Bild finden Allgemeine Java-Themen 3
N Input/Output Bild von WebSite laden? Allgemeine Java-Themen 3
A Input/Output Bild in Java einlesen und analysieren! Allgemeine Java-Themen 8
S programm um bild auszulesen Allgemeine Java-Themen 2
R Bild offenbar zu groß um geladen zu werden? Allgemeine Java-Themen 12
K Quadrat in einem Bild erkennen Allgemeine Java-Themen 33
B Bild verschieben Allgemeine Java-Themen 6
T Bild in jar Paket einbinden Allgemeine Java-Themen 9
D Bild Typ bestimmen Allgemeine Java-Themen 9
0 2D-Grafik Bild einfärben Allgemeine Java-Themen 8
A Bild zusammenbauen! Allgemeine Java-Themen 5
A Bild von Webcam aufzeichnen Allgemeine Java-Themen 14
V 2D-Grafik Bild transparent machen. Allgemeine Java-Themen 4
H Bild einscannen und speichern Allgemeine Java-Themen 29
E Bild mit Listener einfügen Allgemeine Java-Themen 3
B Bild in String einbauen? Allgemeine Java-Themen 3
C Bild auf HDD speichern Allgemeine Java-Themen 4
X Bild aus dem Netz von URL runterladen und in GUI einbinden. Allgemeine Java-Themen 3
F Bild (Point) mit scrollen lassen Allgemeine Java-Themen 5
R Texterkennung - Text aus einem/r Bild/Grafik auslesen Allgemeine Java-Themen 2
B Bild- und Texterkennung Allgemeine Java-Themen 4
S Tracing eines Bildes (a.ka. Bild vektorisieren)..? Allgemeine Java-Themen 2
destroflyer *.dds-Bild anzeigen Allgemeine Java-Themen 12
F Bild aus externer Quelle laden und Skalieren? Allgemeine Java-Themen 11
X Bild im Memory zwischen speichern Allgemeine Java-Themen 11
R JAI - RGB Bild in 3 Einzelbilder zerlegen Allgemeine Java-Themen 4
P Ascii Bild aus einem input file nur kommt nix im outputfile an?????? Allgemeine Java-Themen 5
D Java Thread, Bild wird nur am Ende gezeichnet Allgemeine Java-Themen 5
K Zeichnen auf ein Bild und Scrollen Allgemeine Java-Themen 7
data89 Barcodes in Bild erkennen Allgemeine Java-Themen 17
S Bild anhand von Koordinaten einteilen Allgemeine Java-Themen 7
K Transparente Bilder in Bild positionieren und speichern. Allgemeine Java-Themen 5
W Bild Spiegeln, aber Originalbild ausblenden Allgemeine Java-Themen 2
B Bild wird nicht angezeigt. Allgemeine Java-Themen 10
Developer_X Avatar/Bild ins Profil einbinden Allgemeine Java-Themen 10
C Bild in .txt speichern und wieder als Bild speichern Allgemeine Java-Themen 2
D Bild in text tabelle umwandeln Allgemeine Java-Themen 2
G bild in package Allgemeine Java-Themen 6
MQue bild zoomen Allgemeine Java-Themen 2
R Farbe im Bild ersetzen Allgemeine Java-Themen 11
R PDF einlesen und als Bild abspeichern Allgemeine Java-Themen 8
P Bild aus dem Internet speichern Allgemeine Java-Themen 4
K Schreiben von Bildern: Bild bleibt leer Allgemeine Java-Themen 7
ARadauer Bild verkleinern. Allgemeine Java-Themen 9
F Bild (File) komplett serialisieren Allgemeine Java-Themen 9
H Wie erstelle ich ein Bild ( GeoTIFF ) ? Allgemeine Java-Themen 2
Ark Bild immer als ARGB laden Allgemeine Java-Themen 2
N Hochgeladenes Bild verkleinern und speichern Allgemeine Java-Themen 2
N Graphics2D als Bild abspeichern Allgemeine Java-Themen 6
M bild verkleinern Allgemeine Java-Themen 9
MQue svg- Bild Allgemeine Java-Themen 34
S JPEG Bild übertragen mit RMI ? Allgemeine Java-Themen 4
V Wie kann ich ein Bild in einem Zip Archiv abspeichern? Allgemeine Java-Themen 3
ToNyXXL Als Mauszeiger eigenes Bild verwenden! Allgemeine Java-Themen 3
M bild erkennung Allgemeine Java-Themen 2
S Bild durchs Label laufen Allgemeine Java-Themen 14

Ähnliche Java Themen

Neue Themen


Oben