miamResults4PublicationPALETTE.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. # import
  2. # ------------------------------------------------------------------------------------------
  3. import os
  4. import matplotlib.pyplot as plt
  5. import numpy as np
  6. import multiprocessing as mp
  7. import easygui
  8. import imageio
  9. # miam import
  10. import miam.image.Image as MIMG
  11. import miam.image.imageType as MTYPE
  12. import miam.image.channel as MCH
  13. import miam.image.ColorSpace as MICS
  14. import miam.processing.ColorSpaceTransform as MCST
  15. import miam.processing.TMO_Lightness as TMO_L
  16. import miam.processing.ContrastControl as PCC
  17. import miam.histogram.Histogram as MHIST
  18. import miam.aesthetics.LightnessAesthetics as MLAC
  19. import miam.aesthetics.Palette as MPAL
  20. import miam.imageDB.ImageDB
  21. import miam.imageDB.POGChecker
  22. import miam.imageDB.HwHDRBuilder
  23. import miam.html.generator
  24. import miam.utils
  25. import miam.pointcloud.PointCloud2D as MPC2D
  26. import miam.classification.kmeans
  27. import miam.math.Distance
  28. import miam.math.Normalize
  29. import miam.classification.colorPaletteKmeanDisplay
  30. # ------------------------------------------------------------------------------------------
  31. # MIAM project 2020
  32. # ------------------------------------------------------------------------------------------
  33. # author: remi.cozot@univ-littoral.fr
  34. # ------------------------------------------------------------------------------------------
  35. # --------------------------------------------> Cluster
  36. # --------------------------------------------> Lightness
  37. def clusterPalette():
  38. # ------------------------------------------------------------------------------------------
  39. #
  40. # ------------------------------------------------------------------------------------------
  41. # config: configfile
  42. jsonfile = "../DB/config_POG_DB.json"
  43. # palettes files
  44. allPalettes_2colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_2colorsNoBlack.npy"
  45. allPalettes_3colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_3colorsNoBlack.npy"
  46. allPalettes_4colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_4colorsNoBlack.npy"
  47. allPalettes_5colorsNoBlack = "../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy"
  48. optimalNumberOfClusters = 4 #5
  49. distanceToCentroids_5colorsNoBlack = "../DB/POG_DB_dist_to_centroids_Palette_5colorsNoBlack.npy"
  50. # ------------------------------------------------------------------------------------------
  51. print("MIAM[POG Cluster Palette]")
  52. # ------------------------------------------------------------------------------------------
  53. # boolean to select what to do
  54. # ------------------------------------------------------------------------------------------
  55. displayPalette2 = False
  56. displayPalette3 = False
  57. displayPalette5 = False
  58. clusterPalettes = False
  59. clusterPalettes_ncentroids = False
  60. displayPaletteClasses = True
  61. searchOptimalNumberOfClusters = False
  62. displayBestPaletteClass = True
  63. distanceToCentroids = False
  64. distanceToCentroidsAnalysis = False
  65. bestImagePerClass = True
  66. # ------------------------------------------------------------------------------------------
  67. # first analysis of palettes
  68. # ------------------------------------------------------------------------------------------
  69. if displayPalette2:
  70. # try to see something with palettes
  71. print("MIAM[------------------------------------------]")
  72. print("MIAM[display Palette 2 colors in (L)ab]")
  73. # load all palette 2 colors no black
  74. pal2CNB = np.load(allPalettes_2colorsNoBlack)
  75. print("MIAM[load Palette 2 colors: palette object shape",pal2CNB.shape,"]")
  76. plt.figure("Palette 2 color in ab")
  77. for i,p in enumerate(pal2CNB[0:-1]):
  78. print(i,'/',pal2CNB.shape[0],' ',end='\r')
  79. # plot palette
  80. x = p[:,1] # a -> x
  81. y = p[:,2] # b -> y
  82. plt.plot(x,y)
  83. plt.show(block=True)
  84. # ------------------------------------------------------------------------------------------
  85. if displayPalette3:
  86. # try to see something with palettes
  87. print("MIAM[------------------------------------------]")
  88. print("MIAM[display Palette 3 colors in (L)ab]")
  89. # load all palette 3 colors no black
  90. pal3CNB = np.load(allPalettes_3colorsNoBlack)
  91. print("MIAM[load Palette 3 colors: palette object shape",pal3CNB.shape,"]")
  92. plt.figure("Palette 3 color in ab")
  93. for i,p in enumerate(pal3CNB[0:250]):
  94. print(i,'/',pal3CNB.shape[0],' ',end='\r')
  95. # plot palette
  96. x = p[:,1] # a -> x
  97. x = np.append(x,x[0])
  98. y = p[:,2] # b -> y
  99. y = np.append(y,y[0])
  100. plt.plot(x,y,'o--', linewidth=1, markersize=3)
  101. plt.plot([-100,100],[0,0],'k-')
  102. plt.plot([0,0],[-100,100],'k-')
  103. plt.show(block=True)
  104. # ------------------------------------------------------------------------------------------
  105. if displayPalette5:
  106. # try to see something with palettes
  107. print("MIAM[------------------------------------------]")
  108. print("MIAM[display Palette 5 colors in (L)ab]")
  109. # load all palette 5 colors no black
  110. pal5CNB = np.load(allPalettes_5colorsNoBlack)
  111. print("MIAM[load Palette 5 colors: palette object shape",pal5CNB.shape,"]")
  112. plt.figure("Palette 5 color in ab")
  113. for i,p in enumerate(pal5CNB[0:-1]):
  114. print(i,'/',pal5CNB.shape[0],' ',end='\r')
  115. # plot palette
  116. x = p[:,1] # a -> x
  117. y = p[:,2] # b -> y
  118. pc = MPC2D.PointCloud2D(x,y)
  119. xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull())
  120. plt.plot(xx,yy,'o--', linewidth=1, markersize=3)
  121. plt.plot([-100,100],[0,0],'k-')
  122. plt.plot([0,0],[-100,100],'k-')
  123. plt.show(block=True)
  124. # ------------------------------------------------------------------------------------------
  125. # second analysis of palettes: k-means of palettes
  126. # ------------------------------------------------------------------------------------------
  127. if clusterPalettes:
  128. # load all palette 5 colors no black
  129. pal5CNB = np.load(allPalettes_5colorsNoBlack)
  130. print("MIAM[load Palette (5 colors): palette object shape",pal5CNB.shape,"]")
  131. print("MIAM[clustering Palette (5 colors) launch !]")
  132. # __init__(self, distance, normalize):
  133. km = miam.classification.kmeans.kmeans(miam.math.Distance.Distance(miam.math.Distance.cL2distance),
  134. miam.math.Normalize.Normalize(miam.math.Normalize.sortNorm))
  135. # kmeans(self,samples, nbClusters, nbIter, display = None, initRange= ...):
  136. centroids,assigments,assigmentsIdx = km.kmeans(pal5CNB[0:1000],
  137. 4, #4
  138. 100, #100
  139. display = miam.classification.colorPaletteKmeanDisplay.colorPaletteKmeanDisplay(),
  140. initRange=[(0,100),(-100,100),(-100,100)],
  141. multiPro=True)
  142. print("MIAM[clustering done !]")
  143. # plot centroids
  144. plt.figure("Palette (5 color) in ab")
  145. for p in centroids:
  146. # plot palette
  147. x = p[:,1] # a -> x
  148. y = p[:,2] # b -> y
  149. pc = MPC2D.PointCloud2D(x,y)
  150. xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull())
  151. plt.plot(xx,yy,'o--', linewidth=1, markersize=3)
  152. plt.plot([-100,100],[0,0],'k-')
  153. plt.plot([0,0],[-100,100],'k-')
  154. plt.show(block=True)
  155. # np.save("../DB/"+"POG_DB"+'_centroids_palette_5colors_4centroids',centroids)
  156. # np.save("../DB/"+"POG_DB"+'_assigments_palette_5colors_4centroids',assigments)
  157. # np.save("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_4centroids',assigmentsIdx)
  158. # print("MIAM[","POG_DB"," clustering save saved !]")
  159. # test the number of centroids
  160. # ------------------------------------------------------------------------------------------
  161. if clusterPalettes_ncentroids:
  162. # load all palette 5 colors no black
  163. pal5CNB = np.load(allPalettes_5colorsNoBlack)
  164. print("MIAM[load Palette 5 colors: palette object shape",pal5CNB.shape,"]")
  165. print("MIAM[clustering Palette 5 colors launch !]")
  166. # __init__(self, distance, normalize):
  167. km = miam.classification.kmeans.kmeans(miam.math.Distance.Distance(miam.math.Distance.cL2distance),
  168. miam.math.Normalize.Normalize(miam.math.Normalize.sortNorm))
  169. for nbc in [2,3,4,5,6,7,8,9,10]: #,11,12,13,14,15]:
  170. print("MIAM[clustering Palette 5 colors:",str(nbc)," centroids launch !]")
  171. # kmeans
  172. centroids,assigments,assigmentsIdx = km.kmeans(pal5CNB,
  173. nbc,
  174. 500,
  175. display=miam.classification.colorPaletteKmeanDisplay.colorPaletteKmeanDisplay(),
  176. initRange=[(0,100),(-100,100),(-100,100)],
  177. multiPro=True)
  178. print("MIAM[clustering done !]")
  179. np.save("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(nbc)+'centroids',centroids)
  180. np.save("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(nbc)+'centroids',assigments)
  181. np.save("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(nbc)+'centroids',assigmentsIdx)
  182. print("MIAM[","POG_DB"," clustering save saved !]")
  183. # ------------------------------------------------------------------------------------------
  184. # analysis of palettes classes
  185. # ------------------------------------------------------------------------------------------
  186. if displayPaletteClasses:
  187. numberOfClusters = [2,3,4,5,6,7,8,9,10,11,12,13,14,15]
  188. for numberOfCluster in numberOfClusters:
  189. print("----------------------------------------------")
  190. print("numberOfCluster:",numberOfCluster)
  191. print("----------------------------------------------")
  192. # load centroids , etc.
  193. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  194. assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  195. assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  196. # plot images of palette
  197. fig, ax = plt.subplots(numberOfCluster,1)
  198. fig.suptitle("CentroidsImage:"+str(numberOfCluster)+"/ palette 5 colors")
  199. for i,p in enumerate(centroids):
  200. # debug
  201. print("| palette (",i,"): number of image assigned >>", len(assigmentsIdx[i]))
  202. # create palette object
  203. pal = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab())
  204. # create image of palette
  205. imgPal = pal.createImageOfPalette()
  206. imgPal.plot(ax[i],title=False)
  207. plt.show(block=False)
  208. # plot centroids
  209. figC = plt.figure()
  210. figC.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors")
  211. for i,p in enumerate(centroids):
  212. # plot palette
  213. x = p[:,1] # a -> x
  214. y = p[:,2] # b -> y
  215. pc = MPC2D.PointCloud2D(x,y)
  216. xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull())
  217. plt.plot(xx,yy,'o--', linewidth=1, markersize=3)
  218. if numberOfCluster != numberOfClusters[-1]:
  219. plt.show(block=False)
  220. else:
  221. plt.show(block=True)
  222. # ------------------------------------------------------------------------------------------
  223. if searchOptimalNumberOfClusters:
  224. # find the optimal number of clusters
  225. res = []
  226. numberOfClusters = [2,3,4,5,6,7,8,9,10]
  227. #distance
  228. distance = miam.math.Distance.Distance(miam.math.Distance.cL2distance)
  229. for numberOfCluster in numberOfClusters:
  230. # DEBUG
  231. print("--------------------------------------------------------------")
  232. print(" number of clusters:",numberOfCluster)
  233. print("--------------------------------------------------------------")
  234. # load centroids , etc.
  235. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  236. assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  237. assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  238. allSumD2 = 0
  239. for i,centroid in enumerate(centroids):
  240. # DEBUG
  241. print("| centroids(",i,"): number of assigments >>", len(assigments[i]))
  242. print("+-------------------------------------------------------------")
  243. PaletteCentroid = MPAL.Palette('Palette_'+str(i),centroid, MICS.ColorSpace.buildLab())
  244. sumD2 = 0
  245. for j,ass in enumerate(assigments[i]):
  246. # DEBUUG
  247. print("| > assigment(",j,")/", len(assigments[i])," ",end='\r')
  248. PaletteAss = MPAL.Palette('Palette_'+str(i),ass, MICS.ColorSpace.buildLab())
  249. # compute distance
  250. D2 = distance.eval(PaletteCentroid.colors,PaletteAss.colors)**2
  251. sumD2 +=D2 # sum of distance between a centroids and its assigments
  252. allSumD2 += sumD2 # sum of distance between all centroids and their respectives assigments
  253. res.append(allSumD2)
  254. ypps = []
  255. for i,y in enumerate(res[1:-1]):
  256. ypp = res[i+1]+res[i-1]-2*res[i]
  257. print("d2 (sum of squared distance)/d (nb clusters) (",i,"):",ypp)
  258. ypps.append(ypp)
  259. plt.figure("sum of squared distance / number of centroids")
  260. plt.plot(numberOfClusters,res,'b-')
  261. plt.plot(numberOfClusters[1:-1],ypps,'r')
  262. plt.show(block=True)
  263. # ------------------------------------------------------------------------------------------
  264. if displayBestPaletteClass:
  265. numberOfCluster = 5
  266. print("----------------------------------------------")
  267. print("numberOfCluster:",numberOfCluster)
  268. print("----------------------------------------------")
  269. # load centroids , etc.
  270. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  271. assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  272. assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  273. colors = ['b', 'g','r','c','m']
  274. # plot number of assigments per cluster
  275. figNBA = plt.figure("number of assigments per cluster ['b', 'g','r','c','m']")
  276. nbAss = []
  277. for i,p in enumerate(centroids): nbAss.append(len(assigmentsIdx[i]))
  278. plt.bar(colors,nbAss,color=colors)
  279. plt.show(block=False)
  280. # plot images of palette
  281. fig, ax = plt.subplots(numberOfCluster,2)
  282. fig.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors ['b', 'g','r','c','m']")
  283. for i,p in enumerate(centroids):
  284. # debug
  285. print("| palette (",i,"): number of image assigned >>", len(assigmentsIdx[i]))
  286. # create palette object
  287. pal = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab())
  288. # create image of palette
  289. imgPal = pal.createImageOfPalette()
  290. imgPal.plot(ax[i,1],title=False)
  291. ax[i,0].plot(0,0,'o'+colors[i],markersize=10)
  292. ax[i,0].axis("off")
  293. plt.show(block=False)
  294. # plot centroids
  295. figC = plt.figure()
  296. figC.suptitle("Centroids:"+str(numberOfCluster)+"/ palette 5 colors")
  297. for i,p in enumerate(centroids):
  298. # plot palette
  299. x = p[:,1] # a -> x
  300. y = p[:,2] # b -> y
  301. pc = MPC2D.PointCloud2D(x,y)
  302. xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull())
  303. plt.plot(xx,yy,colors[i]+'o--', linewidth=1, markersize=3)
  304. plt.show(block=True)
  305. # ------------------------------------------------------------------------------------------
  306. # POG: cluster analysis PART 1: distance to each centroids
  307. # -----------------------------------------------------------------------------------------
  308. if distanceToCentroids:
  309. numberOfCluster = 5
  310. print("----------------------------------------------")
  311. print("numberOfCluster:",numberOfCluster)
  312. print("----------------------------------------------")
  313. # load centroids , etc.
  314. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  315. assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  316. assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  317. # load all palette
  318. allPalettes = np.load("../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy", allow_pickle=True)
  319. #distance
  320. distance = miam.math.Distance.Distance(miam.math.Distance.cL2distance)
  321. # buid palette objects
  322. pCentroids = []
  323. for i,cent in enumerate(centroids):
  324. c = MPAL.Palette('Palette_'+str(i),cent, MICS.ColorSpace.buildLab())
  325. pCentroids.append(c)
  326. # distToCentroids
  327. distToCentroids = []
  328. # distance to centroids
  329. for i, palette in enumerate(allPalettes):
  330. # DEBUG
  331. print("> palette(",i,")/", allPalettes.shape[0]," ",end='\r')
  332. # get raw image histogram and build Histogram Object
  333. p = MPAL.Palette('Palette_'+str(i),palette, MICS.ColorSpace.buildLab())
  334. distToCent = []
  335. for j,hc in enumerate(pCentroids):
  336. d = distance.eval(hc.colors,p.colors)
  337. distToCent.append(d)
  338. distToCentroids.append(distToCent)
  339. np.save(distanceToCentroids_5colorsNoBlack,distToCentroids)
  340. rows = len(distToCentroids)
  341. cols = len(list(zip(*distToCentroids))) #cols = len(distToCentroids[0])
  342. print("")
  343. print("MIAM[distToCentroids.shape(", rows,"x",cols,")]")
  344. print("MIAM[distToCentroids[0]:", distToCentroids[0],")]")
  345. print("MIAM[","POG_DB"," distance for each image to each centroids saved !]")
  346. # ------------------------------------------------------------------------------------------
  347. if distanceToCentroidsAnalysis:
  348. numberOfCluster = 5
  349. print("----------------------------------------------")
  350. print(" distance to centroids ")
  351. print("----------------------------------------------")
  352. print("numberOfCluster:",numberOfCluster)
  353. print("----------------------------------------------")
  354. distToCentroids = np.load(distanceToCentroids_5colorsNoBlack, allow_pickle=True)
  355. # get data
  356. fig, ax = plt.subplots(1,numberOfCluster)
  357. fig.suptitle('distance to centroids')
  358. colors = ['b', 'g','r','c','m','y','k']
  359. # sort
  360. for i in range(numberOfCluster):
  361. idxSorted = np.argsort(distToCentroids[:,i])#[::-1]
  362. for j in range(numberOfCluster):
  363. ax[i].plot((distToCentroids[idxSorted[0:1000],j]),colors[j%len(colors)]+'o', markersize=1)
  364. plt.show(block=True)
  365. # ------------------------------------------------------------------------------------------
  366. if bestImagePerClass:
  367. # config: configfile
  368. jsonfile = "../DB/config_POG_DB.json"
  369. # loading POG
  370. pogDB = miam.imageDB.ImageDB.ImageDB(jsonConfigFile =jsonfile)
  371. pogDB.check(miam.imageDB.POGChecker.POGChecker(local=True))
  372. print("MIAM[",pogDB.name,":(csvFileName:: ",pogDB.csvFileName,", imagePATH::",pogDB.imagePATH,")]")
  373. # number of class
  374. numberOfCluster = 5
  375. print("MIAM[ number of Palette Class:",numberOfCluster,"]")
  376. # load centroids , etc.
  377. centroids = np.load("../DB/"+"POG_DB"+'_centroids_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  378. assigments = np.load("../DB/"+"POG_DB"+'_assigments_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  379. assigmentsIdx = np.load("../DB/"+"POG_DB"+'_assigmentsIdx_palette_5colors_'+str(numberOfCluster)+'centroids'+'.npy', allow_pickle=True)
  380. # for each palette/image distance to each cluster
  381. distToCentroids = np.load(distanceToCentroids_5colorsNoBlack, allow_pickle = True)
  382. # load all palette
  383. allPalettes = np.load("../DB/POG_DB_Lab_kmeans_Palette_5colorsNoBlack.npy", allow_pickle=True)
  384. # for each class
  385. for i,p in enumerate(centroids):
  386. # palette of class
  387. pCentroid = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab())
  388. pcCentroid = MPC2D.PointCloud2D(pCentroid.colors[:,1],pCentroid.colors[:,2])
  389. xxCentroid,yyCentroid = MPC2D.PointCloud2D.toXYarray(pcCentroid.convexHull())
  390. imgPaletteCentroid = pCentroid.createImageOfPalette()
  391. # sort image according to class distance
  392. idxSorted = np.argsort(distToCentroids[:,i])#[::-1]
  393. # for ten best image of the current class
  394. for j in range(3):
  395. # best j-th image
  396. imagefilename = pogDB.db[idxSorted[j]]
  397. print("class(",i,"): best", j,">>",imagefilename)
  398. img = MIMG.Image.read(imagefilename)
  399. jj = idxSorted[j]
  400. p = allPalettes[jj]
  401. pImg = MPAL.Palette('Palette_'+str(i),p, MICS.ColorSpace.buildLab())
  402. imgPImg = pImg.createImageOfPalette()
  403. # palette contour
  404. pcImage = MPC2D.PointCloud2D(pImg.colors[:,1],pImg.colors[:,2])
  405. xxImage, yyImage = MPC2D.PointCloud2D.toXYarray(pcImage.convexHull())
  406. # figure and axes
  407. fig, ax = plt.subplots(2,2) # 1 row x 2 columns
  408. fig.suptitle('best image('+str(j)+')/class('+str(i)+')')
  409. ax[0,0].set_title('image')
  410. img.plot(ax[0,0],title=False)
  411. imgPImg.plot(ax[1,0],title=False)
  412. ax[1,0].set_title('palette of image')
  413. ax[0,1].set_title('palettes (red class/blue image)')
  414. _range = max([np.amax(np.abs(centroids[:,:,1])),np.amax(np.abs(centroids[:,:,2]))])
  415. for k, c in enumerate(centroids):
  416. # plot palette
  417. x = c[:,1] # a -> x
  418. y = c[:,2] # b -> y
  419. pc = MPC2D.PointCloud2D(x,y)
  420. xx,yy = MPC2D.PointCloud2D.toXYarray(pc.convexHull())
  421. if k != i: ax[0,1].plot(xx,yy,'m--')
  422. ax[0,1].plot(xxCentroid,yyCentroid,'ro--')
  423. ax[0,1].plot(xxImage,yyImage,'bo-')
  424. ax[0,1].plot([- _range, _range],[0,0],'k')
  425. ax[0,1].plot([0,0],[-_range,_range],'k')
  426. imgPaletteCentroid.plot(ax[1,1],title=False)
  427. ax[1,1].set_title("palette of class")
  428. plt.show(block=True)