Thanks for all the ideas, guys! @crackwitz’s suggestions were particularly helpful.
I tested most of the methods; here is a wrap-up:
- Map/reduce/filter: not really applicable. Most of the time the images aren’t reduced, and often we need to manipulate array indexes, which is impossible with these methods (or with other matrix operators)
-
Pyton wrapper for C code: very interesting solution, but unfortunately you need to create an OpenCV module - and putting application-specific code in a library is a bad idea. However it would be great if there was a simple wrapper to create a python header and a
.so
file from a C++ code - Cython - this is the best solution. The time-critical Python code gets translated to C (and binary code if necessary), and imported.
As I didn’t find any simple example on Cython/OpenCV, I’m attaching my simple testing code below. It is mostly based on this tutorial. Note that this is my first experiment, so probably it can still be optimized/simplified, butI still hope this can help!
My results on a 10MP photo: OpenCV: 0.003s; Numpy: 0.023s Python loops: 12.9s[!!!] Cython loops: 0.01s
thresholding.py
import cv2
import numpy as np
import time
# import and compile cython code
import pyximport
pyximport.install()
import fastthreshold
def pythonthresh(gray):
res = np.zeros(gray.shape, np.uint8)
for y in range(gray.shape[0]):
for x in range(gray.shape[1]):
res[y, x] = 255 if gray[y, x] > th else 0
return res
# Open file and convert to grayscale
filename = "IMG_02506.jpg" # change this
img = cv2.imread(filename)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th = 128
# OpenCV thresholding
t1 = time.time()
res1 = cv2.threshold(gray, th, 255, cv2.THRESH_BINARY)
t2 = time.time()
print(" ------ CV2 thresholding: %s seconds -------" % (t2-t1))
# Numpy thresholding
# probably can be optimized, the multiplication takes time
res3 = (gray > th) * 255
t3 = time.time()
print(" ----- Numpy thresholding: %s seconds ------" % (t3-t2))
# iterating through the array using for loops; function above
res2 = pythonthresh(gray)
t4 = time.time()
print(" --- Per pixel thresholding: %s seconds ---" % (t4-t3))
# fast iteration using cython
out = np.zeros(gray.shape, np.uint8)
fastthreshold.fastthreshold(th, gray, out)
t5 = time.time()
print(" ---- Cython thresholding: %s seconds ------" % (t5-t4))
fastthreshold.pyx
#cython: language_level=3
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef fastthreshold(int th, unsigned char[:,:] gray,unsigned char[:,:] output):
cpdef int x,y
for y in range(gray.shape[0]):
for x in range(gray.shape[1]):
output[y,x] = 255 if gray[y,x]>th else 0