from PIL import Image
from copy import deepcopy
from math import sqrt,pi,atan2
import numpy as np

#VARIABLES UNIVERSELLES et FONCTION FINALE

#récupération de l'image
im=Image.open("cassiopee.jpg")



data = list(im.getdata())
r,g,b = im.split()
print(im.size, im.format,im.mode)
#caractéristiques de l'image
s=im.size
m=im.mode
#im.getpixel(())
hauteur=im.size[1]#nb de lignes de pixels
largeur=im.size[0]# nb de colonnes de pixels

def definir(im,nombre): #nombre le nombre d'étoiles de la constellation
    #im=inversion(im)
    #im.show()
    imf2=niveau_de_gris(im)
    #print(moyenne)
    #moyenne=moyenne*facteur
    imf3=simplifié(imf2)
    #imf3.show()
    B=binaire(imf3)
    nettoyage(B)
    #print(B)
    L,nbLabels=flood_fill(B)
    #print(nbLabels)
    #print(L)
    liste_centres=centres(nbLabels,L,nombre)
    #print(liste_centres)
    check(liste_centres)
    centres_classés=classer_centres(liste_centres)
    #print(centres_classés)
    listepositions=positions(centres_classés,liste_centres)
    print(np.array(listepositions,float))
    #return listepositions

    
   
#RESERVE#

#L=[]
#for i in range(hauteur):
#    for j in range (largeur): #parcours
       # pixel=im.getpixel((j,i))#création d'une liste de pixels(liste de trois entiers) de gauche à droite puis de haut en bas
       # L.append(pixel) 

def matrice0(hauteur,largeur):#crée une matrice de zéros
    M=[]
    nbLabels=0
    for i in range (hauteur):
        M.append([])
        for j in range (largeur):
            M[i].append(0)
    return M


#inversion (négatif)
def inversion(im):
    imf1=Image.new(m,s)
    for i in range(hauteur):
        for j in range(largeur):
            pixel = im.getpixel((j,i)) # récupération du pixel
        # on calcule le complement à MAX pour chaque composante - effet négatif
            p = (255 - pixel[0], 255 - pixel[1], 255 - pixel[2])
        # composition de la nouvelle image
            imf1.putpixel((j,i), p)
    #imf1.show()
    return imf1

#niveau de gris
def niveau_de_gris(im):
    imf2=Image.new(m,s)
    somme=0
    for i in range(hauteur):
        for j in range(largeur):
            pixel = im.getpixel((j,i)) # récupération du pixel
            
# calcul du poids de chaque composante du gris dans le pixel (CIE709:convention européenne)
            gris = int(0.2125 * pixel[0] + 0.7154 * pixel[1] + 0.0721 * pixel[2])
            somme+=gris
            p = (gris,gris,gris)

    # composition de la nouvelle image
            imf2.putpixel((j,i), p)
    imf2.show()
    return imf2

def simplifié(imf2): #donne une image avec uniquement les 'valeurs extrêmes' (infonctionelle ici)
    imf3=Image.new(m,s)
    somme=0
    for i in range(hauteur):
        for j in range(largeur):
            pixel = imf2.getpixel((j,i))
            if (pixel[0]+pixel[1]+pixel[2])/3 <125:#<--seuil
                 pixel = (0,0,0)#pixels noirs
                 
            else :
                pixel = (255,255,255)
                imf3.putpixel((j,i), pixel)
        
    #imf3.show()
    return imf3

def binaire(imf3): #prend une image binaire et renvoie une matrice binaire
    B=deepcopy(matrice0(hauteur,largeur))
    for i in range (hauteur):
        for j in range (largeur):
             pixel = imf3.getpixel((j,i))
             if pixel!=(0,0,0):
                 B[i][j]=1
    
    return B

def nettoyage(B):
    for i in range(hauteur):
        B[i][0],B[i][largeur-1]=0,0
    for j in range(largeur):
        B[0][j],B[hauteur-1][j]=0,0 #pour éviter les erreurs 'out of range'
             
def flood_fill(B):
    L=deepcopy(matrice0(hauteur,largeur))
    nbLabels=0
    for i in range (hauteur):
        for j in range (largeur):
            if B[i][j]==1:
                nbLabels+=1
                connexites(i,j,B,L,nbLabels)            
    #print(nbLabels)       
    return L,nbLabels
    

def connexites(i,j,B,L,nbLabels):#récursif
    pixel=B[i][j]
    if pixel==1:
        L[i][j]=nbLabels
        B[i][j]=0
        if B[i][j+1]==1:
            connexites(i,j+1,B,L,nbLabels)
        if B[i-1][j]==1:
            connexites(i-1,j,B,L,nbLabels)
        if B[i][j-1]==1:
            connexites(i,j-1,B,L,nbLabels)
        if B[i+1][j]==1:
             connexites(i+1,j,B,L,nbLabels)


