Hallo --
Nach dem Strom hab' ich schon länger damit geliebtäugelt, den Wasserverbrauch zu erfassen.
Meine Wasseruhr ist so ein Ding: http://www.nk-se.de/uploads/pics/Gnswzal2.jpg
Impulse sind da nicht, eine zweite Uhr hinter die vom Versorger wollte ich nicht unbedingt einbauen, und die Berichte, die man im Netz über Ableseköpfe, gekauft oder selbst gebaut, findet, sind auch meist nicht ermutigend.
Aber da lag noch diese Webcam, vor Jahren mal für x,99 aus der Grabbelkiste gefischt, die mit 320x240 Pixel Auflösung nicht wirklich für was Sinnvolles taugte.
Da ich überhaupt keine Motivation zum Anstreichen hatte, wurde das Ding flugs 'professionell' an der Wasseruhr befestigt, und ich war erstaunt, dass da doch ein Bild rauskommt.
Der ideale Bildausschnitt - das habe ich mir erst nachher überlegt - ist, dass man einen der runden Zähler (bei mir der Literzähler) etwa halb auf dem Bild sehen möchte. Die Erkennung kann man dann nämlich darauf basieren, dass relativ viel Rot vom Zeiger auf dem Bild ist.
Die Auswertung erfolgt mit Python - man möge meinen Code freundlichst kommentieren, gestern früh wusste ich noch nicht, wie Python aussieht. Ich habe in erster Linie Code-Fragmente aus dem www zusammengeklebt.
Die Logik ist folgende:
Ein Frame wird aus der Kamera gelesen.
Es wird verwischt, dann verkleinert (von 320x240 auf 40x30px), damit es schneller rechnet.
Dann wird nach rot gesucht, und ein Threshold gebildet, der rot zu weiss und alles andere zu schwarz schiebt.
Das Resultat ist ein schwarzes Bild mit einem mehr oder weniger grossen weissen Blob.
Die schwarzen Pixel werden gezählt (bei einem 40x30 Bild maximal 1200)
Wenn es recht wenige schwarze Pixel sind, heisst das, dass die Zählernadel auf dem Bild ist, und es wird eine 1 auf die Zähler-GA geschickt (braucht eine Hilfsvariable, damit es nicht bei jedem folgenden Frame triggert).
Wenn es wieder recht viele schwarze Pixel sind, wird die Hilfsvariable zurückgesetzt.
... und dann wieder von vorne.
Zum Konfigurieren habe ich mir Originalbild und transformiertes Bild sowie die Zahl der schwarzen Pixel anzeigen lassen. So konnte ich relativ schnell die Thresholds finden, ab denen der Zähler erscheint bzw verschwindet.
Das werkelt jetzt seit gestern mittag und hat auf gut 200 Liter Verbrauch gerade mal 2 Liter 'verpasst' - und da gehe ich bei einem davon aus, dass es an dem Default-Wert-setzen beim Start-Up lag. Der Maximaldurchfluss in der Zeit dürfte etwa 12 Liter/Minute betragen haben, das wäre also eine Umdrehung etwa alle 5 Sekunden. Unter der Annahme, dass der Trigger in einem Winkel von 45 Grad erkennt, bräuchte man etwa acht Bilder pro Umdrehung, um keine Umdrehung zu verpassen. Das sollte auch bei 30 Liter/Minute also noch passen. Der Code läuft hier auf einem komfortabel ausgestatteten Linux-Rechner so nebenher und fällt nicht auf, was die Rechenlast angeht.
SWMBO war nicht begeistert. Anstreichen muss ich trotzdem, heute oder morgen...
Nach dem Strom hab' ich schon länger damit geliebtäugelt, den Wasserverbrauch zu erfassen.
Meine Wasseruhr ist so ein Ding: http://www.nk-se.de/uploads/pics/Gnswzal2.jpg
Impulse sind da nicht, eine zweite Uhr hinter die vom Versorger wollte ich nicht unbedingt einbauen, und die Berichte, die man im Netz über Ableseköpfe, gekauft oder selbst gebaut, findet, sind auch meist nicht ermutigend.
Aber da lag noch diese Webcam, vor Jahren mal für x,99 aus der Grabbelkiste gefischt, die mit 320x240 Pixel Auflösung nicht wirklich für was Sinnvolles taugte.
Da ich überhaupt keine Motivation zum Anstreichen hatte, wurde das Ding flugs 'professionell' an der Wasseruhr befestigt, und ich war erstaunt, dass da doch ein Bild rauskommt.
Der ideale Bildausschnitt - das habe ich mir erst nachher überlegt - ist, dass man einen der runden Zähler (bei mir der Literzähler) etwa halb auf dem Bild sehen möchte. Die Erkennung kann man dann nämlich darauf basieren, dass relativ viel Rot vom Zeiger auf dem Bild ist.
Die Auswertung erfolgt mit Python - man möge meinen Code freundlichst kommentieren, gestern früh wusste ich noch nicht, wie Python aussieht. Ich habe in erster Linie Code-Fragmente aus dem www zusammengeklebt.
Die Logik ist folgende:
Ein Frame wird aus der Kamera gelesen.
Es wird verwischt, dann verkleinert (von 320x240 auf 40x30px), damit es schneller rechnet.
Dann wird nach rot gesucht, und ein Threshold gebildet, der rot zu weiss und alles andere zu schwarz schiebt.
Das Resultat ist ein schwarzes Bild mit einem mehr oder weniger grossen weissen Blob.
Die schwarzen Pixel werden gezählt (bei einem 40x30 Bild maximal 1200)
Wenn es recht wenige schwarze Pixel sind, heisst das, dass die Zählernadel auf dem Bild ist, und es wird eine 1 auf die Zähler-GA geschickt (braucht eine Hilfsvariable, damit es nicht bei jedem folgenden Frame triggert).
Wenn es wieder recht viele schwarze Pixel sind, wird die Hilfsvariable zurückgesetzt.
... und dann wieder von vorne.
Zum Konfigurieren habe ich mir Originalbild und transformiertes Bild sowie die Zahl der schwarzen Pixel anzeigen lassen. So konnte ich relativ schnell die Thresholds finden, ab denen der Zähler erscheint bzw verschwindet.
Das werkelt jetzt seit gestern mittag und hat auf gut 200 Liter Verbrauch gerade mal 2 Liter 'verpasst' - und da gehe ich bei einem davon aus, dass es an dem Default-Wert-setzen beim Start-Up lag. Der Maximaldurchfluss in der Zeit dürfte etwa 12 Liter/Minute betragen haben, das wäre also eine Umdrehung etwa alle 5 Sekunden. Unter der Annahme, dass der Trigger in einem Winkel von 45 Grad erkennt, bräuchte man etwa acht Bilder pro Umdrehung, um keine Umdrehung zu verpassen. Das sollte auch bei 30 Liter/Minute also noch passen. Der Code läuft hier auf einem komfortabel ausgestatteten Linux-Rechner so nebenher und fällt nicht auf, was die Rechenlast angeht.
SWMBO war nicht begeistert. Anstreichen muss ich trotzdem, heute oder morgen...
Code:
#!/usr/bin/env python import cv2 import numpy as np import os import time debug = 0 # if debug show windows with stream and console info if debug: cv2.namedWindow("original") # open window for original stream cv2.namedWindow("transform") # open window for transformed stream vc = cv2.VideoCapture(-1) # capture from first /dev/video device if vc.isOpened(): # try to get the first frame rval, frame = vc.read() # read frame print frame.shape # frame shape gives width, heigh, color else: rval = False lasttrigger = 0 # init the trigger while rval: img=cv2.GaussianBlur(frame, (9,9), 9) # blur the image reduce=cv2.resize(img, (40,30)) # reduce the size for faster processing hsv = cv2.cvtColor(reduce, cv2.COLOR_BGR2HSV) # change color scheme to HSV red_lower=np.array([150,150,0],np.uint8) # between this and red_upper=np.array([190,255,255],np.uint8) # this is red thresh = cv2.inRange(hsv, red_lower, red_upper) # check for redness hist = cv2.calcHist([thresh],[0],None,[1],[0,1]) # transform red to white, anything else to black if debug: cv2.imshow("original", frame) # show the original image cv2.imshow("transform", thresh) # show the transformed image. should be white # pointer on black background print hist[0] # this shows blackness of the image. if the image # is 40x30, it can have maximum 1200 black pixels # if the pointer is not there, should be close to # that value if hist[0] > 1150 and lasttrigger == 1: # if we triggered and it's very black, trigger to 0 print 0 lasttrigger=0 elif hist[0] < 1130 and lasttrigger == 0: # if it's less black, trigger to 1 lasttrigger=1 os.system('/usr/bin/groupwrite "ip:192.168.4.6" "8/0/0" 1') # send a knx write rval, frame = vc.read() # next frame if debug: key = cv2.waitKey(10) # exit on escape key (in debug mode) if key == 27: # exit on ESC break if debug: cv2.destroyWindow("original") # make the windows go away cv2.destroyWindow("transform")
Kommentar