Raspberry Video Camera – Teil 18: SW Farbkalibrierung

Die Raspberry Video Camera soll genau dann ein Video aufzeichnen, wenn ein Eichhörnchen ins Bild kommt. Und das soll ein Python-Programm anhand der typischen Farben der Eichhörnchen erkennen. Das Münchner Oachkatzl ist entweder rotbraun, wie der Kamerad hier im Titelbild, oder dunkelbraun. Beide haben weißes Brust- und Bauchfell. Darauf muss das Programm, das den Videodatenstrom analysiert, natürlich eingehen und ständig das Videobild auf die Eichhörnchenfarben hin untersuchen. Wie das softwaretechnisch funktioniert, haben wir im entsprechenden Python-Programm bereits gesehen. Aber woher bekommen wir die Zahlen für die Farbwerte? Genau diese Frage wird in diesem Artikel beantwortet.

Zuerst aber wieder ein Oachkatzl-Video. Mehr davon gibts in meinem YouTube-Kanal.

Farben aus Bildern extrahieren

Im vorangegangenen Artikel hatten wir ja schon ein wenig mit Bildern in OpenCV gespielt. Wir hatten uns die zahlenmäßige Kodierung von Bildern angesehen und welche Informationen ein Histogramm über die Farbverteilung in einem Bild liefern kann. Darauf werden wir jetzt aufbauen und ein Python-Programm entwickeln, das anhand von konkreten Eichhörnchenbildern Histogramme für Farbwert, Sättigung und Helligkeitswert zeichnet. Den Histogrammen können wir dann entnehmen, welche Werte typisch für Eichhörnchen sind. Oder für andere Objekte, je nach Anwendungsfall. Obwohl wir für die heutige Analysearbeit die Raspberry Kamera nicht brauchen und alles auch auf einem anderen Linuxrechner machen könnten, verwende ich für die Auswertung trotzdem die Raspberry Pi Kamera-Maschine. Denn dort ist bereits OpenCV installiert. Bevor es ans Python-Programm geht, müssen wir aber noch zwei Vorarbeiten erledigen.

Vorarbeiten

Matplotlib installieren

Die Histogramme wollen wir ja nicht mit Geodreieck und Buntstift selber zeichnen, das soll ein Python-Programm am Raspberry Pi übernehmen. Damit Python das kann, brauchen wir noch etwas Software in Gestalt von Matplotlib. Das ist ein Plotting-Framework, mit dem sich Grafiken wie eben Histogramme plotten lassen. Die Installation läuft wie gewohnt auf der Linuxebene mit apt-get install:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install python3-matplotlib

Eichhörnchenbilder vorbereiten

Und selbstverständlich brauchen wir Bilder und zwar mindestens jeweils eins von den folgenden:

  • Rotbraunes Eichhörnchen ohne Hintergrund (freigestellt)
  • Dunkelbraunes Eichhörnchen ohne Hintergrund (freigestellt)
  • Hintergrund alleine ohne Eichhörnchen

Alle Bilder sollten am besten die selbe Auflösung haben, wie die Bilder, die record2.py aus dem Videodatenstrom exportiert. Das wären 640×360 Pixel. Die Bilder können – sofern noch keine zur Verfügung stehen – leicht aus einem bereits aufgezeichneten Oachkatzlvideo entnommen werden. Das machen wir aber nicht am Raspberry Pi, sondern an einem Desktop-PC oder Laptop, denn für die Video- und Bildbearbeitung brauchen wir Monitor und Maus. Ich selbst benutze Kdenlive für den Videoschnitt und The Gimp zur Bildbearbeitung unter Ubuntu Linux. Es kann aber jedes andere Video- und Bildbearbeitungsprogramm, auch unter Windows, verwendet werden.

Einzelbilder aus Video exportieren

In Kdenlive öffnen wir eine Videodatei als Clip. Dann navigieren wir mit Play, Pause und den Einzelbildtasten zu einem geeigneten Frame, klicken mit der rechten Maustaste ins Bild und dann auf Extract Frame. Dann kann das Bild gespeichert werden. Das machen wir für zumindest ein rotbraunes Eichhörnchen, ein dunkelbraunes und ein Hintergrundbild. Ich empfehle, die Bilder im PNG-Format zu speichern.

Hintergrund ausschneiden

