OpenCV is an excellent library for Computer Vision. I have been using it for years and it helped me a lot during my master thesis.
OpenCV 1.0 can be easily installed in Ubuntu via the repositories. You can install OpenCV 2.0 by following one of my previous posts http://www.samontab.com/web/2010/03/installing-opencv-2-0-in-ubuntu/
Unfortunately, the newer version of OpenCV, 2.1, which was released on April has a slightly different installation procedure. Since it contains many bug fixes and some nice new additions, I will show you how to install it.
Here are the steps that I used to successfully install OpenCV 2.1 in Ubuntu 9.10. I have used this procedure for previous versions of Ubuntu as well with minor modifications (if any).
First, you need to install many dependencies, such as support for reading and writing jpg files, movies, etc… This step is very easy, you only need to write the following command in the Terminal
?
1
sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg62-dev libtiff4-dev cmake libswscale-dev libjasper-dev
The next step is to get the OpenCV 2.1 code:
?
1
2
3
4
cd ~
wget http://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.1/OpenCV-2.1.0.tar.bz2/download
tar -xvf OpenCV-2.1.0.tar.bz2
cd OpenCV-2.1.0/
In this version of OpenCV, the configure utility has been removed. Therefore you need to use Cmake to generate the makefile. Just execute the following line at the console. Note that there is a dot at the end of the line, it is an argument for the cmake program and it means current directory.
?
1
cmake .
Check that the above command produces no error and that in particular it reports FFMPEG as 1. If this is not the case you will not be able to read or write videos.
configuring opencv2.1
Now, you are ready to compile and install OpenCV 2.1:
?
1
2
make
sudo make install
Now you have to configure the library. First, open the opencv.conf file with the following code:
?
1
sudo gedit /etc/ld.so.conf.d/opencv.conf
Add the following line at the end of the file(it may be an empty file, that is ok) and then save it:
?
1
/usr/local/lib
Run the following code to configure the library:
?
1
sudo ldconfig
Now you have to open another file:
?
1
sudo gedit /etc/bash.bashrc
Add these two lines at the end of the file and save it:
?
1
2
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH
Finally, open a new console, restart the computer or logout and then login again. OpenCV will not work correctly until you do this.
Now you have OpenCV 2.1 installed in your computer.
Let’s check some demos included in OpenCV:
?
1
2
3
4
5
6
cd ~
mkdir openCV_samples
cp OpenCV-2.1.0/samples/c/* openCV_samples
cd openCV_samples/
chmod +x build_all.sh
./build_all.sh
Some of the training data for object detection is stored in /usr/local/share/opencv/haarcascades. You need to tell OpenCV which training data to use. I will use one of the frontal face detectors available. Let’s find a face:
?
1
./facedetect --cascade="/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml" --scale=1.5 lena.jpg
Note the scale parameter. It allows you to increase or decrease the size of the smallest object found in the image (faces in this case). Smaller numbers allows OpenCV to find smaller faces, which may lead to increasing the number of false detections. Also, the computation time needed gets larger when searching for smaller objects.
In OpenCV 2.1, the grabcut algorithm is provided in the samples. This is a very nice segmentation algorithm that needs very little user input to segment the objects in the image. For using the demo, you need to select a rectangle of the area you want to segment. Then, hold the Control key and left click to select the background (in Blue). After that, hold the Shift key and left click to select the foreground (in Red). Then press the n key to generate the segmentation. You can press n again to continue to the next iteration of the algorithm.
?
1
./grabcut lena.jpg
This image shows the initial rectangle for defining the object that I want to segment.
Now I roughly set the foreground (red) and background (blue).
When you are ready, press the n key to run the grabcut algorithm. This image shows the result of the first iteration of the algorithm.
Now let’s see some background subtraction from a video. The original video shows a hand moving in front of some trees. OpenCV allows you to separate the foreground (hand) from the background (trees).
?
1
./bgfg_segm tree.avi
There are many other samples that you can try.
แสดงบทความที่มีป้ายกำกับ pythons แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ pythons แสดงบทความทั้งหมด
วันพฤหัสบดีที่ 31 มีนาคม พ.ศ. 2554
วันอังคารที่ 29 มีนาคม พ.ศ. 2554
Fun with Python, OpenCV and face detection
I had some fun with Gary Bishop’s OpenCV Python wrapper this morning. I wanted to try out OpenCV for detecting faces using a web cam. This could be used for instance to see if someone is sitting behind his desk or not. I used Gary’s Python wrapper since I didn’t want to code in C++.
I didn’t know where to start, so I searched for existing OpenCV face detection examples. I found a blog post by Nirav Patel explaining how to use OpenCV’s official Python bindings to perform face detection. Nirav will be working on a webcam module for Pygame for the Google Summer of Code.
I managed to rewrite Nirav’s example to get it working with CVtypes:
Here’s the code. Although it’s just a quick and dirty hack, it might be useful to others. It requires CVtypes and OpenCV, and was tested on Ubuntu Hardy with a Logitech QuickCam Communicate Deluxe webcam. You will need Nirav’s Haar cascade file as well.
import sys
from CVtypes import cv
def detect(image):
image_size = cv.GetSize(image)
# create grayscale version
grayscale = cv.CreateImage(image_size, 8, 1)
cv.CvtColor(image, grayscale, cv.BGR2GRAY)
# create storage
storage = cv.CreateMemStorage(0)
cv.ClearMemStorage(storage)
# equalize histogram
cv.EqualizeHist(grayscale, grayscale)
# detect objects
cascade = cv.LoadHaarClassifierCascade('haarcascade_frontalface_alt.xml', cv.Size(1,1))
faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.HAAR_DO_CANNY_PRUNING, cv.Size(50, 50))
if faces:
print 'face detected!'
for i in faces:
cv.Rectangle(image, cv.Point( int(i.x), int(i.y)),
cv.Point(int(i.x + i.width), int(i.y + i.height)),
cv.RGB(0, 255, 0), 3, 8, 0)
if __name__ == "__main__":
print "OpenCV version: %s (%d, %d, %d)" % (cv.VERSION,
cv.MAJOR_VERSION,
cv.MINOR_VERSION,
cv.SUBMINOR_VERSION)
print "Press ESC to exit ..."
# create windows
cv.NamedWindow('Camera', cv.WINDOW_AUTOSIZE)
# create capture device
device = 0 # assume we want first device
capture = cv.CreateCameraCapture(0)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_WIDTH, 640)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_HEIGHT, 480)
# check if capture device is OK
if not capture:
print "Error opening capture device"
sys.exit(1)
while 1:
# do forever
# capture the current frame
frame = cv.QueryFrame(capture)
if frame is None:
break
# mirror
cv.Flip(frame, None, 1)
# face detection
detect(frame)
# display webcam image
cv.ShowImage('Camera', frame)
# handle events
k = cv.WaitKey(10)
if k == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break
A known problem is that pressing the escape key doesn’t quit the program. Might be something wrong in my use of the cv.WaitKey function. Meanwhile you can just use Ctrl+C. All in all, the face detection works pretty well. It doesn’t recognize multiple faces yet, but that might be due to the training data. It would be interesting to experiment with OpenCV’s support for eye tracking in the future.
Update: the script does recognize multiple faces in a frame. Yesterday when Alex stood at my desk, it recognized his face as well. I think it didn’t work before because I used cv.Size(100, 100) for the last parameter of cv.HaarDetectObjects instead of cv.Size(50, 50). This parameter indicates the minimum face size (in pixels). When people were standing around my desk, they were usually farther away from the camera. Their face was then probably smaller than 100×100 pixels.
Just a quick note on ctypes. I remember when I created PydgetRFID that I tried to use libphidgets’ SWIG-generated Python bindings, but couldn’t get them to work properly. I had read about ctypes, and decided to use it for creating my own wrapper around libphidgets. Within a few hours I had a working prototype. When you’re struggling with SWIG-generated Python bindings, or have some C library without bindings that you would like to use, give ctypes a try. Gary Bishop wrote about a couple of interesting ctypes tricks to make the process easier.
I didn’t know where to start, so I searched for existing OpenCV face detection examples. I found a blog post by Nirav Patel explaining how to use OpenCV’s official Python bindings to perform face detection. Nirav will be working on a webcam module for Pygame for the Google Summer of Code.
I managed to rewrite Nirav’s example to get it working with CVtypes:
Here’s the code. Although it’s just a quick and dirty hack, it might be useful to others. It requires CVtypes and OpenCV, and was tested on Ubuntu Hardy with a Logitech QuickCam Communicate Deluxe webcam. You will need Nirav’s Haar cascade file as well.
import sys
from CVtypes import cv
def detect(image):
image_size = cv.GetSize(image)
# create grayscale version
grayscale = cv.CreateImage(image_size, 8, 1)
cv.CvtColor(image, grayscale, cv.BGR2GRAY)
# create storage
storage = cv.CreateMemStorage(0)
cv.ClearMemStorage(storage)
# equalize histogram
cv.EqualizeHist(grayscale, grayscale)
# detect objects
cascade = cv.LoadHaarClassifierCascade('haarcascade_frontalface_alt.xml', cv.Size(1,1))
faces = cv.HaarDetectObjects(grayscale, cascade, storage, 1.2, 2, cv.HAAR_DO_CANNY_PRUNING, cv.Size(50, 50))
if faces:
print 'face detected!'
for i in faces:
cv.Rectangle(image, cv.Point( int(i.x), int(i.y)),
cv.Point(int(i.x + i.width), int(i.y + i.height)),
cv.RGB(0, 255, 0), 3, 8, 0)
if __name__ == "__main__":
print "OpenCV version: %s (%d, %d, %d)" % (cv.VERSION,
cv.MAJOR_VERSION,
cv.MINOR_VERSION,
cv.SUBMINOR_VERSION)
print "Press ESC to exit ..."
# create windows
cv.NamedWindow('Camera', cv.WINDOW_AUTOSIZE)
# create capture device
device = 0 # assume we want first device
capture = cv.CreateCameraCapture(0)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_WIDTH, 640)
cv.SetCaptureProperty(capture, cv.CAP_PROP_FRAME_HEIGHT, 480)
# check if capture device is OK
if not capture:
print "Error opening capture device"
sys.exit(1)
while 1:
# do forever
# capture the current frame
frame = cv.QueryFrame(capture)
if frame is None:
break
# mirror
cv.Flip(frame, None, 1)
# face detection
detect(frame)
# display webcam image
cv.ShowImage('Camera', frame)
# handle events
k = cv.WaitKey(10)
if k == 0x1b: # ESC
print 'ESC pressed. Exiting ...'
break
A known problem is that pressing the escape key doesn’t quit the program. Might be something wrong in my use of the cv.WaitKey function. Meanwhile you can just use Ctrl+C. All in all, the face detection works pretty well. It doesn’t recognize multiple faces yet, but that might be due to the training data. It would be interesting to experiment with OpenCV’s support for eye tracking in the future.
Update: the script does recognize multiple faces in a frame. Yesterday when Alex stood at my desk, it recognized his face as well. I think it didn’t work before because I used cv.Size(100, 100) for the last parameter of cv.HaarDetectObjects instead of cv.Size(50, 50). This parameter indicates the minimum face size (in pixels). When people were standing around my desk, they were usually farther away from the camera. Their face was then probably smaller than 100×100 pixels.
Just a quick note on ctypes. I remember when I created PydgetRFID that I tried to use libphidgets’ SWIG-generated Python bindings, but couldn’t get them to work properly. I had read about ctypes, and decided to use it for creating my own wrapper around libphidgets. Within a few hours I had a working prototype. When you’re struggling with SWIG-generated Python bindings, or have some C library without bindings that you would like to use, give ctypes a try. Gary Bishop wrote about a couple of interesting ctypes tricks to make the process easier.
วันอังคารที่ 22 มีนาคม พ.ศ. 2554
[Python] Identify the bottlenecks by Python profilers
Python Profiler package เป็น package ไว้สำหรับ วิเคราะห์ประสิทธิภาพของโปรแกรมที่เขียนด้วยภาษา python เพื่อหา bottleneck หรือปัญหาคอขวดของโปรแกรมของเราว่าอยู่ตรงไหน
Minimum-requirement: Python 2.6 or later [use profiler and pstats package]
ถ้าเครื่องไหนไม่สามารถใช้งานได้ ให้ลงก่อน ด้วยคำสั่งดังกล่าว
$ sudo aptitude install python-profiler
ปกติแล้ว Python profilers จะมี standard library ชื่อว่า profile กับ cProfile ผมแนะนำให้ใช้ cProfile ดีกว่าครับ เพราะค่อนข้าง low-level กว่าและมี overhead ต่ำกว่าด้วยครับ
ตัวอย่างการใช้งานทั่วๆไป
import cProfile
import pstats
def foo():
...
if __name__ == '__main__':
cProfile.run('foo()')
วิธีใช้งานคือ เรียกคำสั่ง cProfile.run(‘ ชื่อฟังก์ชั่น ‘) แค่นั้นเองครับ ง่ายมาก
ตัวอย่างการใช้งานเมื่อมีการส่ง parameter ให้ function
import cProfile
import pstats
def foo(bar):
...
if __name__ == '__main__':
cProfile.run('foo()',[bar])
วิธีใช้งานคือ เรียกคำสั่ง cProfile.run(‘ ชื่อฟังก์ชั่น ‘, list ของ parameter )
ตัวอย่างของผลลัพท์
2706 function calls (2004 primitive calls) in 4.504 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.006 0.003 0.953 0.477 pobject.py:75(save_objects)
43/3 0.533 0.012 0.749 0.250 pobject.py:99(evaluate)
...
2706 function calls (2004 primitive calls) in 4.504 CPU seconds
หมายถึง มีการเรียก function 2706 ครั้ง ภายในเวลา 4.504 วินาที สำหรับ primitive calls หมายถึง จำนวนการเรียกฟังก์ชั่นแบบไม่ recursive นั่นคือ ถ้ามีการ recursive primitive จะนับแค่ 1 ครั้งเท่านั้น
ncalls หมายถึง จำนวนครั้งที่เรียก function นั้นๆๆ
tottime หมายถึง ปริมาณเวลาทั้งหมด ที่ใช้ในการเรียก function ทั้งหมด
percall หมายถึง สัดส่วน ncall/tottime
cumtime (cumulative time) เวลาที่ใช้ใน function นั้นๆ
percall หมายถึง สัดส่วน primitive call/cumulative time
filename:lineno(function) ระบุ ชื่อไฟล์ บรรทัดที่? และชื่อ function นั้นๆ
สำหรับรายละเอียดเพิ่มเติมสามารถดูได้จาก http://docs.python.org/library/profile.html
Minimum-requirement: Python 2.6 or later [use profiler and pstats package]
ถ้าเครื่องไหนไม่สามารถใช้งานได้ ให้ลงก่อน ด้วยคำสั่งดังกล่าว
$ sudo aptitude install python-profiler
ปกติแล้ว Python profilers จะมี standard library ชื่อว่า profile กับ cProfile ผมแนะนำให้ใช้ cProfile ดีกว่าครับ เพราะค่อนข้าง low-level กว่าและมี overhead ต่ำกว่าด้วยครับ
ตัวอย่างการใช้งานทั่วๆไป
import cProfile
import pstats
def foo():
...
if __name__ == '__main__':
cProfile.run('foo()')
วิธีใช้งานคือ เรียกคำสั่ง cProfile.run(‘ ชื่อฟังก์ชั่น ‘) แค่นั้นเองครับ ง่ายมาก
ตัวอย่างการใช้งานเมื่อมีการส่ง parameter ให้ function
import cProfile
import pstats
def foo(bar):
...
if __name__ == '__main__':
cProfile.run('foo()',[bar])
วิธีใช้งานคือ เรียกคำสั่ง cProfile.run(‘ ชื่อฟังก์ชั่น ‘, list ของ parameter )
ตัวอย่างของผลลัพท์
2706 function calls (2004 primitive calls) in 4.504 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
2 0.006 0.003 0.953 0.477 pobject.py:75(save_objects)
43/3 0.533 0.012 0.749 0.250 pobject.py:99(evaluate)
...
2706 function calls (2004 primitive calls) in 4.504 CPU seconds
หมายถึง มีการเรียก function 2706 ครั้ง ภายในเวลา 4.504 วินาที สำหรับ primitive calls หมายถึง จำนวนการเรียกฟังก์ชั่นแบบไม่ recursive นั่นคือ ถ้ามีการ recursive primitive จะนับแค่ 1 ครั้งเท่านั้น
ncalls หมายถึง จำนวนครั้งที่เรียก function นั้นๆๆ
tottime หมายถึง ปริมาณเวลาทั้งหมด ที่ใช้ในการเรียก function ทั้งหมด
percall หมายถึง สัดส่วน ncall/tottime
cumtime (cumulative time) เวลาที่ใช้ใน function นั้นๆ
percall หมายถึง สัดส่วน primitive call/cumulative time
filename:lineno(function) ระบุ ชื่อไฟล์ บรรทัดที่? และชื่อ function นั้นๆ
สำหรับรายละเอียดเพิ่มเติมสามารถดูได้จาก http://docs.python.org/library/profile.html
opimize โปรแกรมที่เขียนด้วยภาษา python
blog นี้จะมาบอกว่า เราจะ opimize โปรแกรมที่เขียนด้วยภาษา python ได้อย่างไรบ้าง
อย่างแรก ให้ติดตั้ง Python profiler ก่อน คลิก เพื่อดูว่าแต่ละ function ใช้เวลาในการทำงานนานเท่าไหร่
blog นี้ ผมจะสรุปจาก PerformanceTips ละกันครับ
1. เลือก Data structure ให้เหมาะสม
2. ใช้ Sorting ของ Python
อ้างอิงจาก Comparing the well-known sorting algorithm ซึ่งผมเคยเทียบประสิทธิภาพไปแล้วว่า python sorting เร็วกว่าใครเพื่อน นอกจากนั้น Guido van Rossum ยังแนะนำให้ใช้ comparator
3. String Concatenation
หลีกเลี่ยง (เอา string ใน list มา concat กัน)
s = ""
for substring in list:
s += substring
แนะนำ
s = "".join(list)
หลีกเลี่ยง
out = "" + head + prologue + query + tail + ""
แนะนำ
out = "%s%s%s%s" % (head, prologue, query, tail)
แต่จะดูดีและเร็วขึ้นอีก ถ้าเขียนแบบนี้ (โฮก!! หล่อมาก++)
out = "%(head)s%(prologue)s%(query)s%(tail)s" % locals()
4. Loops แนะนำให้ใช้ map-function
หลีกเลี่ยง (แปลง string ใน list เป็น upper case)
newlist = []
for word in oldlist:
newlist.append(word.upper())
แนะนำ
newlist = map(str.upper, oldlist)
หรือ
newlist = (s.upper() for s in oldlist)
5. Avoiding dot…
หลีกเลี่ยงการใช้ method chaining เช่น ‘AbCDe1234′.lower().count(‘a’) เป็นต้น
6. Local Variable
Python สามารถ access local variable ได้เร็วกว่า global variable
7. Initialize dictionary element
แนะนำให้ตั้งค่าเริ่มต้นให้กับ dictionary
wdict = {}
for word in words:
if word not in wdict:
wdict[word] = 0
wdict[word] += 1
หรือเขียนได้อีกแบบ
wdict = {}
for word in words:
try:
wdict[word] += 1
except KeyError:
wdict[word] = 1
8. import statement overhead
ทุกคำสั่ง import จะมี overhead เสมอ และหลีกเลี่ยงการใช้ import ภายใน function เช่น
def foo():
import os
...
9. Data aggregation
หลีกเลี่ยงการใช้ for loop ไปเรียก function
หลีกเลี่ยง
import time
x = 0
def doit1(i):
global x
x = x + i
list = range(100000)
t = time.time()
for i in list:
doit1(i)
print "%.3f" % (time.time()-t)
แนะนำ
import time
x = 0
def doit2(list):
global x
for i in list:
x = x + i
list = range(100000)
t = time.time()
doit2(list)
print "%.3f" % (time.time()-t)
10. use xrange instead of range
โอ้ 10 ข้อแหนะ ถ้าทำได้หมดแล้วยังไม่เร็วขึ้น แนะนำให้ใช้ Python Psyco ละครับครับ
อย่างแรก ให้ติดตั้ง Python profiler ก่อน คลิก เพื่อดูว่าแต่ละ function ใช้เวลาในการทำงานนานเท่าไหร่
blog นี้ ผมจะสรุปจาก PerformanceTips ละกันครับ
1. เลือก Data structure ให้เหมาะสม
2. ใช้ Sorting ของ Python
อ้างอิงจาก Comparing the well-known sorting algorithm ซึ่งผมเคยเทียบประสิทธิภาพไปแล้วว่า python sorting เร็วกว่าใครเพื่อน นอกจากนั้น Guido van Rossum ยังแนะนำให้ใช้ comparator
3. String Concatenation
หลีกเลี่ยง (เอา string ใน list มา concat กัน)
s = ""
for substring in list:
s += substring
แนะนำ
s = "".join(list)
หลีกเลี่ยง
out = "" + head + prologue + query + tail + ""
แนะนำ
out = "%s%s%s%s" % (head, prologue, query, tail)
แต่จะดูดีและเร็วขึ้นอีก ถ้าเขียนแบบนี้ (โฮก!! หล่อมาก++)
out = "%(head)s%(prologue)s%(query)s%(tail)s" % locals()
4. Loops แนะนำให้ใช้ map-function
หลีกเลี่ยง (แปลง string ใน list เป็น upper case)
newlist = []
for word in oldlist:
newlist.append(word.upper())
แนะนำ
newlist = map(str.upper, oldlist)
หรือ
newlist = (s.upper() for s in oldlist)
5. Avoiding dot…
หลีกเลี่ยงการใช้ method chaining เช่น ‘AbCDe1234′.lower().count(‘a’) เป็นต้น
6. Local Variable
Python สามารถ access local variable ได้เร็วกว่า global variable
7. Initialize dictionary element
แนะนำให้ตั้งค่าเริ่มต้นให้กับ dictionary
wdict = {}
for word in words:
if word not in wdict:
wdict[word] = 0
wdict[word] += 1
หรือเขียนได้อีกแบบ
wdict = {}
for word in words:
try:
wdict[word] += 1
except KeyError:
wdict[word] = 1
8. import statement overhead
ทุกคำสั่ง import จะมี overhead เสมอ และหลีกเลี่ยงการใช้ import ภายใน function เช่น
def foo():
import os
...
9. Data aggregation
หลีกเลี่ยงการใช้ for loop ไปเรียก function
หลีกเลี่ยง
import time
x = 0
def doit1(i):
global x
x = x + i
list = range(100000)
t = time.time()
for i in list:
doit1(i)
print "%.3f" % (time.time()-t)
แนะนำ
import time
x = 0
def doit2(list):
global x
for i in list:
x = x + i
list = range(100000)
t = time.time()
doit2(list)
print "%.3f" % (time.time()-t)
10. use xrange instead of range
โอ้ 10 ข้อแหนะ ถ้าทำได้หมดแล้วยังไม่เร็วขึ้น แนะนำให้ใช้ Python Psyco ละครับครับ
สมัครสมาชิก:
บทความ (Atom)