Wednesday, November 11, 2009

Face Detection "Hello World" in IronPython using Emgu CV and OpenCV

While following the instructions for setting up IronPython to use Emgu CV:
http://www.emgu.com/wiki/index.php/Setting_up_Emgu_CV_and_IronPython
I had a few problems. I started by trying to use latest versions (2.0) of these packages but kept getting dll load errors like:
"SystemError: The type initializer for 'Emgu.CV.CvInvoke' threw an exception."
I put my best google-foo on it and tried things like upgrading .Net to 3.5 but no dice. So I backtracked to Emgu CV 1.5 and OpenCV 1.1 and was able to getting it working:


import sys
import clr

sys.path.append(r"C:\OpenCV11\bin")
sys.path.append(r"C:\apps\Emgu1.5")

clr.AddReferenceToFile("Emgu.CV.dll")
clr.AddReferenceToFile("Emgu.Util.dll")
clr.AddReferenceToFile("Emgu.CV.UI.dll")
clr.AddReference("System.Drawing")

from Emgu.CV import Image, HaarCascade
from Emgu.CV.UI import ImageViewer
from Emgu.CV.Structure import Gray
from System import Byte
from System.Drawing import Size
from Emgu.CV.CvEnum import HAAR_DETECTION_TYPE

detector = HaarCascade(r"C:\OpenCV11\data\haarcascades\haarcascade_frontalface_alt2.xml")

img = Image[Gray, Byte](r"C:\OpenCV11\samples\c\lena.jpg")

# http://www.cognotics.com/opencv/servo_2007_series/part_2/page_2.html
#http://www.emgu.com/wiki/files/2.0.0.0/html/11c784fc-7d30-a921-07ec-ecdb7d217bbe.htm
scaleIncreaseRate = 1.1
minNeighbors = 3
minSearchScale = Size(img.Width/8, img.Height/8) # As a ratio of the image size:
#Or a fixed pixel size: minSearchScale = Size(100,100)
iChannel = 0 # only 1 channel

objectsDetected = img.DetectHaarCascade(
detector,
scaleIncreaseRate,
minNeighbors,
HAAR_DETECTION_TYPE.DO_CANNY_PRUNING,
minSearchScale
)[iChannel]

for obj in objectsDetected:
print "Object Rectange: %s" % obj.rect
img.Draw(obj.rect, Gray(255), 1)

ImageViewer.Show(img)

A couple notes compared to the Emgu wiki version--I was able to get everything working without having to disturb the IronPython install (I didn't copy any files into the IronPython start directory). I simply linked used sys.path to add the locations where the dll's live. Also, I did explicit import for everything. It's a bit more work to figure out what needs to be imported, but it avoids namespace pollution issues. Also, the img.Draw line needed a few tweaks. I had to drop the [float] bit from the original. And with the original version, I was also getting an error on this same line, saying:

TypeError: expected MCvBox2D, got MCvAvgComp

I was able to work around this by passing in the ".rect" rectangle attribute to the Draw method (I'm guessing the api has evolved since the 1.4 Emgu version used for the original). Lastly, I was getting two objects detected--so I used parameters to the detector to only get the single face in the image (basically by telling it to use a larger minimum detection size, minSearchScale). Anyway, now it works the way I was hoping.

And here's some bits about the environment, and the results it prints out:

C:\temp>"C:\Program Files\IronPython 2.6\ipy"
IronPython 2.6 (2.6.10920.0) on .NET 2.0.50727.3603
Type "help", "copyright", "credits" or "license" for more information
>>> execfile(r"C:\work\EmguTest.py")
Object Rectange: {X=222,Y=206,Width=163,Height=163}

And lastly, I'd be remiss if I didn't include lovely Lena, with face detected (in B&W, sorry about that Lena).

UPDATE:
When I tried to port the above configuration to my target server, I started getting that Emgu.CV.CvInvoke exception again. I upgraded the server to .Net 3.5 but that didn't get it. Then I applied the Microsoft Visual C++ 2005 SP1 Redistributable Package (see link) to the server and then it ran without error. So to summarize, I was able to get this running using Emgu CV 1.5, OpenCv 1.1, and the Visual C++ 2005 SP1 package installation. It runs on IronPython 2.0.1 and 2.6. I'm not certain if a .Net 3.5 had any effect:

Microsoft Visual C++ 2005 SP1 Redistributable Package Download

2 comments:

Anonymous said...

It's 2012, and this still works. I had to change for my install paths, and the img.HaarCascadeDetect throws a deprecation warning. I also didn't have to link OpenCV in my system path. Thanks a bunch!

FCW

Anonymous said...

To clarify, I'm using the newest release of everything (IronPython 2.7.2.1, Emgu 2.3.0, OpenCV 2.3.1). Thanks again!

FCW