3

I have a 2D numpy matrix of size 512x256. I can easily convert it to an image using PIL, or scipy, etc. but that gives me the shape of a rectangle of size 512x256, obviously. I am wondering if I can do something to make this matrix take shape of a cone like the figure attached? enter image description here

How I am thinking about it is that the first column of the matrix would be the left most line of the cone and the next column of the matrix would be a little right to that line, and so on. Since the angle between the two extremes is 45 degrees and I have 256 columns, that would be mean that each line gets an increment of (45/256) degree angle? These are just some rough thoughts but I wanted to learn from the community if they have any ideas about how should I proceed with this? I am envisioning a black square main image and this cone in the middle of it. Any ideas/thoughts?

Testing123
  • 363
  • 2
  • 12
  • you will always need the full pixel matrix to do an image, so when you want to transform from a equidistant cartesian coordinate system but still do a pixelbased picture you will have to think of a scheme of what to put into the pixels that per definition will be empty once you have made your cone. If you google 'projections' or 'transforms' you should find what you seek in terms of making your cone. But as pointed out, you still have the 'empty' pixels to fill to your liking. Or maybe you are lucky and someone has made a library for this, if so I'm not aware of it. – ahed87 Apr 08 '18 at 01:22
  • So, what do you actually want to achieve, i.e. what is the higher level of problem that you are looking at? I mean there are plenty of software out there that will blend/morph vector graphics (and pixel graphics as well), but your starting point is an image represented by a numpy matrix? – ahed87 Apr 08 '18 at 01:24
  • basically, you're looking for a transformation from polar coordinates to linear, where X in the orignal image is angle and Y is distance. [This post](https://stackoverflow.com/questions/3798333/image-information-along-a-polar-coordinate-system) might be of some use – Marat Apr 08 '18 at 01:42
  • @ahed87 - have you seen ultrasound images? They are of cone shape. You are right that my starting point wasn't a numpy matrix, it was raw data of numbers. I had to clean it up and all and then create several matrices, where each matrix represents a frame. And yes, Google didn't return any handy library that I can use for this transformation. – Testing123 Apr 09 '18 at 14:26

1 Answers1

2

Here is a quick & dirty solution that maps polar coordinates in the result image to rectangular coordinates in the original image and uses interp2d on each channel of the original image:

import numpy as np
from scipy import misc
from scipy.interpolate import interp2d
from math import pi, atan2, hypot

inputImagePath = 'wherever/whateverYouWantToInterpolate.jpg'
resultWidth = 800
resultHeight = 600
centerX = resultWidth / 2
centerY = - 50.0
maxAngle =  45.0 / 2 / 180 * pi
minAngle = -maxAngle
minRadius = 100.0
maxRadius = 600.0

inputImage = misc.imread(inputImagePath)
h,w,chn = inputImage.shape
print(f"h = {h} w = {w} chn = {chn}")
channels = [inputImage[:,:,i] for i in range(3)]
interpolated = [interp2d(range(w), range(h), c) for c in channels]
resultImage = np.zeros([resultHeight, resultWidth, 3], dtype = np.uint8)

for c in range(resultWidth):
  for r in range(resultHeight):
    dx = c - centerX
    dy = r - centerY
    angle = atan2(dx, dy) # yes, dx, dy in this case!
    if angle < maxAngle and angle > minAngle:
      origCol = (angle - minAngle) / (maxAngle - minAngle) * w
      radius = hypot(dx, dy)
      if radius > minRadius and radius < maxRadius:
        origRow = (radius - minRadius) / (maxRadius - minRadius) * h
        for chn in range(3):
          resultImage[r, c, chn] = interpolated[chn](origCol, origRow)

import matplotlib.pyplot as plt
plt.imshow(resultImage)
plt.show()

Produces:

warped logo of StackOverflow

The performance is terrible, didn't bother to "vectorize". Will update when find out how.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
  • Hey @Andrey. I just saw your answer and reading through the code. Btw, what's "chn" in "h,w,chn = inputImage.shape"? – Testing123 Apr 09 '18 at 14:28
  • @Testing123 number of color **ch**a**n**nels, should usually be `3`, could be omitted. I think if I replace the `3` at a few other places by `chn`, it should work with grayscale images too. ;; It's not China's country code, and the code is not "made in China" if you meant that... ;) – Andrey Tyukin Apr 09 '18 at 14:54
  • Ha ha..."China Fund Inc" sounds better :) Jokes apart, your solution works! – Testing123 Apr 15 '18 at 20:53