I need to do some fast thresholding of a large amount of images, with a specific range for each of the RGB channels, i.e. remove (make black) all R values not in [100;110], all G values not in [80;85] and all B values not in [120;140]
Using the python bindings to OpenCV gives me a fast thresholding, but it thresholds all three RGP channels to a single value:
cv.Threshold(cv_im,cv_im,threshold+5, 100,cv.CV_THRESH_TOZERO_INV)
cv.Threshold(cv_im,cv_im,threshold-5, 100,cv.CV_THRESH_TOZERO)
Alternatively I tried to do it manually by converting the image from PIL to numpy:
arr=np.array(np.asarray(Image.open(filename).convert('RGB')).astype('float'))
for x in range(img.size[1]):
for y in range(img.size[0]):
bla = 0
for j in range(3):
if arr[x,y][j] > threshold2[j] - 5 and arr[x,y][j] < threshold2[j] + 5 :
bla += 1
if bla == 3:
arr[x,y][0] = arr[x,y][1] = arr[x,y][2] = 200
else:
arr[x,y][0] = arr[x,y][1] = arr[x,y][2] = 0
While this works as intended, it is horribly slow!
Any ideas as to how I can get a fast implementation of this?
Many thanks in advance, Bjarke
I think the inRange opencv method is what you are interested in. It will let you set multiple thresholds simultaneously.
So, with your example you would use
# Remember -> OpenCV stores things in BGR order
lowerBound = cv.Scalar(120, 80, 100);
upperBound = cv.Scalar(140, 85, 110);
# this gives you the mask for those in the ranges you specified,
# but you want the inverse, so we'll add bitwise_not...
cv.InRange(cv_im, lowerBound, upperBound, cv_rgb_thresh);
cv.Not(cv_rgb_thresh, cv_rgb_thresh);
Hope that helps!