Grundlagen der Videotechnik Python Video/Image Einführung Zunaechst: Gängige Linux Konsolen Befehle: Befehl : Erklaerung man Befehl : manual pages (Erklaerung) fuer „Befehl“. Beispiel: man cd cd : change directory, "/" : root directory, "." : current directory, „..“ : eine directory hoeher. Beispiel: cd .. pwd : print working directory ps : print running processes ps ­ef | more print all processes page by page ps ­ef | grep prozessname : prozesse mit diesem Namen werden ausgegeben. kill Nummer: Beendet Programm oder Prozess mit Process ID "Nummer", die vorher mit ps gesehen wurde. df : disk free du : disk usage, shows usage for directories whoami : print username finger username : print information about username date : show date and time time : measures time of a command, e.g. time ls who : shows who is logged in uptime: Shows time since last boot top : shows processes sorted by cpu suage mv : move, mv source destination rm : remove mkdir : make directory cat : "concatenate", outputs the contents of a file more : shows an input or file one page at a time, more filename, or from input e.g.: ls | more xterm : start x­terminal which befehl : shows path to befehl shutdown now : shuts down computer now vi : vidual editor: terminal based editor. Befehle: esc: commmand mode, in command mode: :w write, :q quit, x delete character, i insert in write mode (enter text) ssh : secure shell, e.g. ssh servername man : manual pages, e.g. man ssh cp : copy a file or directory, e.g. cp filename directory, original is kept, unlike with „mv“. scp : secure copy, between networked machines, e.g. scp . [email protected]:dir chmod : change mode: change access rights for files or directories. To make a file executable: chmod ug+x file. User and group get the right to execute the file. ifconfig : show network data like ip address sox : audio tools, e.g. command "play" wget : copy entire website trees Im Konsolen-Fenster installiere nun pythonopencv (falls nicht schon geschehen). Dies ist die sog. Open Computer Vision Library: sudo apt­get install python­opencv Dann starte ipython: ipython –pylab import cv2 Interessante Befehle in ipython --pylab: help(funktionsname) oder ?funktionsname: hilfefunktion fuer den Befehl Beispiel: help(sin) Nuetzliche Befehle: cv2.imread, zum Einlesen von JPEG Bildern aus einer Datei, cv2.imwrite, zum Schreiben von JPEG Bildern in eine Datei, cv2.imshow, zum Darstellen von Bildern aus arrays, imshow, (aus der Library matplotlib.pyplot, die duch –pylab schon geladen wurde) Beispiel: Nehme ein Foto auf mit unserm Python Skript „imagerecdisp.py“ mit der Komandozeile: python imagerecdisp.py Dann lesen wir in python das Photo ein mit: photo=cv2.imread('pycolorphoto.jpg'); Wir zeigen sehen dann die Groesse des Bildes mit „shape“: print("Photo dimensions:",photo.shape) ('Photo dimensions:', (480, 640, 3)) Hier ist 480 und 640 die Anzahl der Pixel im Bild, vertikal und horizontal. Die „3“ stammt von den 3 Grundfarben Rot, Grün, Blau (RGB). Beachte dass Python sie in der Reihenfolge BGR speichert. D.h. die Farbkomponenten sind der letzte Index eines Pixels, und Index 0 entspricht Blau, 1 entspricht Gruen, und Index 2 entspricht Rot. Wir haben hier Zugang zu den einzelnen Pixeln, z.B. Pixel an der Position 0,0, von der Grundfarbe Blau, ist: photo[0,0,0] 88 Die „88“ sind ein Intensitaetswert, der sich zwischen 0 und 255 bei Bildern befindet (entspr. 8 bit pro Grundfarbe). Darstellen koennen wir das Bild in der Matrix „photo“ mit dem Befehl: cv2.imshow('Photo',photo) Anzeigen nur der Blau-Komponente als Graustufen-Bild (cmap bedeutet color map): cv2.imshow('Blau­Komponente',photo[:,:,0]) Videoverarbeitung Die OpenCV Library gibt uns auch die Möglichkeit, Daten direkt von einer Webcam am Rechner, wie dem Raspberry Pi, zu streamen! Dazu gibt es den Befehl: cap = cv2.VideoCapture(0) Dieser greift auf die Default Kamera 0 zu, welches z.B. die angesteckte USB-Webcam ist. „cap“ enthaelt einen Pointer mit der Adresse dieser Kamera. Einen Frame dieses Streams koennen wir auslesen mit: [retval, frame] = cap.read() wobei „retval“ ein return value ist (der sagt ob alles in Ordnung ist), und „frame“ enthaelt den so gewonnenen Frame. Mit cv2.imshow('frame',frame) Koennen wir diesen Frame dann in einem Fenster anzeigen. Wenn wir dies in einer unendlichen Schleife tun, bekommen wir das live Vider Kamera im Fenster angezeigt. Ein Beispielprogramm dazu ist: import cv2 #Program to capture a video from the default camera (0) and display it live on the screen cap = cv2.VideoCapture(0) while(True): # Capture frame­by­frame [retval, frame] = cap.read() # Display the resulting frame cv2.imshow('frame',frame) if cv2.waitKey(1) & 0xFF == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows() Speicher dies als „videorecdisp.py“, und rufe es dann vom Konsolenfenser auf mit: python videorecdisp.py und man erhaelt das live Video. Man beendet die Anzeige mit tippen von „q“. Eine praktische Anwendung ist z.B. eine „Rohr Kamera“ mit Schwanenhals zum Inspizieren von Rohren. Ein weiteres Beispiel ist unsere Aufnahme und das Abspeichern eines Fotos von dieser Webcam: import cv2 #Program to capture an image from a camera and display it live on the screen cap = cv2.VideoCapture(0) # Capture frame ret, frame = cap.read() # Display the resulting frame cv2.imshow('frame',frame) cv2.imwrite('pycolorphoto.jpg', frame) while(True): if cv2.waitKey(1) & 0xFF == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows() Abspeichern mit dem Namen „imagerecdisp.py“, und start mit: python imagerecdisp.py gleich nach dem Start wird das Foto geschossen und angezeigt. Die Anzeige wird wieder mit tippen von „q“ beendet. Das folgende Beispiel zeigt den Inhalt des obersten linken Pixels des Videos bei Start des Programms: import cv2 #Program to capture an image from a camera and display the pixel value on the screen cap = cv2.VideoCapture(0) # Capture one frame [ret, frame] = cap.read() print("image format: ", frame.shape) print("pixel 0,0: ",frame[0,0,:]) Speichere es unter „pyimageshowpixel.py“ und starte es mit: python pyimageshowpixel.py mit Output: ('image format: ', (480, 640, 3)) ('pixel 0,0: ', array([ 35, 167, 146], dtype=uint8)) Beachte dass wir nur das Pixel addressiert hatten, daher nur 2 Indizes: frame[0,0,:]. Der Doppelpunkt „:“ bedeutet, dass alle Indizes dieser Dimension angesprochen werden. Auf diese Weise koennten wir auch einen Index Bereich ansprechen, durch Anfang:Ende, z.B.: 0:3 spricht die Indizes 0,1,2 an (beachte: nicht den Endwert, die 3). In unserm Fall ist die obige Schreibweise also identisch mit: frame[0,0,0:3] Als Ausgabe bekommen wir daher nicht nur einen Wert, sonder ein Array mit den Werten der 3 Grundfarben, in der Reihenfolge BGR. „Rot“ hat hier also den Wert 146, Gruen 167, und Blau 35. Man sieht auch dass die Zahlendarstellung dazu „uint8“ ist, das heisst: unsigned integer mit 8 bit, also eine Zahl zwische 0 und 255 (= 8 2 −1 ). Mit folgendem Programm könne wir die zu R, G, und B gehoerenden Komponenten als Video betrachten: import numpy as np import cv2 #Program to capture a video from a camera and display Original and R,G,B, compinents live on the screen cap = cv2.VideoCapture(0) cv2.namedWindow('Original') cv2.namedWindow('B Komponente') cv2.namedWindow('G Komponente') cv2.namedWindow('R Komponente') while(True): # Capture frame­by­frame ret, frame = cap.read() # Display the resulting frame cv2.imshow('Original',frame) cv2.imshow('B Komponente',frame[:,:,0]) cv2.imshow('G Komponente',frame[:,:,1]) cv2.imshow('R Komponente',frame[:,:,2]) if cv2.waitKey(1) & 0xFF == ord('q'): break # When everything done, release the capture cap.release() cv2.destroyAllWindows() Nenne es videorecdispRGB.py und starte es im Konsolenfenster mit: python videorecdispRGB.py Beachte: Die zu der jeweiligen Komponente (R,G,B) gehoerenden Farben erscheinen im zugehoerigen Video heller. Hier sieht man auch: Jedes Pixel benötigt einen Informationsgehalt von 3 Byte (Byte=8bit). Wir haben 480x640 Pixel, also 307200 Pixel pro Frames. Wenn wir 25 Frames pro Sekunde haben, kommen wir so auf 307200 x 25 x 3 bits pro sekunde (b/s), also 23040000 b/s, ca. 23 Mb/s! Das ist deutlich mehr als die meisten Internet Anschluesse bieten, geschweige denn fuer drahtlose Übertragung. Wir muessen uns fuer eine (drahtlose) Uebertragung also ueberlegen, wie wir die noetige Bitrate reduzieren. Eine simple Methode, die schon mal einen Faktor 3 bringt, ist ein schwarz-weiss Video statt Farbe zu uebertragen. Dies benoetigt nur 1 Byte pro pixel fuer die Helligkeit. Um den richtigen Helligkeitseindruck zu erzeugen, muessen wir die relative, unterschiedliche empfindlichkeit des menschlichen Auges fuer die 3 Grundfarben beruecksichtigen. Durch empirische untersuchung der subjektiven Helligkeitsempfindung wurde folgendes Verhaeltnis fuer die Grundfarben R,G,B gefunden: 0.299; 0.587; 0.114 Wir sehen: Das Auge ist am empfindlichsten fuer die Grundfarbe Gruen, gefolgt von Rot, und deutlich geringer fuer Blau. Wenn wir also die Grundfarben-Werte unseres Videos entsprechend gewichten, bekommen wir ein passendes Schwarz-Weiss Bild. Dessen Helligkeitswert bezeichnen wir mit Y: Y=0.299*R+ 0.587*G+ 0.114*B Beachte: Da die Summe der 3 Faktoren gleich 1 ist, hat Y den gleichen Wertebereich wie R,G,B. Python Beispiel zu Berechnung der so. „Luminanz“ Komponente Y, der Helligkeit, oder der Schwarz/Weiss Version des Bildes. Zum Vergleich wird noch die „Gruen“ Komponente wiedergegeben: python videorecprocy.py Beachte: Y gibt am besten den menschlichen Helligkeitseindruck wieder, die Gruen Komponente ist eine gewisse Approximation davon. Allerdings ist eine Schwarz/Weiss Ubertragung nicht sehr zufriedenstellend. Wie koennen wir also Farbe mit relativ geringer Bitrate uebertragen? Wieviele Pixel benoetigen wir ueberhaupt fuer eine qualitativ gute Darstellung? Fuer die Beantwortung dieser Fragen muessen wir uns die Eigenschaften des Auges ansehen.