Hep merak etmişimdir, işimiz insan-bilgisayar etkileşimi ama bilgisayar bizle etkileşiyor, biz onunla nasıl etkileşeceğiz diye. GNU/Linux kullanıyorsanız 15 dakikada bilgisayarınızı Azınlık Raporu’ndaki muhteşem etkileşim sahnesinin çoook minimal haline getirebilir ve küçük Tom Cruise’u oynayabilirsiniz.

İhtiyacımız olan paketler: python, opencv (halihazırda python kodları geliyor) ve xdotool


Tarif:

  • Üstteki paketleri sisteminize kurun. Ben Ubuntu kullandığım için apt-get ile kurdum, depoda mevcuttular.
  • Sonra alttaki koddaki gerekli yerleri değiştirip eğlenin (değiştirmeniz gerekebilecek yerlerde !!! var).

Kod özetle şunu yapıyor: Opencv kullanarak yüzünüzü buluyor. Ardından bulduğu konuma göre farenin (imlecin) yerini güncelliyor. Kafanızı sağa sola hareket ettirdikçe fare oynuyor. Hani blobby oyunu vardı, fareyle oynanabilen voleybol oyunu. Eğer yurtta kaldıysanız belki bilirsiniz, efsane yurt oyunlarındandır. İşte öyle bir oyunu bu şekilde oynamanın önü açık. Yurtta işiniz gücünüz yoksa kodu geliştirip kafanızla topa vuruyormuşçasına blobby oynayabilirsiniz.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
"""Yüz takibi ile fare oynatmaca
 
İsmail Arı, 2008
 
Not: Çıkmak için bir tuşa basın"""
 
import os
import sys
from opencv.cv import *
from opencv.highgui import *
 
# Opencv'nin yüklü olduğu klasörde haarcascades_bişeybişey.xml tarzı dosyalar olacak.
# Bunlar yüz modelleri dosyaları. Onlardan ben karşıdan olanı kullanıyorum ama istediğinizi seçip deneyebilirsiniz.
cascade_name = "modellerin_oldugu_klasor/haarcascade_frontalface_alt.xml" # !!!
 
# Haar tabanlı yüz bulma için parametreler hakkında:
# http://opencv.willowgarage.com/documentation/python/pattern_recognition.html?highlight=cvhaardetectobjects#HaarDetectObjects
# varsayılan değerler şöyleydi: scale_factor=1.1, min_neighbors=3, flags=0, min_size=(0, 0)
# !!!
min_size = cvSize(20, 20)
scale_factor = 1.2
min_neighbors = 3
haar_flags = CV_HAAR_DO_CANNY_PRUNING
 
# Global değişkenler
cascade = None
storage = cvCreateMemStorage(0)
input_name = 0 # ilk kamera
 
def detect_and_draw( img ):
    gray = cvCreateImage( cvSize(img.width,img.height), 8, 1 );
    small_img = cvCreateImage( cvSize( cvRound (img.width/scale_factor),
                                    cvRound (img.height/scale_factor)), 8, 1 );
    cvCvtColor( img, gray, CV_BGR2GRAY );
    cvResize( gray, small_img, CV_INTER_LINEAR );
 
    cvEqualizeHist( small_img, small_img );
 
    cvClearMemStorage( storage );
 
    if( cascade ):
        t = cvGetTickCount();
        faces = cvHaarDetectObjects( small_img, cascade, storage,
                                    scale_factor, min_neighbors, haar_flags, min_size );
        t = cvGetTickCount() - t;
        print "Bulma zamani = %gms" % (t/(cvGetTickFrequency()*1000.))
        if faces:
            for r in faces:
                pt1 = cvPoint( int(r.x*scale_factor), int(r.y*scale_factor))
                pt2 = cvPoint( int((r.x+r.width)*scale_factor), int((r.y+r.height)*scale_factor) )
                cvRectangle( img, pt1, pt2, CV_RGB(255,0,0), 3, 8, 0 )
                cx = (pt1.x + pt2.x) / 2
                cy = (pt1.y + pt2.y) / 2
                os.system("xdotool mousemove " + str(2*cx) + " " + str(2*cy)) # xdotool'a koordinatları gönderelim
 
 
    cvShowImage( "Sonuc", img );
 
 
if __name__ == '__main__':
 
    cascade = cvLoadHaarClassifierCascade( cascade_name, cvSize(1,1) )
 
    if not cascade:
        print "HATA: xml dosyasini dogru verdiginize emin misiniz?"
        sys.exit(-1)
 
    capture = cvCreateCameraCapture( int(input_name) )
 
    cvNamedWindow( "Sonuc", 1 )
 
    frame_copy = None
    while True: 
        frame = cvQueryFrame( capture )
        if( not frame ):
            break;
        if( not frame_copy ):
            frame_copy = cvCreateImage( cvSize(frame.width,frame.height),
                                        IPL_DEPTH_8U, frame.nChannels )
 
        cvFlip( frame, frame_copy, 1 ) # Buna gerek olmayabilir, benim kamerada gerek oldu
 
        detect_and_draw( frame_copy )
 
        if( cvWaitKey( 10 ) >= 0 ):
            break;
 
    cvDestroyWindow("Sonuc")

Dediğim gibi bu çook minimal bir etkileşim gösterimidir. Fareyi nasıl kontrol edebiliriz diye meraktan denemiştim. Eğlencesine yani. O sebeple kod farklı yerlerden kopyala-yapıştır, değiştir-dene tarzı oldu ve normalde yazılması gereken temiz, güzel kod standartından çok uzak.