2016-10-05 1 views
1

emprunt cet exemple de astropy:masque une image section (np.ndarray) qui est située entre deux courbes

import numpy as np 
from matplotlib import pyplot as plt 
from astropy.io import fits 
from astropy.wcs import WCS 
from astropy.utils.data import download_file 

fits_file = 'http://data.astropy.org/tutorials/FITS-images/HorseHead.fits' 
image_file = download_file(fits_file, cache=True) 
hdu = fits.open(image_file)[0] 
wcs = WCS(hdu.header) 

fig = plt.figure() 
ax = fig.add_subplot(111) 
plt.imshow(hdu.data, origin='lower', cmap='cubehelix') 
plt.xlabel('X') 
plt.ylabel('Y') 

x_array = np.arange(0, 1000) 
line_1 = 1 * x_array + 20 * np.sin(0.05*x_array) 
line_2 = x_array - 100 + 20 * np.sin(0.05*x_array) 

plt.plot(x_array, line_1, color='red') 
plt.plot(x_array, line_2, color='red') 

ax.set_xlim(0, hdu.shape[1]) 
ax.set_ylim(0, hdu.shape[0]) 

plt.show() 

Je souhaite calculer la valeur de pixel médian (dans la direction y par exemple) qui se trouve entre la deux courbes:

enter image description here

je crois que la chose intelligente serait de créer un masque pour la région d'intérêt.

Y a-t-il un moyen de générer ce masque sans boucler sur les pixels de l'image?

Edit 1: question d'améliorer la compréhension Modified

Edit 2: J'ai changé l'exemple pour mieux représenter le titre de la question (courbes au lieu de lignes droites)

+0

Vous souhaitez calculer la valeur médiane de quoi, exactement? Si vous essayez de trouver le centre de la zone délimitée par ces deux lignes, n'est-ce pas simplement le milieu d'un trapèze? – blacksite

+0

Désolé, je voulais dire la valeur de pixel médiane entre ces lignes dans la direction y. – Delosari

+0

Vous pouvez donc trouver les coordonnées du milieu de ce trapèze, puis indexer l'image pour trouver la valeur RVB. Travailler sur une solution maintenant .... – blacksite

Répondre

3

Une manière assez simple de générer un tel masque serait être d'utiliser le numpy.mgrid thingy qui vous donne essentiellement des tableaux de coordonnées x et y (dans ce cas 2D) qui peuvent ensuite être utilisés pour calculer le masque avec l'équation des lignes.

Edit: condition que vous pouvez exprimer votre masque en utilisant une équation (comme f(x,y)<0 où f est une fonction que vous voulez) ou une combinaison de ces équations, vous pouvez faire tout ce que vous voulez. Voici un exemple avec votre nouveau masque avec quelques pièces d'art supplémentaires:

import numpy as np 
import matplotlib.pyplot as plt 

y,x=np.mgrid[0:1000,0:1000] 

#a wiggly ramp 
plt.subplot(221) 
mask0=(y < x + 20 * np.sin(0.05*x)) & (y > x - 100 + 20 * np.sin(0.05*x)) 
plt.imshow(mask0,origin='lower',cmap='gray') 

#a ramp 
plt.subplot(222) 
mask1=(y < x) & (x < y+100) 
plt.imshow(mask1,origin='lower',cmap='gray') 

#a disk 
plt.subplot(223) 
mask2=(200**2>(x-500)**2+(y-500)**2) 
plt.imshow(mask2,origin='lower',cmap='gray') 

#a ying-yang attempt 
plt.subplot(224) 
mask3= (mask2 & (0 < np.sin(3.14*x/250)*100 + 500 - y) & (30**2 < (x-620)**2+(y-500)**2))| (30**2 > (x-380)**2+(y-500)**2) 
plt.imshow(mask3,origin='lower',cmap='gray') 

plt.show() 

Sortie:

Output

+0

Merci beaucoup @jadsq pour votre exemple. Je n'étais pas au courant de cette méthode mgrid ... Cependant, je n'ai pas donné un bon exemple pour ma question: cette solution fonctionnera pour les lignes droites mais pas les courbes ... J'ai changé mon code initial pour mieux représenter le problème ...Pensez-vous qu'il peut être adapté d'une manière ou d'une autre? – Delosari

+0

Wow c'est très chouette merci beaucoup !! – Delosari

5

L'extrait de code ci-dessous crée un masque, définit toutes les valeurs en dehors du masque à nan, puis utilise nanmedian de NumPy pour calculer la quantité désirée dans la direction indiquée.

import numpy as np 

import matplotlib.pyplot as plt 
from matplotlib import gridspec 

from skimage.measure import grid_points_in_poly 


# Create test image 
N = 900 
image = np.sin(np.linspace(0, 2 * np.pi, N * N).reshape((N, N)) ** 2) 

# Define the mask polygon 
poly = [[N, 0], 
     [0, N], 
     [100, N], 
     [N, 100]] 

# Create the mask (True is inside the polygon) 
mask = grid_points_in_poly(image.shape, poly) 

# Set everything outside the mask to nan 
masked_image = image.copy() 
masked_image[~mask] = np.nan 

# Perform the required operation 
row_med = np.nanmedian(masked_image, axis=1) 

# The rest of the code is to visualize the result 
fig = plt.figure(figsize=(15, 10)) 
gs = gridspec.GridSpec(1, 3, width_ratios=(1, 1, 1/8)) 
ax0 = plt.subplot(gs[0]) 
ax1 = plt.subplot(gs[1]) 
ax2 = plt.subplot(gs[2]) 

ax0.imshow(image, cmap='gray') 
ax0.set_title('Input image') 
ax0.set_xlim(0, N) 

ax1.imshow(masked_image, cmap='gray') 
ax1.set_title('Masked image') 
ax1.set_xlim(0, N) 

ax2.plot(row_med, np.arange(N)) 
ax2.set_ylim([N, 0]) 
ax2.set_xlim([-1.5, 1.5]) 
ax2.set_title('Row median') 

plt.tight_layout() 
plt.show() 

Median along rows inside region of interest

+1

Merci beaucoup pour la réponse Stefan! C'est très propre, cependant je pense que je ne me suis pas bien expliqué: je crois que cette méthode polygonale ne fonctionnera que si les arêtes des sections sont complètement droites ... Cela ne donnera pas la bonne solution pour les arêtes courbes ... Pensez-vous cela peut-il être adapté en quelque sorte? (J'ai mis à jour l'exemple en utilisant un peu le vôtre) – Delosari

+0

Dans ce cas, les deux solutions affichées ci-dessus combinées vous offrent ce dont vous avez besoin. Pas que vous consommez beaucoup de mémoire avec cette opération; une boucle en Cython, numba, pypi, etc. serait beaucoup plus rapide. –