views:

55

answers:

1

Hey,

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

+3  A: 

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!

Joe Kington
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?
bluth
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...
Joe Kington
bluth
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)`?
Joe Kington
I must say very clever. That did the trick. Thank you for all your help, very much appreciated.
bluth