def centres(nbLabels,L,nombre):
    liste_coord=[]
    longueurs=[] #suite qui compile les longueurs des sous-listes de la liste list_coord
    étoiles=[] #liste des coordonnées "intéréssantes"
    liste_centres=[]
    for k in range (nbLabels):
        liste_coord.append([])
    for i in range(hauteur):
        for j in range (largeur):
            if L[i][j]!=0:
                liste_coord[(L[i][j]-1)].append([i,j]) 
    #print(liste_coord)
    taille=len(liste_coord)
    for h in range (taille):
        longueurs.append(len(liste_coord[h]))
    longueurs.sort()
    plus_petit_pt=longueurs[(nombre*(-1))] #nb de pixels composant le plus petit point qui intéresse
    for l in range (taille):
        if len(liste_coord[l])>=plus_petit_pt:
            étoiles.append(liste_coord[l])
    #print (étoiles)
    for s in range(nombre):
        x,y=0,0
        for a in range(len(étoiles[s])):
            x+=étoiles[s][a][0]
            y+=étoiles[s][a][1]
        X=x/len(étoiles[s])
        Y=y/len(étoiles[s])
        liste_centres.append([X,Y])
    return liste_centres

def classer_centres(liste_centres):
    N=len(liste_centres)
    centres_classés=[]
    for k in range(N):
        distancemax=0
        point1=[0,0]
        for l in range(N):
            if k!=l:
                distance=sqrt((liste_centres[k][0]-liste_centres[l][0])**2+(liste_centres[k][1]-liste_centres[l][1])**2)
                #print(distance)
                if distance>distancemax:
                    distancemax=distance
                    point1=liste_centres[l]
        #print("distancemax=",distancemax)
        centres_classés.append([liste_centres[k],distancemax,point1])
    return centres_classés


def positions(centres_classés,liste_centres):
    N=len(centres_classés)
    positions=[]
    #je cherche le point en  le plus près de tous les autres pour
    #servir d'origine au repère
    distancemax1minimale=centres_classés[0][1]
    i=0
    for k in range(1,N):
        if centres_classés[k][1]<distancemax1minimale:
            distancemax1minimale=centres_classés[k][1]
            i=k #indice du point ds la liste centres_classés qui servira d'origine du répère
#coordonnées du point d'origine
    #print(i)
    #print(distancemax1minimale)
    X=centres_classés[i][0][0]
    Y=centres_classés[i][0][1]
    angleref=atan2((centres_classés[i][2][1]-Y),(centres_classés[i][2][0]-X))
    del(liste_centres[i])
    for j in range(N-1):
        x=liste_centres[j][0]-X
        y=liste_centres[j][1]-Y
        angle=atan2(y,x)
        distance_relative=sqrt(x**2+y**2)/distancemax1minimale
        if angle>=angleref:
            positions.append([distance_relative,(angle-angleref)])
        else :
            positions.append([distance_relative,2*pi+(angle-angleref)])
    return positions
                         

def check(liste_centres):
    imf=Image.new(m,s)
    imf=inversion(imf)
    pixel=(255,0,0)
    for k in range (len(liste_centres)):
        imf.putpixel((int(liste_centres[k][1]),int(liste_centres[k][0])), pixel)
    imf.save('imf.jpg')
    
                    
            
        










#*************************************************************************************************************#



 #création d'une listes de listes contenant mles coordonées des pixels d'un même amat
def amats (C): #1ère tentative du 21 novembre
    k,i=0,0
    L=[]
    while k<= len(C):
        L.append([C[k]])
        while i <= len(C):
           
            for w in range(len(L[-1])):
                if C[k+w][0]==C[i][0] or C[k+w][0]==C[i][0]+1 or C[k+w][0]==C[i][0]-1 or C[k+w][1]==C[i][1] or C[k+w][1]==C[i][1]+1 or C[k+w][1]==C[i][1]+1:
                    L[-1].append(C[i])
                    del C[i]
                
            i+=i
        k+=k


    
    
    
    # définition d'UN SEUL amats de points comme une liste de coordonées (non utile)
def points():
    for i in range(hauteur):
        for j in range(largeur):
            pixel = imf2.getpixel((j,i))
            if pixel!=(0,0):
                k=1
                while pixel!=(0,0):
                    pixel=imf2.getpixel((j-k,i))
                
#mardi 5 décembre :
#méthode par "forage"
def points2(imf3):
    Coordonées=[]
    for i in range (hauteur):
        for j in range (largeur):
             pixel = imf3.getpixel((j,i))
             if pixel==(0,0,0):#repérage des pixels blancs
                 retenue1=j
                 #pour  la recherche à droite/gauche/pour la suppression

                 pixel = imf3.getpixel((j,i-1))
                 profondeur=0
                 diamètre=0
                 #1)'forage'
                 while pixel ==(0,0,0):
                     i-=1
                     profondeur=+1
                 #1' moyenne hauteur
                 moy_hauteur=i-profondeur//2
                 #2) Recherche à droite
                 pixel = imf3.getpixel((retenue1+1,moy_hauteur))
                 while pixel ==(0,0,0):
                     retenue+=1
                     diamètre+=1
                 diamètre_droite=diamètre
                 #3) Recherche à gauche
                 retenue1=j
                 pixel = imf3.getpixel((retenue1-1,moy_hauteur))
                 while pixel ==(0,0,0):
                     retenue1-=1
                     diamètre+=1
                 retenue1=j
                 #4) Moyenne de la largeur ou 'diamètre'
                      
                 moy_diamètre=retenue1+diamètre_droite - diamètre + diamètre//2
                 Coordonnées.append([moy_diamètre,moy_hauteur])
                 #5) Suppression
                 retenue1=j
                 for k in range (retenue1-diamètre,retenue1-diamètre):
                     for l in range (i,i+2+profondeur):
                         pixel = imf3.getpixel((k,l))
                         pixel=(0,0,0)
        return Coordonées


                
                 
                
                
        
