Crea sito

Blender + OpenCV + Python = 3D immersive enviroment

apr 9, 2010   //   by f24h   //   Blender, Blog, Programming, opencv, python  //  No Comments

Dato che ultimamente il 3D va molto di moda (vedi avatar) ho rispolverato un vecchio programma che avevo fatto seguendo qualche guida qua e la sulla rete.

Come sospettavo il programma non funzionava più perche la versione di opencv per python che utilizzavo è stata fortemente modificata.

Il programma originale era costituito da due file, uno eseguito “stand alone” che faceva tutto il lavoro sporco (riconosceva il volto e ne salvava posizione e dimensioni) e uno che veniva eseguito nel game engine di Blender che leggeva solamente le variabili prodotte dal primo. Lo scambio di variabili era estremamente poco performante in quanto le salvava su un file che poi il game engine di Blender avrebbe letto, per il salvataggio delle variabili utilizzavo pickle.

Ora volendo fare di meglio ho usato per la comunicazione fra processi una pipe con nome (vedi Python + pickle + pipe = IPC made simple).

Ecco un video di quello che sono riuscito ad ottenere (non adatto ai deboli di stomaco)

Ecco il codice del programma che rileva il volto esaustivamente commentato, ho utilizzato opencv per il riconoscimento del volto.

#!/usr/bin/env  python

import cPickle as pickle
import cv, os, sys

def CameraDetect():

def detect(image):
#creazione versione bianco e nero
grayscale = cv.CreateImage((image.width, image.height), 8, 1)
cv.CvtColor(image, grayscale, cv.CV_BGR2GRAY)
#creazione storage
storage = cv.CreateMemStorage(0)
#equalizzazione
cv.EqualizeHist(grayscale, grayscale)
#Rilevamento
cascade = cv.Load('/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml')
faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.CV_HAAR_FIND_BIGGEST_OBJECT) #CV_HAAR_DO_CANNY_PRUNING
#evidenzia facce e ritorna posizione in percentuale rispetto alla grandezza della finestra
if faces:
for (x, y, width, height),n in faces:
#disegno rettangolo
cv.Rectangle(image, ( int(x), int(y)),
(int(x + width), int(y + height)),
cv.CV_RGB(0, 255, 0), 3, 8, 0)
#Posizioni relative al centro della finestra
x = (image.width/2-(x+(width/2)))*-1
y = (image.height/2-(y+(height/2)))*-1
width = (width*100)/image.width
height = (height*100)/image.height
#scrittura sulla pipe
os.write(fd, pickle.dumps((x, y, width, height)))

#creazione finestra
cv.NamedWindow("Camera")
#creazione dispositivo di acquisizione
capture = cv.CaptureFromCAM(0)
#controllo
if not capture:
print "errore apertura dispositivo di acquisizione"
sys.exit(1)
#creazione pipe e apertura
os.mkfifo("/tmp/pipe")
fd = os.open("/tmp/pipe", os.O_WRONLY)
while 1:
#rileva immagine corrente
frame = cv.QueryFrame(capture)
if frame is None:
break
#specchia l'immagine
cv.Flip(frame, None, 1)
#rilevamento volto
detect(frame)
#visualizza l'immagine nella finestra
cv.ShowImage("Camera", frame)
#waitkey per l'uscita non implementato
k = cv.WaitKey(2)

if __name__ == "__main__":
CameraDetect()

Ecco lo script che muove la telecamera all’interno di Blender esaustivamente commentato.

#!/usr/bin/env  python

import cPickle as pickle
import Rasterizer, os

#non avevo voglia di importare anche questo (vedi articolo pipe python)
class PipeReader:
"""A file-like read-only interface to a file descriptor."""
def __init__(self, fd):
self.fd = fd

def read(self, bytes):
return os.read(self.fd, bytes)

def readline(self):
line = ""
while line[-1:] != "\n":
line = line + os.read(self.fd, 1)
return line

def pipeload(fd):
"""Unpickle an object from the stream given by a numeric descriptor."""
return pickle.load(PipeReader(fd))

#Get controller
cont = GameLogic.getCurrentController()

#Oggetto che possiede il controller
own = cont.owner

#Property del cubo
#modificabili con i tasti (vedi file allegato)
sensX = own["sens_speedX"]
sensY = own["sens_speedY"]
sens_mov = own["sens_movimento"]

#posizione corrente
current = own.worldPosition #Ritorna array [x,y,z]

#Get actuators
lookLeftRight = cont.actuators["LookLeftRight"]
lookUpDown = cont.actuators["LookUpDown"]

#funzione che ritorna i valori letti dalla pipe
def move():
fd = os.open("/tmp/pipe", os.O_RDONLY)
ret = pipeload(fd)
os.close(fd)
return ret

move = move()

#definizione velocità e verso del movimento
#sull'asse x
speedx = (move[0]*sens_mov-current[0])*sensX

#settaggio della velocità nell'attuatore
lookLeftRight.dLoc = [speedx, 0.0, 0.0]

#definizione velocità e verso del movimento
#sull'asse y
speedy = (move[2]-current[1])*sensY

#settaggio della velocità nell'attuatore
lookUpDown.dLoc = [0.0, speedy, 0.0]

#attivazione degli attuatori
cont.activate(lookLeftRight)
cont.activate(lookUpDown)

da QUI potete scaricare un archivio contenente tutti i file necessari per far girare il programma e delle istruzioni per far funzionare il tutto.

Leave a comment