def iterative_zoom( image, mindiff=1.0, zoomshape=[10, 10], return_zoomed=False, zoomstep=2, verbose=False, minmax=np.min, ploteach=False, return_center=True, ): """ Iteratively zoom in on the *minimum* position in an image until the delta-peak value is below `mindiff` Parameters ---------- image : np.ndarray Two-dimensional image with a *minimum* to zoom in on (or maximum, if specified using `minmax`) mindiff : float Minimum difference that must be present in image before zooming is done zoomshape : [int,int] Shape of the "mini" image to create. Smaller is faster, but a bit less accurate. [10,10] seems to work well in preliminary tests (though unit tests have not been written) return_zoomed : bool Return the zoomed image in addition to the measured offset? zoomstep : int Amount to increase the zoom factor by on each iteration. Probably best to stick with small integers (2-5ish). verbose : bool Print out information about zoom factor, offset at each iteration minmax : np.min or np.max Can zoom in on the minimum or maximum of the image ploteach : bool Primarily a debug tool, and to be used with extreme caution! Will open a new figure at each iteration showing the next zoom level. return_center : bool Return the center position in original image coordinates? If False, will retern the *offset from center* instead (but beware the conventions associated with the concept of 'center' for even images). Returns ------- The y,x offsets (following numpy convention) of the center position of the original image. If `return_zoomed`, returns (zoomed_image, zoom_factor, offsets) because you can't interpret the zoomed image without the zoom factor. """ image_zoom = image argminmax = np.argmin if "min" in minmax.__name__ else np.argmax zf = 1.0 # "zoom factor" initialized to 1 for the base shift measurement offset = np.array([0] * image.ndim, dtype="float") # center offset delta_image = image_zoom - minmax(image_zoom) xaxzoom = np.indices(image.shape) if ploteach: ii = 1 pl.figure(ii) pl.clf() pl.pcolor(np.arange(image.shape[0] + 1) - 0.5, np.arange(image.shape[1] + 1) - 0.5, image) minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) pl.plot(minpos[1], minpos[0], "wx") # check to make sure the smallest *nonzero* difference > mindiff while np.abs(delta_image[np.abs(delta_image) > 0]).min() > mindiff: minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) center = xaxzoom[0][minpos], xaxzoom[1][minpos] offset = xaxzoom[0][minpos] - (image.shape[0] - 1) / 2, xaxzoom[1][minpos] - (image.shape[1] - 1) / 2 zf *= zoomstep xaxzoom, image_zoom = zoom.zoom_on_pixel(image, center, usfac=zf, outshape=zoomshape, return_xouts=True) delta_image = image_zoom - minmax(image_zoom) # base case: in case you can't do any better... # (at this point, you're all the way zoomed) if np.all(delta_image == 0): if verbose: print "Can't zoom any further. zf=%i" % zf break if verbose: print ( "Zoom factor %6i, center = %30s, offset=%30s, minpos=%30s, min|diff|=%15g" % ( zf, ",".join(["%15g" % c for c in center]), ",".join(["%15g" % c for c in offset]), ",".join(["%5i" % c for c in minpos]), np.abs(delta_image[np.abs(delta_image) > 0]).min(), ) ) if ploteach: ii += 1 pl.figure(ii) pl.clf() pl.pcolor(centers_to_edges(xaxzoom[1][0, :]), centers_to_edges(xaxzoom[0][:, 0]), image_zoom) pl.contour(xaxzoom[1], xaxzoom[0], image_zoom - image_zoom.min(), levels=[1, 5, 15], cmap=pl.cm.gray) pl.plot(center[1], center[0], "wx") minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) pl.plot(xaxzoom[1][minpos], xaxzoom[0][minpos], "w+") pl.arrow( center[1], center[0], xaxzoom[1][minpos] - center[1], xaxzoom[0][minpos] - center[0], color="w", head_width=0.1 / zf, linewidth=1.0 / zf, length_includes_head=True, ) pl.figure(1) # pl.contour(xaxzoom[1],xaxzoom[0],image_zoom-image_zoom.min(),levels=[1,5,15],cmap=pl.cm.gray) pl.arrow( center[1], center[0], xaxzoom[1][minpos] - center[1], xaxzoom[0][minpos] - center[0], color="w", head_width=0.1 / zf, linewidth=1.0 / zf, length_includes_head=True, ) if return_center: result = center else: result = offset if return_zoomed: return image_zoom, zf, result else: return result
def iterative_zoom_1d( data, mindiff=1.0, zoomshape=(10,), return_zoomed=False, zoomstep=2, verbose=False, minmax=np.min, return_center=True, ): """ Iteratively zoom in on the *minimum* position in a spectrum or timestream until the delta-peak value is below `mindiff` Parameters ---------- data : np.ndarray One-dimensional array with a *minimum* (or maximum, as specified by minmax) to zoom in on mindiff : float Minimum difference that must be present in image before zooming is done zoomshape : int Shape of the "mini" image to create. Smaller is faster, but a bit less accurate. 10 seems to work well in preliminary tests (though unit tests have not been written) return_zoomed : bool Return the zoomed image in addition to the measured offset? zoomstep : int Amount to increase the zoom factor by on each iteration. Probably best to stick with small integers (2-5ish). verbose : bool Print out information about zoom factor, offset at each iteration minmax : np.min or np.max Can zoom in on the minimum or maximum of the image return_center : bool Return the center position in original image coordinates? If False, will retern the *offset from center* instead (but beware the conventions associated with the concept of 'center' for even images). Returns ------- The x offsets of the center position of the original spectrum. If `return_zoomed`, returns (zoomed_image, zoom_factor, offsets) because you can't interpret the zoomed spectrum without the zoom factor. """ data_zoom = data argminmax = np.argmin if "min" in minmax.__name__ else np.argmax zf = 1.0 # "zoom factor" initialized to 1 for the base shift measurement offset = 0.0 delta_data = data_zoom - minmax(data_zoom) xaxzoom = np.arange(data.size) # check to make sure the smallest *nonzero* difference > mindiff while np.abs(delta_data[np.abs(delta_data) > 0]).min() > mindiff: minpos = argminmax(data_zoom) center = (xaxzoom.squeeze()[minpos],) offset = (xaxzoom.squeeze()[minpos] - (data.size - 1) / 2,) zf *= zoomstep xaxzoom, data_zoom = zoom.zoom_on_pixel(data, center, usfac=zf, outshape=zoomshape, return_xouts=True) delta_data = data_zoom - minmax(data_zoom) # base case: in case you can't do any better... # (at this point, you're all the way zoomed) if np.all(delta_data == 0): if verbose: print "Can't zoom any further. zf=%i" % zf break if verbose: print ( "Zoom factor %6i, center = %30s, offset=%30s, minpos=%30s, mindiff=%30s" % ( zf, "%15g" % center, "%15g" % offset, "%15g" % minpos, "%15g" % np.abs(delta_data[np.abs(delta_data) > 0]).min(), ) ) if return_center: result = center else: result = offset if return_zoomed: return data_zoom, zf, result else: return result
def fourier_combine(highresfitsfile, lowresfitsfile, matching_scale=60*u.arcsec, scale=False, return_hdu=False, ): """ Simple reimplementation of 'feather' for 2D images """ raise "Obsolete" f1 = fits.open(highresfitsfile) w1 = wcs.WCS(f1[0].header) f2 = fits.open(lowresfitsfile) w2 = wcs.WCS(f2[0].header) nax1,nax2 = f1[0].header['NAXIS1'], f1[0].header['NAXIS2'] # We take care of zooming later... #if not(nax1 == f2[0].header['NAXIS1'] and nax2 == f2[0].header['NAXIS2']): # raise ValueError("Images are not in the same pixel space; reproject " # "them to common pixel space first.") pixscale1 = w1.wcs.get_cdelt()[1] pixscale2 = w2.wcs.get_cdelt()[1] center = w1.sub([wcs.WCSSUB_CELESTIAL]).wcs_pix2world([nax1/2.], [nax2/2.], 1) frame = 'icrs' if w1.celestial.wcs.ctype[0][:2] == 'RA' else 'galactic' if w2.celestial.wcs.ctype[0][:2] == 'RA': center = coordinates.SkyCoord(*(center*u.deg), frame=frame).fk5 cxy = center.ra.deg,center.dec.deg elif w2.celestial.wcs.ctype[0][:4] == 'GLON': center = coordinates.SkyCoord(*(center*u.deg), frame=frame).galactic cxy = center.l.deg,center.b.deg im1 = f1[0].data.squeeze() im1[np.isnan(im1)] = 0 shape = im1.shape im2raw = f2[0].data.squeeze() im2raw[np.isnan(im2raw)] = 0 if len(shape) != im2raw.ndim: raise ValueError("Different # of dimensions in the interferometer and " "single-dish images") if len(shape) == 3: if shape[0] != im2raw.shape[0]: raise ValueError("Spectral dimensions of cubes do not match.") center_pixel = w2.sub([wcs.WCSSUB_CELESTIAL]).wcs_world2pix(cxy[0], cxy[1], 0)[::-1] zoomed = zoom_on_pixel(np.nan_to_num(im2raw), center_pixel, usfac=np.abs(pixscale2/pixscale1), outshape=shape) im2 = zoomed xax,psd1 = fft_psd_tools.PSD2(im1, oned=True) xax,psd2 = fft_psd_tools.PSD2(im2, oned=True) xax_as = (pixscale1/xax*u.deg).to(u.arcsec) if scale: closest_point = np.argmin(np.abs(xax_as-matching_scale)) scale_2to1 = (psd1[closest_point] / psd2[closest_point])**0.5 else: scale_2to1 = 1 fft1 = np.fft.fft2(im1) fft2 = np.fft.fft2(im2) * scale_2to1 xgrid,ygrid = (np.indices(shape)-np.array([(shape[0]-1.)/2,(shape[1]-1.)/2.])[:,None,None]) sigma = np.abs(shape[0]/((matching_scale/(pixscale1*u.deg)).decompose().value)) / np.sqrt(8*np.log(2)) kernel = np.fft.fftshift(np.exp(-(xgrid**2+ygrid**2)/(2*sigma**2))) kernel/=kernel.max() fftsum = kernel*fft2 + (1-kernel)*fft1 combo = np.fft.ifft2(fftsum) if not return_hdu: return combo elif return_hdu: combo_hdu = fits.PrimaryHDU(data=np.abs(combo), header=w1.to_header()) return combo_hdu
def fourier_combine( highresfitsfile, lowresfitsfile, matching_scale=60 * u.arcsec, scale=False, return_hdu=False, ): """ Simple reimplementation of 'feather' for 2D images """ raise "Obsolete" f1 = fits.open(highresfitsfile) w1 = wcs.WCS(f1[0].header) f2 = fits.open(lowresfitsfile) w2 = wcs.WCS(f2[0].header) nax1, nax2 = f1[0].header['NAXIS1'], f1[0].header['NAXIS2'] # We take care of zooming later... #if not(nax1 == f2[0].header['NAXIS1'] and nax2 == f2[0].header['NAXIS2']): # raise ValueError("Images are not in the same pixel space; reproject " # "them to common pixel space first.") pixscale1 = w1.wcs.get_cdelt()[1] pixscale2 = w2.wcs.get_cdelt()[1] center = w1.sub([wcs.WCSSUB_CELESTIAL]).wcs_pix2world([nax1 / 2.], [nax2 / 2.], 1) frame = 'icrs' if w1.celestial.wcs.ctype[0][:2] == 'RA' else 'galactic' if w2.celestial.wcs.ctype[0][:2] == 'RA': center = coordinates.SkyCoord(*(center * u.deg), frame=frame).fk5 cxy = center.ra.deg, center.dec.deg elif w2.celestial.wcs.ctype[0][:4] == 'GLON': center = coordinates.SkyCoord(*(center * u.deg), frame=frame).galactic cxy = center.l.deg, center.b.deg im1 = f1[0].data.squeeze() im1[np.isnan(im1)] = 0 shape = im1.shape im2raw = f2[0].data.squeeze() im2raw[np.isnan(im2raw)] = 0 if len(shape) != im2raw.ndim: raise ValueError("Different # of dimensions in the interferometer and " "single-dish images") if len(shape) == 3: if shape[0] != im2raw.shape[0]: raise ValueError("Spectral dimensions of cubes do not match.") center_pixel = w2.sub([wcs.WCSSUB_CELESTIAL ]).wcs_world2pix(cxy[0], cxy[1], 0)[::-1] zoomed = zoom_on_pixel(np.nan_to_num(im2raw), center_pixel, usfac=np.abs(pixscale2 / pixscale1), outshape=shape) im2 = zoomed xax, psd1 = fft_psd_tools.PSD2(im1, oned=True) xax, psd2 = fft_psd_tools.PSD2(im2, oned=True) xax_as = (pixscale1 / xax * u.deg).to(u.arcsec) if scale: closest_point = np.argmin(np.abs(xax_as - matching_scale)) scale_2to1 = (psd1[closest_point] / psd2[closest_point])**0.5 else: scale_2to1 = 1 fft1 = np.fft.fft2(im1) fft2 = np.fft.fft2(im2) * scale_2to1 xgrid, ygrid = (np.indices(shape) - np.array([(shape[0] - 1.) / 2, (shape[1] - 1.) / 2.])[:, None, None]) sigma = np.abs(shape[0] / ( (matching_scale / (pixscale1 * u.deg)).decompose().value)) / np.sqrt(8 * np.log(2)) kernel = np.fft.fftshift(np.exp(-(xgrid**2 + ygrid**2) / (2 * sigma**2))) kernel /= kernel.max() fftsum = kernel * fft2 + (1 - kernel) * fft1 combo = np.fft.ifft2(fftsum) if not return_hdu: return combo elif return_hdu: combo_hdu = fits.PrimaryHDU(data=np.abs(combo), header=w1.to_header()) return combo_hdu
def iterative_zoom(image, mindiff=1., zoomshape=[10, 10], return_zoomed=False, zoomstep=2, verbose=False, minmax=np.min, ploteach=False, return_center=True): """ Iteratively zoom in on the *minimum* position in an image until the delta-peak value is below `mindiff` Parameters ---------- image : np.ndarray Two-dimensional image with a *minimum* to zoom in on (or maximum, if specified using `minmax`) mindiff : float Minimum difference that must be present in image before zooming is done zoomshape : [int,int] Shape of the "mini" image to create. Smaller is faster, but a bit less accurate. [10,10] seems to work well in preliminary tests (though unit tests have not been written) return_zoomed : bool Return the zoomed image in addition to the measured offset? zoomstep : int Amount to increase the zoom factor by on each iteration. Probably best to stick with small integers (2-5ish). verbose : bool Print out information about zoom factor, offset at each iteration minmax : np.min or np.max Can zoom in on the minimum or maximum of the image ploteach : bool Primarily a debug tool, and to be used with extreme caution! Will open a new figure at each iteration showing the next zoom level. return_center : bool Return the center position in original image coordinates? If False, will retern the *offset from center* instead (but beware the conventions associated with the concept of 'center' for even images). Returns ------- The y,x offsets (following numpy convention) of the center position of the original image. If `return_zoomed`, returns (zoomed_image, zoom_factor, offsets) because you can't interpret the zoomed image without the zoom factor. """ image_zoom = image argminmax = np.argmin if "min" in minmax.__name__ else np.argmax zf = 1. # "zoom factor" initialized to 1 for the base shift measurement offset = np.array([0] * image.ndim, dtype='float') # center offset delta_image = (image_zoom - minmax(image_zoom)) xaxzoom = np.indices(image.shape) if ploteach: ii = 1 pl.figure(ii) pl.clf() pl.pcolor( np.arange(image.shape[0] + 1) - 0.5, np.arange(image.shape[1] + 1) - 0.5, image) minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) pl.plot(minpos[1], minpos[0], 'wx') # check to make sure the smallest *nonzero* difference > mindiff while np.abs(delta_image[np.abs(delta_image) > 0]).min() > mindiff: minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) center = xaxzoom[0][minpos], xaxzoom[1][minpos] offset = xaxzoom[0][minpos] - (image.shape[0] - 1) / 2, xaxzoom[1][ minpos] - (image.shape[1] - 1) / 2 zf *= zoomstep xaxzoom, image_zoom = zoom.zoom_on_pixel(image, center, usfac=zf, outshape=zoomshape, return_xouts=True) delta_image = image_zoom - minmax(image_zoom) # base case: in case you can't do any better... # (at this point, you're all the way zoomed) if np.all(delta_image == 0): if verbose: print "Can't zoom any further. zf=%i" % zf break if verbose: print( "Zoom factor %6i, center = %30s, offset=%30s, minpos=%30s, min|diff|=%15g" % (zf, ",".join(["%15g" % c for c in center]), ",".join( ["%15g" % c for c in offset]), ",".join(["%5i" % c for c in minpos]), np.abs(delta_image[np.abs(delta_image) > 0]).min())) if ploteach: ii += 1 pl.figure(ii) pl.clf() pl.pcolor(centers_to_edges(xaxzoom[1][0, :]), centers_to_edges(xaxzoom[0][:, 0]), image_zoom) pl.contour(xaxzoom[1], xaxzoom[0], image_zoom - image_zoom.min(), levels=[1, 5, 15], cmap=pl.cm.gray) pl.plot(center[1], center[0], 'wx') minpos = np.unravel_index(argminmax(image_zoom), image_zoom.shape) pl.plot(xaxzoom[1][minpos], xaxzoom[0][minpos], 'w+') pl.arrow(center[1], center[0], xaxzoom[1][minpos] - center[1], xaxzoom[0][minpos] - center[0], color='w', head_width=0.1 / zf, linewidth=1. / zf, length_includes_head=True) pl.figure(1) #pl.contour(xaxzoom[1],xaxzoom[0],image_zoom-image_zoom.min(),levels=[1,5,15],cmap=pl.cm.gray) pl.arrow(center[1], center[0], xaxzoom[1][minpos] - center[1], xaxzoom[0][minpos] - center[0], color='w', head_width=0.1 / zf, linewidth=1. / zf, length_includes_head=True) if return_center: result = center else: result = offset if return_zoomed: return image_zoom, zf, result else: return result
def iterative_zoom_1d(data, mindiff=1., zoomshape=(10, ), return_zoomed=False, zoomstep=2, verbose=False, minmax=np.min, return_center=True): """ Iteratively zoom in on the *minimum* position in a spectrum or timestream until the delta-peak value is below `mindiff` Parameters ---------- data : np.ndarray One-dimensional array with a *minimum* (or maximum, as specified by minmax) to zoom in on mindiff : float Minimum difference that must be present in image before zooming is done zoomshape : int Shape of the "mini" image to create. Smaller is faster, but a bit less accurate. 10 seems to work well in preliminary tests (though unit tests have not been written) return_zoomed : bool Return the zoomed image in addition to the measured offset? zoomstep : int Amount to increase the zoom factor by on each iteration. Probably best to stick with small integers (2-5ish). verbose : bool Print out information about zoom factor, offset at each iteration minmax : np.min or np.max Can zoom in on the minimum or maximum of the image return_center : bool Return the center position in original image coordinates? If False, will retern the *offset from center* instead (but beware the conventions associated with the concept of 'center' for even images). Returns ------- The x offsets of the center position of the original spectrum. If `return_zoomed`, returns (zoomed_image, zoom_factor, offsets) because you can't interpret the zoomed spectrum without the zoom factor. """ data_zoom = data argminmax = np.argmin if "min" in minmax.__name__ else np.argmax zf = 1. # "zoom factor" initialized to 1 for the base shift measurement offset = 0. delta_data = (data_zoom - minmax(data_zoom)) xaxzoom = np.arange(data.size) # check to make sure the smallest *nonzero* difference > mindiff while np.abs(delta_data[np.abs(delta_data) > 0]).min() > mindiff: minpos = argminmax(data_zoom) center = xaxzoom.squeeze()[minpos], offset = xaxzoom.squeeze()[minpos] - (data.size - 1) / 2, zf *= zoomstep xaxzoom, data_zoom = zoom.zoom_on_pixel(data, center, usfac=zf, outshape=zoomshape, return_xouts=True) delta_data = data_zoom - minmax(data_zoom) # base case: in case you can't do any better... # (at this point, you're all the way zoomed) if np.all(delta_data == 0): if verbose: print "Can't zoom any further. zf=%i" % zf break if verbose: print( "Zoom factor %6i, center = %30s, offset=%30s, minpos=%30s, mindiff=%30s" % ( zf, "%15g" % center, "%15g" % offset, "%15g" % minpos, "%15g" % np.abs(delta_data[np.abs(delta_data) > 0]).min(), )) if return_center: result = center else: result = offset if return_zoomed: return data_zoom, zf, result else: return result