Newer
Older
from scipy.optimize import minimize
from scipy.ndimage import gaussian_filter,shift
from .settings import Settings
"""[summary]
Parameters
----------
x : [type]
[description]
Returns
-------
[type]
[description]
"""
return np.median(np.abs(x - np.median(x)))
def prepare_image_conf(img, conf, orientation, img_std=-1):
# Generates properly aligned images, as the crossmatching code works
# assuming a fixed relative orientation of the images.
#
# Returns the rotated image, a rotated filtered image to be
# used in the crossmatching plus a confidence map. If apply_filter
# is switched on, a median substracted image (either 1D or 2D median)
# is returned as fimg_filt, otherwise a copy of the original image
Parameters
----------
img : [type]
[description]
conf : [type]
[description]
orientation : str
[description]
img_std : int, optional
[description], by default -1
Returns
-------
[type]
[description]
"""
img_fin = np.rot90(img, 1)
conf_fin = np.rot90(conf, 1)
img_fin = img.copy()
conf_fin = conf.copy()
# if STD=-1 the std for the confidence mask is computed over the image,
# otherwise the valued passed as STD is used. By default the code uses
# a STD computed over the whole cube, that is mucho more robust that
if img_std == -1:
mask_fin[np.abs(img_filt) <= N_SIGMA_CLIP * 1.48 * mad(img_filt)] = 0.0
def find_overlap_conf_old_version( # noqa
img_ref,
conf_ref,
img_obj,
conf_obj,
This calculates the displacementes that minimize the squared difference
between images.
Parameters
----------
img_ref : [type]
[description]
conf_ref : [type]
[description]
img_obj : [type]
[description]
conf_obj : [type]
[description]
blind_start : bool, optional
[description], by default True
init_desp : list, optional
[description], by default [-50, 1858]
[description], by default -1
Returns
-------
[type]
[description]
"""
assert orientation is not None, 'orientation cannot be None'
REFINE_CHI = True
STEPS = 30 # The chi surface will be of STEPSxSTEPS size
# DELTA is the step that dx and dy are increased at each
# point of the evaliations of chi.
#
# If an initial estimate is provided, the (dx,dy) space
# of possible displacements to explore is narrower
if init_desp is None:
init_desp = [-50, 1858]
# By default the code assumes that img0 is the reference image and that
# img1 is aligned along the X direction (in the python matrix coordinate
# frame). If this is not the case, ORIENTATION is set to Y and the images
# rotated inside prepare_image
img0, img0_filt, mask0 = prepare_image_conf(
img_ref, conf_ref, orientation, img_std=img_std
)
img1, img1_filt, mask1 = prepare_image_conf(
img_obj, conf_obj, orientation, img_std=img_std
# the first iteration sets up the displacements to be
# add 10 so that at least there are 10px to compare overlap
# desp_large runs along the direction where the displacement is
# the largest, so typically will have values between 1700 and 2100,
# while desp_short runs in the other, and moves between -200 and 200.
desp_large = DET_SIZE - 10 - \
np.arange(STEPS + 1) * DELTA[i_delta] - 1.0
desp_short = (
np.arange(STEPS + 1) * DELTA[i_delta]
- (STEPS - 1) * DELTA[i_delta] * 0.5
)
else:
# in case there is a prior estimation of the displacement
# that minimizes chi, the vectors are centered at that point
desp_short = (
np.arange(STEPS) * DELTA[i_delta]
- (STEPS - 1) * DELTA[i_delta] * 0.5
+ dx
)
# this just makes sure that we don't run out of image
if (STEPS - 1) * DELTA[i_delta] * 0.5 + dy >= DET_SIZE:
delta_cor = (STEPS - 1) * DELTA[i_delta] * 0.5 + dy - DET_SIZE
desp_large = (
np.arange(STEPS) * DELTA[i_delta]
- (STEPS - 1) * DELTA[i_delta] * 0.5
+ dy
- delta_cor
)
# because these will be used as indexes, need to be
desp_y = desp_large.astype(int)
desp_x = desp_short.astype(int)
chi = np.zeros((len(desp_x), len(desp_y)))
npx = np.ones((len(desp_x), len(desp_y)))
t_ref = img0[:, dy:]
err_ref = np.sqrt(img0[:, dy:]) # assuming poisson errors
mask_ref = mask0[:, dy:]
t1 = img1[:, 0:-dy]
maskt = mask1[:, 0:-dy]
err_1 = np.sqrt(img1[:, 0:-dy])
for j, dx in enumerate(desp_x):
if dx < 0:
# this is the difference of the overlap of the reference image
# and the displaced image. Depending on whether the small displacemente
# is positive, negative or zero the indexes need to be generated,
# so there's on branch of the if
t1[abs(dx):, ] * maskt[abs(dx):, :] - # noqa
t_ref[0:dx, ] * mask_ref[0:dx, :] # noqa
mask_final = maskt[abs(dx):, :] + mask_ref[0:dx, :] # noqa
err_ref[0:dx, :] ** 2 + err_1[abs(dx):, ] ** 2 # noqa
temp = t1 * maskt - t_ref * mask_ref
div_t = np.sqrt(err_ref ** 2 + err_1 ** 2)
mask_final = maskt + mask_ref
t1[0:-dx, ] * maskt[0:-dx, ] # noqa
- t_ref[dx:, ] * mask_ref[dx:, ] # noqa
mask_final = maskt[0:-dx, ] + mask_ref[dx:, ] # noqa
err_ref[np.abs(dx):, ] ** 2 + err_1[0:-dx, ] ** 2 # noqa
# if there are not enough good pixels we set chi to 10e7
if mask_final.sum() > 0:
chi[j, i] = np.mean(
(temp[mask_final > 0] / div_t[mask_final > 0]) ** 2
)
npx[j, i] = np.sum(mask_final)
if REFINE_CHI:
# this generates an estimation of the "background" of the chi surface,
# that sometimes is heplful, mostly for cosmetic reasons, to have a flat
# chi with a very clear minumum
temp_bg0 = np.array(list(np.median(chi, 0)) * chi.shape[1]).reshape(
chi.shape
)
chi -= temp_bg0
# now finfing the minimum
i_x, i_y = np.where(chi == chi.min())
try:
# in case of many nans, this fails, default to middle
dx = desp_x[i_x][0]
dy = desp_y[i_y][0]
dx = np.median(desp_x)
dy = np.median(desp_y)
if 'x' in orientation:
dx, dy = dy, -dx
if '-' in orientation:
dx, dy = -dx, -dy
def compare_imgs(
desp,
im1,
co1,
im2,
co2,
do_print
):
im2_desp = shift(im2, desp, mode='constant', cval=0, order=1)
co2_desp = shift(co2, desp, mode='constant', cval=0, order=1)
err = np.sum(
(co_all * (im2_desp - im1)**2) / (im1 + 0.001)
) / np.sum(co_all)
if np.isnan(err):
return np.inf
if do_print:
t_s = ''
for t in desp:
if np.abs(t) < 1e-3:
t_s += ' {0:.1e}'.format(t)
else:
t_s += ' {0:.3f}'.format(t)
print(t_s + ' {0:f}'.format(err))
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
return err
def find_overlap_conf( # noqa
img_ref,
conf_ref,
img_obj,
conf_obj,
desp
):
"""[summary]
This calculates the displacementes that minimize the squared difference
between images.
Parameters
----------
img_ref : [type]
[description]
conf_ref : [type]
[description]
img_obj : [type]
[description]
conf_obj : [type]
[description]
desp : []
[description]
Returns
-------
[type]
[description]
"""
if desp[0] < 0:
r_low_px_0 = 0
r_high_px_0 = img_ref.shape[0] + int(desp[0]) - 1
o_low_px_0 = abs(int(desp[0]))
o_high_px_0 = img_ref.shape[0] - 1
else:
r_low_px_0 = int(desp[0])
r_high_px_0 = img_ref.shape[0] - 1
o_low_px_0 = 0
o_high_px_0 = img_ref.shape[0] - int(desp[0]) - 1
if desp[1] < 0:
r_low_px_1 = 0
r_high_px_1 = img_ref.shape[1] + int(desp[1]) - 1
o_low_px_1 = abs(int(desp[1]))
o_high_px_1 = img_ref.shape[1] - 1
else:
r_low_px_1 = int(desp[1])
r_high_px_1 = img_ref.shape[1] - 1
o_low_px_1 = 0
o_high_px_1 = img_ref.shape[1] - int(desp[1]) - 1
r_img_cut = gaussian_filter(
img_ref[r_low_px_0:r_high_px_0, r_low_px_1:r_high_px_1], 3
)
r_con_cut = conf_ref[r_low_px_0:r_high_px_0, r_low_px_1:r_high_px_1]
o_img_cut = gaussian_filter(
img_obj[o_low_px_0:o_high_px_0, o_low_px_1:o_high_px_1], 3
)
o_con_cut = conf_obj[o_low_px_0:o_high_px_0, o_low_px_1:o_high_px_1]
res = minimize(
compare_imgs, [0., 0.],
args=(r_img_cut, r_con_cut, o_img_cut, o_con_cut, False),
method='Powell', options={'ftol': Settings.ftol_desp}
)
final_desp = [desp[0] + res['x'][0], desp[1] + res['x'][1]]
# mutual information
o_img_desp = shift(o_img_cut, final_desp, mode='constant', cval=0, order=1)
mi = mutual_information(r_img_cut, o_img_desp)
return final_desp[0], final_desp[1], mi