Zuletzt geändert am 3. April 2019 um 22:02

OpenCV mit Python

Installation

Nach Update auf Pycharm 2019.1 kann es zu Problemen mit ALtGr+[ etc. kommen

Workaround: In PyCharm click Ctrl + Shift + A. Then write registry and click on it. Find actionSystem.fix.alt.gr and uncheck it.

Raspberry Pi

OpenCV Installation

  • Installiere eine aktuelle Version mit Allem von Raspbian auf die SD-Karte, richte alles ein, update das System via:

sudo apt update && sudo apt upgrade -y

  • Installiere alles Mögliche nach was OpenCV so braucht (alles muss in eine Zeile):
sudo apt install libatlas3-base libsz2 libharfbuzz0b libtiff5 libjasper1 libilmbase12 libopenexr22 libilmbase12 libgstreamer1.0-0 libavcodec57 libavformat57 libavutil55 libswscale4 libqtgui4 libqt4-test libqtcore4 libwebp6
  • Installiere dann OpenCV (und falls es fehlt numpy) via pip3, hier als root, in der fettesten Geschmacksrichtung:

sudo pip3 install opencv-contrib-python numpy

  • Teste ob numpy und opencv richtig installiert sind. Öffne dazu python3 auf der Konsole und probiere aus, ob die beiden folgenden Befehle kein Fehler ausgeben:
    • import numpy
    • import cv2
    • quit()

Wenn beim import cv2 Fehlermeldungen angezeigt werden, hilft es folgende libs zu installieren:

sudo apt-get install libcblas-dev
sudo apt-get install libhdf5-dev
sudo apt-get install libhdf5-serial-dev
sudo apt-get install libatlas-base-dev
sudo apt-get install libjasper-dev 
sudo apt-get install libqtgui4 
sudo apt-get install libqt4-test
  • Tipp: Als IDE unter Raspbian für Python3 ist Thonny ein Versuch wert:
    • Installation am besten via pip: sudo pip3 install thonny
    • Nach dem starten von Thonny unter "Tools->Options...->General" den UI mode auf "expert" stellen, bei der Gelegenheit kann auch gleich ein dunkles Theme eingestellt werden, dann sieht es auch gut aus.
    • Das Ding kann Variablen anschauen, Breakpoints setzen, Variabelninhalte anzeigen und Pakete installieren und zeigt Vorschläge zum sauberen Programmieren - also ein Ersatz für das PyCharm, was unter Raspberry nicht läuft.

Kamera Installation

  • Aktiviere die Kamera: sudo raspi-config, dann unter "5 Interfacing Option" die Kamera aktivieren. Tool beenden über "Finish", Raspberry neu starten sudo reboot
  • Teste die Kamera via raspivid -t 5000 : Der Videostream sollte für 5s zu sehen sein.
  • Damit auch Standard-Beispiele laufen, sollte die Raspberry-Kamera noch als V4L2-Device eingebunden werden. Dazu folgendes tun:
    • Edititere die Datei /etc/modules als root via sudo nano /etc/modules
    • Füge am Ende der Datei eine Zeile mit dem Inhalt bcm2835-v4l2 ein, Datei dann mit STRG+o speichern, den Editor mit STRG+x verlassen, das System neu starten
    • Danach sollte das Kommando ls /dev/video0 eine Device-Datei finden und keinen Fehler ausgeben. Wenn nicht, hilft es evtl. im obigen Schritt noch vor die bcm2835-v4l2-Zeile eine Zeile mit folgendem Inhalt einzufügen: v4l2_common (auch hier nach neu booten). Bei mir war das allerdings nicht nötig.
  • Jetzt kann alles zusammen getestet werden, in dem das Skript im Abschnitt OpenCV_mit_Python#Testen_der_Kamera_unter_Python-OpenCV auf der Konsole oder z.B. in Thonny gestartet wird. Es sollte ein Fenster mit dem Kamerabild in Graustufen anzeigen.

Windows (und ggf auch Mac/Linux) via PyCharm

  • Installiere Python3 von Python.org: Wichtig:
    • Per Rechtsklick als Admin installieren
    • Bei Installation auch pip installieren lassen und Pfade setzen lassen
  • Installiere PyCharm Community Edition von Jetbrains
    • Darin habe ich dann ein neues Projekt angelegt, dabei "Virtualenv" als Environment gewählt
    • Über "File->Settings..." das Settings-Fenster öffnen,
      • darin dann Links das eigene "Projekt: xxx" ausklappen, dort drunter auf "Project Interpreter" gehen
      • Hier sollte jetzt eine Python3-Version ausgewählt sein und unter den Packages mind. "pip" vorhanden sein
      • Über das kleine "+"-Symbol recht weit rechts können nun weitere Packages für das Projekt installiert werden, es öffnet sich ein Fenster "Available Packages"
        • Darin in der Suche "opencv" eingeben und das Paket "opencv-contrib-python" installieren - unten wird dann irgendwo angezeigt ob es geklappt hat
        • Darin dann auch noch nach "numpy" suchen und das Paket "numpy" installieren
        • Dann das Packet-Manager-Fenster schliessen
      • Auch das Settings-Fenster mit "OK" schliessen
    • Vermutlich muss man jetzt trotzdem noch etwas warten, weil PyCharm im Hintergrund immernoch installiert. Erst wenn PyCharm fertig ist, kann man das test_video.py starten.

Testen der Kamera unter Python-OpenCV

Das folgende Skript sollte unter allen Betriebsystemen laufen, unter Linux/Raspbian wird ein V4L2 Device benötigt, unter Windows ging es direkt. Das folgende Skript auf der jeweiligen Maschine ausprobieren - via Terminal, Thonny, PyCharm oder was auch immer:

import numpy as np
import cv2 as cv
cap = cv.VideoCapture(0)
while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # Our operations on the frame come here
    gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
    # Display the resulting frame
    cv.imshow('Hit ESC to close', gray)
    if cv.waitKey(1) & 0xFF == 27:
        break
# When everything done, release the capture
cap.release()
cv.destroyAllWindows()

Es sollte das Videobild in Graustufen angezeigt werden, im aktiven Kamerabildfenster "ESC" drücken, um das Program ordentlich zu beenden.

RAW-Zugriff auf die Raspberry Pi Kamera

Mit dem folgenden Skript kann ohne V4L2-Treiber auf die Raspberry Pi Kamera zugegriffen werden. Evtl. ermöglicht das auch feinere Einstellungsmöglichkeiten der Kamera wie z.B. Belichtungszeit etc.

# OpenCV camera test special for Raspberry Pi
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
import numpy as np

# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
camera.rotation = 0
rawCapture = PiRGBArray(camera, size=camera.resolution)

# allow the camera to warmup
time.sleep(1)

# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    # grab the raw NumPy array representing the image, then initialize the timestamp
    # and occupied/unoccupied text
    image = frame.array
    
    # show the frame
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    cv2.imshow("Hit ESC to end", gray.astype(np.uint8))
    
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)

    # if the `q` or ESC key was pressed, break from the loop
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q") or key == 27:
        break

