-
Nicolas Fernandez Cinquepalmi authored25f1951f
Ejercicio Nº 1: Ejercicios para practicar numpy y optimización con scipy
Autor: Nicolás Fernández Cinquepalmi
Breve descripción: En observaciones astronómicas e imágenes en general, llamamos resolución espacial a la distancia angular minima a la que pueden estar dos fuentes puntuales de luz y aun poder ser reconocidas como objetos individuales.
En el caso de la astronomía, este efecto tiene que ver con la dispersión de la luz al atravezar la atmósfera, la cual hace que una estrella, que debería en principio aparecer como una fuente puntual (pues las estrellas están muy lejos), aparezca en cambio como una mancha. Así, si dos estrellas están demasiado cerca sus manchas se superpondrán hasta el punto en que sea imposible distinguirlas como fuentes individuales.
Para modelar este efecto, típicamente consideramos la acción de la atmósfera como la convolución de la imagen "perfecta" (como se vería desde el espacio) con un kernel gaussiano. El ancho de esa función gaussiana 2D caracteriza las condiciones de observación, varía con las condiciones climáticas y para cada sitio de la Tierra.
La resolución espacial normalmente se toma como el FWHM de la gaussiana caracteristica registrada durante una observación. Es decir, si dos estrellas están a una distancia aparente en el cielo menor que el FWHM del efecto atmosférico, la luz de ambas fuentes se mezclará después de la convolución hasta el punto de impedir reconocerlas de modo individual.
Además, la atmósfera puede interactuar de maneras distintas con la luz de distintas longitudes de onda, de manera que el ancho de la gaussiana puede ser distinto para observaciones con diferentes filtros.
El objetivo de esta tarea es medir de forma aproximada la resolución espacial en una noche de observación en Zapatoca, Santander (Colombia), a partir de una foto del cielo estrellado.
Paso 1: Comenzamos con importar los módulos necesarios para este trabajo.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import image
from matplotlib import pyplot
from PIL import Image
from scipy import optimize
from matplotlib.pyplot import figure
Paso 2: Cargamos la imagen desde su ubicación en el repositorio.
imageRGB = image.imread('/home/fernandezn/ejercicios-clase-05-datos/data/zapatocaImage.jpeg')/255
print("Dimensiones de la imagen:")
print(imageRGB.shape)
print("Dtype:")
print(imageRGB.dtype)
Dimensiones de la imagen:
(789, 1184, 3)
Dtype:
float64
pyplot.imshow(imageRGB)
pyplot.show()
Paso 3: Convertimos la imagen RGB en escala de grises haciendo un promedio de los 3 canales.
im_gray = np.mean(imageRGB, axis = 2)
plt.imshow(im_gray, cmap='gray')
<matplotlib.image.AxesImage at 0x7f85e058a080>
Paso 4: Realizamos cortes de la imagen, localizados en una estrella particular. Luego calculamos los centros para localizarlos en la imagen.
im_cut1 = im_gray[540:570,640:680]
max_index = np.where(im_cut1 >= np.max(im_cut1))
x01 = np.mean(max_index[1])
y01 = np.mean(max_index[0])
im_cut2 = im_gray[300:315,470:485]
max_index = np.where(im_cut2 >= np.max(im_cut2))
x02 = np.mean(max_index[1])
y02 = np.mean(max_index[0])
im_cut3 = im_gray[310:325,615:640]
max_index = np.where(im_cut3 >= np.max(im_cut3))
x03 = np.mean(max_index[1])
y03 = np.mean(max_index[0])
im_cut4 = im_gray[295:315,470:490]
max_index = np.where(im_cut4 >= np.max(im_cut4))
x04 = np.mean(max_index[1])
y04 = np.mean(max_index[0])
fig, axs = plt.subplots(2,2, figsize=(10,10))
axs[0,0].imshow(im_cut1, cmap='gray')
axs[0,0].plot(x01,y01,c='r',marker='+',markersize = 30)
axs[1,0].imshow(im_cut2, cmap='gray')
axs[1,0].plot(x02,y02,c='r',marker='+',markersize = 30)
axs[0,1].imshow(im_cut3, cmap='gray')
axs[0,1].plot(x03,y03,c='r',marker='+',markersize = 30)
axs[1,1].imshow(im_cut4, cmap='gray')
axs[1,1].plot(x04,y04,c='r',marker='+',markersize = 30)
[<matplotlib.lines.Line2D at 0x7f85e04be710>]
Paso 5: Definimos la función gaussiana 2D, la función de los momentos estadísticos y la función para realizar el ajuste.
def gaussian(height, center_x, center_y, width_x, width_y):
"""Returns a gaussian function with the given parameters"""
width_x = float(width_x)
width_y = float(width_y)
return lambda x,y: height*np.exp(
-(((center_x-x)/width_x)**2+((center_y-y)/width_y)**2)/2)
def moments(data):
"""Returns (height, x, y, width_x, width_y)
the gaussian parameters of a 2D distribution by calculating its
moments """
total = data.sum()
X, Y = np.indices(data.shape)
x = (X*data).sum()/total
y = (Y*data).sum()/total
col = data[:, int(y)]
width_x = np.sqrt(np.abs((np.arange(col.size)-x)**2*col).sum()/col.sum())
row = data[int(x), :]
width_y = np.sqrt(np.abs((np.arange(row.size)-y)**2*row).sum()/row.sum())
height = data.max()
return height, x, y, width_x, width_y
def fitgaussian(data):
"""Returns (height, x, y, width_x, width_y)
the gaussian parameters of a 2D distribution found by a fit"""
sigma = np.sqrt(data)
params = moments(data)
errorfunction = lambda p: np.ravel((gaussian(*p)(*np.indices(data.shape)) - data)/sigma)
p, success = optimize.leastsq(errorfunction, params)
return p
Paso 6: Realizamos el ajuste gaussiano para cada corte y calculamos su valor de FWHM.
# FIT IMAGEN 1
Xin, Yin = np.mgrid[0:30, 0:40]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(im_cut1, cmap=plt.cm.cubehelix)
params = fitgaussian(im_cut1)
fit = gaussian(*params)
plt.contour(fit(*np.indices(im_cut1.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM1 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM1,2))
El valor de FWHM es: 42.97
# FIT IMAGEN 2
Xin, Yin = np.mgrid[0:15, 0:25]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(im_cut2, cmap=plt.cm.cubehelix)
params = fitgaussian(im_cut2)
fit = gaussian(*params)
plt.contour(fit(*np.indices(im_cut2.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM2 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM2,2))
El valor de FWHM es: 23.25
# FIT IMAGEN 3
Xin, Yin = np.mgrid[0:14, 0:14]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(im_cut3, cmap=plt.cm.cubehelix)
params = fitgaussian(im_cut3)
fit = gaussian(*params)
plt.contour(fit(*np.indices(im_cut3.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM3 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM3,2))
El valor de FWHM es: 21.82
# FIT IMAGEN 4
Xin, Yin = np.mgrid[0:20, 0:20]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(im_cut4, cmap=plt.cm.cubehelix)
params = fitgaussian(im_cut4)
fit = gaussian(*params)
plt.contour(fit(*np.indices(im_cut4.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM4 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM4,2))
El valor de FWHM es: 37.46
Paso 7: Calculamos el valor medio, mediana y desvío estandar de los FWHM obtenidos para los cortes realizados. Por último, realizamos un histograma.
FWHM = [FWHM1, FWHM2, FWHM3, FWHM4]
Media = np.round(np.mean(FWHM),2)
Mediana = np.round(np.median(FWHM),2)
Desvio = np.round(np.std(FWHM),2)
print('El valor medio de FWHM es: ', Media)
print('La mediana de FWHM es: ', Mediana)
print('El desvío estándar de FWHM es: ', Desvio)
plt.hist(FWHM, bins = [0,10,20,30,40,50])
plt.title("Histograma Gray")
plt.show()
El valor medio de FWHM es: 31.37
La mediana de FWHM es: 30.35
El desvío estándar de FWHM es: 9.07
Comentario: Cuanto menor sea el FWHM de tu fotografía mejor, ya que esto indica que la luz está más concentrada en el punto de origen que la causa y menos desparramada por los píxeles adyacentes. En este caso el valor medio es de 31.37.
Paso 8: Realizamos el ajuste gaussiano, de la misma forma pero ahora con el canal rojo.
image_red = np.copy(imageRGB) # creo una copia de la imagen para preservar la original
image_red[:,:,1]=0
image_red[:,:,2]=0
plt.title("Canal rojo")
plt.imshow(image_red)
<matplotlib.image.AxesImage at 0x7f85dcae0940>
im_red = np.mean(image_red, axis = 2)
red_cut1 = im_red[540:570,640:680]
max_index = np.where(red_cut1 >= np.max(red_cut1))
r_x01 = np.mean(max_index[1])
r_y01 = np.mean(max_index[0])
red_cut2 = im_red[300:315,470:485]
max_index = np.where(red_cut2 >= np.max(red_cut2))
r_x02 = np.mean(max_index[1])
r_y02 = np.mean(max_index[0])
red_cut3 = im_red[310:325,615:640]
max_index = np.where(red_cut3 >= np.max(red_cut3))
r_x03 = np.mean(max_index[1])
r_y03 = np.mean(max_index[0])
red_cut4 = im_red[295:315,470:490]
max_index = np.where(red_cut4 >= np.max(red_cut4))
r_x04 = np.mean(max_index[1])
r_y04 = np.mean(max_index[0])
fig, axs = plt.subplots(2,2, figsize=(10,10))
axs[0,0].imshow(red_cut1)
axs[0,0].plot(r_x01,r_y01,c='b',marker='+',markersize = 30)
axs[1,0].imshow(red_cut2)
axs[1,0].plot(r_x02,r_y02,c='b',marker='+',markersize = 30)
axs[0,1].imshow(red_cut3)
axs[0,1].plot(r_x03,r_y03,c='b',marker='+',markersize = 30)
axs[1,1].imshow(red_cut4)
axs[1,1].plot(r_x04,r_y04,c='b',marker='+',markersize = 30)
[<matplotlib.lines.Line2D at 0x7f85dc99b128>]
# FIT IMAGEN_RED 1
Xin, Yin = np.mgrid[0:30, 0:40]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(red_cut1, cmap=plt.cm.cubehelix)
params = fitgaussian(red_cut1)
fit = gaussian(*params)
plt.contour(fit(*np.indices(red_cut1.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_r1 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_r1,2))
El valor de FWHM es: 55.27
# FIT IMAGEN_RED 2
Xin, Yin = np.mgrid[0:15, 0:25]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(red_cut2, cmap=plt.cm.cubehelix)
params = fitgaussian(red_cut2)
fit = gaussian(*params)
plt.contour(fit(*np.indices(red_cut2.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_r2 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_r2,2))
El valor de FWHM es: 27.58
# FIT IMAGEN_RED 3
Xin, Yin = np.mgrid[0:14, 0:14]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(red_cut3, cmap=plt.cm.cubehelix)
params = fitgaussian(red_cut3)
fit = gaussian(*params)
plt.contour(fit(*np.indices(red_cut3.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_r3 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_r3,2))
El valor de FWHM es: 26.51
# FIT IMAGEN_RED 4
Xin, Yin = np.mgrid[0:20, 0:20]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(red_cut4, cmap=plt.cm.cubehelix)
params = fitgaussian(red_cut4)
fit = gaussian(*params)
plt.contour(fit(*np.indices(red_cut4.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_r4 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_r4,2))
El valor de FWHM es: 46.59
FWHM_r = [FWHM_r1, FWHM_r2, FWHM_r3, FWHM_r4]
Media = np.round(np.mean(FWHM_r),2)
Mediana = np.round(np.median(FWHM_r),2)
Desvio = np.round(np.std(FWHM_r),2)
print('El valor medio de FWHM es: ', Media)
print('La mediana de FWHM es: ', Mediana)
print('El desvío estándar de FWHM es: ', Desvio)
plt.hist(FWHM_r, bins = [10,20,30,40,50,60])
plt.title("Histograma Red")
plt.show()
El valor medio de FWHM es: 38.99
La mediana de FWHM es: 37.09
El desvío estándar de FWHM es: 12.33
Comentario: El valor medio para el canal rojo es de 38.99, lo cual indica que el cielo posee altos valores de rojo.
Paso 9: Se realiza el mismo proceso para el canal verde.
image_green = np.copy(imageRGB) # creo una copia de la imagen para preservar la original
image_green[:,:,0]=0
image_green[:,:,2]=0
plt.title("Canal verde")
plt.imshow(image_green)
<matplotlib.image.AxesImage at 0x7f85dc9f7e10>
im_green = np.mean(image_green, axis = 2)
green_cut1 = im_green[540:570,640:680]
max_index = np.where(green_cut1 >= np.max(green_cut1))
g_x01 = np.mean(max_index[1])
g_y01 = np.mean(max_index[0])
green_cut2 = im_green[300:315,470:485]
max_index = np.where(green_cut2 >= np.max(green_cut2))
g_x02 = np.mean(max_index[1])
g_y02 = np.mean(max_index[0])
green_cut3 = im_green[310:325,615:640]
max_index = np.where(green_cut3 >= np.max(green_cut3))
g_x03 = np.mean(max_index[1])
g_y03 = np.mean(max_index[0])
green_cut4 = im_green[295:315,470:490]
max_index = np.where(green_cut4 >= np.max(green_cut4))
g_x04 = np.mean(max_index[1])
g_y04 = np.mean(max_index[0])
fig, axs = plt.subplots(2,2, figsize=(10,10))
axs[0,0].imshow(green_cut1)
axs[0,0].plot(g_x01,g_y01,c='b',marker='+',markersize = 30)
axs[1,0].imshow(green_cut2)
axs[1,0].plot(g_x02,g_y02,c='b',marker='+',markersize = 30)
axs[0,1].imshow(green_cut3)
axs[0,1].plot(g_x03,g_y03,c='b',marker='+',markersize = 30)
axs[1,1].imshow(green_cut4)
axs[1,1].plot(g_x04,g_y04,c='b',marker='+',markersize = 30)
[<matplotlib.lines.Line2D at 0x7f85dc8a5f98>]
# FIT IMAGEN_GREEN 1
Xin, Yin = np.mgrid[0:30, 0:40]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(green_cut1, cmap=plt.cm.cubehelix)
params = fitgaussian(green_cut1)
fit = gaussian(*params)
plt.contour(fit(*np.indices(green_cut1.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_g1 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_g1,2))
El valor de FWHM es: 42.65
# FIT IMAGEN_GREEN 2
Xin, Yin = np.mgrid[0:15, 0:25]
data = gaussian(3, 100, 100, 20, 40)(Xin, Yin) + np.random.random(Xin.shape)
plt.matshow(green_cut2, cmap=plt.cm.cubehelix)
params = fitgaussian(green_cut2)
fit = gaussian(*params)
plt.contour(fit(*np.indices(green_cut2.shape)), cmap=plt.cm.copper)
ax = plt.gca()
(height, x, y, width_x, width_y) = params
plt.text(0.95, 0.05, """
x : %.1f
y : %.1f
width_x : %.1f
width_y : %.1f""" %(x, y, width_x, width_y),
fontsize=16, horizontalalignment='right',
verticalalignment='bottom', transform=ax.transAxes,c='white')
FWHM_g2 = 2*np.sqrt(2*np.log(2))*width_x
print('El valor de FWHM es: ',np.round(FWHM_g2,2))
El valor de FWHM es: 24.13