Das Hintergrundbild muss lediglich auf 640x360px verkleinert werden, die Eichhörnchen müssen zusätzlich freigestellt werden, das bedeutet, dass wir den Hintergrund entfernen müssen. Wir wollen schließlich nur die Farben der Eichhörnchen ermitteln, nicht die der Landschaft dahinter. Freistellen, das kann wieder jedes Grafikprogramm. Wir laden das Bild und fahren mit einem Umrisswerkzeug die Konturen des Eichhörnchens nach. Dabei kommt es nicht darauf an, akkurat den Umrissen der Hörnchen zu folgen, sondern darauf, nur Eichhörnchenfarben einzufangen. Alles was Hintergrundfarbe ist, soll weg bleiben. Sobald die Kontur geschlossen ist, invertieren wir die Auswahl und drücken Entf. um alles zu löschen, was außerhalb des Eichhörnchens liegt. Wir haben nun ein grob ausgeschnittenes Eichhörnchen vor transparentem Hintergrund. (Der Hintergrund darf auch gerne schwarz sein – nur falls er weiß ist oder eine andere Farbe hat, müssen wir später im Programm eine Anpassung vornehmen. Das Bild skalieren wir jetzt noch auf 640x360px und exportieren es wieder als PNG-Bild. Alle drei Bilder kommen dann auf den Raspberry Pi und zwar ins Verzeichnis samples/ des Users Pi (/home/pi/samples/).

Python zeichnet Histogramme (histogram.py)

Wie alle Python-Programme in diesem Projekt kommt histogram.py ins Homeverzeichnis des Users Pi. Und so sieht es aus:

import cv2
import matplotlib
# do not try to find a display
matplotlib.use('Agg') 
from matplotlib import pyplot as plt

dir = 'samples/'

# Load images
rtImg = cv2.imread(dir+'red.png',1)
bnImg = cv2.imread(dir+'brown.png',1)
gnImg = cv2.imread(dir+'bg.jpg',1)

# Convert BGR to HSV
rtHsv = cv2.cvtColor(rtImg, cv2.COLOR_BGR2HSV)
bnHsv = cv2.cvtColor(bnImg, cv2.COLOR_BGR2HSV)
gnHsv = cv2.cvtColor(gnImg, cv2.COLOR_BGR2HSV)


# Calc hue histograms
rtHist = cv2.calcHist([rtHsv],[0],None,[180],[0,180])
bnHist = cv2.calcHist([bnHsv],[0],None,[180],[0,180])
gnHist = cv2.calcHist([gnHsv],[0],None,[180],[0,180])
rtHist[0]=0
bnHist[0]=0

# Normalize histograms
cv2.normalize(rtHist,rtHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(bnHist,bnHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(gnHist,gnHist,0,100,cv2.NORM_MINMAX)

# Plot histograms
plt.title('Histogram for HSV Hue')
plt.xlabel('Bins')
plt.ylabel('# of Pixels')
plt.plot(rtHist, 'red')
plt.plot(bnHist, 'brown')
plt.plot(gnHist, 'green')
plt.xlim([0,179])
plt.ylim([0,100])
plt.savefig('hue.png')
plt.close()


# Calc saturation histograms
rtHist = cv2.calcHist([rtHsv],[1],None,[256],[0,256])
bnHist = cv2.calcHist([bnHsv],[1],None,[256],[0,256])
gnHist = cv2.calcHist([gnHsv],[1],None,[256],[0,256])
rtHist[0]=0
bnHist[0]=0

# Normalize histograms
cv2.normalize(rtHist,rtHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(bnHist,bnHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(gnHist,gnHist,0,100,cv2.NORM_MINMAX)

# Plot histograms
plt.title('Histogram for HSV Saturation')
plt.xlabel('Bins')
plt.ylabel('# of Pixels')
plt.plot(rtHist, 'red')
plt.plot(bnHist, 'brown')
plt.plot(gnHist, 'green')
plt.xlim([0,255])
plt.ylim([0,100])
plt.savefig('satu.png')
plt.close()


# Calc value histograms
rtHist = cv2.calcHist([rtHsv],[2],None,[256],[0,256])
bnHist = cv2.calcHist([bnHsv],[2],None,[256],[0,256])
gnHist = cv2.calcHist([gnHsv],[2],None,[256],[0,256])
rtHist[0]=0
bnHist[0]=0

# Normalize histograms
cv2.normalize(rtHist,rtHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(bnHist,bnHist,0,100,cv2.NORM_MINMAX)
cv2.normalize(gnHist,gnHist,0,100,cv2.NORM_MINMAX)

# Plot histograms
plt.title('Histogram for HSV Value')
plt.xlabel('Bins')
plt.ylabel('# of Pixels')
plt.plot(rtHist, 'red')
plt.plot(bnHist, 'brown')
plt.plot(gnHist, 'green')
plt.xlim([0,255])
plt.ylim([0,100])
plt.savefig('valu.png')
plt.close()

Bei den Imports am Programmanfang wird natürlich cv2 geladen und dann pyplot aus matplotlib. Hier gibt es aber eine Besonderheit:

import matplotlib
matplotlib.use('Agg') 
from matplotlib import pyplot as plt

Pyplot will standardmäßig auf einem Bildschirm ausgeben und sucht bereits beim Import nach einem solchen. Da an unserem Raspberry Py jedoch kein Display angeschlossen ist, würde der Import in einen Fehler laufen. Das umgehen wir, in dem wir zuerst matplotlib laden, einen entsprechenden Parameter setzen und dann erst pyplot als plt importieren. Als nächstes setzen wir das Unterverzeichnis, in dem sich die Bilder befinden und laden dann alle drei Bilder in je eine Variable entsprechend ihrer Farbe. Wobei Grün für den Hintergrund steht und das Hintergrundbild im Beispiel auch JPG-Format hat, was hier kein Problem ist, da der Hintergrund keine transparenten Bereiche hat. Nun wandeln wir die Farbräume aller drei Bilder nach HSV – das kennen wir im Prinzip schon vom letzten Artikel. Jetzt sind wir soweit, dass wir Histogramme berechnen können und diese dann plotten. Das ganze passiert dreimal und zwar für Hue, Saturation und Value – wir erhalten also drei Plotbilder mit jeweils drei Kurven. Die Abläufe sind dabei fast identisch, ich beschreibe das hier mal für das Hue-Histogramm. Das Histogramm für das rote Eichhörnchen wird so berechnet:

rtHist = cv2.calcHist([rtHsv],[0],None,[180],[0,180])

calcHist bekommt folgende Parameter übergeben:

  • [rtHsv] – ein Array, das das entsprechende HSV-Bild enthält,
  • [0] – das ist der erste Farbkanal, also Hue (für Saturation wird dann später eine 1 stehen, für Value 2)
  • None – hier könne man eine Maske übergeben, brauchen wir aber nicht
  • [180] – Anzahl der betrachteten Histogrammschritte (auf der x-Achse), auch Bins genannt. Wir nehmen hier die volle Auflösung, also 180 Bins für Hue und 256 später für Saturation und Value.
  • [0,180] – ausgewerteter Bereich, hier 0 bis 179 (der höhere Wert ist immer exclusiv zu sehen). Bei Saturation und Value ist der Wertebereich [0, 256]

Eine Anmerkung zu den Bins: Wir leisten uns hier den Luxus, für jeden möglichen Hue-Wert, die Anzahl der vorkommenden Pixel zu berechnen. Das ist für unseren Zweck auch sinnvoll, wir wollen ja eine möglichst genaue Aussage, welche Farben bei Eichhörnchen vorkommen. Man könnte die Anzahl der Bins aber auch kleiner wählen, um die Datenmenge klein zu halten und die Laufzeit zu verkürzen. Würden wir als Bins den Wert 45 anstelle von 180 nehmen, dann hätten wir auf der x-Achse nur 45 Teilungen und jeder X-Wert würde für 4 Hue-Werte (180/45) stehen, also 0,1,2,3 – 4,5,6,7 bis 176,177,178,179. Benachbarte Farben würden also zusammengefasst werden. Nachdem auch die Histogramme für das braune Eichhörnchen und für den Hintergrund berechnet sind, müssen wir ein wenig tricksen. Wir haben bei den Eichhörnchen einen transparenten Hintergrund, der kodiert wie die Farbe Schwarz mit [0 0 0] und da der Hintergrund eine große Fläche einnimmt, ist die Pixelanzahl für Hue-Wert 0 sehr hoch, obwohl uns der Hintergrund überhaupt nicht interessiert. Deshalb eliminieren wir die schwarze Farbe an dieser Stelle mit:

rtHist[0]=0
bnHist[0]=0

Wer bei seinen Eichhörnchenbildern keinen transparenten oder schwarzen Hintergrund gewählt hat, der muss diese Wertenullung entsprechend im Programm anpassen. Die Farbe Weiß kodiert zum Beispiel als [0 0 255] – also bei Value aufpassen. Da die Eichhörnchen auf den beiden Bildern möglicherweise unterschiedlich groß sind und das Hintergrundbild in jedem Fall mehr Farbe mitbringt, bietet es sich an, hier maßstäblich eine Angleichung vorzunehmen. Das ganze nennt sich Normalisierung und bewirkt, dass alle drei Histogramme auf der y-Skala in den gleichen Wertebereich eingepasst werden. Ich nehme dazu den Wertebereich von 0 bis 100, dann ist die am häufigsten vorkommende Farbe in jedem Bild gleich 100. Die drei Kurven werden also größenmäßig angeglichen. 0 bis 100 ist hier willkürlich gewählt, gebräuchlich ist auch 0 bis 255 oder 0 bis 1, jeder wie er will. Mir gefällt die Vorstellung, dass der Maximalwert gleich 100% ist. Beim normalize-Befehl muss ich das Histogramm zweimal angeben, wenn Ziel gleich Quelle sein soll, dann Minimal- und Maximalwert und die Art der Normalisierung, hier NORM_MINMAX.

cv2.normalize(rtHist,rtHist,0,100,cv2.NORM_MINMAX)

Und dann wird geplottet. Die meisten Befehle setzen Titel, Achsenbeschriftung und Achsenskalierung, der eigentliche Poltbefehl lautet:

plt.plot(rtHist, 'red')

Wobei 'red' die Stiftfarbe ist. Wir plotten alle drei Histogramme in eine Grafik, speichern diese dann und löschen sie mit close aus dem Speicher. Dann wiederholen wir den ganzen Vorgang für Saturation und Value, so dass wir am Ende drei Grafiken im Homeverzeichnis liegen haben. Und so (oder so ähnlich) sehen die aus):

Histogramme

Hue

Als erstes das Histogramm für den Farbton. Auf der X-Achse sind von 0 bis 179 alle Farbwerte aufgetragen. 0 entspricht der Farbe Rot, dann kommen Gelb und Grün, in der Mitte bei 90 kann man sich ein helles Blau vorstellen und dann geht es über Violett zurück nach Rot. Ein Ausschlag einer Kurve in Y-Richtung ist dann ein Maß dafür, wie häufig eine Farbe in einem Bild vertreten ist. Hier sieht man auch die Normalisierung – Jede Kurve hat ihr Maximum bei einem Y-Wert von 100. Die grüne Kurve steht für den Hintergrund, die rote für das rotbraune Eichhörnchen und die braune Kurve für das dunkelbraune. Die gute Nachricht in diesem Histogramm ist, dass sich die Farbwerte der beiden Eichhörnchen gut vom Hintergrund unterscheiden und wir keine Schwierigkeiten haben, die Bereiche zahlenmäßig von einander abzugrenzen.

Saturation

Nicht ganz so gut sieht es bei der Sättigung aus. Das rote Eichhörnchen liegt zum Glück mit seinem Maximum weit weg vom Hintergrund, aber die Kurve des dunkelbraunen Eichhörnchen weist starke Parallelen zur Sättigungskurve des Hintergrunds auf. Kein Wunder, die Äste der Kiefer sind ebenso dunkelbraun.

Value

Beim Helligkeitswert schauen wir zuerst auf die grüne Kurve für den Hintergrund und finden sehr weit rechts einen schmalen aber maximal hohen Peak. Das sind die fast weißen Bereiche der Stange, des Schälchens und des sichtbaren Himmels. Der Rest des Hintergrunds ist eher dunkel, allerdings wieder mit starken Überschneidungen mit dem dunkelbraunen Eichhörnchen. Das Rote ließe sich zahlenmäßig aber gut vom Hintergrund ablösen. Als kleines Zwischenfazit halte ich fest: Das rotbraune Eichhörnchen unterscheidet sich in allen drei Farbkanälen deutlich vom Hintergrund, das dunkelbraune zumindest im Farbwert. Was die Sättigung und den Helligkeitswert angeht, lässt sich das Dunkelbraune nur schwer vom Hintergrund unterscheiden. Bevor wir nun tatsächlich Werte ablesen, möchte ich noch einen Versuch machen. Im Moment betrachten wir genau ein (1) rotbraunes Eichhörnchen und ein dunkelbraunes. Aber sind die alle gleich? Und wie ändern sich vielleicht die Farben über den Tag bei verschiedenen Lichtverhältnissen?

Streuung der Farbwerte

Das vorgestellte Programm lässt sich leicht dahingehend erweitern, dass nicht 2 Eichhörnchenbilder analysiert werden, sondern 10. 5 vom rotbraunen und 5 vom dunkelbraunen Eichhörnchen. Den Programmcode spare ich mir hier und komme gleich zu den Histogrammen.

Hue

Saturation

Value

Durch die vielen Linien wird es nun etwas unübersichtlich, aber ich fasse die wesentlichen Erkenntnisse einmal zusammen: Eichhörnchen ist nicht Eichhörnchen, bei unterschiedlichen Beleuchtungssituationen ergeben sich recht unterschiedliche Kurven. Speziell beim Farbton (Hue) fällt auf, dass nun sowohl bei den roten, als auch bei den brauen Eichhörnchen hohe Spitzen links und rechts vom Nullwert (Rot-Wert) auftreten. Signifikante Unterschiede zwischen Eichhörnchen und Hintergrund finden wir hauptsächlich im Hue-Kanal und weniger bei Saturation und Value.

Maximaler oder minimaler Ansatz?

Versucht man jetzt konkret Zahlengrenzwerte festzulegen, zwischen denen sich typischerweise Hue, Saturation und Value von Eichhörnchen liegen, so kann man zwei verschiedene Ansätze verfolgen:

a) Eine maximale Herangehensweise

Hier versuchen wir jeweils getrennt für rote und braune Eichhörnchen die gesamte Bandbreite der HSV-Werte zu erfassen. Bei der Sättigung für das braune Eichhörnchen zum Beispiel ein Bereich zwischen 20 und 140. Damit würden wir erreichen, dass von jedem Eichhörnchen möglichst die volle Bandbreite der Fellvarianz erkannt wird und die Anzahl der erkannten Pixel hoch sein wird. Allerdings werden so – auch wenn kein Eichhörnchen im Bild ist – viele Bereiche des Hintergrunds falsch positiv erkannt.

b) Eine minimale Herangehensweise

Hier nehmen wir nur die Bereiche, in denen Spitzenwerte auftreten, also vielleicht 60 oder 80 auf der Y-Skala. Im Beispiel der Sättigung für das braune Eichhörnchen nur ein Bereich von 30 bis 65. Ausreißer werden ignoriert. Und wir versuchen – so weit das möglich ist – auch die grüne Kurve für den Hintergrund zu berücksichtigen, um die Bereiche, die im Hintergrund stark vertreten sind, auszusparen. Bei diesem Ansatz werden wir – so lange kein Eichhörnchen im Bild ist – nur sehr wenige Pixel erkennen oder fast gar keine. Im Gegenzug werden aber von den Eichhörnchen auch nur Teile der Körperfläche erkannt, die Pixelanzahl für die Hörnchen ist also geringer. Ein Richtig oder Falsch gibt es hier leider nicht, ich empfehle für die eigene Bildsituation einige Versuche zu machen. Mir selbst gefällt der minimale Ansatz, denn er besitzt die Schönheit, dass ohne Eichhörnchen im Bild auch so gut wie nichts erkannt wird. Und auch wenn dann vom Eichhörnchen selbst nur ein Teil des Körpers zu einer Erkennung führt, so reicht das oft immer noch für ein sauberes Triggersignal. Die beiden Ansätze lassen sich auch ein wenig mischen. Zum einen, in dem für den Farbwert ein schmalbandiger Ansatz verfolgt wird und für Sättigung und Helligkeit ein toleranter. Und zum zweiten in dem dort ein breiterer Bereich gewählt wird, wo sich die Werte für Eichhörnchen und Hintergrund nicht überschneiden. Und andererseits Eichhörnchenwerte dort nicht berücksichtigt werden, wo sie auch stark im Hintergrund vertreten sind. So kann man für das rotbraune Eichhörnchen einen mehr maximalen Ansatz verfolgen und für das dunkelbraune einen minimalen.

Meine Werte

Die will ich natürlich nicht verheimlichen, sie stehen ja auch bereits im Programm (analyze.py)

Hörnchen Hue Saturation Value
Rot-1 0 – 11 70 – 170 110 – 220
Rot-2 165 – 179 70 – 170 110 – 220
Braun-1 12 – 17 40 – 65 220 – 255
Braun-2 125 – 170 30 – 65 45 – 110

Wir brauchen sowohl für das rote, als auch für das braune Eichhörnchen zwei Bereiche. Das liegt daran, dass beide Farbwerte beinhalten, die links und rechts von 0 auf dem Farbkreis liegen. Und ein Bereich über die Nullgrenze hinweg kann nicht gebildet werden. Deshalb haben wir für die beiden Eichhörnchen insgesamt vier Bereiche, deren erkannte Pixel dann vereinigt werden. Beim roten Eichhörnchen sind Saturation und Value in beiden Bereichen gleich, weil ich hier einen eher großzügigen Ansatz verfolge. Beim dunklen Hörnchen grenzen auch Sättigungs- und Helligkeitsbereiche noch weiter ein um maximale Distanz zu den Hintergrundfarben zu erreichen. Die Übernahme der Werte ins Python-Programm analyze.py sieht dann so aus (hier nur der entsprechende Programmausschnitt):

# define range of red color in HSV
    lower_value = np.array([0,70,110])
    upper_value = np.array([11,170,220])
    maskRed = cv2.inRange(hsv, lower_value, upper_value)
    lower_value = np.array([165,70,110])
    upper_value = np.array([179,170,220])
    maskRed2 = cv2.inRange(hsv, lower_value, upper_value)
# define range of brown color in HSV
    lower_value = np.array([12,40,220])
    upper_value = np.array([17,65,255])
    maskBrown = cv2.inRange(hsv, lower_value, upper_value)
    lower_value = np.array([125,30,45])
    upper_value = np.array([170,65,110])
    maskBrown2 = cv2.inRange(hsv, lower_value, upper_value)
# Mask for red and brown
    mask = maskRed+maskRed2+maskBrown+maskBrown2
    pixDetected = cv2.countNonZero(mask)

Wie gut funktioniert das?

Sagen wir mal gut. Für die rotbraunen Eichhörnchen sogar sehr gut, für die dunkelbraunen immer noch ausreichend gut. Erkannt werden damit alle Eichhörnchen-Besuche vor der Kamera, sehr verlässlich auch Krähen und selbst der Buntspecht hat es schon aufs Video geschafft. Es passieren allerdings auch Aufnahmen ohne Tierbesuch und zwar gerne dann, wenn sich die Lichtverhältnisse sehr schnell ändern und dadurch die adaptiven gleitenden Durchschnitte ausgetrickst werden. Gegenlichtsituationen, Wolken, die vor die Sonne ziehen, bzw. sie schnell wieder freigeben – das sind die schwierigen Momente für die Farberkennung. Ich rege an, hier selber weiter zu experimentieren und meinen Programmvorschlag zu erweitern und auszubauen. Denkbar wäre es zum Beispiel, bei kritischen Hintergrundsituationen nicht das ganze Bild auszuwerten, sondern nur eine so genannte ROI (region of interest). Die ROI wäre ein eingeschränkter Bildbereich, in dem überhaupt nur Tiere auftreten können, in meinem Beispiel also ein Streifen oberhalb der Stange in der Körperhöhe von Eichhörnchen. Durch einen kleineren Bildbereich verbessert sich das Verhältnis von Eichhörnchenfläche zu Hintergrundfläche, was eine Erkennung deutlich erleichtert. Eine weitere Möglichkeit zur Verbesserung der Erkennungsqualität werde ich im nächsten Artikel vorstellen. Die Kombination von Farberkennung und Bewegungssensor.

 


Weitere Artikel in dieser Kategorie:

2 Kommentare

  1. Detlef Brauckhoff

    Hat mit einer kleinen Änderung (statt bg.jpg wieder bg.png) einwandfrei bei mir funktioniert. Tolle Idee mit den Histogrammen!

  2. Helmut (Beitrag Autor)

    Ja genau, wenn das eigene Bild ein PNG ist, dann darf man mein JPG natürlich nicht übernehmen.

Schreiben Sie einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.