cv2.destroyAllWindows()
camera.close()

Es sollte das Videobild in Graustufen angezeigt werden, im aktiven Kamerabildfenster "ESC" drücken, um das Program ordentlich zu beenden.

OpenCV Cheats

  • Tutorials hier: https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html
  • Buntes Bild in Graustufen umwandeln: gray = cv2.cvtColor(bild,cv2.COLOR_BGR2GRAY)
  • Graustufen Bild in Buntbild umwandeln: bunt = cv2.cvtColor(gray,cv2.COLOR_GRAY2BGR) (es bleibt Grau, kann dann aber eingefärbt werden)
  • Kasten in ein Bild malen: cv2.rectangle(bild, (x0,y0), (x1,y1), (b,g,r), rahmendicke)
  • Text ins Bild malen: cv2.putText(bild, "Hallo", (10,400), cv2.FONT_HERSHEY_PLAIN, 1, (255,0,255)) (Größerer Font: cv2.FONT_HERSHEY_SIMPLEX)
  • Bildbereich kopieren: block = bild[y0:y1, x0:x1]
  • Bildbereich woanders einfügen (Größe muss genau passen!): bild[y0:y1, x0:x1] = block
  • Alle Farbkomponenten eines Pixels ändern: bild[x,y] = [b,g,r]
  • Nur eine Farbkomponente ändern (hier g = Index 1 da Reihenfolge BGR): bild[x,y,1] = 255
  • 8-Bit Farbkomponenten holen: bild.astype(np.uint8) (falls man mal mit float oder so gerechnet hat)
  • ArUco Marker (QR-Code ähnlich). http://www.philipzucker.com/aruco-in-opencv/

