title: Project image onto inside of sphere with Python Numpy
body: <h2>Problem:</h2>
  
  <p>Let's say I have a large image, 5000x3000 pixels. I want to paste this image onto the inside of a sphere of some arbitrary radius.</p>
  
  <p>To do this I will import the image as an array and I will determine the centre of the array. I will loop through each pixel, determining how far displaced it is from the centre, and using this x and y displacement I will use simple geometry to determine where it should be copied to on an output array. </p>
  
  <p>Below are some examples of what my inputs and outputs are (but on a far smaller scale than I am trying to use).</p>
  
  <p><strong>Example Input</strong></p>
  
  <p><a href="https://i.stack.imgur.com/IpT2u.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/IpT2u.jpg" alt="Example input image"></a></p>
  
  <p><strong>Example Output</strong></p>
  
  <p><a href="https://i.stack.imgur.com/KYyqO.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/KYyqO.jpg" alt="Example output image"></a></p>
  
  <p>How can I speed up my method, which being pixel by pixel over a very large array, takes minutes, using python and numpy?</p>
  
  <hr>
  
  <h2>Code:</h2>
  
  <pre><code>(x_d, y_d, z_d) = image.shape #get image dimensions
  (x_c, y_c) = (x_d/2.0, y_d/2.0) #determine centre of image
  new_image = np.zeros([x_m, y_m, d]) #create empty output image
  
  for x in range(0, x_d): #iterate across pixels
      for y in range(0, y_d): #iterate down pixels
          (x_1, y_1) = (x-x_c, y-y_c) #determine pixel displacement from centre
          (r_x, r_y) = (np.sqrt((rad**2.0)-(y_1**2.0)), np.sqrt((rad**2.0)-(x_1**2.0))) #determine relative radius (maths part 2)
          #determine the relative radius
          x_2 = int(np.round(r_x*np.sin(x_1/r_x), 0)) #determine new x-position (maths part 1)
          y_2 = int(np.round(r_y*np.sin(y_1/r_y), 0)) #determine new y-position (maths part 1)
          x_2 = int(np.round(x_2+x_c, 0)) #convert back to absolute pixel location
          y_2 = int(np.round(y_2+y_c, 0)) #convert back to absolute pixel location
          new_image[x_2, y_2, :] = image[x, y, :] #...place the pixel there
  </code></pre>
  
  <hr>
  
  <h2>Attempts:</h2>
  
  <p>I have searched for pre-built libraries to do this, but I struggle with some of the specific terminology and haven't found anything yet.</p>
  
  <p>I have tried reading and writing array values using numpy's item and itemset functions, but that actually seems to slow down the processing.</p>
  
  <p>Since I will be running this over multiple images I have tried generating the transformation array first, but this has only a very small impact on run times. ie:</p>
  
  <pre><code>def generate_array(array, rad):
      """
      Function takes image and returns array that can be used to warp it
      """
      #array generated as code above but saved to 2 dimensional array for resultant x and y locations
      return array
  
  def spherize(image, array):
      """
      Function takes image and warps it up as defined by the array
      """
      #image processed as code above but maths is not performed, instead output x and y locations are read from previously generated array
      return new_image
  </code></pre>
  
  <hr>
  
  <h2>Maths:</h2>
  
  <p><a href="https://i.stack.imgur.com/IpT2u.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/CXQKk.png" alt="Image explaining maths part 1 referred to in the code"></a>
  <em>Image explaining "maths part 1" as referred to in the code.</em> This gets the resultant pixel location as if seen from the top of the sphere on which the image has been pasted. This works in one dimension should the radius remain the same in the other dimension, however for a sphere this effective radius changes since the circle drawn out on the inside of the sphere becomes smaller the further away you are from the centre. As such "maths part 2" finds the effective radius of the circle drawn out on the inside of the sphere in x given a displacement from the centre of the sphere in y.</p>
  
  <p><a href="https://i.stack.imgur.com/KYyqO.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yaP1B.png" alt="Image explaining maths part 2 referred to in the code"></a>
  <em>Image explaining "maths part 2" as referred to in the code.</em> This finds the effective radius with which to calculate resultant x location based on the displacement from the centre of the sphere in y.</p>