Matt W-D
Matt W-D

Reputation: 1625

python: OpenCV Root Directory

I am using OpenCV for various object detectors, and I am finding it difficult to write portable code.

For instance, to load a face detector, on a mac with OpenCV installed via homebrew, I have to write:

haar=cv.Load('/usr/local/Cellar/opencv/2.4.2/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml')

This is not portable; if I wish to change to another machine I'll have to determine another absolute path and change this code.

Is there a variable that holds the OpenCV root for OpenCV? That way I could write something like:

haar=cv.Load(os.path.join(OpenCVRoot, "haarcascades", 
                          "haarcascade_frontalface_default.xml"))

UPDATE: It looks like this is not just a problem for me; it is also a problem for the OpenCV documentation. The documentation contains the following broken example code:

>>> import cv
>>> image = cv.LoadImageM("lena.jpg", cv.CV_LOAD_IMAGE_GRAYSCALE)
>>> cascade = cv.Load("../../data/haarcascades/haarcascade_frontalface_alt.xml")
>>> print cv.HaarDetectObjects(image, cascade, cv.CreateMemStorage(0), 1.2, 2, 0, (20, 20))
[((217, 203, 169, 169), 24)]

This would be simple to avoid if there was a way to infer where examples like lena.jpg and the pre-trained classifiers were installed.

Source: http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html (Retrieved 3/5/13)

Upvotes: 8

Views: 20500

Answers (5)

Tomasz Gandor
Tomasz Gandor

Reputation: 8833

It seems there is little hope of having a single mechanism which would be portable across time and space (versions and platforms/environments), but there is some progress - I don't know which version introduced it, but 4.0 has it:

cv2.data.haarcascades - string pointing to a directory, e.g.:

>>> import cv2
>>> cv2.data
<module 'cv2.data' from 'C:\\Users\\USERNAME\\Anaconda3\\envs\\py36\\lib\\site-packages\\cv2\\data\\__init__.py'>
>>> cv2.data.haarcascades
'C:\\Users\\USERNAME\\Anaconda3\\envs\\py36\\lib\\site-packages\\cv2\\data\\'
>>> cv2.__version__
'4.0.0'

But unfortunately, for 3.2.x and 3.4.x there is no such module...

So you could do:

if hasattr(cv2, 'data'):
    print('Cascades are here:', cv2.data.haarcascades)
else:
    print('This may not work:')
    print(normpath(realpath(cv2.__file__) + '../../../../../share/OpenCV/haarcascades'))

Upvotes: 2

Peter
Peter

Reputation: 13505

I'm in the same boat, and it is an annoying boat.

One convention you can use to deal with such portability issues is use configuration files. In your case, you could have a file ~/.myprojectrc, which could contain:

[cv]
cvroot = '/usr/local/Cellar/opencv/2.4.2/share/OpenCV/`

Files in this format can be read by ConfigParser objects, which should go something like:

import ConfigParser
import os
CONFIG = ConfigParser.ConfigParser()
config_path = os.path.join(os.path.expanduser('~'), '.myprojectrc')
if not os.path.exists(config_path):
    raise Exception('You need to make a "~/.myprojectrc" file with your cv path or something')
CONFIG.read(config_path)

...

cv_root = CONFIG.get('cv', 'cvroot')

Then at least when someone uses the code on another machine they don't have to modify any code, they just need to create the config file with the opencv path, and they get a clear error message telling them to do so.

Upvotes: 0

Kai Mysliwiec
Kai Mysliwiec

Reputation: 354

You can use cv2.__file__ to get path to the module and then use os.path to resolve symlinks and do some path manipulation. This line of code returns the directory of the haarcascades files on my Mac OS homebrew installation. It may work on other installations too.

from os.path import realpath, normpath
normpath(realpath(cv2.__file__) + '../../../../../share/OpenCV/haarcascades')

Upvotes: 7

Thai Tran
Thai Tran

Reputation: 9935

Why don't just copy that folder containing the xml files to your local workspace folder and use the relative path? As I remember, it does not cost much space on your hard drive

Upvotes: -2

PurityLake
PurityLake

Reputation: 1120

check this link

You can use sys.platform to determine the platform and set a different default path depending on the return from sys.platform

Upvotes: -1

Related Questions