From 58174f6adad424a8fdca37f512986ca13696a830 Mon Sep 17 00:00:00 2001 From: Alexander Mordvintsev Date: Wed, 7 Mar 2012 11:09:27 +0000 Subject: [PATCH] Added GIL-release code into python wrappers Added gabor_threads.py sample --- modules/python/src2/gen2.py | 2 + samples/python2/common.py | 10 +++++ samples/python2/gabor_threads.py | 67 ++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) create mode 100644 samples/python2/gabor_threads.py diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index 830c3784c6..a76c519644 100644 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -19,7 +19,9 @@ gen_template_parse_args = Template("""const char* keywords[] = { $kw_list, NULL gen_template_func_body = Template("""$code_decl $code_parse { + Py_BEGIN_ALLOW_THREADS $code_fcall; + Py_END_ALLOW_THREADS $code_ret; } """) diff --git a/samples/python2/common.py b/samples/python2/common.py index f2e74fc3d9..aade8d3cfa 100644 --- a/samples/python2/common.py +++ b/samples/python2/common.py @@ -1,6 +1,7 @@ import numpy as np import cv2 import os +from contextlib import contextmanager image_extensions = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.pbm', '.pgm', '.ppm'] @@ -116,6 +117,15 @@ def nothing(*arg, **kw): def clock(): return cv2.getTickCount() / cv2.getTickFrequency() +@contextmanager +def Timer(msg): + print msg, '...', + start = clock() + try: + yield + finally: + print "%.2f ms" % ((clock()-start)*1000) + class RectSelector: def __init__(self, win, callback): self.win = win diff --git a/samples/python2/gabor_threads.py b/samples/python2/gabor_threads.py new file mode 100644 index 0000000000..bf1ee0cd13 --- /dev/null +++ b/samples/python2/gabor_threads.py @@ -0,0 +1,67 @@ +''' +gabor_threads.py +========= + +Sample demonstrates: +- use of multiple Gabor filter convolutions to get Fractalius-like image effect (http://www.redfieldplugins.com/filterFractalius.htm) +- use of python threading to accelerate the computation + +Usage +----- +gabor_threads.py [image filename] + +''' + +import numpy as np +import cv2 +from threading import Lock +from multiprocessing.pool import ThreadPool + + +def build_filters(): + filters = [] + ksize = 31 + for theta in np.arange(0, np.pi, np.pi / 16): + kern = cv2.getGaborKernel((ksize, ksize), 4.0, theta, 10.0, 0.5, 0, ktype=cv2.CV_32F) + kern /= 1.5*kern.sum() + filters.append(kern) + return filters + +def process(img, filters): + accum = np.zeros_like(img) + for kern in filters: + fimg = cv2.filter2D(img, cv2.CV_8UC3, kern) + np.maximum(accum, fimg, accum) + return accum + +def process_threaded(img, filters, threadn = 8): + accum = np.zeros_like(img) + accum_lock = Lock() + def f(kern): + fimg = cv2.filter2D(img, cv2.CV_8UC3, kern) + with accum_lock: + np.maximum(accum, fimg, accum) + pool = ThreadPool(processes=threadn) + pool.map(f, filters) + return accum + +if __name__ == '__main__': + import sys + from common import Timer + + print __doc__ + try: img_fn = sys.argv[1] + except: img_fn = '../cpp/baboon.jpg' + + img = cv2.imread(img_fn) + filters = build_filters() + + with Timer('running single-threaded'): + res1 = process(img, filters) + with Timer('running multi-threaded'): + res2 = process_threaded(img, filters) + + print 'res1 == res2: ', (res1 == res2).all() + cv2.imshow('img', img) + cv2.imshow('result', res2) + cv2.waitKey()