4

I'm working on an image processing program with OpenCV and numpy. For most pixel operations, I'm able to avoid nested for loops by using np.vectorize(), but one of the functions I need to implement requires as a parameter the 'distance from center', or basically the coordinates of the point being processed.

Pseudoexample :

myArr = [[0,1,2]
         [3,4,5]]

def myFunc(val,row,col):
    return [row,col]

f = np.vectorize(myFunc)
myResult = f(myArr,row,col)

I obviously can't get elemX and elemY from the vectorized array, but is there another numpy function I could use in this situation or do I have to use for loops?, Is there a way to do it using openCV?

The function I need to put each pixel through is : f(i, j) = 1/(1 + d(i, j)/L) , d(i,j) being the euclidean distance of the point from the center of the image.

smci
  • 32,567
  • 20
  • 113
  • 146
xShirase
  • 11,975
  • 4
  • 53
  • 85

2 Answers2

1

You can get an array of distance from the center using the following lines (which is an example, there are a lot of ways to do this):

    import numpy as np

myArr = np.array([[0,1,2], [3,4,5]])

nx, ny = myArr.shape
x = np.arange(nx) - (nx-1)/2.  # x an y so they are distance from center, assuming array is "nx" long (as opposed to 1. which is the other common choice)
y = np.arange(ny) - (ny-1)/2.
X, Y = np.meshgrid(x, y)
d = np.sqrt(X**2 + Y**2)

#  d = 
#  [[ 1.11803399  1.11803399]
#   [ 0.5         0.5       ]
#   [ 1.11803399  1.11803399]]

Then you can calculate f(i, j) by:

f = 1/(1 + d/L)


As an aside, your heavy use of np.vectorize() is a bit dubious. Are you sure it's doing what you want, and did you note the statement from the documentation:

The vectorize function is provided primarily for convenience, not for performance. The implementation is essentially a for loop.

It's generally better to just write you code in vectorized form (like my line for f above which will work whether L is an array or a scaler), and not use numpy.vectorize(), and these are different things.

tom10
  • 67,082
  • 10
  • 127
  • 137
  • As an aside, I've started coding in Python last night ;-) Much appreciated advice, I haven't had the time to learn best practices yet! – xShirase Jun 06 '15 at 21:44
  • 1
    @xShirase: especially if that's the case, I'd skip the use of `np.vectorize` altogether. It will set you off on the wrong track (I've never used it once in years of working with numpy). Instead, numpy should make things both easier to write, and faster to run, like the expression for `f` above; both of which are things you want. Maybe a super short numpy tutorial would be in order to start you on the right track. – tom10 Jun 06 '15 at 21:50
  • I usually code on Node.JS, but this time I have to implement some heavy matrices calculations so had to switch to Python, so my code is definitely not optimized. I'm not sure I understand this bit : `as opposed to 1. which is the other common choice` could you recommend a good tutorial maybe? – xShirase Jun 06 '15 at 21:53
  • 1
    @xShirase: When considering the actual size represented by an image, there's a fair amount of variation in what's needed, which is why I wrote it out explicitly here. It's seemed like you wanted your arrays to represent an image size corresponding to the number of pixels along each axis. Another common thing people want is where the positions of the pixels to run from 0 to 1 across both axes, or -.5 to .5 or something like that. Anyway, all of those should just involve a few simply changes to the `x` and `y` lines. – tom10 Jun 06 '15 at 22:00
  • Alright, got it, thanks for the tips, going for a numpy crash course now! Also, as the image is from OpenCV, shape returns y,x instead of x,y (and RGB is BGR, go figure) – xShirase Jun 06 '15 at 22:03
1

np.vectorize don't accelerate the code, you can vectorize it this way, `

# This compute distance between all points of MyArray and the center

dist_vector= np.sqrt(np.sum(np.power(center-MyArray,2),axis=1))


# F will contain the target value for each point

F = 1./(1 + 1. * dist_vector/L)
farhawa
  • 10,120
  • 16
  • 49
  • 91