def calculate_wake_distance(self): horizontal_line_image_coords = self.image_canvas.canvas.canvas_shape_coords_to_image_coords(self.variables.horizontal_line_id) sicd_meta = self.variables.image_reader.base_reader.sicd_meta points = np.asarray(np.reshape(horizontal_line_image_coords, (2, 2))) ecf_ground_points = point_projection.image_to_ground(points, sicd_meta) geo_ground_point_1 = geocoords.ecf_to_geodetic((ecf_ground_points[0, 0], ecf_ground_points[0, 1], ecf_ground_points[0, 2])) geo_ground_point_2 = geocoords.ecf_to_geodetic((ecf_ground_points[1, 0], ecf_ground_points[1, 1], ecf_ground_points[1, 2])) distance = math.sqrt( (ecf_ground_points[0, 0] - ecf_ground_points[1, 0])**2 + (ecf_ground_points[0, 1] - ecf_ground_points[1, 1])**2 + (ecf_ground_points[0, 2] - ecf_ground_points[1, 2])**2) return distance
def test_ecf_to_geodetic(self): out = geocoords.ecf_to_geodetic(ecf[0, :]) with self.subTest(msg="basic shape check"): self.assertEqual(out.shape, (3, )) with self.subTest(msg="basic value check"): self.assertTrue(numpy.all(numpy.abs(out - llh[0, :]) < tolerance)) out2 = geocoords.ecf_to_geodetic(ecf) with self.subTest(msg="2d shape check"): self.assertEqual(out2.shape, ecf.shape) with self.subTest(msg="2d value check"): self.assertTrue(numpy.all(numpy.abs(out2 - llh) < tolerance)) with self.subTest(msg="error check"): self.assertRaises(ValueError, geocoords.ecf_to_geodetic, numpy.arange(4))
def set_reference_point(self, reference_point=None): """ Sets the reference point, which must be provided in ECF coordinates. Parameters ---------- reference_point : None|numpy.ndarray The reference point (origin) of the planar grid. If None, then the `sicd.GeoData.SCP.ECF` will be used. Returns ------- None """ if reference_point is None: if self.sicd.RadarCollection.Area is None: reference_point = self.sicd.GeoData.SCP.ECF.get_array() else: reference_point = self.sicd.RadarCollection.Area.Plane.RefPt.ECF.get_array( ) if not (isinstance(reference_point, numpy.ndarray) and reference_point.ndim == 1 and reference_point.size == 3): raise ValueError('reference_point must be a vector of size 3.') self._reference_point = reference_point # set the reference hae ref_llh = ecf_to_geodetic(reference_point) self._reference_hae = ref_llh[2]
def get_geo_lon_lat(self): if hasattr(self.meta, "GeoData"): try: scp = [ self.meta.GeoData.SCP.ECF.X, self.meta.GeoData.SCP.ECF.Y, self.meta.GeoData.SCP.ECF.Z ] except Exception as e: logging.error( "Unable to get geolocation data in ECF form {}".format(e)) # TODO: might take this out if it's not part of the SICD standard elif hasattr(self.meta, "SRP"): if self.meta.SRP.SRPType == "FIXEDPT": scp = self.meta.SRP.FIXEDPT.SRPPT scp = [scp.X, scp.Y, scp.Z] elif self.meta.SRP.SRPType == "PVTPOLY": # TODO: implement this for the case where we need to do a polynomial pass try: lla = geocoords.ecf_to_geodetic(scp) lat = lla[0] lon = lla[1] except Exception as e: logging.error( "could not find latitude and longitude information in the SICD metadata. {}" .format(e)) return lat, lon
def _derive_corner_from_plane(self): # try to define the corner points - for SICD 0.5. if self.Corner is not None: return # nothing to be done if self.Plane is None: return # nothing to derive from corners = self.Plane.get_ecf_corner_array() self.Corner = [ LatLonHAECornerRestrictionType(**{'Lat': entry[0], 'Lon': entry[1], 'HAE': entry[2], 'index': i+1}) for i, entry in enumerate(geocoords.ecf_to_geodetic(corners))]
def _write_collection_wedge(kmz_document, sicd, time_args, arp_llh, time_array, folder): """ Writes the collection wedge. Parameters ---------- kmz_document : Document sicd : SICDType time_args : dict arp_llh : None|numpy.ndarray time_array : None|numpy.ndarray folder : minidom.Element Returns ------- None """ if time_array is None or arp_llh is None: return if sicd.Position is not None and sicd.Position.GRPPoly is not None: grp = sicd.Position.GRPPoly(time_array) elif sicd.GeoData is not None and sicd.GeoData.SCP is not None: grp = numpy.reshape(sicd.GeoData.SCP.ECF.get_array(), (1, 3)) else: return frm = '{1:0.8f},{0:0.8f},{2:0.2f}' grp_llh = ecf_to_geodetic(grp) if numpy.any(~numpy.isfinite(grp_llh)): logging.error( 'There are nonsense entries (nan or +/- infinity) in the scp/ground range locations.' ) coord_array = [frm.format(*el) for el in arp_llh] if len(grp_llh) > 1: coord_array.extend(frm.format(*el) for el in grp_llh[::-1, :]) else: coord_array.append(frm.format(*grp_llh[0, :])) coord_array.append(frm.format(*arp_llh[0, :])) coords = ' '.join(coord_array) placemark = kmz_document.add_container( par=folder, description='collection wedge for {}'.format(_get_sicd_name(sicd)), styleUrl='#collection', **time_args) kmz_document.add_polygon(coords, par=placemark, extrude=False, tesselate=False, altitudeMode='absolute')
def from_sicd(cls, sicd): """ Construct the sensor info from a sicd structure Parameters ---------- sicd : SICDType Returns ------- SensorInfoType """ transmit_freq_proc = sicd.ImageFormation.TxFrequencyProc center_freq = transmit_freq_proc.center_frequency * 1e-9 bandwidth = transmit_freq_proc.bandwidth * 1e-9 polarization = sicd.ImageFormation.get_polarization().replace(':', '') look = 'Left' if sicd.SCPCOA.SideOfTrack == 'L' else 'Right' arp_pos_llh = ecf_to_geodetic(sicd.SCPCOA.ARPPos.get_array()) # calculate heading heading_ned = ecf_to_ned(sicd.SCPCOA.ARPVel.get_array(), sicd.SCPCOA.ARPPos.get_array(), absolute_coords=False) heading = numpy.rad2deg(numpy.arctan2(heading_ned[1], heading_ned[0])) # calculate track angle first_pos_ecf = sicd.Position.ARPPoly(0) last_pos_ecf = sicd.Position.ARPPoly(sicd.Timeline.CollectDuration) diff_ned = ecf_to_ned(last_pos_ecf - first_pos_ecf, sicd.SCPCOA.ARPPos.get_array(), absolute_coords=False) track_angle = numpy.rad2deg(numpy.arctan2(diff_ned[1], diff_ned[0])) return SensorInfoType( Name=sicd.CollectionInfo.CollectorName, Type='SAR', Mode=sicd.CollectionInfo.RadarMode.ModeType, Band=sicd.ImageFormation.get_transmit_band_name(), Bandwidth=bandwidth, CenterFrequency=center_freq, Polarization=polarization, Range=sicd.SCPCOA.SlantRange, DepressionAngle=sicd.SCPCOA.GrazeAng, Aimpoint=sicd.GeoData.SCP.LLH.get_array(), AircraftHeading=heading, AircraftTrackAngle=track_angle, Look=look, SquintAngle=SquintAngleType(SlantPlane=sicd.SCPCOA.DopplerConeAng, GroundPlane=sicd.SCPCOA.Squint), AircraftLocation=arp_pos_llh, AircraftVelocity=sicd.SCPCOA.ARPVel.get_array())
def _write_arp_location(kmz_document, sicd, time_args, time_array, folder): """ Parameters ---------- kmz_document : Document sicd : SICDType time_args : dict time_array : None|numpy.ndarray folder : minidom.Element Returns ------- None|Numpy.ndarray """ if time_array is None: return None if sicd.Position is not None and sicd.Position.ARPPoly is not None: arp_pos = sicd.Position.ARPPoly(time_array) elif sicd.SCPCOA.ARPPos is not None and sicd.SCPCOA.ARPVel is not None: arp_pos = sicd.SCPCOA.ARPPos.get_array() + numpy.outer( time_array, sicd.SCPCOA.ARPVel.get_array()) else: return None arp_llh = ecf_to_geodetic(arp_pos) if numpy.any(~numpy.isfinite(arp_llh)): logging.error( 'There are nonsense entries (nan or +/- infinity) in the aperture location.' ) coords = ['{1:0.8f},{0:0.8f},{2:0.2f}'.format(*el) for el in arp_llh] whens = [ str( sicd.Timeline.CollectStart.astype('datetime64[us]') + int_func(el * 1e6)) + 'Z' for el in time_array ] placemark = kmz_document.add_container( par=folder, description='aperture position for {}'.format(_get_sicd_name(sicd)), styleUrl='#arp', **time_args) kmz_document.add_gx_track(coords, whens, par=placemark, extrude=True, tesselate=True, altitudeMode='absolute') return arp_llh
def North(self): """ float: The north angle. """ lat, lon, hae = ecf_to_geodetic(self.SCP) lat_r = numpy.deg2rad(lat) lon_r = numpy.deg2rad(lon) N = numpy.array( [-numpy.sin(lat_r)*numpy.cos(lon_r), -numpy.sin(lat_r)*numpy.sin(lon_r), numpy.cos(lat_r)]) Nprime = N - self.slant_z*(N.dot(self.normal_vector)/self.slant_z.dot(self.normal_vector)) return numpy.rad2deg(numpy.arctan2(self.col_vector.dot(Nprime), self.row_vector.dot(Nprime)))
def _split_lat_lon_quad(ll_quad, split_fractions): """ Helper method for recursively splitting the lat/lon quad box. Parameters ---------- ll_quad : numpy.ndarray split_fractions : list|tuple Returns ------- numpy.ndarray """ r1, r2, c1, c2 = split_fractions # [0] corresponds to (max_row, 0) # [1] corresponds to (max row, max_col) # [2] corresponds to (0, max_col) # [3] corresponds to (0, 0) # do row split # [0] = r2*[0] + (1-r2)*[3] # [1] = r2*[1] + (1-r2)*[2] # [2] = r1*[1] + (1-r1)*[2] # [3] = r1*[0] + (1-r1)*[3] row_split = numpy.array([ [r2, 0, 0, 1-r2], [0, r2, 1-r2, 0], [0, r1, 1-r1, 0], [r1, 0, 0, 1-r1], ], dtype='float64') # do column split # [0] = (1-c1)*[0] + c1*[1] # [1] = (1-c2)*[0] + c2*[1] # [2] = c2*[2] + (1-c2)*[3] # [3] = c1*[2] + (1-c1)*[3] col_split = numpy.array([ [1-c1, c1, 0, 0], [1-c2, c2, 0, 0], [0, 0, c2, 1-c2], [0, 0, c1, 1-c1],], dtype='float64') split = col_split.dot(row_split) llh_temp = numpy.zeros((4, 3)) llh_temp[:, :2] = ll_quad ecf_coords = geodetic_to_ecf(llh_temp) split_ecf = split.dot(ecf_coords) return ecf_to_geodetic(split_ecf)[:, :2]
def get_llh_image_corners(self) -> Optional[numpy.ndarray]: """ The corner points of the overall ortho-rectified output in Lat/Lon/HAE coordinates. The ordering of these points follows the SICD convention. Returns ------- None|numpy.ndarray """ ecf_corners = self.get_ecf_image_corners() if ecf_corners is None: return None else: return ecf_to_geodetic(ecf_corners)
def ortho_to_llh(self, ortho_coords): """ Get the lat/lon/hae coordinates for the point(s) in ortho-rectified coordinates. Parameters ---------- ortho_coords : numpy.ndarray Point(s) in the ortho-recitified coordinate system, of the form `(ortho_row, ortho_column)`. Returns ------- numpy.ndarray """ ecf = self.ortho_to_ecf(ortho_coords) return ecf_to_geodetic(ecf)
def interpolate_corner_points_string(entry, rows, cols, icp): """ Interpolate the corner points for the given subsection from the given corner points. This supplies entries for the NITF headers. Parameters ---------- entry : numpy.ndarray The corner pints of the form `(row_start, row_stop, col_start, col_stop)` rows : int The number of rows in the parent image. cols : int The number of cols in the parent image. icp : the parent image corner points in geodetic coordinates. Returns ------- str """ if icp is None: return '' if icp.shape[1] == 2: icp_new = numpy.zeros((icp.shape[0], 3), dtype=numpy.float64) icp_new[:, :2] = icp icp = icp_new icp_ecf = geodetic_to_ecf(icp) const = 1. / (rows * cols) pattern = entry[numpy.array([(0, 2), (1, 2), (1, 3), (0, 3)], dtype=numpy.int64)] out = [] for row, col in pattern: pt_array = const * numpy.sum( icp_ecf * (numpy.array([rows - row, row, row, rows - row]) * numpy.array( [cols - col, cols - col, col, col]))[:, numpy.newaxis], axis=0) pt = LatLonType.from_array(ecf_to_geodetic(pt_array)[:2]) dms = pt.dms_format(frac_secs=False) out.append('{0:02d}{1:02d}{2:02d}{3:s}'.format(*dms[0]) + '{0:03d}{1:02d}{2:02d}{3:s}'.format(*dms[1])) return ''.join(out)
def sarpy2ortho(ro, pix, decimation=10): nx = ro.sicdmeta.ImageData.FullImage.NumCols ny = ro.sicdmeta.ImageData.FullImage.NumRows nx_dec = round(nx / decimation) ny_dec = round(ny / decimation) xv, yv = np.meshgrid(range(nx), range(ny), indexing='xy') xv = xv[::decimation, ::decimation] yv = yv[::decimation, ::decimation] npix = xv.size xv = np.reshape(xv, (npix, 1)) yv = np.reshape(yv, (npix, 1)) im_points = np.concatenate([yv, xv], axis=1) ground_coords = image_to_ground(im_points, ro.sicdmeta) ground_coords = ecf_to_geodetic(ground_coords) minx = np.min(ground_coords[:, 1]) maxx = np.max(ground_coords[:, 1]) miny = np.min(ground_coords[:, 0]) maxy = np.max(ground_coords[:, 0]) xi, yi = create_ground_grid(minx, maxx, miny, maxy, nx_dec, ny_dec) ground_coords[:, [0, 1]] = ground_coords[:, [1, 0]] pix = np.reshape(pix, npix) gridded = griddata(ground_coords[:, 0:2], pix, (xi, yi), method='nearest').astype(np.uint8) ul = [maxy, minx] lr = [miny, maxx] extent = [ul, lr] extent_poly = bounds_2_shapely_polygon(min_x=minx, max_x=maxx, min_y=miny, max_y=maxy) geot = world_poly_to_geo_t(extent_poly, npix_x=nx_dec, npix_y=ny_dec) return gridded, extent, geot
def callback_save_kml(self, event): kml_save_fname = tkinter.filedialog.asksaveasfilename( initialdir=os.path.expanduser("~/Downloads")) kml_util = KmlUtil() canvas_shapes = self.canvas_demo_image_panel.canvas.variables.shape_ids for shape_id in canvas_shapes: image_coords = self.canvas_demo_image_panel.canvas.get_shape_image_coords( shape_id) shape_type = self.canvas_demo_image_panel.canvas.get_shape_type( shape_id) if image_coords: sicd_meta = self.canvas_demo_image_panel.canvas.variables.canvas_image_object.reader_object.sicdmeta image_points = numpy.zeros((int(len(image_coords) / 2), 2)) image_points[:, 0] = image_coords[0::2] image_points[:, 1] = image_coords[1::2] ground_points_ecf = point_projection.image_to_ground( image_points, sicd_meta) ground_points_latlon = geocoords.ecf_to_geodetic( ground_points_ecf) world_y_coordinates = ground_points_latlon[:, 0] world_x_coordinates = ground_points_latlon[:, 1] xy_point_list = [ (x, y) for x, y in zip(world_x_coordinates, world_y_coordinates) ] if shape_id == self.canvas_demo_image_panel.canvas.variables.zoom_rect_id: pass elif shape_type == self.canvas_demo_image_panel.canvas.variables.select_rect_id: pass elif shape_type == self.canvas_demo_image_panel.canvas.SHAPE_TYPES.POINT: kml_util.add_point(str(shape_id), xy_point_list[0]) elif canvas_shapes == self.canvas_demo_image_panel.canvas.SHAPE_TYPES.LINE: kml_util.add_linestring(str(shape_id), xy_point_list) elif shape_type == self.canvas_demo_image_panel.canvas.SHAPE_TYPES.POLYGON: kml_util.add_polygon(str(shape_id), xy_point_list) elif shape_type == self.canvas_demo_image_panel.canvas.SHAPE_TYPES.RECT: kml_util.add_polygon(str(shape_id), xy_point_list) kml_util.write_to_file(kml_save_fname)
def test_values_both_ways(self): shp = (8, 5) rand_llh = numpy.empty(shp + (3, ), dtype=numpy.float64) rand_llh[:, :, 0] = 180 * (numpy.random.rand(*shp) - 0.5) rand_llh[:, :, 1] = 360 * (numpy.random.rand(*shp) - 0.5) rand_llh[:, :, 2] = 1e5 * numpy.random.rand(*shp) rand_ecf = geocoords.geodetic_to_ecf(rand_llh) rand_llh2 = geocoords.ecf_to_geodetic(rand_ecf) rand_ecf2 = geocoords.geodetic_to_ecf(rand_llh2) llh_diff = numpy.abs(rand_llh - rand_llh2) ecf_diff = numpy.abs(rand_ecf - rand_ecf2) with self.subTest(msg="llh match"): self.assertTrue(numpy.all(llh_diff < tolerance)) with self.subTest(msg="ecf match"): self.assertTrue(numpy.all(ecf_diff < tolerance))
def extract_location(): ll_coords = None if isinstance(sidd, SIDDType2): try: ll_coords = sidd.GeoData.ImageCorners.get_array( dtype=numpy.dtype('float64')) except AttributeError: pass elif isinstance(sidd, SIDDType1): try: ll_coords = sidd.GeographicAndTarget.GeographicCoverage.Footprint.get_array( dtype=numpy.dtype('float64')) except AttributeError: pass if ll_coords is not None: llh_coords = numpy.zeros((ll_coords.shape[0], 3), dtype=numpy.float64) llh_coords[:, :2] = ll_coords ecf_coords = geodetic_to_ecf(llh_coords) coords = ecf_to_geodetic(numpy.mean(ecf_coords, axis=0)) variables['lat'] = coords[0] variables['lon'] = coords[1]
def from_sicd(cls, sicd): """ Construct the sensor info from a sicd structure Parameters ---------- sicd : SICDType Returns ------- DetailSensorInfoType """ transmit_freq_proc = sicd.ImageFormation.TxFrequencyProc center_freq = 0.5 * (transmit_freq_proc.MinProc + transmit_freq_proc.MaxProc) * 1e-9 polarization = sicd.ImageFormation.get_polarization().replace(':', '') look = 'Left' if sicd.SCPCOA.SideOfTrack == 'L' else 'Right' slant_squint = 90 - sicd.SCPCOA.DopplerConeAng ground_squint = 90 - numpy.rad2deg( numpy.arccos( numpy.cos(numpy.deg2rad(sicd.SCPCOA.DopplerConeAng)) / numpy.cos(numpy.deg2rad(sicd.SCPCOA.GrazeAng)))) arp_pos_llh = ecf_to_geodetic(sicd.SCPCOA.ARPPos.get_array()) return DetailSensorInfoType( Name=sicd.CollectionInfo.CollectorName, Type='SAR', Mode=sicd.CollectionInfo.RadarMode.ModeType, Band=sicd.ImageFormation.get_transmit_band_name(), CenterFrequency=center_freq, Polarization=polarization, Range=sicd.SCPCOA.SlantRange, DepressionAngle=sicd.SCPCOA.GrazeAng, Aimpoint=sicd.GeoData.SCP.LLH.get_array(), Look=look, SquintAngle=SquintAngleType(SlantPlane=slant_squint, GroundPlane=ground_squint), AircraftLocation=arp_pos_llh, AircraftVelocity=sicd.SCPCOA.ARPVel.get_array())
def extract_global(): if cphd.Global is None: return try: variables['collect_start'] = cphd.Global.CollectStart except AttributeError: pass try: variables['collect_duration'] = cphd.Global.CollectDuration except AttributeError: pass try: llh_coords = cphd.Global.ImageArea.Corner.get_array( dtype=numpy.dtype('float64')) ecf_coords = geodetic_to_ecf(llh_coords) coords = ecf_to_geodetic(numpy.mean(ecf_coords, axis=0)) variables['lat'] = coords[0] variables['lon'] = coords[1] except AttributeError: pass
def best_physical_location_fit( structs: Sequence[Union[SICDType, SIDDType1, SIDDType2]], locs: Union[numpy.ndarray, list, tuple], **minimization_args) -> Tuple[numpy.ndarray, float, Any]: """ Given a collection of SICD and/or SIDDs and a collection of image coordinates, each of which identifies the pixel location of the same feature in the respective image, determine the (best fit) geophysical location of this feature. This assumes that any adjustable parameters used for the SICD/SIDD projection model have already been applied (via :func:`define_coa_projection`). Parameters ---------- structs : Sequence[SICDType|SIDDType1|SIDDType2] The collection of sicds/sidds, of length `N` locs : numpy.ndarray|list|tuple The image coordinate collection, of shape `(N, 2)` minimization_args The keyword arguments (after `args` argument) passed through to :func:`scipy.optimize.minimize`. This will default to `'Powell'` optimization, which seems generally much more reliable for this problem than the steepest descent based approaches. Returns ------- ecf_location : numpy.ndarray The location in question, in ECF coordinates residue : float The mean square residue of the physical distance between the given location and the image locations projected into the surface of given HAE value result The minimization result object """ def get_mean_location(hae_value, log_residue=False): ecf_locs = numpy.zeros((points, 3), dtype='float64') for i, (loc, struct) in enumerate(zip(locs, structs)): ecf_locs[i, :] = struct.project_image_to_ground( loc, projection_type='HAE', hae0=hae_value) ecf_mean = numpy.mean(ecf_locs, axis=0) diff = ecf_locs - ecf_mean residue = numpy.sum(diff * diff, axis=1) if log_residue: logger.info( 'best physical location residues [m^2]\n{}'.format(residue)) avg_residue = numpy.mean(residue) return ecf_mean, avg_residue def average_residue(hae_value): return get_mean_location(hae_value)[1] points = len(structs) if points < 2: raise ValueError( 'At least 2 structs must be present to determine the best location' ) if points != locs.shape[0]: raise ValueError( 'The number of structs must match the number of locations') struct0 = structs[0] if isinstance(struct0, SICDType): h0 = struct0.GeoData.SCP.LLH.HAE elif isinstance(struct0, (SIDDType1, SIDDType2)): ref_ecf = struct0.Measurement.ReferencePoint.ECEF.get_array() h0 = ecf_to_geodetic(ref_ecf)[2] else: raise TypeError('Got unexpected structure type {}'.format( type(struct0))) if 'method' not in minimization_args: minimization_args['method'] = 'Powell' result = minimize(average_residue, h0, **minimization_args) if not result.success: raise ValueError('Optimization failed {}'.format(result)) values = get_mean_location(result.x, log_residue=True) return values[0], values[1], result
def ECF(self, value): if value is not None: self._ECF = _parse_serializable(value, 'ECF', self, XYZType) self._LLH = LatLonHAERestrictionType.from_array( ecf_to_geodetic(self._ECF.get_array()))
def create_ortho( self, output_ny, output_nx, ): input_image_data = self.display_image display_image_nx = input_image_data.shape[1] display_image_ny = input_image_data.shape[0] image_points = np.zeros((display_image_nx * display_image_ny, 2)) canvas_coords_1d = np.zeros(2 * display_image_nx * display_image_ny) tmp_x_vals = np.arange(0, display_image_ny) tmp_y_vals = np.zeros(display_image_ny) for x in range(display_image_nx): start_index = display_image_ny * 2 * x + 1 end_index = start_index + display_image_ny * 2 canvas_coords_1d[start_index:end_index:2] = tmp_x_vals canvas_coords_1d[display_image_ny * x * 2::2][0:display_image_ny] = tmp_y_vals + x full_image_coords = self.canvas_coords_to_full_image_yx( canvas_coords_1d) image_points[:, 0] = full_image_coords[0::2] image_points[:, 1] = full_image_coords[1::2] sicd_meta = self.reader_object.sicd_meta ground_points_ecf = point_projection.image_to_ground( image_points, sicd_meta) ground_points_latlon = geocoords.ecf_to_geodetic(ground_points_ecf) world_y_coordinates = ground_points_latlon[:, 0] world_x_coordinates = ground_points_latlon[:, 1] x = np.ravel(world_x_coordinates) y = np.ravel(world_y_coordinates) z = np.ravel(np.transpose(input_image_data)) ground_x_grid, ground_y_grid = self._create_ground_grid( min(x), max(x), min(y), max(y), output_nx, output_ny) ortho_image = interp.griddata((x, y), z, (ground_x_grid, ground_y_grid), method='nearest') s = np.zeros((output_nx * output_ny, 3)) s[:, 0] = ground_y_grid.ravel() s[:, 1] = ground_x_grid.ravel() s[:, 2] = ground_points_latlon[0, 2] s_ecf = geocoords.geodetic_to_ecf(s) gridded_image_pixels = point_projection.ground_to_image( s_ecf, sicd_meta) full_image_coords_y = full_image_coords[0::2] full_image_coords_x = full_image_coords[1::2] mask = np.ones_like(gridded_image_pixels[0][:, 0]) indices_1 = np.where( gridded_image_pixels[0][:, 0] < min(full_image_coords_y)) indices_2 = np.where( gridded_image_pixels[0][:, 1] < min(full_image_coords_x)) indices_3 = np.where( gridded_image_pixels[0][:, 0] > max(full_image_coords_y)) indices_4 = np.where( gridded_image_pixels[0][:, 1] > max(full_image_coords_x)) mask[indices_1] = 0 mask[indices_2] = 0 mask[indices_3] = 0 mask[indices_4] = 0 mask_2d = np.reshape(mask, (output_ny, output_nx)) return ortho_image * mask_2d