-
Sasiri Juliana Vargas Urbano authoreda1ab2a5c
Tareas Clase 5
Ejercicio - Resolución espacial
Nombre: Sasiri Juliana Vargas Urbano
Correo: sasiri.vargas@correounivalle.edu.co
Usuario Mattermost: vargass
Objetivo de la tarea: 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.
Se importan las librerias
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from scipy.optimize import leastsq # Para optimizar las funciones
import statistics as stat
import math
NOTA:
Por facilidad, se creó una clase para el posterior análisis de todas las estrellas, las funciones dentro de la clase tienen como base el funcionamiento de las funciones presentadas a lo largo de este notebook
from Clase_estrella import *
Paso 1 - Leer la imagen almacenada
#Para abrir la información de la imagen
imagen = plt.imread('./data/zapatocaImage.jpeg')
#Son 3 matrices de dimensiones 789 x 1184
print(imagen.shape)
(789, 1184, 3)
Imagen a tratar:
#Impresion de la imagen original
plt.imshow(imagen)
<matplotlib.image.AxesImage at 0x7f38c3d63940>
#Canales RGB
#Según la forma en la que se declaran los arreglos, se pueden formar diferentes matrices
#que representan los canales RGB
R = imagen[:,:,0] #Red
G = imagen[:,:,1] #Green
B = imagen[:,:,2] # Blue
Para entender la composición de colores RGB de la anterior imagen, se grafica cada una de las matrices (R,G y B), haciendo las demás cero, de esta forma se obtiene:
imagen_copy = np.copy(imagen) #Se copia la imagen para no perder la original
#Para el canal Rojo ---------------------------------
imagen_copy[:,:,0]=imagen[:,:,0]
imagen_copy[:,:,1]=0
imagen_copy[:,:,2]=0
Rojo = imagen_copy
imagen_copy = np.copy(imagen)
#Para el canal Verde ---------------------------------
imagen_copy[:,:,0]=0
imagen_copy[:,:,1]=imagen[:,:,1]
imagen_copy[:,:,2]=0
Verde = imagen_copy
imagen_copy = np.copy(imagen)
#Para el canal Azul ---------------------------------
imagen_copy[:,:,0]=0
imagen_copy[:,:,1]=0
imagen_copy[:,:,2]=imagen[:,:,2]
Azul = imagen_copy
#Impresion de imágenes
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(16,9))
ax1.imshow(Rojo)
ax1.set_title('Canal Rojo')
ax2.imshow(Verde)
ax2.set_title('Canal Verde')
ax3.imshow(Azul)
ax3.set_title('Canal Azul')
Text(0.5, 1.0, 'Canal Azul')
Paso 2 - Escala de grises
Existen distintos métodos por los cuales podemos encontrar la imagen a escala de grises
Método del promedio
Se realiza el promedio por cada pixel y se encuentra la luminosidad que luego se reescala con una escala de grises
#Método del promedio
imagen_gris=(R+G+B)/3
#NOTA: Por prueba y error, encontré que multiplicando por 0.1 a R, se encuentra una mejor visualización de la imagen
#(Esto está relacionado con el siguiente método)
imagen_griss=(R*0.1+G+B)/3
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(16,9))
ax1.imshow(imagen_gris, cmap='gray')
ax1.set_title('Método del promedio')
ax2.imshow(imagen_griss, cmap='gray')
ax2.set_title('Modificación método del promedio')
Text(0.5, 1.0, 'Modificación método del promedio')
Método pesado o de luminosidad
Se pesa la cantidad de R,G y B, con parámetros tales que, cuando se tiene una superposición de los R, G, B pesados, el ojo humano ve en escala de grises.
#Método pesado
imagen_grisss = (0.299*R+0.587*G+0.114*B)
fig=plt.figure(figsize=(16,5))
plt.imshow(imagen_grisss, cmap='gray')
<matplotlib.image.AxesImage at 0x7f38c3c5b198>
Las imágenes cirrespondientes a R,G,B en escala de grises se verían como:
fig, (ax1, ax2, ax3) = plt.subplots(1,3, figsize=(16,9))
ax1.imshow(R, cmap='gray')
ax1.set_title('Canal Rojo')
ax2.imshow(G, cmap='gray')
ax2.set_title('Canal Verde')
ax3.imshow(B, cmap='gray')
ax3.set_title('Canal Azul')
Text(0.5, 1.0, 'Canal Azul')
Se pueden observar unas ciertas diferencias entre las intensidades de las estrellas y por lo tanto, para el análisis de las estrellas, pueden existir diferencias para los parámetros de ajuste.
Paso 3 - Recorte de estrellas y ajuste gausiano 2D
Se escoje el rango de los pixeles de una estrella con prueba y error En primera instancia se trata de escogerla centrada
estrella = imagen_grisss[535:570, 645:680]
plt.imshow(estrella, cmap='gray')
plt.title('Primera estrella')
Text(0.5, 1.0, 'Primera estrella')
Para efectos del análisis posterior, también se recorta un fragmento con varias estrellas.
estrella_2 = imagen_grisss[330:380, 520:570]
plt.imshow(estrella_2, cmap='gray')
plt.title('Segunda estrella')
Text(0.5, 1.0, 'Segunda estrella')
Para el primer análisis de optimización se toma la 'Primera estrella'.
Para utilizar la función leastsq de scipy para optimizar se necesitan de las siguientes funciones:
#Definición del error, para una función gaussiana
#Error = Valor teórico - Valor experimental
def residuos(p, yy, xx, zz):
a, b, c, x0, y0 = p
exponente = -((xx-x0)**2 + (yy-y0)**2) / (2*c**2)
error = zz - (a * np.exp(exponente) + b)
return error.reshape(-1) #Se retorna un arreglo 1D, ya que esto es lo que recibe leastsq (función de scipy)
#NOTA: Para mayor información de esta función, pedir help() dentro de la clase Estrella_a
#Definición de una función que calcula una Gaussiana 2D
def gauss2D(x, y, p):
a, b, c, x0, y0 = p
exponente = -((x-x0)**2 + (y-y0)**2) / (2*c**2)
z = a * np.exp(exponente) + b
return z
#NOTA: Para mayor información de esta función, pedir help() dentro de la clase Estrella_a
Para el ajuste, se hacen dos arreglos de prueba x y y de dimensiones igual a 'estrella' (la imagen a analizar)
#Arreglos de prueba
x = np.arange(0,255,7.3)
y = np.arange(0,255,7.3)
#Grilla
yy, xx = np.meshgrid(x,y)
#Parámetros de ajuste tentativos
pe=np.array([2,15,15,5,5])
Haciendo uso de todo lo anterior, se obtienen los valores ajustados por míminos cuadrados de los parámetros de ajuste, esto se hace con la función leastsq de scipy
ajuste, dim = leastsq(residuos, pe, args=(xx, yy, estrella))
print(ajuste)
[149.8213941 119.16039711 -34.31135287 127.16003106 130.26587992]
Visualización del ajuste y la estrella escogida
zz= gauss2D(xx,yy,ajuste)
fig, (ax1, ax2) = plt.subplots(1,2, figsize=(9,6))
ax1.imshow(estrella, cmap='gray')
ax1.set_title('Estrella a analizar')
ax2.imshow(zz,cmap="gray")
ax2.set_title('Ajuste')
Text(0.5, 1.0, 'Ajuste')
Estadística con más estrellas
Para el análisis de más estrellas se crea una función que busca estrellas analizando una imagen de entrada.
Para ello se crean dos funciones, miniframe_estrella y estrellas_recortadas
def miniframe_estrella(estrellita_, fila, z_):
"""
Encuentra el arreglo de la imagen de la estrella recortada.
---------------------------------------------------
FUNCIONAMIENTO:
estrellita: Imagen a analizar
fila: fila de estrellita donde se encuentra la estrella
z_: Arreglo donde se guardan las posibles estrellas
"""
ancho=[]
nx, ny = np.shape(estrellita_)
#El siguiente for recorre la imagen ingresada, en la fila seleccionada
#Añade elementos a la lista ancho, mientras que la intensidad de la estrella sea mayor que 0.8
#Cuando se encuentra el centro de la estrella, el for para
#Conociendo la cantidad de elementos añadido a la lista ancho, se encuentra el radio de la estrella
for j in range(ny):
if (estrellita_[z_[0,fila],j] > 0.8) and (j != z_[1,fila]):
ancho.append(1)
radio = len(ancho)
#Creacion de un miniframe que contiene solo la estrella a analizar
star = estrellita_[z_[0,fila]-len(ancho)-5:z_[0,fila]+len(ancho)+5, z_[1,fila]-len(ancho)-5:z_[1,fila]+len(ancho)+5]
#star = estrellita_[z_[0,fila]-10:z_[0,fila]+10, z_[1,fila]-10:z_[1,fila]+10]
#Retorna el array correspondiente a la imagen del miniframe
return radio, star
#Intensidad recomendada: 240
def estrellas_recortadas(img_es, intensidad):
"""
Retorna un arreglo, tal que cada una de sus componentes es la imagen recortada de las estrellas identificadas en la imagen de ingreso
---------------------------------------------------
FUNCIONAMIENTO:
img_es: Imagen a analizar
intensidad: Intensidad de estrellas deseada para analizar. Parámetro de 0 a 254. Intensidad recomendada: 240
"""
#Primero se escala con la intensidad de estrellas deseada para buscar
estrellita=img_es/intensidad
#Se identifican las candidatas a estrellas
z = np.where(estrellita > 1)
z=np.array(z)
n, nz = np.shape(z)
k=0
#Se crea una lista para las estrellas de salida
lista_estrellas = []
#El ciclo a continuación funciona de la siguiente manera:
#Se hace la diferencia en valor absoluto de una candidata, con la candidata siguiente. Se obtiene un arreglo 2x2
#Si la suma del anterior arreglo es menor o igual a dos, significa que las candidatas a estrellas son contiguas y por consiguiente se asume que es la misma estrella
#Si la suma del anterior arreglo es mayor, entonces se continuan evaluando las demás estrellas con el mismo procedimiento
#Los frames de estrellas se almacenan en la lista: 'lista_estrellas'
while k in range(nz-2):
# 2. Es decir que vuelve aquí*
k += 1
r = abs(z[:,k]-z[:,k+1])
r_sum = r.sum()
if r_sum <= 2:
radio, miniestrella = miniframe_estrella(estrellita, k, z)
lista_estrellas.append(miniestrella)
else:
continue # 1. Continua con el ciclo*
#lista_estrellas = np.array(lista_estrellas)
return lista_estrellas
Utilizando la imagen de 'Estrella 2' para el análisis, se encuentran las siguientes entrellas dentro.
lista_estrellas=estrellas_recortadas(estrella_2, 240)
fig, axs = plt.subplots(2, 2, figsize=(6,6))
axs[0, 0].imshow(lista_estrellas[0], cmap='gray')
axs[0, 0].set_title('Estrella 1')
axs[0, 1].imshow(lista_estrellas[1], cmap='gray')
axs[0, 1].set_title('Estrella 2')
axs[1, 0].imshow(lista_estrellas[2], cmap='gray')
axs[1, 0].set_title('Estrella 3')
axs[1, 1].imshow(lista_estrellas[3], cmap='gray')
axs[1, 1].set_title('Estrella 4')
# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax in axs.flat:
ax.label_outer()
Para el análisis de las anteriores estrellas se hace uso de la clase, se presenta además el ajuste gaussiano de dichas estrellas
#Conversion a la clase estrella
clase_estrella=[]
for item in lista_estrellas:
clase_estrella.append(Estrella_a(item))
#Impresión de las imagenes
#Para recordar: p = [a, b, c, x0, y0]
p1=np.array([1,0,1,5,5])
graficas=[]
parametros=[]
for i in range(0,len(clase_estrella)):
uno, dos = clase_estrella[i].ajusteGauss(p1)
graficas.append(uno)
parametros.append(dos)
#Impresion de imagenes
fig, axs = plt.subplots(2, 2, figsize=(6,6))
<<<<<<< HEAD
axs[0, 0].imshow(graficas[0], cmap='gray')
axs[0, 0].set_title('Estrella 1')
axs[0, 1].imshow(graficas[1], cmap='gray')
axs[0, 1].set_title('Estrella 2')
axs[1, 0].imshow(graficas[2], cmap='gray')
axs[1, 0].set_title('Estrella 3')
axs[1, 1].imshow(graficas[3], cmap='gray')
axs[1, 1].set_title('Estrella 4')
# Hide x labels and tick labels for top plots and y ticks for right plots.
for ax in axs.flat:
ax.label_outer()
Análisis estadistico
Para encontrar la mediana, media, moda y desviacion estandar del ajuste hecho se hace lo siguiente:
evaluar=np.array(parametros)
evaluar=evaluar*2*math.sqrt(2*math.log(2))
zz=evaluar
#Media
media=np.mean(zz)
#Mediana
mediana=np.median(zz)
#Moda
moda=stat.mode(np.round(zz,3).reshape(-1))
#Desviacion estandar con scipy
desviacion=stat.stdev(zz.reshape(-1))
#Desviacion estandar con numpy
desviacion1=zz.std()
print('Mediana: ', mediana)
print('Media: ', media)
print('Moda: ', moda)
print('Desviacion estandar 1: ', desviacion)
print('Desviacion estandar 2: ', desviacion1)
Mediana: 2.9331335083105
Media: 6.958263965191911
Moda: 15.497
Desviacion estandar 1: 6.4437838006164565
Desviacion estandar 2: 6.280623550702009
Para hacer el histograma
#Histograma
plt.figure(figsize=(9,4))
plt.hist(zz, bins=5, histtype='bar', alpha=0.7, edgecolor = 'black', linewidth=0.2)
plt.show()
estrellas_para_estadistica = estrellas_recortadas(imagen_grisss, 230)
#Para guardar el notebook a .md
! jupyter nbconvert --to markdown Entrega.ipynb
[NbConvertApp] Converting notebook Entrega.ipynb to markdown
[NbConvertApp] Support files will be in Entrega_files/
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Making directory Entrega_files
[NbConvertApp] Writing 13781 bytes to Entrega.md
=======