Python, webcam et différence d’images…

J’étais en train de me faire un système de localisation de la position d’un laser, dans le but de pouvoir contrôler des applications par ce biais, et surtout dans le but de jouer un peu avec python, opencv et la webcam.
Visiblement, pour le jeu c’est mission réussie, pour le laser ça fera sans doute l’objet d’un autre billet.

Ici je vais vous présenter la différence entre 2 images, converties au préalable en niveau de gris. Le résultat est très sympa à voir.

Et en bonus, une vidéo, parce que le principal intérêt est que ça fait ressortir le mouvement.

Comment ça fonctionne

Le principe est très simple : on récupère une frame, qu’on converti en niveau de gris. On prend ensuite l’image courante de la webcam, qu’on converti égalstrongent en niveau de gris, puis on affiche la différence entre les 2 images (la fonction cvAbsDiff le fait très bien, mais ce n’est pas compliqué à coder manuellstrongent).

NB : pour que ça soit réellement exploitable dans un logiciel de détection de position (pour trouver la position d’un laser par exemple), et faut au préalable faire la moyenne de quelques frames, sinon les perturbations ont trop d’effet, et on se retrouve régulièrsement avec plusieurs tâches lumineuses.

Voici le code permettant de générer les images et la vidéo ci-dessus. À l’origine il n’était pas destiné à cet usage, je l’ai un peu modifié, il reste cependant quelques noms de fonctions pas logiques hors contexte, des fonctions inutiles, et de nombreux appels de fonctions pourraient être évités en re-codant proprement.

webcam.py

#!/usr/bin/python</code>

from opencv.highgui import *
from opencv.cv import *
import image as im
from image_manager import *
import sys

class Webcam:
    """ Manages the webcam """
    def __init__(self, index=-1):
        self.capture=cvCreateCameraCapture(index)

def __del__(self):
    cvReleaseCapture(self.capture)

def getFrame(self):
    return cvQueryFrame(self.capture)

def getImage(self):
    """ Get image """
    frame=self.getFrame()
    return im.Image(frame)

def getGrayscaleFrame(self):
    """ Return the frame converted into gray levels """
    colorImg=self.getFrame()
    nvgImg = cvCreateImage(cvGetSize(colorImg), colorImg.depth, 1);
    cvConvertImage(colorImg, nvgImg)
    return nvgImg

def getGrayscaleImage(self):
    """ Get image converted into grayscale """
    frame=self.getGrayscaleFrame()
    return im.Image(frame)

image.py

from opencv.cv import *
from opencv import adaptors

class Image:
    def __init__(self, image):
        self.image=image

def grayscale(self):
    colorImg=self.getFrame()
    nvgImg = cvCreateImage(cvGetSize(colorImg), colorImg.depth, 1);
    cvConvertImage(colorImg, nvgImg);
    return nvgImg

def getPixel(self, x, y):
    """ Hack to get the pixel, since we can't access cvScalar
    with python, too bad"""
    pil_image = adaptors.Ipl2PIL (self.image)
    return pil_image.getpixel ((x, y))

def reduce(self, ratio):
    destImg = cvCreateImage(cvSize(self.image.width/ratio,
    self.image.height/ratio), self.image.depth,
    cvResize( self.image, destImg)
    return destImg

def luminosityMedium(self):
    luminosity=0
    nbpix = 0
# reduce 100 times to calculate faster
    img = self.reduce(100)
        for y in range(0,img.width):
            for x in range(0, img.height):
            pix = self.getPixel(x, y)
            luminosity+=pix
            nbpix+=1
    if nbpix>0:
        return luminosity/nbpix

def image(self):
    return self.image

main.py

from opencv.cv import *
from image import *
from webcam import *

class Localisator:
    def __init__(self, webcam):
        self.webcam = webcam
        self.frame = webcam.getGrayscaleFrame()
        self.frames = []
        self.mediumLuminosity = 0

def trackLaser(self):
    self.frame = self.webcam.getGrayscaleFrame()
    self.img = Image(self.frame)
    self.mediumLuminosity = self.img.luminosityMedium()
    self.imageDiff(self.mediumLuminosity+5)

def imageDiff(self, limit):
# reduce 50 times to calculate faster
# img = self.img.reduce(1)
    img = self.img.reduce(1)
    img_bin = cvCloneImage(img)
# diff between the images
    cvAbsDiff(img, self.webcam.getGrayscaleFrame(), img_bin);
# Keep only light above the given limit
#cvThreshold(img_bin, img_bin, limit, 255, CV_THRESH_BINARY);
    self.frame = img_bin

def renderedImage(self):
    return self.frame

cvNamedWindow("window1",CV_WINDOW_AUTOSIZE)
w = Webcam()
loc = Localisator(w)

while True:
    loc.trackLaser()
    cvShowImage("window1",loc.renderedImage())
    c=cvWaitKey(10)
    if c==chr(27):
        cvDestroyWindow("window1")
        sys.exit(0)

Quelques explications
Le code en lui-même est assez simple, grâce à opencv.
Je pense qu’il n’y a pas besoin de beaucoup d’explications, donc je vais me contenter des fonctions d’opencv.
cvAbsDiff : fait la différence entre 2 images.
cvThreshold : ici je l’ai commentée, mais elle est très utile dans des programmes de détection : elle converti une image en ne gardant que les pixels de luminosité supérieur à un seuil.

Vous pouvez télécharger les sources. Le code est sous licence GNU GPL >=2.

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

%d blogueurs aiment cette page :