I have an application where I am using matplotlib to display elliptical regions on an image. To do this I'm using mpl.patches.Circle along with mp.patches.Affine2D to warp unit circles into an elliptical shape.
import numpy as np
import matplotlib as mpl
import pyplot as plt
invVR_mats = np.array([
[[ 7.80247545, 0. , 92.9254837 ],
[ -3.46026921, 10.85727882, 17.53866959],
[ 0. , 0. , 1. ]],
[[ 11.42656994, 0. , 76.86006927],
[ -3.26515651, 9.61946297, 24.79440498],
[ 0. , 0. , 1. ]],
[[ 10.40444851, 0. , 140.62428284],
[ -10.94557095, 10.59212685, 24.91024971],
[ 0. , 0. , 1. ]],])
invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
for invVR in invVR_mats]
ell_actors = [mpl.patches.Circle((0, 0), 1, transform=invVR)
for invVR in invVR_aff2Ds]
coll = mpl.collections.PatchCollection(ell_actors)
plt.figure()
ax = plt.gca()
ax.set_ylim(0, 100)
ax.set_xlim(0, 300)
ax.add_collection(coll)
There is a point in my application that the ellipses in one image are put in correspondence with ellipses from a second image using a homography matrix. So far I have been using it to warp points from image1 into image2.
I would like to get a visual idea of how these ellipses warp into image2. I can transform my affine matrices with this homography matrix, but the resulting matrix is no longer affine. (I believe it represents a general conic, either a circle, ellipse, hyperbola, or parabola)
from numpy.core.umath_tests import matrix_multiply
H = np.array([[ -0.70098, 0.12273, 5.18734],
[ 0.12444, -0.63474, 14.13995],
[ 0.00004, 0.00025, -0.64873]])
HinvVR_mats = matrix_multiply(H, invVR_mats)
print(HinvVR_mats)
#---------
np.array([
[[ -5.89405808e+00, 1.33251383e+00, -5.77990446e+01],
[ 3.16731132e+00, -6.89154916e+00, 1.45711021e+01],
[ -5.52968284e-04, 2.71431970e-03, -6.40628313e-01]],
[[ -8.41052966e+00, 1.18059669e+00, -4.56470140e+01],
[ 3.49444781e+00, -6.10585793e+00, 7.96641640e+00],
[ -3.59226330e-04, 2.40486574e-03, -6.39456996e-01]],
[[ -8.63666024e+00, 1.29997173e+00, -9.03302348e+01],
[ 8.24232128e+00, -6.72324660e+00, 1.58277039e+01],
[ -2.32021480e-03, 2.64803171e-03, -6.36877466e-01]]])
If I de-homogenize only the last column I can find the center of where the ellipse was projected, but I would like to see some shape information as well.
So far the best I've done is just de-homogenizing the last column and ignoring the values in [:, 2, 0] and [:, 2, 1]
HinvVR_mats = np.divide(HinvVR_mats , HinvVR_mats[:, None, None, 2, 2])
print(HinvVR_mats)
array([[[ 9.20043332e+00, -2.08001083e+00, 9.02224323e+01],
[ -4.94407015e+00, 1.07574845e+01, -2.27450173e+01],
[ 8.63165541e-04, -4.23696494e-03, 1.00000000e+00]],
[[ 1.31526118e+01, -1.84624877e+00, 7.13840248e+01],
[ -5.46471120e+00, 9.54850438e+00, -1.24580956e+01],
[ 5.61767769e-04, -3.76079354e-03, 1.00000000e+00]],
[[ 1.35609449e+01, -2.04116458e+00, 1.41832989e+02],
[ -1.29417694e+01, 1.05565779e+01, -2.48520394e+01],
[ 3.64311021e-03, -4.15783546e-03, 1.00000000e+00]]])
Is there a way I can tranform mpl.patches.Circle (or any other patch for that matter) using a non-affine matrix. The documentation seems to suggest it is possible, but I'm not seeing any way to go about it.
I have
I was able to solve this by looking at the tutorial posted by tcaswell
I had to create my own tranformation class though which looked like this
class HomographyTransform(mpl.transforms.Transform):
"""
References:
http://stackoverflow.com/questions/28401788/using-homogeneous-transforms-non-affine-with-matplotlib-patches?noredirect=1#comment45156353_28401788
http://matplotlib.org/users/transforms_tutorial.html
"""
input_dims = 2
output_dims = 2
is_separable = False
def __init__(self, H, axis=None, use_rmin=True):
mpl.transforms.Transform.__init__(self)
self._axis = axis
self._use_rmin = use_rmin
self.H = H
def transform_non_affine(self, input_xy):
"""
The input and output are Nx2 numpy arrays.
"""
import vtool as vt
_xys = input_xy.T
xyz = vt.add_homogenous_coordinate(_xys)
xyz_t = vt.matrix_multiply(self.H, xyz)
xy_t = vt.remove_homogenous_coordinate(xyz_t)
output_xy = xy_t.T
return output_xy
#transform_non_affine.__doc__ = mpl.transforms.Transform.transform_non_affine.__doc__
def transform_path_non_affine(self, path):
vertices = path.vertices
if len(vertices) == 2 and vertices[0, 0] == vertices[1, 0]:
return mpl.path.Path(self.transform(vertices), path.codes)
ipath = path.interpolated(path._interpolation_steps)
return mpl.path.Path(self.transform(ipath.vertices), ipath.codes)
#transform_path_non_affine.__doc__ = mpl.transforms.Transform.transform_path_non_affine.__doc__
The functions called by my own library vtool are:
def add_homogenous_coordinate(_xys):
assert _xys.shape[0] == 2
_zs = np.ones((1, _xys.shape[1]), dtype=_xys.dtype)
_xyzs = np.vstack((_xys, _zs))
return _xyzs
def remove_homogenous_coordinate(_xyzs):
assert _xyzs.shape[0] == 3
_xys = np.divide(_xyzs[0:2], _xyzs[None, 2])
return _xys
and matrix_multiply is the same matrix_multiply used earlier.
and my function to create the transform matrices currently looks like this:
def get_invVR_aff2Ds(kpts, H=None):
""" Returns matplotlib keypoint transformations (circle -> ellipse) """
#invVR_mats = ktool.get_invV_mats(kpts, with_trans=True, with_ori=True)
invVR_mats = ktool.get_invVR_mats3x3(kpts)
if H is None:
invVR_aff2Ds = [mpl.transforms.Affine2D(invVR)
for invVR in invVR_mats]
else:
# not actually affine
invVR_aff2Ds = [HomographyTransform(H.dot(invVR))
for invVR in invVR_mats]
return invVR_aff2Ds
Related
I want to apply a transformation matrix to a set of points. So the set of points:
points = np.array([[0 ,20], [0, 575], [0, 460]])
And I want to use the matrix I calculated with cv2.getPerspectiveTransform() which is a 3x3 matrix.
matrix = np.array([
[ -4. , -3. , 1920. ],
[ -2.25 , -1.6875 , 1080. ],
[ -0.0020833, -0.0015625, 1. ]])
Then I pass the array and a matrix to the following function:
def poly_points_transform(poly_points, matrix):
poly_points_transformed = np.empty_like(poly_points)
for i in range(len(poly_points)):
point = np.array([[poly_points[i]]])
transformed_point = cv2.perspectiveTransform(point, matrix)
np.append(poly_points_transformed, transformed_point)
return poly_points_transformed
Now It doesn't throw an error, but it just copies the src array to the poly_points_transformed. It might be something really rudimentary and stupid. If it is the case, I am sorry, but could someone give me a hint on what is wrong? Thanks in advance
We may solve it with one line of code:
transformed_point = cv2.perspectiveTransform(np.array([points], np.float64), matrix)[0]
As Micka commented cv2.perspectiveTransform takes a list of points (and returns a list of points as output).
np.array([points]) is used because cv2.perspectiveTransform expects 3D array.
For details see trouble getting cv.transform to work.
np.float64 is used in case the dtype of points is int32 (the method accepts float64 and float32 types).
[0] is used for removing the redundant dimension (convert from 3D to 2D).
For fixing the loop, replace np.append(poly_points_transformed, transformed_point) with:
poly_points_transformed[i] = transformed_point[0].
Since the array is initialized to poly_points_transformed = np.empty_like(poly_points), we can't use np.append().
Code sample:
import cv2
import numpy as np
points = np.array([[0.0 ,20.0], [0.0, 575.0], [0.0, 460.0]])
matrix = np.array([
[ -4. , -3. , 1920. ],
[ -2.25 , -1.6875 , 1080. ],
[ -0.0020833, -0.0015625, 1. ]])
# transformed_point = cv2.perspectiveTransform(np.array([points], np.float64), matrix)[0]
def poly_points_transform(poly_points, matrix):
poly_points_transformed = np.empty_like(poly_points)
for i in range(len(poly_points)):
point = np.array([[poly_points[i]]])
transformed_point = cv2.perspectiveTransform(point, matrix)
poly_points_transformed[i] = transformed_point[0] #np.append(poly_points_transformed, transformed_point)
return poly_points_transformed
poly_points_transformed = poly_points_transform(points, matrix)
The result is:
poly_points_transformed =
array([[1920., 1080.],
[1920., 1080.],
[1920., 1080.]])
Why are we getting [1920.0, 1080.0] value for all the transformed points?
Lets transform the middle point mathematically:
Multiply matrix by point (with 1 in the third index)
[ -4. , -3. , 1920. ] [ 0]
[ -2.25 , -1.6875 , 1080. ] * [575] =
[ -0.0020833, -0.0015625, 1. ] [ 1]
p = matrix # np.array([[0.0], [575.0], [1.0]]) =
[1.950000e+02]
[1.096875e+02]
[1.015625e-01]
Now divide the coordinates by the last element (converting homogeneous coordinates to Euclidian coordinates):
[1.950000e+02/1.015625e-01] [1920]
[1.096875e+02/1.015625e-01] = p / p[2] = [1080]
[1.015625e-01/1.015625e-01] [ 1]
The equivalent Euclidian point is [1920, 1080].
The transformation matrix may be wrong, because it transforms all the input points (with x coordinate equals 0) to the same output point...
I have this function for computing a rotation matrix:
import numpy as np
from scipy.spatial.transform import Rotation as R
def rotation_matrix(phi,theta,psi):
# Pure rotation in X
def Rx(phi):
return np.matrix([[ 1, 0 , 0 ],
[ 0, np.cos(phi) ,-np.sin(phi) ],
[ 0, np.sin(phi) , np.cos(phi)]])
# Pure rotation in y
def Ry(theta):
return np.matrix([[ np.cos(theta), 0, np.sin(theta)],
[ 0 , 1, 0 ],
[-np.sin(theta) , 0, np.cos(theta)]])
# Pure rotation in z
def Rz(psi):
return np.matrix([[ np.cos(psi), -np.sin(psi) , 0 ],
[ np.sin(psi) , np.cos(psi) , 0 ],
[ 0 , 0 , 1 ]])
return Rx(phi)*Ry(theta)*Rz(psi)
I know that scipy has a built-in function to compute rotation matrices, however I am being able to get the same results as the function.
I have the following example:
rotVec = np.array([np.pi/3, np.pi/4, 0]) # 60º in x-axis, 45º in y-axis
rotMat1 = rotation_matrix(*rotVec)
rotMat2 = R.from_euler('xyz', rotVec).as_matrix() # not the same result
What am I doing wrong?
OK...
It appears to be with capital letters in the rotation axis
rotVec = np.array([np.pi/3, np.pi/4, 0]) # 60º in x-axis, 45º in y-axis
rotMat1 = rotation_matrix(*rotVec)
rotMat2 = R.from_euler('XYZ', rotVec).as_matrix()
soo, for rotational matrix you need to multiplication from right to left, so this
return Rx(phi)*Ry(theta)*Rz(psi)
should be:
return Rz(psi)* Ry(theta)*Rx(phi)
instead
I'm implementing the Nearest Centroid Classification algorithm and I'm kind of blocked on how to use numpy.mean in my case.
So suppose I have some spherical datasets X:
[[ 0.39151059 3.48203037]
[-0.68677876 1.45377717]
[ 2.30803493 4.19341503]
[ 0.50395297 2.87076658]
[ 0.06677012 3.23265678]
[-0.24135103 3.78044279]
[-0.05660036 2.37695381]
[ 0.74210998 -3.2654815 ]
[ 0.05815341 -2.41905942]
[ 0.72126958 -1.71081388]
[ 1.03581142 -4.09666955]
[ 0.23209714 -1.86675298]
[-0.49136284 -1.55736028]
[ 0.00654881 -2.22505305]]]
and the labeled vector Y:
[0. 0. 0. 0. 0. 0. 0. 1. 1. 1. 1. 1. 1. 1.]
An example with 100 2D data points gives the following result:
The NCC algorithm consists of first calculating the class mean of each class (0 and 1: that's blue and red) and then calculating the nearest class centroid for the next data point.
This is my current function:
def mean_ncc(X,Y):
# find unique classes
m_cids = np.unique(Y) #[0. 1.]
# compute class means
mu = np.zeros((len(cids), X.shape[1])) #[[0. 0.] [0. 0.]] (in the case where Y has 2 unique points (0 and 1)
for class_idx, class_label in enumerate(cids):
mu[class_idx, :] = #problem here
return mu
So here I want an array containing the class means of '0' (blue) points and '1' (red) points:
How can I specify the number of elements of X whose mean I want to calculate?
I would like to do something like this:
for class_idx, class_label in enumerate(m_cids):
mu[class_idx, :] = np.mean(X[only the elements,that contains the same class_label], axis=0)
Is it possible or is there another way to implement this?
You could use something like this:
import numpy as np
tags = [0, 0, 1, 1, 0, 1]
values = [5, 4, 2, 5, 9, 8]
tags_np = np.array(tags)
values_np = np.array(values)
print(values_np[tags_np == 1].mean())
EDIT: You will surely need to look more into the axis parameter for the mean function:
import numpy as np
values = [[5, 4],
[5, 4],
[4, 3],
[4, 3]]
values_np = np.array(values)
tags_np = np.array([0, 0, 1, 1])
print(values_np[tags_np == 0].mean(axis=0))
Suppose that I have an variable x with the shape of (Time: 127, bottom_top: 58, south_north: 76, west_east: 96), where the bottom_top does not explicitly contain the value of original pressure. That is to say that the original pressure level come from a new variable p with the same shape of (Time: 127, bottom_top: 58, south_north: 76, west_east: 96).
What I want to do is to conduct an interpolation in the bottom_top direction of x from original pressure p to a new pressure level p_new. For exampe,
x[0,:,1,1].values =
array([404.13263, 404.13217, 404.13174, 404.11353, 404.11615, 404.1033 ,
404.0999 , 404.0954 , 404.0902 , 404.07092, 404.05087, 404.04208,
404.0345 , 404.01535, 403.98822, 403.95865, 403.92953, 403.90146,
403.88913, 403.88214, 403.87677, 403.8698 , 403.86185, 403.8513 ,
403.83362, 403.8124 , 403.791 , 403.76935, 403.7525 , 403.72525,
403.6679 , 403.61584, 403.52277, 403.44308, 403.36752, 403.2787 ,
403.17352, 403.0464 , 402.89468, 402.69656, 402.52823, 402.40897,
402.3129 , 402.2052 , 402.11267, 402.06073, 402.03674, 401.99417,
401.81857, 401.57474, 401.34845, 401.14847, 400.97156, 400.95645,
400.92035, 400.7942 , 400.16495, 398.33502], dtype=float32)
p[0,:,1,1].values =
array([86983.83 , 86819.19 , 86656.23 , 86487.69 , 86326.62 , 86120.52 ,
85831.95 , 85461.48 , 85050.03 , 84598. , 84103.71 , 83613.43 ,
83075.71 , 82500. , 81923.46 , 81346.94 , 80730.56 , 80030.49 ,
79289.44 , 78507.66 , 77642.914 , 76696.05 , 75707.52 , 74719.38 ,
73690.03 , 72619.51 , 71549.4 , 70438.445 , 69286.41 , 68093.85 ,
66819.19 , 65503.797 , 64148.29 , 62711.4 , 61234.523 , 59716.75 ,
58158.11 , 56557.582 , 54874.125 , 53109.348 , 51303.953 , 49458.043 ,
47530.21 , 45519.61 , 43423.426 , 41243.23 , 38992.438 , 36712.22 ,
34389.49 , 31879.646 , 29135.926 , 26400.299 , 23733.72 , 20932.85 ,
18026.195 , 15077.396 , 11595.89 , 7294.6274], dtype=float32)
p_new =
array([1.00758e+05, 9.00880e+04, 8.03100e+04, 7.13940e+04, 6.32770e+04,
5.59420e+04, 4.93250e+04, 4.33770e+04, 3.80270e+04, 3.32140e+04,
2.89180e+04, 2.50580e+04, 2.16130e+04, 1.85420e+04, 1.58370e+04,
1.34660e+04, 1.14090e+04, 9.64300e+03, 8.15100e+03, 6.90200e+03,
5.86000e+03, 4.98700e+03, 4.25500e+03, 3.63600e+03, 3.11200e+03,
2.66800e+03, 2.29100e+03, 1.97200e+03, 1.69900e+03, 1.46600e+03,
1.26700e+03, 1.09600e+03, 9.49000e+02, 8.23000e+02, 7.15000e+02,
6.21000e+02, 5.40000e+02, 4.70000e+02, 4.10000e+02, 3.58000e+02,
3.12000e+02, 2.73000e+02, 2.40000e+02, 2.10000e+02, 1.85000e+02,
1.63000e+02, 1.43000e+02, 1.26000e+02, 1.11000e+02, 9.80000e+01,
8.70000e+01, 7.70000e+01, 6.70000e+01, 5.90000e+01, 5.20000e+01,
4.60000e+01, 4.00000e+01, 3.50000e+01, 3.10000e+01, 2.70000e+01,
2.40000e+01, 2.10000e+01, 1.80000e+01, 1.60000e+01, 1.40000e+01,
1.20000e+01, 1.00000e+01, 9.00000e+00, 8.00000e+00, 7.00000e+00,
6.00000e+00])
Is there any method that I can directly interpolate like
x_new = interpolation(x,p,p_new).
Thanks in advance.
I need to interpolate along various axes quite frequently. I use the following as a general solution. There are easier specific solutions. e.g iterate along each axis using nested for loops. I have the iter_1d function in a numpy utilities file. I'm not sure it's the best approach but it's worked well for me.
# A general solution
import numpy as np
from scipy.interpolate import interp1d
# I've found this useful but never know whether there's a better way
def iter_1d( shape, axis=-1 ):
""" Iterator for all 1d slices along 'axis' in an array of 'shape'.
It returns a generic selection, not a selection of a specific array
Usage: for s in iterate_1d(arr.shape, 2):
print(arr[s], b[s], c[s])
"""
while axis<0:
axis+=len(shape)
limits = list(shape) # [ 127, 58, 76, 96 ]
current = [0]*len(shape) # [ 0, 0, 0, 0 ]
current[axis] = slice(None) # [ 0, :, 0, 0 ]
target = list(range(len(shape)-1, -1, -1)) # Reversed array of axis pointers
# e.g 4d case: target = [ 3, 2, 1, 0 ]
target.remove(axis) # Remove the 'axis' index from this list
# e,g, case: axis = 1 from above target = [ 3, 2, 0 ]
def incr_current():
""" Increments the 'right hand' index in current.
If this overflows, increnent the one before etc...
Returns True until axis 0 overflows, then returns False
"""
nonlocal current
for ix in target:
current[ix] += 1
if current[ix] < limits[ix]: return True
current[ix] = 0
return False
cont=True
while cont:
yield tuple(current)
cont = incr_current()
# Thos can iterate 1d slices along any axis. The question is for axis 1
def do_interpolate( x_new, x, y, axis=-1 ):
""" Will interpolate all 1D slices of the axis specified."""
result = np.empty_like(x_new)
for sel in iter_1d( x.shape, axis ):
do_interp = interp1d(x[sel], y[sel], fill_value='extrapolate')
result[sel] = do_interp(x_new[sel])
return result
x_new = do_interpolate( p_new, p, x, axis = 1 )
The interpolation functions all work from a 1d independent variable so as each set of p is associated with a different set of x the interpolation object must be generated for each slice.
For the specific requirement in the question it may be easier to simply iterate with loops.
# Specific solution
def interpolate( x, p, p_new):
result = np.empty_like(p_new)
for t in range(127):
for ns in range(76):
for ew in range(96):
sel = np.s_[t, :, ns, ew]
do_interp = interp1d(p[sel], x[sel], fill_value='extrapolate')
result[sel] = do_interp(p_new[sel])
return result
x_new = interpolate( x, p, p_new )
I'm working on Python 2.7. I have to define some Areas of Interest (AoI) on a picture. Basically, I'm trying to do this drawing an ellipse (or more) on a specific part of the picture and to get the coordinates (x; y) of its contour. I want to save these coordinates on a file, in order to use them later to see whether (or not) my data are inside this area.
This is my code:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Ellipse, Circle
from matplotlib.path import Path
# Get an example image
img = imread('sposa.png')
# Create a figure. Equal aspect so circles look circular
fig,ax = plt.subplots(1)
ax.set_aspect('equal')
# Show the image
ax.imshow(img)
ax.set_xlim(0,1600)
ax.set_ylim(0,1200)
# Now, loop through coord arrays, and create a circle at each x,y pair
ellipse = Ellipse((1000, 400), width=400, height=100, edgecolor='white',facecolor='none',linewidth=2)
ax.add_patch(ellipse)
path = ellipse.get_path()
# Show the image
plt.show()
When I run the code, I get this (that is exactly what I want):
However, when I print the path in order to check it, I get the following output, which (I suppose) is exclusively related to the ellipse.
Path(array([[ 0. , -1. ],
[ 0.2652031 , -1. ],
[ 0.51957987, -0.89463369],
[ 0.70710678, -0.70710678],
[ 0.89463369, -0.51957987],
[ 1. , -0.2652031 ],
[ 1. , 0. ],
[ 1. , 0.2652031 ],
[ 0.89463369, 0.51957987],
[ 0.70710678, 0.70710678],
[ 0.51957987, 0.89463369],
[ 0.2652031 , 1. ],
[ 0. , 1. ],
[-0.2652031 , 1. ],
[-0.51957987, 0.89463369],
[-0.70710678, 0.70710678],
[-0.89463369, 0.51957987],
[-1. , 0.2652031 ],
[-1. , 0. ],
[-1. , -0.2652031 ],
[-0.89463369, -0.51957987],
[-0.70710678, -0.70710678],
[-0.51957987, -0.89463369],
[-0.2652031 , -1. ],
[ 0. , -1. ],
[ 0. , -1. ]]), array([ 1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 79], dtype=uint8))
However, I need a list of coordinates of the ellipse in relation to the pixel of the picture (1600 X 1200). I'm probably using the wrong function or there is something that does not match between the picture and the ellipse.
I should obtain something like this (this is an example from a previous experiment):
[ Path(array([[ 1599. , 868.86791294],
[ 1598. , 868.87197971],
[ 1597. , 868.8801087 ],
...,
[ 1597. , 675.30378536],
[ 1598. , 675.31373204],
[ 1599. , 675.31870792]]), None)]
665
Can anyone help me?
Thank you in advance,
R
You should use Ellipse.get_path().vertices, however it's not in the correct coordinates system. To transform it, apply ellipse.get_patch_transform().transform to it. See below a working example
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
from matplotlib.path import Path
from matplotlib.patches import PathPatch
img = plt.imread("image.jpg")
fig, ax = plt.subplots(1)
ax.set_aspect('equal')
ax.imshow(img)
# Create the base ellipse
ellipse = Ellipse((300, 300), width=400, height=100,
edgecolor='white', facecolor='none', linewidth=2)
# Get the path
path = ellipse.get_path()
# Get the list of path vertices
vertices = path.vertices.copy()
# Transform the vertices so that they have the correct coordinates
vertices = ellipse.get_patch_transform().transform(vertices)
# You can then save the vertices array to a file: csv, pickle... It's up to you
plt.show()
the path array appears to be a coarse normalized circle - I'd ignore it
you have the ellipse info already
ellipse = Ellipse((1000, 400), width=400, height=100, ...)
I would just do a sin, cos paramaterized ellipse based on the 1st few numbers in Ellipse((1000, 400), width=400, height=100which are the center point and axis lengths if you want to draw a hi res ellipse explicitly
for a membership test (x - x_0)^2/a^2 + (y - y_0)^2/b^2 <= 1 is probably best where a, b
are 1/2 of the respective width=400, height=100
of course you would only need to test pixel indices within the bounding rectangle