def test_fit_wcs_from_points_CRPIX_bounds(): # Test CRPIX bounds requirement wcs_str = """ WCSAXES = 2 / Number of coordinate axes CRPIX1 = 1045.0 / Pixel coordinate of reference point CRPIX2 = 1001.0 / Pixel coordinate of reference point PC1_1 = 0.00056205870415378 / Coordinate transformation matrix element PC1_2 = -0.00569181083243 / Coordinate transformation matrix element PC2_1 = 0.0056776810932466 / Coordinate transformation matrix element PC2_2 = 0.0004208048403273 / Coordinate transformation matrix element CDELT1 = 1.0 / [deg] Coordinate increment at reference point CDELT2 = 1.0 / [deg] Coordinate increment at reference point CUNIT1 = 'deg' / Units of coordinate increment and value CUNIT2 = 'deg' / Units of coordinate increment and value CTYPE1 = 'RA---TAN' / Right ascension, gnomonic projection CTYPE2 = 'DEC--TAN' / Declination, gnomonic projection CRVAL1 = 104.57797893504 / [deg] Coordinate value at reference point CRVAL2 = -74.195502593322 / [deg] Coordinate value at reference point LONPOLE = 180.0 / [deg] Native longitude of celestial pole LATPOLE = -74.195502593322 / [deg] Native latitude of celestial pole TIMESYS = 'TDB' / Time scale TIMEUNIT= 'd' / Time units DATEREF = '1858-11-17' / ISO-8601 fiducial time MJDREFI = 0.0 / [d] MJD of fiducial time, integer part MJDREFF = 0.0 / [d] MJD of fiducial time, fractional part DATE-OBS= '2019-03-27T03:30:13.832Z' / ISO-8601 time of observation MJD-OBS = 58569.145993426 / [d] MJD of observation MJD-OBS = 58569.145993426 / [d] MJD at start of observation TSTART = 1569.6467941661 / [d] Time elapsed since fiducial time at start DATE-END= '2019-03-27T04:00:13.831Z' / ISO-8601 time at end of observation MJD-END = 58569.166826748 / [d] MJD at end of observation TSTOP = 1569.6676274905 / [d] Time elapsed since fiducial time at end TELAPSE = 0.02083332443 / [d] Elapsed time (start to stop) TIMEDEL = 0.020833333333333 / [d] Time resolution TIMEPIXR= 0.5 / Reference position of timestamp in binned data RADESYS = 'ICRS' / Equatorial coordinate system """ wcs_header = fits.Header.fromstring(wcs_str, sep='\n') ffi_wcs = WCS(wcs_header) yi, xi = (1000, 1000) y, x = (10, 200) center_coord = SkyCoord(ffi_wcs.all_pix2world([[xi + x // 2, yi + y // 2]], 0), unit='deg')[0] ypix, xpix = [arr.flatten() for arr in np.mgrid[xi:xi + x, yi:yi + y]] world_pix = SkyCoord(*ffi_wcs.all_pix2world(xpix, ypix, 0), unit='deg') fit_wcs = fit_wcs_from_points((ypix, xpix), world_pix, proj_point='center') assert (fit_wcs.wcs.crpix.astype(int) == [1100, 1005]).all() assert fit_wcs.pixel_shape == (200, 10)
def draw_guide_stars(cls, img, img_stars, pattern, max=20, color=(255, 255, 255)): """Given an image and a list of Centroids draw lines in the image between them in order. :param img: Image to draw in. :param img_stars: List of stars to draw lines to. :param pattern: Pattern of stars.""" # Build WCS pixels_x = np.array([]) pixels_y = np.array([]) stars_ra = [] stars_dec = [] for found_star in pattern: if found_star.is_identified(): pixels_x = np.append(pixels_x, found_star.centroid.x) pixels_y = np.append(pixels_y, found_star.centroid.y) stars_ra.append(found_star.real_star.ra) stars_dec.append(found_star.real_star.dec) stars = SkyCoord(ra=stars_ra, dec=stars_dec, unit=u.deg) wcs = fit_wcs_from_points((pixels_x, pixels_y), stars) img_stars_to_label = [] for img_star in img_stars: for found_star in pattern: if found_star.centroid == img_star.centroid and found_star.is_identified(): img_star.labeled = True img_stars_to_label.append(img_star) # Set wcs coordinates to ImageStars for img_star in img_stars: pixel_x = np.array([[img_star.centroid.x]]) pixel_y = np.array([[img_star.centroid.y]]) coords_ra, coords_dec = wcs.wcs_pix2world(pixel_x, pixel_y, 0) coords = SkyCoord(ra=coords_ra, dec=coords_dec, unit=u.deg) img_star.set_wcs_coords(coords) labeled = 0 for hip_number in catalog._guide_stars: star = catalog.get_star_by_id(int(hip_number)) coords_a = SkyCoord(ra=star.ra, dec=star.dec, unit=u.deg) max = 10 for img_star in img_stars_to_label[:max]: if img_star.is_labeled(): continue coords_b = img_star.get_wcs_coords() if coords_a.separation(coords_b) < 0.5 * u.deg: center = (img_star.centroid.x - 20, img_star.centroid.y + 25) cv2.putText(img, str(star.name), center, cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 1) labeled += 1 img_star.set_labeled() return labeled
def wcs_sip_fit(cat_df, init_wcs, sip_degree=3, x_key='xcentroid', y_key='ycentroid', alt_key='Alt', az_key='Az'): """ Take an initial WCS and refine it with SIP distortion terms by fitting to a larger catalog in a pandas datafrom, cat_df. The input dataframe needs to have both X/Y image positions and object Alt/Az. """ wcs_refined = fit_wcs_from_points( (cat_df[x_key].array, cat_df[y_key].array), SkyCoord(cat_df[az_key] * u.deg, cat_df[alt_key] * u.deg), projection=init_wcs, proj_point=SkyCoord(0 * u.deg, 90 * u.deg), sip_degree=sip_degree) return wcs_refined
def wcs(): d = rotate() xyrot = (np.array(d['x2']), np.array(d['y2'])) wcs = utils.fit_wcs_from_points(xyrot, coord, center) print(wcs) header = fits.Header() header.extend(wcs.to_header(), update=True) pc1_1 = header['PC1_1'] scale = -pc1_1 * 2 / (np.sqrt(2)) sin_a = pc1_1 / scale alpha = np.rad2deg(np.arcsin(sin_a)) print(alpha) w = WCS(header) e = dict() world = w.wcs_pix2world(d['x2'], d['y2'], 0) e['xr'] = world[0] e['yr'] = world[1] return (e)
def wcs(xyrot): # Center of "sky L" #center = SkyCoord(ra=0.11, dec=0.11, unit=(u.deg,u.deg)) # Coordinates of "sky L" expressed in ra,dec # ra,dec = ([0.11, 0.11, 0.11, 0.11, 0.12, 0.13], # [0.14, 0.13, 0.12, 0.11, 0.11, 0.11] ) center = SkyCoord(246.7368408, 43.480712949, frame = 'icrs', unit = (u.deg,u.deg)) ra,dec = (np.array([246.75001315, 246.75001315, 246.72033646, 246.72303144, 246.74164072, 246.73540614, 246.73379121, 246.73761455, 246.7179495 , 246.73051123, 246.71970072, 246.7228646 , 246.72647213, 246.7188386 , 246.7314031 , 246.71821002, 246.74785534, 246.73265223, 246.72579817, 246.71943263]), np.array([43.48690547, 43.48690547, 43.46792989, 43.48075238, 43.49560501, 43.48903538, 43.46045875, 43.47030776, 43.46132376, 43.48252763, 43.46802566, 43.46035331, 43.48218262, 43.46908299, 43.46131665, 43.46560591, 43.47791234, 43.45973025, 43.47208325, 43.47779988])) coord = SkyCoord(ra=ra, dec=dec, unit=(u.deg,u.deg)) # Fitting "pixel L" and "sky L" wcs = utils.fit_wcs_from_points(xyrot, coord, center, sip_degree=2) # Coordinates of "sky L" expressed in pixel x,y = wcs.all_pix2world(ra,dec, 0) cd = wcs.wcs.cd # rotation matrix # norm = np.linalg.norm(cd) # norm # cd_norm = cd / norm ### fig = plt.figure(figsize=(6,6)) ax = fig.add_subplot(111) ax.plot(xyrot[0],xyrot[1],'ob') # pixel L ax.plot(x,y,'xr') # sky L in pixel #ax.plot(ra,dec,'xg') # sky L in radec plt.savefig("filname.ps") # scusa, non mi va il terminale tk... plt.close('all') return cd
def test_issue10991(): # test issue #10991 (it just needs to run and set the user defined crval) xy = np.array([[1766.88276168, 662.96432257, 171.50212526, 120.70924648], [1706.69832901, 1788.85480559, 1216.98949653, 1307.41843381]]) world_coords = SkyCoord([(66.3542367 , 22.20000162), (67.15416174, 19.18042906), (65.73375432, 17.54251555), (66.02400512, 17.44413253)], frame="icrs", unit="deg") proj_point = SkyCoord(64.67514918, 19.63389538, frame="icrs", unit="deg") fit_wcs = fit_wcs_from_points( xy=xy, world_coords=world_coords, proj_point=proj_point, projection='TAN' ) projlon = proj_point.data.lon.deg projlat = proj_point.data.lat.deg assert (fit_wcs.wcs.crval == [projlon, projlat]).all()
def test_fit_wcs_from_points(header_str, crval, sip_degree, user_proj_point, exp_max_dist, exp_std_dist): header = fits.Header.fromstring(header_str, sep='\n') header["CRVAL1"] = crval true_wcs = WCS(header, relax=True) # Getting the pixel coordinates x, y = np.meshgrid(list(range(10)), list(range(10))) x = x.flatten() y = y.flatten() # Calculating the true sky positions world_pix = true_wcs.pixel_to_world(x, y) # which projection point to use if user_proj_point: proj_point = world_pix[0] projlon = proj_point.data.lon.deg projlat = proj_point.data.lat.deg else: proj_point = 'center' # Fitting the wcs fit_wcs = fit_wcs_from_points((x, y), world_pix, proj_point=proj_point, sip_degree=sip_degree) # Validate that the true sky coordinates # match sky coordinates calculated from the wcs fit world_pix_new = fit_wcs.pixel_to_world(x, y) dists = world_pix.separation(world_pix_new) assert dists.max() < exp_max_dist assert np.std(dists) < exp_std_dist if user_proj_point: assert (fit_wcs.wcs.crval == [projlon, projlat]).all()
def test_fit_wcs_from_points(): header_str_linear = """ XTENSION= 'IMAGE ' / Image extension BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 50 NAXIS2 = 50 PCOUNT = 0 / number of parameters GCOUNT = 1 / number of groups RADESYS = 'ICRS ' EQUINOX = 2000.0 WCSAXES = 2 CTYPE1 = 'RA---TAN' CTYPE2 = 'DEC--TAN' CRVAL1 = 250.3497414839765 CRVAL2 = 2.280925599609063 CRPIX1 = 1045.0 CRPIX2 = 1001.0 CD1_1 = -0.005564478186178 CD1_2 = -0.001042099258152 CD2_1 = 0.00118144146585 CD2_2 = -0.005590816683583 """ header_str_sip = """ XTENSION= 'IMAGE ' / Image extension BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 50 NAXIS2 = 50 PCOUNT = 0 / number of parameters GCOUNT = 1 / number of groups RADESYS = 'ICRS ' EQUINOX = 2000.0 WCSAXES = 2 CTYPE1 = 'RA---TAN-SIP' CTYPE2 = 'DEC--TAN-SIP' CRVAL1 = 250.3497414839765 CRVAL2 = 2.280925599609063 CRPIX1 = 1045.0 CRPIX2 = 1001.0 CD1_1 = -0.005564478186178 CD1_2 = -0.001042099258152 CD2_1 = 0.00118144146585 CD2_2 = -0.005590816683583 A_ORDER = 2 B_ORDER = 2 A_2_0 = 2.02451189234E-05 A_0_2 = 3.317603337918E-06 A_1_1 = 1.73456334971071E-05 B_2_0 = 3.331330003472E-06 B_0_2 = 2.04247482482589E-05 B_1_1 = 1.71476710804143E-05 AP_ORDER= 2 BP_ORDER= 2 AP_1_0 = 0.000904700296389636 AP_0_1 = 0.000627660715584716 AP_2_0 = -2.023482905861E-05 AP_0_2 = -3.332285841011E-06 AP_1_1 = -1.731636633824E-05 BP_1_0 = 0.000627960882053211 BP_0_1 = 0.000911222886084808 BP_2_0 = -3.343918167224E-06 BP_0_2 = -2.041598249021E-05 BP_1_1 = -1.711876336719E-05 A_DMAX = 44.72893589844534 B_DMAX = 44.62692873032506 """ header_linear = fits.Header.fromstring(header_str_linear, sep='\n') header_sip = fits.Header.fromstring(header_str_sip, sep='\n') true_wcs_linear = WCS(header_linear, relax=True) true_wcs_sip = WCS(header_sip, relax=True) # Getting the pixel coordinates x, y = np.meshgrid(list(range(10)), list(range(10))) x = x.flatten() y = y.flatten() # Calculating the true sky positions world_pix_linear = true_wcs_linear.pixel_to_world(x, y) world_pix_sip = true_wcs_sip.pixel_to_world(x, y) # Fitting the wcs, no distortion. fit_wcs_linear = fit_wcs_from_points((x, y), world_pix_linear, proj_point='center', sip_degree=None) # Fitting the wcs, with distortion. fit_wcs_sip = fit_wcs_from_points((x, y), world_pix_sip, proj_point='center', sip_degree=2) # Validate that the true sky coordinates calculated with `true_wcs_linear` # match sky coordinates calculated from the wcs fit with only linear terms world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y) dists = world_pix_linear.separation(world_pix_linear_new) assert dists.max() < 7e-5 * u.deg assert np.std(dists) < 2.5e-5 * u.deg # Validate that the true sky coordinates calculated with `true_wcs_sip` # match the sky coordinates calculated from the wcs fit with SIP of same # degree (2) world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y) dists = world_pix_sip.separation(world_pix_sip_new) assert dists.max() < 7e-6 * u.deg assert np.std(dists) < 2.5e-6 * u.deg # Test 360->0 degree crossover header_linear["CRVAL1"] = 352.3497414839765 header_sip["CRVAL1"] = 352.3497414839765 true_wcs_linear = WCS(header_linear, relax=True) true_wcs_sip = WCS(header_sip, relax=True) # Calculating the true sky positions world_pix_linear = true_wcs_linear.pixel_to_world(x, y) world_pix_sip = true_wcs_sip.pixel_to_world(x, y) # Fitting the wcs, no distortion. fit_wcs_linear = fit_wcs_from_points((x, y), world_pix_linear, proj_point='center', sip_degree=None) # Fitting the wcs, with distortion. fit_wcs_sip = fit_wcs_from_points((x, y), world_pix_sip, proj_point='center', sip_degree=2) # Validate that the true sky coordinates calculated with `true_wcs_linear` # match sky coordinates calculated from the wcs fit with only linear terms world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y) dists = world_pix_linear.separation(world_pix_linear_new) assert dists.max() < 7e-5 * u.deg assert np.std(dists) < 2.5e-5 * u.deg
def test_fit_wcs_from_points(): header_str_linear = """ XTENSION= 'IMAGE ' / Image extension BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 50 NAXIS2 = 50 PCOUNT = 0 / number of parameters GCOUNT = 1 / number of groups RADESYS = 'ICRS ' EQUINOX = 2000.0 WCSAXES = 2 CTYPE1 = 'RA---TAN' CTYPE2 = 'DEC--TAN' CRVAL1 = 250.3497414839765 CRVAL2 = 2.280925599609063 CRPIX1 = 1045.0 CRPIX2 = 1001.0 CD1_1 = -0.005564478186178 CD1_2 = -0.001042099258152 CD2_1 = 0.00118144146585 CD2_2 = -0.005590816683583 """ header_str_sip = """ XTENSION= 'IMAGE ' / Image extension BITPIX = -32 / array data type NAXIS = 2 / number of array dimensions NAXIS1 = 50 NAXIS2 = 50 PCOUNT = 0 / number of parameters GCOUNT = 1 / number of groups RADESYS = 'ICRS ' EQUINOX = 2000.0 WCSAXES = 2 CTYPE1 = 'RA---TAN-SIP' CTYPE2 = 'DEC--TAN-SIP' CRVAL1 = 250.3497414839765 CRVAL2 = 2.280925599609063 CRPIX1 = 1045.0 CRPIX2 = 1001.0 CD1_1 = -0.005564478186178 CD1_2 = -0.001042099258152 CD2_1 = 0.00118144146585 CD2_2 = -0.005590816683583 A_ORDER = 2 B_ORDER = 2 A_2_0 = 2.02451189234E-05 A_0_2 = 3.317603337918E-06 A_1_1 = 1.73456334971071E-05 B_2_0 = 3.331330003472E-06 B_0_2 = 2.04247482482589E-05 B_1_1 = 1.71476710804143E-05 AP_ORDER= 2 BP_ORDER= 2 AP_1_0 = 0.000904700296389636 AP_0_1 = 0.000627660715584716 AP_2_0 = -2.023482905861E-05 AP_0_2 = -3.332285841011E-06 AP_1_1 = -1.731636633824E-05 BP_1_0 = 0.000627960882053211 BP_0_1 = 0.000911222886084808 BP_2_0 = -3.343918167224E-06 BP_0_2 = -2.041598249021E-05 BP_1_1 = -1.711876336719E-05 A_DMAX = 44.72893589844534 B_DMAX = 44.62692873032506 """ # A known header that failed before header_str_prob = """ NAXIS = 2 / number of array dimensions WCSAXES = 2 / Number of coordinate axes CRPIX1 = 1024.5 / Pixel coordinate of reference point CRPIX2 = 1024.5 / Pixel coordinate of reference point CD1_1 = -1.7445934400771E-05 / Coordinate transformation matrix element CD1_2 = -4.9826985362578E-08 / Coordinate transformation matrix element CD2_1 = -5.0068838822312E-08 / Coordinate transformation matrix element CD2_2 = 1.7530614610951E-05 / Coordinate transformation matrix element CTYPE1 = 'RA---TAN' / Right ascension, gnomonic projection CTYPE2 = 'DEC--TAN' / Declination, gnomonic projection CRVAL1 = 5.8689341666667 / [deg] Coordinate value at reference point CRVAL2 = -71.995508583333 / [deg] Coordinate value at reference point """ header_linear = fits.Header.fromstring(header_str_linear, sep='\n') header_sip = fits.Header.fromstring(header_str_sip, sep='\n') header_prob = fits.Header.fromstring(header_str_prob, sep='\n') true_wcs_linear = WCS(header_linear, relax=True) true_wcs_sip = WCS(header_sip, relax=True) true_wcs_prob = WCS(header_prob, relax=True) # Getting the pixel coordinates x, y = np.meshgrid(list(range(10)), list(range(10))) x = x.flatten() y = y.flatten() # Calculating the true sky positions world_pix_linear = true_wcs_linear.pixel_to_world(x, y) world_pix_sip = true_wcs_sip.pixel_to_world(x, y) world_pix_prob = true_wcs_prob.pixel_to_world(x, y) # Fitting the wcs, no distortion. fit_wcs_linear = fit_wcs_from_points((x, y), world_pix_linear, proj_point='center', sip_degree=None) # Fitting the wcs, with distortion. fit_wcs_sip = fit_wcs_from_points((x, y), world_pix_sip, proj_point='center', sip_degree=2) # Fitting the problematic WCS fit_wcs_prob = fit_wcs_from_points((x, y), world_pix_prob, proj_point='center', sip_degree=None) # Validate that the true sky coordinates calculated with `true_wcs_linear` # match sky coordinates calculated from the wcs fit with only linear terms world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y) dists = world_pix_linear.separation(world_pix_linear_new) assert dists.max() < 7e-5 * u.deg assert np.std(dists) < 2.5e-5 * u.deg # Validate that the true sky coordinates calculated with `true_wcs_sip` # match the sky coordinates calculated from the wcs fit with SIP of same # degree (2) world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y) dists = world_pix_sip.separation(world_pix_sip_new) assert dists.max() < 7e-6 * u.deg assert np.std(dists) < 2.5e-6 * u.deg # Validate that the true sky coordinates calculated from the problematic # WCS match world_pix_prob_new = fit_wcs_prob.pixel_to_world(x, y) dists = world_pix_prob.separation(world_pix_prob_new) assert dists.max() < 7e-6 * u.deg assert np.std(dists) < 2.5e-6 * u.deg # Test 360->0 degree crossover header_linear["CRVAL1"] = 352.3497414839765 header_sip["CRVAL1"] = 352.3497414839765 header_prob["CRVAL1"] = 352.3497414839765 true_wcs_linear = WCS(header_linear, relax=True) true_wcs_sip = WCS(header_sip, relax=True) true_wcs_prob = WCS(header_prob) # Calculating the true sky positions world_pix_linear = true_wcs_linear.pixel_to_world(x, y) world_pix_sip = true_wcs_sip.pixel_to_world(x, y) world_pix_prob = true_wcs_prob.pixel_to_world(x, y) # Fitting the wcs, no distortion. fit_wcs_linear = fit_wcs_from_points((x, y), world_pix_linear, proj_point='center', sip_degree=None) # Fitting the wcs, with distortion. fit_wcs_sip = fit_wcs_from_points((x, y), world_pix_sip, proj_point='center', sip_degree=2) # Fitting the problem WCS fit_wcs_prob = fit_wcs_from_points((x, y), world_pix_prob, proj_point='center', sip_degree=None) # Validate that the true sky coordinates calculated with `true_wcs_linear` # match sky coordinates calculated from the wcs fit with only linear terms world_pix_linear_new = fit_wcs_linear.pixel_to_world(x, y) dists = world_pix_linear.separation(world_pix_linear_new) assert dists.max() < 7e-5 * u.deg assert np.std(dists) < 2.5e-5 * u.deg # Validate fit with SIP world_pix_sip_new = fit_wcs_sip.pixel_to_world(x, y) dists = world_pix_sip.separation(world_pix_sip_new) assert dists.max() < 7e-6 * u.deg assert np.std(dists) < 2.5e-6 * u.deg # Validate the problematic WCS world_pix_prob_new = fit_wcs_prob.pixel_to_world(x, y) dists = world_pix_prob.separation(world_pix_prob_new) assert dists.max() < 7e-6 * u.deg assert np.std(dists) < 2.5e-6 * u.deg # Test CRPIX bounds requirement wcs_str = """ WCSAXES = 2 / Number of coordinate axes CRPIX1 = 1045.0 / Pixel coordinate of reference point CRPIX2 = 1001.0 / Pixel coordinate of reference point PC1_1 = 0.00056205870415378 / Coordinate transformation matrix element PC1_2 = -0.00569181083243 / Coordinate transformation matrix element PC2_1 = 0.0056776810932466 / Coordinate transformation matrix element PC2_2 = 0.0004208048403273 / Coordinate transformation matrix element CDELT1 = 1.0 / [deg] Coordinate increment at reference point CDELT2 = 1.0 / [deg] Coordinate increment at reference point CUNIT1 = 'deg' / Units of coordinate increment and value CUNIT2 = 'deg' / Units of coordinate increment and value CTYPE1 = 'RA---TAN' / Right ascension, gnomonic projection CTYPE2 = 'DEC--TAN' / Declination, gnomonic projection CRVAL1 = 104.57797893504 / [deg] Coordinate value at reference point CRVAL2 = -74.195502593322 / [deg] Coordinate value at reference point LONPOLE = 180.0 / [deg] Native longitude of celestial pole LATPOLE = -74.195502593322 / [deg] Native latitude of celestial pole TIMESYS = 'TDB' / Time scale TIMEUNIT= 'd' / Time units DATEREF = '1858-11-17' / ISO-8601 fiducial time MJDREFI = 0.0 / [d] MJD of fiducial time, integer part MJDREFF = 0.0 / [d] MJD of fiducial time, fractional part DATE-OBS= '2019-03-27T03:30:13.832Z' / ISO-8601 time of observation MJD-OBS = 58569.145993426 / [d] MJD of observation MJD-OBS = 58569.145993426 / [d] MJD at start of observation TSTART = 1569.6467941661 / [d] Time elapsed since fiducial time at start DATE-END= '2019-03-27T04:00:13.831Z' / ISO-8601 time at end of observation MJD-END = 58569.166826748 / [d] MJD at end of observation TSTOP = 1569.6676274905 / [d] Time elapsed since fiducial time at end TELAPSE = 0.02083332443 / [d] Elapsed time (start to stop) TIMEDEL = 0.020833333333333 / [d] Time resolution TIMEPIXR= 0.5 / Reference position of timestamp in binned data RADESYS = 'ICRS' / Equatorial coordinate system """ wcs_header = fits.Header.fromstring(wcs_str, sep='\n') ffi_wcs = WCS(wcs_header) yi, xi = (1000, 1000) y, x = (10, 200) center_coord = SkyCoord(ffi_wcs.all_pix2world([[xi + x // 2, yi + y // 2]], 0), unit='deg')[0] ypix, xpix = [arr.flatten() for arr in np.mgrid[xi:xi + x, yi:yi + y]] world_pix = SkyCoord(*ffi_wcs.all_pix2world(xpix, ypix, 0), unit='deg') fit_wcs = fit_wcs_from_points((ypix, xpix), world_pix, proj_point='center') assert (fit_wcs.wcs.crpix.astype(int) == [1100, 1005]).all() assert fit_wcs.pixel_shape == (200, 10)
def _fit_cutout_wcs(self, cutout_wcs, cutout_shape): """ Given a full (including SIP coefficients) wcs for the cutout, calculate the best fit linear wcs, and a measure of the goodness-of-fit. The new WCS is stored in ``self.cutout_wcs``. Goodness-of-fit measures are returned and stored in ``self.cutout_wcs_fit``. Parameters ---------- cutout_wcs : `~astropy.wcs.WCS` The full (including SIP coefficients) cutout WCS object cutout_shape : tuple The shape of the cutout in the form (width, height). Returns ------- response : tuple Goodness-of-fit statistics. (max dist, sigma) """ # Getting matched pixel, world coordinate pairs # We will choose no more than 100 pixels spread evenly throughout the image # Centered on the center pixel. # To do this we the appropriate "step size" between pixel coordinates # (i.e. we take every ith pixel in each row/column) [TODOOOOOO] # For example in a 5x7 cutout with i = 2 we get: # # xxoxoxx # ooooooo # xxoxoxx # ooooooo # xxoxoxx # # Where x denotes the indexes that will be used in the fit. y, x = cutout_shape i = 1 while (x / i) * (y / i) > 100: i += 1 xvals = list(reversed(range(x // 2, -1, -i)))[:-1] + list( range(x // 2, x, i)) if xvals[-1] != x - 1: xvals += [x - 1] if xvals[0] != 0: xvals = [0] + xvals yvals = list(reversed(range(y // 2, -1, -i)))[:-1] + list( range(y // 2, y, i)) if yvals[-1] != y - 1: yvals += [y - 1] if yvals[0] != 0: yvals = [0] + yvals pix_inds = np.array(list(product(xvals, yvals))) world_pix = SkyCoord(cutout_wcs.all_pix2world(pix_inds, 0), unit='deg') # Getting the fit WCS linear_wcs = fit_wcs_from_points([pix_inds[:, 0], pix_inds[:, 1]], world_pix, proj_point='center') self.cutout_wcs = linear_wcs # Checking the fit (we want to use all of the pixels for this) pix_inds = np.array( list( product(list(range(cutout_shape[1])), list(range(cutout_shape[0]))))) world_pix = SkyCoord(cutout_wcs.all_pix2world(pix_inds, 0), unit='deg') world_pix_new = SkyCoord(linear_wcs.all_pix2world(pix_inds, 0), unit='deg') dists = world_pix.separation(world_pix_new).to('deg') sigma = np.sqrt(sum(dists.value**2)) self.cutout_wcs_fit['WCS_MSEP'][0] = dists.max().value self.cutout_wcs_fit['WCS_SIG'][0] = sigma return (dists.max(), sigma)