Download - Robot Pendeteksi Object
TUGAS ROBOTIKA
PENDETEKSI OBYEK WAJAH DENGAN WEBCAM PADA
RASPBERRY PI
OLEH :
MUH. AZHARI AMINUDIN (12041001)
BIDANG STUDI TEKNIK ELEKTRONIKA
PROGRAM STUDI TEKNIK ELEKTRO
FAKULTAS TEKNIK
UNIVERSITAS BHAYANGKARA SURABAYA
2016
1. Pendahuluan
Pada makalah ini dijelaskan mengenai mengidentifikasi dan melacak obyek wajah pada
raspberry pi dengan library OpenCV (Computer Vision). Sersor yang dipakai adalah webcam
USB. Sedagkan penggeraknya menggunakan dua motor servo.
Dengan menggunakan koordinat persegi panjang, dilakukan perhitungan posisi (X, Y)
dari pusat wajah. Jika wajah cukup di sisi kiri layar, pan servo akan berputar ke kiri, jika di
sisi kanan akan berputar ke kanan. Ini juga dilakukan pada tilt servo, jika wajah adalah di
bagian atas layar, servo tilt akan berjalan ke atas, jika di bagian bawah servi tiltakan berjalan
ke bawah. Jika wajah terdeteksi cukup dalam pusat gambar, tidak ada tindakan yang
dilakukan oleh servo-servo tersebut. Hal ini untuk mencegah fluktuasi yang tidak perlu karena
kamera telah mengunci diri pada wajah.
2. Perancangan Hardware
Dalam pembuatan hardware ada beberapa komponen yang diperlukan antara lain:
512 MB raspberry pi
2x motor servo
Pan & tilt braket
Webcam USB
Sumber Daya listrik
Kawat hook-up
Raspberry Pi
Selanjutnya dilakukan perakitan dari semua komponen tersebut. Hubungkan merah,
kabel listrik dari servos untuk + 5V, garis tanah hitam ke GND, dan garis sinyal kuning ke pin
output yang diinginkan, GPIO pin 22 dan 23 dalam contoh. Berikut ini adalah diagram dari
rangkaian lengkap.
Gb. Diagram koneksi servo
Gb. Hardware yang telah tersusun
3. Perancangan Software
Langkah pertama dari prosedur ini adalah menginstal library dan package yang
diperlukan dengan menggunakan package manager Raspberry Pi. Buka shell terminal dan
jalankan:
sudo apt-get update && sudo apt-get install git python-OpenCV python-semua-dev
libopencv-dev
Perintah ini akan mendownload semua paket yang dibutuhkan (sekitar 215 MB )
termasuk git version control system, serta OpenCV development headers dan Python
bindings. Langkah selanjutnya adalah mengkonfigurasi Raspberry Pi untuk digunakan dengan
beberapa output PWM. Biasanya, Raspberry Pi hanya memiliki satu saluran output
PWM. Namun, berkat upaya dari Richard Hirst, delapan saluran PWM dapat digunakan
melalui penggunaan servoblaster kernel driver. Dia membuat file, / dev / servoblaster yang
perintah dapat dikirim untuk mengontrol servo-servo. Perintah mengambil bentuk "=" dengan
nomor servo mewakili servo yang diinginkan (misal 0-7 dalam kasus ini) dan posisi servo
mewakili lebar pulsa dalam satuan 10 mikrodetik. Misalnya, untuk mengirim servo 3 lebar
pulsa dari 120 mikrodetik: echo 3 = 120 > / dev / servoblaster. Untuk mengkonfigurasi
servoblaster pada Raspberry Pi, pertama pull down source dari Richard Github repo:
git clone https://github.com/richardghirst/PiBits.git
Kemudian mengubah ke dalam direktori servo blaster, dan menginstal modul:
PiBits cd / ServoBlaster
make install_autostart
Perintah ini juga membentuk aturan udev yang diperlukan untuk mengakses perangkat /
dev / servoblaster. Catatan: menggunakan perintah 'install_autostart' akan membuat
Raspberry Pi untuk memuat modul kernel servoblaster pada setiap boot. Jika tidak ingin
perilaku ini, jalankan 'make install' sebagai gantinya. Dalam kedua kasus, modul belum
dimuat jadi lanjutkan dan isikan modul ke kernel menggunakan modprobe:
sudo modprobe servoblaster
Sekarang semua prasyarat telah terpasang dan perangkat servo blaster dikonfigurasi,
saatnya untuk mendapatkan kode pelacakan wajah dan pergerakan servo. Mengkloning repo
dari Github dibawah ini:
git clone https://github.com/mitchtech/py_servo_facetracker
Sekarang mengubah lokasi direktori ke dalam folder yang dibuat, dan menjalankan
script seperti ini:
cd py_servo_facetracker
python ./facetracker_servo_gpio.py 0
Jika terdapat konfigurasi braket servo berbeda, pan dan tilt axis mungkin perlu
dibalik. Untuk melakukannya, membalikkan tanda pada nilai-nilai panStepSize dan
tiltStepSize. Demikian pula, peningkatan atau penurunan nilai-nilai ini akan mengubah
sensitivitas gerakan, angka yang lebih besar akan menambah derajat perpindahan bingkai
deteksi wajah.
4. Algoritma program
Berikut penjelasan flowchart program pendeteksi wajah. Flowchart terdiri dari
flowchart program utama, flowchart pengolahan citra, dan flowchart pengolahan motor servo.
a. Program Utama
Pertama gambar diambil dari webcam. Selanjutnya masuk ke proses pengolahan citra
mendeteksi wajah dan menghasilkan koodinat x-y. Koordinat tersebut masuk ke proses
pengolahan motor servo yaitu proses untuk mengggerakkan motor servo agar kamera bisa
mengikuti gerakan objek wajah. Gambar dibawah menujukkan florchart program utama.
Gb. Flowchart program utama
b. Proses Pengolahan Citra
Kemudian proses pengolahan citra, pertama gambar webcam di capture, kemudian
melalui proses filter sehingga dapat mempermudah dalam pengklasifikasian objek wajah. Jika
wajah ditemukan maka dilakukan pembuatan garis kotak pada objek yang ditemukan.
Kemudian menghitung titik tengah garis kotak dan disimpan sebagai koordinat x-y. gambar
dibawah menunjukkan flowchart pengolahan citra.
Gb. Flowchart pengolahan citra
c. Proses pengolahan motor servo
Servo yang digunakan ada 2 buah yaitu servo tilt ( bergerak keatas dan kebawah) dan
servo pan (bergerak kekiri dan kekanan). Koordinat x-y yang dihasilkan dari proses
sebelumnya kemudian dibandingkan dengan titik tengah layar capture. Perbandingan inilah
yang akan dijadikan sebagai acuan pergerakan motor servo. Berikut ini adalah flowchart dari
proses pengolahan motor servo.
Gb. Flowchart pengolahan servo
5. Listing Program
#!/usr/bin/python"""This program is demonstration for face and object detection using haar-like features.The program finds faces in a camera image or video stream and displays a red box around them,then centers the webcam via two servos so the face is at the center of the screenBased on facedetect.py in the OpenCV samples directory"""import sysfrom optparse import OptionParserimport cv2.cv as cvimport os
# Parameters for haar detection# From the API:# The default parameters (scale_factor=2, min_neighbors=3, flags=0) are tuned# for accurate yet slow object detection. For a faster operation on real video# images the settings are:# scale_factor=1.2, min_neighbors=2, flags=CV_HAAR_DO_CANNY_PRUNING,# min_size=<minimum possible face sizemin_size = (20, 20)image_scale = 2haar_scale = 1.2min_neighbors = 2haar_flags = cv.CV_HAAR_DO_CANNY_PRUNING
max_pwm = 249min_pwm = 1midScreenWindow = 40 # acceptable 'error' for the center of the screen.panStepSize = 2 # degree of change for each pan updatetiltStepSize = -2 # degree of change for each tilt updateservoPanPosition = 125 # initial pan positionservoTiltPosition = 160 # initial tilt positionpanGpioPin = 2 # servoblaster pin 2 : gpio pin 18tiltGpioPin = 5 # servoblaster pin 5 : gpio pin 23
def detect_and_draw(img, cascade): gray = cv.CreateImage((img.width,img.height), 8, 1) small_img = cv.CreateImage((cv.Round(img.width / image_scale), cv.Round (img.height / image_scale)), 8, 1) # convert color input image to grayscale cv.CvtColor(img, gray, cv.CV_BGR2GRAY) # scale input image for faster processing cv.Resize(gray, small_img, cv.CV_INTER_LINEAR) cv.EqualizeHist(small_img, small_img) midFace = None if(cascade):
t = cv.GetTickCount() # HaarDetectObjects takes 0.02s faces = cv.HaarDetectObjects(small_img, cascade, cv.CreateMemStorage(0), haar_scale, min_neighbors, haar_flags, min_size) t = cv.GetTickCount() - t if faces: for ((x, y, w, h), n) in faces: # the input to cv.HaarDetectObjects was resized, so scale the # bounding box of each face and convert it to two CvPoints pt1 = (int(x * image_scale), int(y * image_scale)) pt2 = (int((x + w) * image_scale), int((y + h) * image_scale)) cv.Rectangle(img, pt1, pt2, cv.RGB(255, 0, 0), 3, 8, 0) # get the xy corner co-ords, calc the midFace location x1 = pt1[0] x2 = pt2[0] y1 = pt1[1] y2 = pt2[1] midFaceX = x1+((x2-x1)/2) midFaceY = y1+((y2-y1)/2) midFace = (midFaceX, midFaceY) cv.ShowImage("result", img) return midFace def move(servo, angle): '''Moves the specified servo to the supplied angle. Arguments: servo the servo number to command, an integer from 0-7 angle the desired pulse width for servoblaster, an integer from 0 to 249 (e.g.) >>> servo.move(2, 90) ... # "move servo #2 to 90 degrees"'''
if (min_pwm <= angle <= max_pwm): command = 'echo %s=%s > /dev/servoblaster' % (str(servo), str(angle)) os.system(command) #print command else: print "Servo angle must be an integer between 0 and 249.\n" if __name__ == '__main__': # parse cmd line options, setup Haar classifier parser = OptionParser(usage = "usage: %prog [options] [camera_index]") parser.add_option("-c", "--cascade", action="store", dest="cascade", type="str", help="Haar cascade file, default %default", default = "./haarcascade_frontalface_alt.xml") (options, args) = parser.parse_args() cascade = cv.Load(options.cascade) if len(args) != 1: parser.print_help() sys.exit(1)
input_name = args[0] if input_name.isdigit(): capture = cv.CreateCameraCapture(int(input_name)) else: print "We need a camera input! Specify camera index e.g. 0" sys.exit(0) cv.NamedWindow("result", 1) if capture: frame_copy = None
move(panGpioPin, servoPanPosition) move(tiltGpioPin, servoTiltPosition)
while True: frame = cv.QueryFrame(capture) if not frame: cv.WaitKey(0) break if not frame_copy: frame_copy = cv.CreateImage((frame.width,frame.height), cv.IPL_DEPTH_8U, frame.nChannels) if frame.origin == cv.IPL_ORIGIN_TL: cv.Copy(frame, frame_copy) else: cv.Flip(frame, frame_copy, 0) midScreenX = (frame.width/2) midScreenY = (frame.height/2) midFace = detect_and_draw(frame_copy, cascade) if midFace is not None: midFaceX = midFace[0] midFaceY = midFace[1] #Find out if the X component of the face is to the left of the middle of the screen. if(midFaceX < (midScreenX - midScreenWindow)): #Update the pan position variable to move the servo to the right. servoPanPosition += panStepSize print str(midFaceX) + " > " + str(midScreenX) + " : Pan Right : " + str(servoPanPosition) #Find out if the X component of the face is to the right of the middle of the screen. elif(midFaceX > (midScreenX + midScreenWindow)): #Update the pan position variable to move the servo to the left. servoPanPosition -= panStepSize print str(midFaceX) + " < " + str(midScreenX) + " : Pan Left : " + str(servoPanPosition) else:
print str(midFaceX) + " ~ " + str(midScreenX) + " : " + str(servoPanPosition) servoPanPosition = min(servoPanPosition, max_pwm) servoPanPosition = max(servoPanPosition, min_pwm) move(panGpioPin, servoPanPosition)
#Find out if the Y component of the face is below the middle of the screen. if(midFaceY < (midScreenY - midScreenWindow)): if(servoTiltPosition <= max_pwm): #Update the tilt position variable to lower the tilt servo. servoTiltPosition -= tiltStepSize print str(midFaceY) + " > " + str(midScreenY) + " : Tilt Down : " + str(servoTiltPosition) #Find out if the Y component of the face is above the middle of the screen. elif(midFaceY > (midScreenY + midScreenWindow)): if(servoTiltPosition >= 1): #Update the tilt position variable to raise the tilt servo. servoTiltPosition += tiltStepSize print str(midFaceY) + " < " + str(midScreenY) + " : Tilt Up : " + str(servoTiltPosition) else: print str(midFaceY) + " ~ " + str(midScreenY) + " : " + str(servoTiltPosition) servoTiltPosition = min(servoTiltPosition, max_pwm) servoTiltPosition = max(servoTiltPosition, min_pwm) move(tiltGpioPin, servoTiltPosition) if cv.WaitKey(10) >= 0: # 10ms delay break cv.DestroyWindow("result")