# import # ------------------------------------------------------------------------------------------ import os import matplotlib.pyplot as plt import numpy as np import multiprocessing as mp import easygui import imageio # miam import import miam.image.Image as MIMG import miam.image.imageType as MTYPE import miam.image.channel as MCH import miam.image.ColorSpace as MICS import miam.processing.ColorSpaceTransform as MCST import miam.processing.TMO_Lightness as TMO_L import miam.processing.ContrastControl as PCC import miam.histogram.Histogram as MHIST import miam.aesthetics.LightnessAesthetics as MLAC import miam.aesthetics.Palette as MPAL import miam.imageDB.ImageDB import miam.imageDB.POGChecker import miam.imageDB.HwHDRBuilder import miam.html.generator import miam.utils import miam.pointcloud.PointCloud2D as MPC2D import miam.classification.kmeans import miam.math.Distance import miam.math.Normalize import miam.classification.colorPaletteKmeanDisplay # ------------------------------------------------------------------------------------------ # MIAM project 2020 # ------------------------------------------------------------------------------------------ # author: remi.cozot@univ-littoral.fr # ------------------------------------------------------------------------------------------ # --------------------------------------------> Cluster # --------------------------------------------> Lightness def clusterPalette(): # ------------------------------------------------------------------------------------------ # # ------------------------------------------------------------------------------------------ # config: configfile jsonfile = "../DB/config_POG_DB.json" # palettes files allPalettes_2colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_2colorsNoBlack.npy" allPalettes_3colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_3colorsNoBlack.npy" allPalettes_4colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_4colorsNoBlack.npy" allPalettes_5colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy" optimalNumberOfClusters = 4 #5 distanceToCentroids_5colorsNoBlack = "../DB/POG_DB_dist_to_centroids_Palette_5colorsNoBlack.npy" # ------------------------------------------------------------------------------------------ print("MIAM[POG Cluster Palette]") # ------------------------------------------------------------------------------------------ # boolean to select what to do # ------------------------------------------------------------------------------------------ displayPalette2 = False displayPalette3 = False displayPalette5 = False clusterPalettes = False clusterPalettes_ncentroids = False displayPaletteClasses = True searchOptimalNumberOfClusters = False displayBestPaletteClass = True distanceToCentroids = False distanceToCentroidsAnalysis = False bestImagePerClass = True # ------------------------------------------------------------------------------------------ # first analysis of palettes # ------------------------------------------------------------------------------------------ if displayPalette2: # try to see something with palettes print("MIAM[------------------------------------------]") print("MIAM[display Palette 2 colors in (L)ab]") # load all palette 2 colors no black pal2CNB = np.load(allPalettes_2colorsNoBlack) print("MIAM[load Palette 2 colors: palette object shape",pal2CNB.shape,"]") plt.figure("Palette 2 color in ab") for i,p in enumerate(pal2CNB[0:-1]): print(i,'/',pal2CNB.shape[0],' ',end='\r') # plot palette x = p[:,1] # a -> x y = p[:,2] # b -> y plt.plot(x,y) plt.show(block=True) # ------------------------------------------------------------------------------------------ if displayPalette3: # try to see something with palettes print("MIAM[------------------------------------------]") print("MIAM[display Palette 3 colors in (L)ab]") # load all palette 3 colors no black pal3CNB = np.load(allPalettes_3colorsNoBlack) print("MIAM[load Palette 3 colors: palette object shape",pal3CNB.shape,"]") plt.figure("Palette 3 color in ab") for i,p in enumerate(pal3CNB[0:250]): print(i,'/',pal3CNB.shape[0],' ',end='\r') # plot palette x = p[:,1] # a -> x x = np.append(x,x[0]) y = p[:,2] # b -> y y = np.append(y,y[0]) plt.plot(x,y,'o--', linewidth=1, markersize=3) plt.plot([-100,100],[0,0],'k-') plt.plot([0,0],[-100,100],'k-') plt.show(block=True) # ------------------------------------------------------------------------------------------ if displayPalette5: # try to see something with palettes print("MIAM[------------------------------------------]") print("MIAM[display Palette 5 colors in (L)ab]") # load all palette 5 colors no black pal5CNB = np.load(allPalettes_5colorsNoBlack) print("MIAM[load Palette 5 colors: palette object shape",pal5CNB.shape,"]") plt.figure("Palette 5 color in ab") for i,p in enumerate(pal5CNB[0:-1]): print(i,'/',pal5CNB.shape[0],' ',end='\r') # plot palette x = p[:,1] # a -> x y = p[:,2] # b -> y pc = MPC2D.PointCloud2D(x,y) xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull()) plt.plot(xx,yy,'o--', linewidth=1, markersize=3) plt.plot([-100,100],[0,0],'k-') plt.plot([0,0],[-100,100],'k-') plt.show(block=True) # ------------------------------------------------------------------------------------------ # second analysis of palettes: k-means of palettes # ------------------------------------------------------------------------------------------ if clusterPalettes: # load all palette 5 colors no black pal5CNB = np.load(allPalettes_5colorsNoBlack) print("MIAM[load Palette (5 colors): palette object shape",pal5CNB.shape,"]") print("MIAM[clustering Palette (5 colors) launch !]") # __init__(self, distance, normalize): km = miam.classification.kmeans.kmeans(miam.math.Distance.Distance(miam.math.Distance.cL2distance), miam.math.Normalize.Normalize(miam.math.Normalize.sortNorm)) # kmeans(self,samples, nbClusters, nbIter, display = None, initRange= ...): centroids,assigments,assigmentsIdx = km.kmeans(pal5CNB[0:1000], 4, #4 100, #100 display = miam.classification.colorPaletteKmeanDisplay.colorPaletteKmeanDisplay(), initRange=[(0,100),(-100,100),(-100,100)], multiPro=True) print("MIAM[clustering done !]") # plot centroids plt.figure("Palette (5 color) in ab") for p in centroids: # plot palette x = p[:,1] # a -> x y = p[:,2] # b -> y pc = MPC2D.PointCloud2D(x,y) xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull()) plt.plot(xx,yy,'o--', linewidth=1, markersize=3) plt.plot([-100,100],[0,0],'k-') plt.plot([0,0],[-100,100],'k-') plt.show(block=True) # np.save("../DB/"+"POG_DB"+'_centroids_palette_5colors_4centroids',centroids) # np.save("../DB/"+"POG_DB"+'_assigments_palette_5colors_4centroids',assigments) # np.save("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_4centroids',assigmentsIdx) # print("MIAM[","POG_DB"," clustering save saved !]") # test the number of centroids # ------------------------------------------------------------------------------------------ if clusterPalettes_ncentroids: # load all palette 5 colors no black pal5CNB = np.load(allPalettes_5colorsNoBlack) print("MIAM[load Palette 5 colors: palette object shape",pal5CNB.shape,"]") print("MIAM[clustering Palette 5 colors launch !]") # __init__(self, distance, normalize): km = miam.classification.kmeans.kmeans(miam.math.Distance.Distance(miam.math.Distance.cL2distance), miam.math.Normalize.Normalize(miam.math.Normalize.sortNorm)) for nbc in [2,3,4,5,6,7,8,9,10]: #,11,12,13,14,15]: print("MIAM[clustering Palette 5 colors:",str(nbc)," centroids launch !]") # kmeans centroids,assigments,assigmentsIdx = km.kmeans(pal5CNB, nbc, 500, display=miam.classification.colorPaletteKmeanDisplay.colorPaletteKmeanDisplay(), initRange=[(0,100),(-100,100),(-100,100)], multiPro=True) print("MIAM[clustering done !]") np.save("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(nbc)+'centroids',centroids) np.save("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(nbc)+'centroids',assigments) np.save("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(nbc)+'centroids',assigmentsIdx) print("MIAM[","POG_DB"," clustering save saved !]") # ------------------------------------------------------------------------------------------ # analysis of palettes classes # ------------------------------------------------------------------------------------------ if displayPaletteClasses: numberOfClusters = [2,3,4,5,6,7,8,9,10,11,12,13,14,15] for numberOfCluster in numberOfClusters: print("----------------------------------------------") print("numberOfCluster:",numberOfCluster) print("----------------------------------------------") # load centroids , etc. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) # plot images of palette fig, ax = plt.subplots(numberOfCluster,1) fig.suptitle("CentroidsImage:"+str(numberOfCluster)+"/ palette 5 colors") for i,p in enumerate(centroids): # debug print("| palette (",i,"): number of image assigned >>", len(assigmentsIdx[i])) # create palette object pal = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab()) # create image of palette imgPal = pal.createImageOfPalette() imgPal.plot(ax[i],title=False) plt.show(block=False) # plot centroids figC = plt.figure() figC.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors") for i,p in enumerate(centroids): # plot palette x = p[:,1] # a -> x y = p[:,2] # b -> y pc = MPC2D.PointCloud2D(x,y) xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull()) plt.plot(xx,yy,'o--', linewidth=1, markersize=3) if numberOfCluster != numberOfClusters[-1]: plt.show(block=False) else: plt.show(block=True) # ------------------------------------------------------------------------------------------ if searchOptimalNumberOfClusters: # find the optimal number of clusters res = [] numberOfClusters = [2,3,4,5,6,7,8,9,10] #distance distance = miam.math.Distance.Distance(miam.math.Distance.cL2distance) for numberOfCluster in numberOfClusters: # DEBUG print("--------------------------------------------------------------") print(" number of clusters:",numberOfCluster) print("--------------------------------------------------------------") # load centroids , etc. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) allSumD2 = 0 for i,centroid in enumerate(centroids): # DEBUG print("| centroids(",i,"): number of assigments >>", len(assigments[i])) print("+-------------------------------------------------------------") PaletteCentroid = MPAL.Palette('Palette_'+str(i),centroid, MICS.ColorSpace.buildLab()) sumD2 = 0 for j,ass in enumerate(assigments[i]): # DEBUUG print("| > assigment(",j,")/", len(assigments[i])," ",end='\r') PaletteAss = MPAL.Palette('Palette_'+str(i),ass, MICS.ColorSpace.buildLab()) # compute distance D2 = distance.eval(PaletteCentroid.colors,PaletteAss.colors)**2 sumD2 +=D2 # sum of distance between a centroids and its assigments allSumD2 += sumD2 # sum of distance between all centroids and their respectives assigments res.append(allSumD2) ypps = [] for i,y in enumerate(res[1:-1]): ypp = res[i+1]+res[i-1]-2*res[i] print("d2 (sum of squared distance)/d (nb clusters) (",i,"):",ypp) ypps.append(ypp) plt.figure("sum of squared distance / number of centroids") plt.plot(numberOfClusters,res,'b-') plt.plot(numberOfClusters[1:-1],ypps,'r') plt.show(block=True) # ------------------------------------------------------------------------------------------ if displayBestPaletteClass: numberOfCluster = 5 print("----------------------------------------------") print("numberOfCluster:",numberOfCluster) print("----------------------------------------------") # load centroids , etc. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) colors = ['b', 'g','r','c','m'] # plot number of assigments per cluster figNBA = plt.figure("number of assigments per cluster ['b', 'g','r','c','m']") nbAss = [] for i,p in enumerate(centroids): nbAss.append(len(assigmentsIdx[i])) plt.bar(colors,nbAss,color=colors) plt.show(block=False) # plot images of palette fig, ax = plt.subplots(numberOfCluster,2) fig.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors ['b', 'g','r','c','m']") for i,p in enumerate(centroids): # debug print("| palette (",i,"): number of image assigned >>", len(assigmentsIdx[i])) # create palette object pal = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab()) # create image of palette imgPal = pal.createImageOfPalette() imgPal.plot(ax[i,1],title=False) ax[i,0].plot(0,0,'o'+colors[i],markersize=10) ax[i,0].axis("off") plt.show(block=False) # plot centroids figC = plt.figure() figC.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors") for i,p in enumerate(centroids): # plot palette x = p[:,1] # a -> x y = p[:,2] # b -> y pc = MPC2D.PointCloud2D(x,y) xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull()) plt.plot(xx,yy,colors[i]+'o--', linewidth=1, markersize=3) plt.show(block=True) # ------------------------------------------------------------------------------------------ # POG: cluster analysis PART 1: distance to each centroids # ----------------------------------------------------------------------------------------- if distanceToCentroids: numberOfCluster = 5 print("----------------------------------------------") print("numberOfCluster:",numberOfCluster) print("----------------------------------------------") # load centroids , etc. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) # load all palette allPalettes = np.load("../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy", allow_pickle=True) #distance distance = miam.math.Distance.Distance(miam.math.Distance.cL2distance) # buid palette objects pCentroids = [] for i,cent in enumerate(centroids): c = MPAL.Palette('Palette_'+str(i),cent, MICS.ColorSpace.buildLab()) pCentroids.append(c) # distToCentroids distToCentroids = [] # distance to centroids for i, palette in enumerate(allPalettes): # DEBUG print("> palette(",i,")/", allPalettes.shape[0]," ",end='\r') # get raw image histogram and build Histogram Object p = MPAL.Palette('Palette_'+str(i),palette, MICS.ColorSpace.buildLab()) distToCent = [] for j,hc in enumerate(pCentroids): d = distance.eval(hc.colors,p.colors) distToCent.append(d) distToCentroids.append(distToCent) np.save(distanceToCentroids_5colorsNoBlack,distToCentroids) rows = len(distToCentroids) cols = len(list(zip(*distToCentroids))) #cols = len(distToCentroids[0]) print("") print("MIAM[distToCentroids.shape(", rows,"x",cols,")]") print("MIAM[distToCentroids[0]:", distToCentroids[0],")]") print("MIAM[","POG_DB"," distance for each image to each centroids saved !]") # ------------------------------------------------------------------------------------------ if distanceToCentroidsAnalysis: numberOfCluster = 5 print("----------------------------------------------") print(" distance to centroids ") print("----------------------------------------------") print("numberOfCluster:",numberOfCluster) print("----------------------------------------------") distToCentroids = np.load(distanceToCentroids_5colorsNoBlack, allow_pickle=True) # get data fig, ax = plt.subplots(1,numberOfCluster) fig.suptitle('distance to centroids') colors = ['b', 'g','r','c','m','y','k'] # sort for i in range(numberOfCluster): idxSorted = np.argsort(distToCentroids[:,i])#[::-1] for j in range(numberOfCluster): ax[i].plot((distToCentroids[idxSorted[0:1000],j]),colors[j%len(colors)]+'o', markersize=1) plt.show(block=True) # ------------------------------------------------------------------------------------------ if bestImagePerClass: # config: configfile jsonfile = "../DB/config_POG_DB.json" # loading POG pogDB = miam.imageDB.ImageDB.ImageDB(jsonConfigFile =jsonfile) pogDB.check(miam.imageDB.POGChecker.POGChecker(local=True)) print("MIAM[",pogDB.name,":(csvFileName:: ",pogDB.csvFileName,", imagePATH::",pogDB.imagePATH,")]") # number of class numberOfCluster = 5 print("MIAM[ number of Palette Class:",numberOfCluster,"]") # load centroids , etc. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True) # for each palette/image distance to each cluster distToCentroids = np.load(distanceToCentroids_5colorsNoBlack, allow_pickle = True) # load all palette allPalettes = np.load("../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy", allow_pickle=True) # for each class for i,p in enumerate(centroids): # palette of class pCentroid = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab()) pcCentroid = MPC2D.PointCloud2D(pCentroid.colors[:,1],pCentroid.colors[:,2]) xxCentroid,yyCentroid = MPC2D.PointCloud2D.toXYarray(pcCentroid.convexHull()) imgPaletteCentroid = pCentroid.createImageOfPalette() # sort image according to class distance idxSorted = np.argsort(distToCentroids[:,i])#[::-1] # for ten best image of the current class for j in range(3): # best j-th image imagefilename = pogDB.db[idxSorted[j]] print("class(",i,"): best", j,">>",imagefilename) img = MIMG.Image.read(imagefilename) jj = idxSorted[j] p = allPalettes[jj] pImg = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab()) imgPImg = pImg.createImageOfPalette() # palette contour pcImage = MPC2D.PointCloud2D(pImg.colors[:,1],pImg.colors[:,2]) xxImage, yyImage = MPC2D.PointCloud2D.toXYarray(pcImage.convexHull()) # figure and axes fig, ax = plt.subplots(2,2) # 1 row x 2 columns fig.suptitle('best image('+str(j)+')/class('+str(i)+')') ax[0,0].set_title('image') img.plot(ax[0,0],title=False) imgPImg.plot(ax[1,0],title=False) ax[1,0].set_title('palette of image') ax[0,1].set_title('palettes (red class/blue image)') _range = max([np.amax(np.abs(centroids[:,:,1])),np.amax(np.abs(centroids[:,:,2]))]) for k, c in enumerate(centroids): # plot palette x = c[:,1] # a -> x y = c[:,2] # b -> y pc = MPC2D.PointCloud2D(x,y) xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull()) if k != i: ax[0,1].plot(xx,yy,'m--') ax[0,1].plot(xxCentroid,yyCentroid,'ro--') ax[0,1].plot(xxImage,yyImage,'bo-') ax[0,1].plot([- _range, _range],[0,0],'k') ax[0,1].plot([0,0],[-_range,_range],'k') imgPaletteCentroid.plot(ax[1,1],title=False) ax[1,1].set_title("palette of class") plt.show(block=True)