Maus-Events

Maus-Events können über ein Callback verarbeitet werden, OpenCV möchte aber wissen, welches der "imshow"-Fenster dafür herangezogen werden soll. Dazu muss das Fenster am Start einmal explizit mit einem Namen versehen werden.

mx = 10
my = 10

def mouseEvent(event,x,y,flags,param):
    global mx,my
    mx = x
    my = y
    #print(x, y)

cv.namedWindow("Window1")
cv.setMouseCallback("Window1", mouseEvent)

Bar/QR Codes Lesen

Eine funktionierende Library dafür ist "zbar" (mit PIP als "pyzbar" zu finden). Allerdings benötigt die Library noch "PIL" (Python Imaging Library), die aktuell als "PILLOW" weitergeführt wird. Um die Examples von "zbar" also ausführen zu können muss neben "PILLOW" noch der Wrapper "PILLOW - PIL" installiert werden.

    decoded = pyzbar.decode(im)

    for obj in decoded:
        print('Typ : ', obj.type)
        print('Wert: ', obj.data, '\n')

OpencvWorkshopQRCodeRecognition.jpg

Optical Flow

Beispiel Code um features zu verfolgen, aka optical flow. Code funktioniert unter OpenCV Version 3.4.4

Datei:OpencvOpticalFlowPICam.py

Datei:OpencvOpticalFlowUSBCam.py

OpencvWorkshopOpticalFlow.jpg

ArUco - Pose Estimation

Findet den ArUco Marker und seine Position sowie Orientierung im Raum.
Über eine Distanzfunktion kann dann z.B. die Entfernung des Markermittelpunktes zur Kamera ermittelt werden. Dieser wird in cm unten links angezeigt.

import numpy as np
import cv2
import cv2.aruco as aruco

cap = cv2.VideoCapture(0)
aruco_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)
parameters = aruco.DetectorParameters_create()

while(True):
    ret, frame = cap.read()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    corners, ids, rejectedImgPoints = aruco.detectMarkers(gray, aruco_dict, parameters=parameters)
    gray = aruco.drawDetectedMarkers(gray, corners, ids)

    mtx = np.array([[5.3434144579284975e+02, 0., 3.3915527836173959e+02],
                    [0., 5.3468425881789324e+02, 2.3384359492532246e+02],
                    [0., 0., 1.]], np.float)
    dist = np.array([-2.8832098285875657e-01, 5.4107968489116441e-02,
                     1.7350162244695508e-03, -2.6133389531953340e-04,
                     2.0411046472667685e-01], np.float)

    if ids != None:  # if aruco marker detected
        rvec, tvec, objp = aruco.estimatePoseSingleMarkers(corners, 3.5, mtx, dist)  # For a single marker
        aruco.drawDetectedMarkers(gray, corners, ids, (0, 255, 0))
        aruco.drawAxis(gray, mtx, dist, rvec, tvec, 10)
        print(tvec[0][0])
        distance = round( np.linalg.norm(tvec[0][0]), 2)
        cv2.putText(gray, str( distance ) + " cm", (10, 400), cv2.FONT_HERSHEY_PLAIN, 1, (255, 0, 255))

    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

ArUco PoseEstimation.png