Rotate small portion of an array by 90 degrees - python

I want to rotate an array but not as a whole, only small portion of it.
I have 512X512 array (basically it is a Gaussian circle at the center (150,150) with 200 radius). Now I want to rotate only small portion (center around (150,150) with radius 100) of the array by 90 degree. Initially I used numpy rot90 module but it rotate each array element which is not I want.

If you can describe the elements that you would like rotated using advanced indexing, then you should be able to perform the rotation using something like the following (assuming your array is called arr):
arr[rs:re,cs:ce] = np.rot90(np.copy(arr[rs:re,cs:ce]))
Here rs, re, cs, and ce would signify the row-start and row-end of a slice, and the column-start and column-end of a slice, respectively.
Here is an example of why the np.copy call is necessary (at least in numpy 1.3.0):
>>> import numpy as np
>>> m = np.array([[i]*4 for i in range(4)])
>>> m
array([[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])
>>> m[1:3,1:3] = np.rot90(m[1:3,1:3]) # rotate middle 2x2
>>> m
array([[0, 0, 0, 0],
[1, 1, 2, 1], # got 1, 2 expected 1, 2
[2, 1, 1, 2], # 1, 1 1, 2
[3, 3, 3, 3]])

Here is some fuller code that does as F.J. has already explained.
And here is the code:
import numpy as np
import scipy
def circle(im, centre_x, centre_y, radius):
grid_x, grid_y = np.mgrid[0:im.shape[0],0:im.shape[1]]
return (grid_x-centre_x)**2 + (grid_y-centre_y)**2 < radius**2
centre_x, centre_y, radius = 150, 200, 100
x_slice = slice(centre_x - radius, centre_x + radius)
y_slice = slice(centre_y - radius, centre_y + radius)
im = scipy.misc.imread('1_tree.jpg')
rotated_square = np.rot90(im[x_slice,y_slice].copy())
im[circle(im, centre_x, centre_y,radius)] = rotated_square[circle(rotated_square,
radius, radius, radius)]
scipy.misc.imsave('sdffs.png',im)

Related

How to find the rotation matrix of 3 orthogonal vectors in space. My current method rotates the vectors to the wrong orientation

I am looking to find the rotation matrix for getting three (almost) orthogonal vectors to be in the same orientation of the world coordinate system.
My three (almost) orthogonal vectors can be represented like this in python:
vectors = np.array([[ 0.43187079, 0.90161148, 0.02417362],
[-0.46076794, 0.19750816, 0.86526495],
[ 0.77535832, -0.38482109, 0.50073167]])
The code I currently use can get the vectors to be parallel to the world coordinates but the orientation is incorrect. Running this code,
xrotation = np.arctan2(vectors[2, 1], vectors[2, 2])
xRot = np.array([[1, 0, 0],
[0, np.cos(xrotation), -np.sin(xrotation)],
[0, np.sin(xrotation), np.cos(xrotation)]])
vectors_x = np.zeros((3, 3))
for i in range(3):
vectors_x[i, :] = np.linalg.inv(xRot.transpose()) # vectors[i, :]
yrotation = np.arctan2(vectors_x[1, 2], vectors_x[1, 0])
yRot = np.array([[np.cos(yrotation), 0, np.sin(yrotation)],
[0, 1, 0],
[-np.sin(yrotation), 0, np.cos(yrotation)]])
vectors_y = np.zeros((3, 3))
for i in range(3):
vectors_y[i, :] = np.linalg.pinv(yRot.transpose()) # vectors_x[i, :]
zrotation = np.arctan2(vectors_y[0, 0], vectors_y[0, 1])
zRot = np.array([[np.cos(zrotation), -np.sin(zrotation), 0],
[np.sin(zrotation), np.cos(zrotation), 0],
[0, 0, 1]])
vectors_z = np.zeros((3, 3))
for i in range(3):
vectors_z[i, :] = np.linalg.pinv(zRot.transpose()) # vectors_y[i, :]
Gives the three rotated orthogonal vectors:
>vectors_z
>array([[-1.11022302e-16, 1.00000000e+00, 3.19660393e-09],
[ 1.00000000e+00, -3.70417658e-09, -2.77555756e-16],
[ 2.12261116e-09, -1.98949113e-09, -1.00000000e+00]])
What do I need to change in the code to get it in the correct orientation which would look like:
array([[ 1, 0, 0],
[ 0, 1, 0],
[ 0, 0, 1]])
I know it's possible to get this by rotating the vectors 90/180 deg in the correct order but there has gotta be a more efficient way to do this by doing something else in the code above.
Thanks for your time!!!
Figured it out. Switched to a ZYZ rotation pattern and redid the euler angle calculation method. Hope this helps someone some day.
import numpy as np
def z_rotation(zrotation):
z1Rot = np.array([[np.cos(zrotation), -np.sin(zrotation), 0],
[np.sin(zrotation), np.cos(zrotation), 0],
[0, 0, 1]])
return z1Rot
def y_rotation(yrotation):
yRot = np.array([[np.cos(yrotation), 0, np.sin(yrotation)],
[0, 1, 0],
[-np.sin(yrotation), 0, np.cos(yrotation)]])
return yRot
def forward_rotation(Rot,vectors_in):
vectors = np.zeros((3, 3))
for i in range(3):
vectors[i, :] = vectors_in[i, :] # Rot
return vectors
def reverse_rotation(Rot, vectors_in):
vectors = np.zeros((3, 3))
for i in range(3):
vectors[i, :] = np.linalg.pinv(Rot.transpose()) # vectors_in[i, :]
return vectors
org_vectors = np.array([[1,0,0],[0,1,0],[0,0,1]])
z1_angle = (-.5 + np.random.random()) * 1800
y_angle = (-.5 + np.random.random()) * 1800
z2_angle = (-.5 + np.random.random()) * 1800
z1 = z1_angle*np.pi/180
y = y_angle*np.pi/180
z2 = z2_angle*np.pi/180
z1Rot = z_rotation(z1)
z1vectors = forward_rotation(z1Rot, org_vectors)
yRot = y_rotation(y)
yvectors = forward_rotation(yRot, z1vectors)
z2Rot = z_rotation(z2)
z2vectors = forward_rotation(z2Rot, yvectors)
z2angle_calc = np.arctan2(z2vectors[2,1],z2vectors[2,0])
z2rot_2 = z_rotation(z2angle_calc)
new_y = forward_rotation(z2rot_2, z2vectors)
yangle_2 = np.arctan2(new_y[2,0],new_y[2,2])
yrot_2 = y_rotation(yangle_2)
new_z1 = forward_rotation(yrot_2, new_y)
z1angle_2 = yangle_2 = np.arctan2(new_z1[0,1],new_z1[0, 0])
z1rot_2 = z_rotation(z1angle_2)
new_org_vectors = forward_rotation(z1rot_2, new_z1)
print(new_org_vectors)

Extract sub arrays based on kernel in numpy

I would like to know if there is an efficient method to get sub-arrays from a larger numpy array.
What I have is an application of np.where. I iterate 'manually' over x and y as offsets and apply where with a kernel to each rectangle extracted from the larger array with proper dimensions.
But is there a more direct approach in numpy's collection of methods?
import numpy as np
example = np.arange(20).reshape((5, 4))
# e.g. a cross kernel
a_kernel = np.asarray([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
np.where(a_kernel, example[1:4, 1:4], 0)
# returns
# array([[ 0, 6, 0],
# [ 9, 10, 11],
# [ 0, 14, 0]])
def arrays_from_kernel(a, a_kernel):
width, height = a_kernel.shape
y_max, x_max = a.shape
return [np.where(a_kernel, a[y:(y + height), x:(x + width)], 0)
for y in range(y_max - height + 1)
for x in range(x_max - width + 1)]
sub_arrays = arrays_from_kernel(example, a_kernel)
This returns the arrays I need for further processing.
# [array([[0, 1, 0],
# [4, 5, 6],
# [0, 9, 0]]),
# array([[ 0, 2, 0],
# [ 5, 6, 7],
# [ 0, 10, 0]]),
# ...
# array([[ 0, 9, 0],
# [12, 13, 14],
# [ 0, 17, 0]]),
# array([[ 0, 10, 0],
# [13, 14, 15],
# [ 0, 18, 0]])]
The context: similar to 2D convolution I would like to apply a custom function on each of the subarrays (e.g. product of squared numbers).
At the moment, you're manually advancing a sliding window over the data - stride tricks to the rescue! (And no, I didn't just make that up - there's actually a submodule called stride_tricks in numpy!) Instead of manually building windows into the data, and calling np.where() on them, if you had the windows in an array, you could call np.where() just once. Stride tricks allow you to create such an array without even having to copy the data.
Let me explain. Normal slices in numpy create views into the original data instead of copies. This is done by referring to the original data, but changing the strides used to access the data (ie. how much to jump between two elements or two rows, and so on). Stride tricks allow you to modify those strides more freely than just slicing and reshaping does, so you can eg. iterate over the same data more than once, which is useful here.
Let me demonstrate:
import numpy as np
example = np.arange(20).reshape((5, 4))
a_kernel = np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
def sliding_window(data, win_shape, **kwargs):
assert data.ndim == len(win_shape)
shape = tuple(dn - wn + 1 for dn, wn in zip(data.shape, win_shape)) + win_shape
strides = data.strides * 2
return np.lib.stride_tricks.as_strided(data, shape=shape, strides=strides, **kwargs)
def arrays_from_kernel(a, a_kernel):
windows = sliding_window(a, a_kernel.shape)
return np.where(a_kernel, windows, 0)
sub_arrays = arrays_from_kernel(example, a_kernel)
The scipy.ndimage module offers a number of filters -- one of which might meet your needs. If none of those filters do what you want, you could use ndimage.generic_filter
to call a custom function on each subarray. ndimage.generic_filter is not as fast as the other ndimage filters, however.
For example,
import numpy as np
example = np.arange(20).reshape((5, 4))
a_kernel = np.asarray([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
# def arrays_from_kernel(a, a_kernel):
# width, height = a_kernel.shape
# y_max, x_max = a.shape
# return [np.where(a_kernel, a[y:(y + height), x:(x + width)], 0)
# for y in range(y_max - height + 1)
# for x in range(x_max - width + 1)]
# sub_arrays = arrays_from_kernel(example, a_kernel)
# for arr in sub_arrays:
# print(arr)
# print('-'*80)
import scipy.ndimage as ndimage
def func(x):
# reject subarrays that extend beyond the border of the `example` array
if not np.isnan(x).any():
y = np.zeros_like(a_kernel, dtype=example.dtype)
np.put(y, np.flatnonzero(a_kernel), x)
print(y)
# Instead or returning 0, you can perform your desired computation on the subarray here.
# Note that you may not need the 2D array y; often, you only need the values in the 1D array x
return 0
result = ndimage.generic_filter(example, func, footprint=a_kernel, mode='constant', cval=np.nan)
For the particular problem of computing the product of squares for each subarray, you
could convert the product into a sum by taking advantage of the fact that A * B = exp(log(A)+log(B)). This would allow you to express the computation as a normal convolution. Now using ndimage.convolve can improve performance a lot. The amount of the improvement depends on the size of example:
import numpy as np
import scipy.ndimage as ndimage
import perfplot
a_kernel = np.asarray([[0, 1, 0], [1, 1, 1], [0, 1, 0]])
def orig(example, a_kernel=a_kernel):
def arrays_from_kernel(a, a_kernel):
width, height = a_kernel.shape
y_max, x_max = a.shape
return [
np.where(a_kernel, a[y : (y + height), x : (x + width)], 1)
for y in range(y_max - height + 1)
for x in range(x_max - width + 1)
]
return [np.prod(x) ** 2 for x in arrays_from_kernel(example, a_kernel)]
def alt(example, a_kernel=a_kernel):
logged = np.log(example)
result = ndimage.convolve(logged, a_kernel, mode="constant", cval=0)[1:-1, 1:-1]
return (np.exp(result) ** 2).ravel()
def make_example(N):
return np.random.random(size=(N, N))
def check(A, B):
return np.allclose(A, B)
perfplot.show(
setup=make_example,
kernels=[orig, alt],
n_range=[2 ** k for k in range(2, 11)],
logx=True,
logy=True,
xlabel="len(example)",
equality_check=check,
)

2d numpy array, making each value the sum of the 3x3 square it is centered at

I have a square 2D numpy array, A, and an array of zeros, B, with the same shape.
For every index (i, j) in A, other than the first and last rows and columns, I want to assign to B[i, j] the value of np.sum(A[i - 1:i + 2, j - 1:j + 2].
Example:
A =
array([[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0])
B =
array([[0, 0, 0, 0, 0],
[0, 3, 4, 2, 0],
[0, 4, 6, 3, 0],
[0, 3, 4, 2, 0],
[0, 0, 0, 0, 0])
Is there an efficient way to do this? Or should I simply use a for loop?
There is a clever (read "borderline smartass") way to do this with np.lib.stride_tricks.as_strided. as_strided allows you to create views into your buffer that simulate windows by adding another dimension to the view. For example, if you had a 1D array like
>>> x = np.arange(10)
>>> np.lib.stride_tricks.as_strided(x, shape=(3, x.shape[0] - 2), strides=x.strides * 2)
array([[0, 1, 2, 3, 4, 5, 6, 7],
[1, 2, 3, 4, 5, 6, 7, 8],
[2, 3, 4, 5, 6, 7, 8, 9]])
Hopefully it is clear that you can just sum along axis=0 to get the sum of each size 3 window. There is no reason you couldn't extrend that to two or more dimensions. I've written the shape and index of the previous example in a way that suggests a solution:
A = np.array([[0, 0, 0, 0, 0],
[0, 1, 0, 1, 0],
[0, 1, 1, 0, 0],
[0, 1, 0, 1, 0],
[0, 0, 0, 0, 0]])
view = np.lib.stride_tricks.as_strided(A,
shape=(3, 3, A.shape[0] - 2, A.shape[1] - 2),
strides=A.strides * 2
)
B[1:-1, 1:-1] = view.sum(axis=(0, 1))
Summing along multiple axes simultaneously has been supported in np.sum since v1.7.0. For older versions of numpy, just sum repeatedly (twice) along axis=0.
Filling in the edges of B is left as an exercise for the reader (since it's not really part of the question).
As an aside, the solution here is a one-liner if you want it to be. Personally, I think anything with as_strided is already illegible enough, and doesn't need any further obfuscation. I'm not sure if a for loop is going to be bad enough performance-wise to justify this method in fact.
For future reference, here is a generic window-making function that can be used to solve this sort of problem:
def window_view(a, window=3):
"""
Create a (read-only) view into `a` that defines window dimensions.
The first ``a.ndim`` dimensions of the returned view will be sized according to `window`.
The remaining ``a.ndim`` dimensions will be the original dimensions of `a`, truncated by `window - 1`.
The result can be post-precessed by reducing the leading dimensions. For example, a multi-dimensional moving average could look something like ::
window_view(a, window).sum(axis=tuple(range(a.ndim))) / window**a.ndim
If the window size were different for each dimension (`window` were a sequence rather than a scalar), the normalization would be ``np.prod(window)`` instead of ``window**a.ndim``.
Parameters
-----------
a : array-like
The array to window into. Due to numpy dimension constraints, can not have > 16 dims.
window :
Either a scalar indicating the window size for all dimensions, or a sequence of length `a.ndim` providing one size for each dimension.
Return
------
view : numpy.ndarray
A read-only view into `a` whose leading dimensions represent the requested windows into `a`.
``view.ndim == 2 * a.ndim``.
"""
a = np.array(a, copy=False, subok=True)
window = np.array(window, copy=False, subok=False, dtype=np.int)
if window.size == 1:
window = np.full(a.ndim, window)
elif window.size == a.ndim:
window = window.ravel()
else:
raise ValueError('Number of window sizes must match number of array dimensions')
shape = np.concatenate((window, a.shape))
shape[a.ndim:] -= window - 1
strides = a.strides * 2
return np.lib.stride_tricks.as_strided(a, shake=shape, strides=strides)
I have found no 'simple' ways of doing this. But here are two ways:
Still involves a for loop
# Basically, get the sum for each location and then pad the result with 0's
B = [[np.sum(A[j-1:j+2,i-1:i+2]) for i in range(1,len(A)-1)] for j in range(1,len(A[0])-1)]
B = np.pad(B, ((1,1)), "constant", constant_values=(0))
Is longer but no for loops (this will be a lot more efficient on big arrays):
# Roll basically slides the array in the desired direction
A_right = np.roll(A, -1, 1)
A_left = np.roll(A, 1, 1)
A_top = np.roll(A, 1, 0)
A_bottom = np.roll(A, -1, 0)
A_bot_right = np.roll(A_bottom, -1, 1)
A_bot_left = np.roll(A_bottom, 1, 1)
A_top_right = np.roll(A_top, -1, 1)
A_top_left = np.roll(A_top, 1, 1)
# After doing that, you can just add all those arrays and these operations
# are handled better directly by numpy compared to when you use for loops
B = A_right + A_left + A_top + A_bottom + A_top_left + A_top_right + A_bot_left + A_bot_right + A
# You can then return the edges to 0 or whatever you like
B[0:len(B),0] = 0
B[0:len(B),len(B[0])-1] = 0
B[0,0:len(B)] = 0
B[len(B[0])-1,0:len(B)] = 0
You can just sum the 9 arrays that make up a block, each one being shifted by 1 w.r.t. the previous in either dimension. Using slice notation this can be done for the whole array A at once:
B = np.zeros_like(A)
B[1:-1, 1:-1] = sum(A[i:A.shape[0]-2+i, j:A.shape[1]-2+j]
for i in range(0, 3) for j in range(0, 3))
General version for arbitrary rectangular windows
def sliding_window_sum(a, size):
"""Compute the sum of elements of a rectangular sliding window over the input array.
Parameters
----------
a : array_like
Two-dimensional input array.
size : int or tuple of int
The size of the window in row and column dimension; if int then a quadratic window is used.
Returns
-------
array
Shape is ``(a.shape[0] - size[0] + 1, a.shape[1] - size[1] + 1)``.
"""
if isinstance(size, int):
size = (size, size)
m = a.shape[0] - size[0] + 1
n = a.shape[1] - size[1] + 1
return sum(A[i:m+i, j:n+j] for i in range(0, size[0]) for j in range(0, size[1]))

How can I mirror a polygon using Python?

I have a set of images over which polygons are drawn. I have the points of those polygons and I draw these using Shapely and check whether certain points from an eye tracker fall into the polygons.
Now, some of those images are mirrored but I do not have the coordinates of the polygons drawn in them. How can I flip the polygons horizontally? Is there a way to do this with Shapely?
if you want to reflect a polygon with respect to a vertical axis, i.e., to flip them horizontally, one option would be to use the scale transformation (using negative unit scaling factor) provided by shapely.affinity or to use a custom transformation:
from shapely.affinity import scale
from shapely.ops import transform
from shapely.geometry import Polygon
def reflection(x0):
return lambda x, y: (2*x0 - x, y)
P = Polygon([[0, 0], [1, 1], [1, 2], [0, 1]])
print(P)
#POLYGON ((0 0, 1 1, 1 2, 0 1, 0 0))
Q1 = scale(P, xfact = -1, origin = (1, 0))
Q2 = transform(reflection(1), P)
print(Q1)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
print(Q2)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
by multiplying [[1,0], [0,-1]], You can get the vertically flipped shape. (I tested this on jupyter notebook)
pts = np.array([[153, 347],
[161, 323],
[179, 305],
[195, 315],
[184, 331],
[177, 357]])
display(Polygon(pts))
display(Polygon(pts.dot([[1,0],[0,-1]])))
And If you multiply [[-1,0],[0,1]], you will get horizontally flipped shape.
Refer linear transformation to understand why this works.

Applying the Sobel filter using scipy

I'm trying to apply the Sobel filter on an image to detect edges using scipy. I'm using Python 3.2 (64 bit) and scipy 0.9.0 on Windows 7 Ultimate (64 bit). Currently my code is as follows:
import scipy
from scipy import ndimage
im = scipy.misc.imread('bike.jpg')
processed = ndimage.sobel(im, 0)
scipy.misc.imsave('sobel.jpg', processed)
I don't know what I'm doing wrong, but the processed image does not look anything like what it should. The image, 'bike.jpg' is a greyscale (mode 'L' not 'RGB') image so each pixel has only one value associated with it.
Unfortunately I can't post the images here yet (don't have enough reputation) but I've provided links below:
Original Image (bike.jpg):
http://s2.postimage.org/64q8w613j/bike.jpg
Scipy Filtered (sobel.jpg):
http://s2.postimage.org/64qajpdlb/sobel.jpg
Expected Output:
http://s1.postimage.org/5vexz7kdr/normal_sobel.jpg
I'm obviously going wrong somewhere! Can someone please tell me where. Thanks.
1) Use a higher precision. 2) You are only calculating the approximation of the derivative along the zero axis. The 2D Sobel operator is explained on Wikipedia. Try this code:
import numpy
import scipy
from scipy import ndimage
im = scipy.misc.imread('bike.jpg')
im = im.astype('int32')
dx = ndimage.sobel(im, 0) # horizontal derivative
dy = ndimage.sobel(im, 1) # vertical derivative
mag = numpy.hypot(dx, dy) # magnitude
mag *= 255.0 / numpy.max(mag) # normalize (Q&D)
scipy.misc.imsave('sobel.jpg', mag)
I couldn't comment on cgohlke's answer so I repeated his answer with a corrction. Parameter 0 is used for vertical derivative and 1 for horizontal derivative (first axis of an image array is y/vertical direction - rows, and second axis is x/horizontal direction - columns). Just wanted to warn other users, because I lost 1 hour searching for mistake in the wrong places.
import numpy
import scipy
from scipy import ndimage
im = scipy.misc.imread('bike.jpg')
im = im.astype('int32')
dx = ndimage.sobel(im, 1) # horizontal derivative
dy = ndimage.sobel(im, 0) # vertical derivative
mag = numpy.hypot(dx, dy) # magnitude
mag *= 255.0 / numpy.max(mag) # normalize (Q&D)
scipy.misc.imsave('sobel.jpg', mag)
or you can use :
def sobel_filter(im, k_size):
im = im.astype(np.float)
width, height, c = im.shape
if c > 1:
img = 0.2126 * im[:,:,0] + 0.7152 * im[:,:,1] + 0.0722 * im[:,:,2]
else:
img = im
assert(k_size == 3 or k_size == 5);
if k_size == 3:
kh = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype = np.float)
kv = np.array([[1, 2, 1], [0, 0, 0], [-1, -2, -1]], dtype = np.float)
else:
kh = np.array([[-1, -2, 0, 2, 1],
[-4, -8, 0, 8, 4],
[-6, -12, 0, 12, 6],
[-4, -8, 0, 8, 4],
[-1, -2, 0, 2, 1]], dtype = np.float)
kv = np.array([[1, 4, 6, 4, 1],
[2, 8, 12, 8, 2],
[0, 0, 0, 0, 0],
[-2, -8, -12, -8, -2],
[-1, -4, -6, -4, -1]], dtype = np.float)
gx = signal.convolve2d(img, kh, mode='same', boundary = 'symm', fillvalue=0)
gy = signal.convolve2d(img, kv, mode='same', boundary = 'symm', fillvalue=0)
g = np.sqrt(gx * gx + gy * gy)
g *= 255.0 / np.max(g)
#plt.figure()
#plt.imshow(g, cmap=plt.cm.gray)
return g
for more see here

Categories

Resources