5

I recently took some code that tracked an object based on color in OpenCV c++ and rewrote it in the python bindings.

The overall results and method were the same minus syntax obviously. But, when I perform the below code on each frame of a video it takes almost 2-3 seconds to complete where as the c++ variant, also below, is instant in comparison and I can iterate between frames as fast as my finger can press a key.

Any ideas or comments?

    cv.PyrDown(img, dsimg)
    for i in range( 0, dsimg.height ):
        for j in range( 0, dsimg.width):

            if dsimg[i,j][1] > ( _RED_DIFF + dsimg[i,j][2] ) and dsimg[i,j][1] > ( _BLU_DIFF + dsimg[i,j][0] ):
                res[i,j] = 255
            else:
                res[i,j] = 0

    for( int i =0; i < (height); i++ ) 
    {
        for( int j = 0; j < (width); j++ )
        {
            if( ( (data[i * step + j * channels + 1]) > (RED_DIFF + data[i * step + j * channels + 2]) ) &&
                ( (data[i * step + j * channels + 1]) > (BLU_DIFF + data[i * step + j * channels]) ) )
                data_r[i *step_r + j * channels_r] = 255;
            else
                data_r[i * step_r + j * channels_r] = 0;
        }
    }

Thanks

1 Answer 1

6

Try using numpy to do your calculation, rather than nested loops. You should get C-like performance for simple calculations like this from numpy.

For example, your nested for loops can be replaced with a couple of numpy expressions...

I'm not terribly familiar with opencv, but I think the python bindings now have a numpy array interface, so your example above should be as simple as:

cv.PyrDown(img, dsimg)

data = np.asarray(dsimg)
blue, green, red = data.T

res = (green > (_RED_DIFF + red)) & (green > (_BLU_DIFF + blue))
res = res.astype(np.uint8) * 255

res = cv.fromarray(res)

(Completely untested, of course...) Again, I'm really not terribly familar with opencv, but nested python for loops are not the way to go about modifying an image element-wise, regardless...

Hope that helps a bit, anyway!

Sign up to request clarification or add additional context in comments.

5 Comments

This definitely speeds things up but I cannot seem to figure out why the result is more closely related to the threshold of my image and it does not find the green areas on the image as it seems it should?
I may have misinterpreted what order the red, green, and blue channels of the image are in... (From your code above, it seemed like blue was the first channel and red was the last...) Maybe try unpacking the "data" array as red, green, blue = data.T? Just a wild guess... I may be completely wrong, there...
Yea, that was my initial thought, but changing the order doesn't produce a different result. The _RED_DIFF and _BLU are high values, 155, so there should not be many white pixels inside the image and yet there is; its almost all white when I put the _DIFF at 255? I can't seem to make sense of the results from res = (green > (_RED_DIFF + red)) & (green > (_BLU_DIFF + blue)).
Hmm... It might be an overflow problem... In numpy, if you're dealing with uint8's, they overflow just like they would in C. If you're adding 155 to a uint8, there's a good chance that a lot of the values are overflowing to lower values. Maybe try casting things as uint16's to begin with? data = np.asarray(dsimg, dtype=np.uint16)?
I must say very clever. That did the trick. Thank you for all your help, very much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.