remi.cozot il y a 3 ans
Parent
commit
bd6672cd8f

+ 167 - 0
_miamG/POGclusterLightness.py

@@ -0,0 +1,167 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, sys
+import matplotlib.pyplot as plt
+import numpy as np
+import scipy.stats
+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 MCHN
+
+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
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def pCompLightnessMoments(filename):
+    
+    # cut filename
+    path, name, ext = miam.utils.splitFileName(filename)
+
+    # read image
+    img = MIMG.Image.read(filename,exif=False)
+    # compute L lightness
+    L = img.getChannelVector(MCHN.channel.L)
+    # get bins
+    L_mean = np.mean(L)
+    L_std  = np.std(L)
+    L_skew = scipy.stats.skew(L)
+
+    #print("<",name,">",end='')
+    print("█",end='')
+    sys.stdout.flush()
+
+    return np.asarray([L_mean,L_std,L_skew])
+
+def pCompHistogram(filename):
+    
+    # cut filename
+    path, name, ext = miam.utils.splitFileName(filename)
+
+    # read image
+    img = MIMG.Image.read(filename,exif=False)
+    # compute histogram
+    histo = MHIST.Histogram.build(img,MIMG.channel.channel.L,50).normalise(norm='dot')
+    # get bins
+    bins = histo.histValue
+
+    #print("<",name,">",end='')
+    print("█",end='')
+    sys.stdout.flush()
+
+
+    return bins
+
+if __name__ == '__main__':
+    print("MIAM[POG Cluster Ligthness]")
+
+    # ------------------------------------------------------------------------------------------
+    # what to do !
+    # ------------------------------------------------------------------------------------------
+    # config: configfile
+    jsonfile = "../DB/config_POG_DB.json"
+    # all lightness moments file
+    allLightness_Moments = "../DB/POG_DB_L_Moments.npy"
+
+    # all lightness histogram file
+    allLightness_50bins = "../DB/POG_DB_L_Hists_50bins.npy"
+    allLightness_100bins = "../DB/POG_DB_L_Hists_100bins.npy"
+
+    # scatter plot: sdt(mean)
+    display_StdMean = True
+    # ------------------------------------------------------------------------------------------
+
+    # pog
+    pogDB = miam.imageDB.ImageDB.ImageDB(jsonConfigFile ="../DB/config_POG_DB.json")
+    pogDB.check(miam.imageDB.POGChecker.POGChecker(local=True))
+
+    print("MIAM[",pogDB.name,":(csvFileName:: ",pogDB.csvFileName,", imagePATH::",pogDB.imagePATH,")]")
+
+    # POG: compute Lightness Moments 
+    # ------------------------------------------------------------------------------------------
+    allMoments = None
+    if not os.path.isfile(allLightness_Moments):
+        print("MIAM[",pogDB.name," lightness moments not found !]")
+
+        nbCpu = mp.cpu_count()
+        print("MIAM[", nbCpu, "cpu cores]")
+        print("MIAM[",pogDB.name,"  number of images:",len(pogDB.db),"]")
+        print("MIAM[",pogDB.name," launch parallel computation of moments !]")
+
+        _pool = mp.Pool()
+        result = _pool.map(pCompLightnessMoments, pogDB.db)
+        allMoments = np.asarray(result)
+        print("")
+        print("[ --------------------------------------------------------]")
+        print("MIAM[",pogDB.name," parallel computation of moments done !]")
+        print("MIAM[",pogDB.name," all moments:",allMoments.shape," ]")
+        np.save("../DB/"+pogDB.name+'_L_Moments',allMoments)
+        print("MIAM[",pogDB.name," all moments saved !]")
+    else:
+        print("")
+        print("[ --------------------------------------------------------]")
+        print("MIAM[",pogDB.name," lightness moments found !]")
+        print("MIAM[",pogDB.name," all moments loaded !]")
+
+        allMoments = np.load(allLightness_Moments)
+        print("MIAM[",pogDB.name," all moments:",allMoments.shape," ]")
+
+    # POG: display Lightness Moments
+    # ------------------------------------------------------------------------------------------
+    if display_StdMean:
+        plt.figure("Lightness: standard deviations/mean")
+        plt.plot(allMoments[:,0],allMoments[:,1],'bo',markersize=2)
+        # k,r = miam.pointcloud.PointCloud2D.PointCloud2D(allMoments[:,0],allMoments[:,1]).removeIsolatedPoint(2.0,1)
+        #k,r = miam.pointcloud.PointCloud2D.PointCloud2D(allMoments[:,0],allMoments[:,1]).removeIsolatedPoint(10.0,500)
+        #plt.plot(k.X,k.Y,'bo',markersize=2)
+        #plt.plot(r.X,r.Y,'ro',markersize=2)
+        plt.plot(allMoments[:,0],allMoments[:,1],'bo',markersize=2)
+
+        plt.show(block=True)
+
+    # POG: compute Lightness Histograms
+    # ------------------------------------------------------------------------------------------
+    if not os.path.isfile(allLightness_50bins):
+        print("MIAM[",pogDB.name," lightness histogram not found !]")
+
+        nbCpu = mp.cpu_count()
+
+        print("MIAM[", nbCpu, "cpu cores]")
+        print("MIAM[",pogDB.name,"  number of images:",len(pogDB.db),"]")
+        print("MIAM[",pogDB.name," launch parallel computation of histograms !]")
+
+        _pool = mp.Pool()
+        result = _pool.map(pCompHistogram, pogDB.db)
+        allHist = np.asarray(result)
+        print("")
+        print("[ ---------------------------------------------------------- ]")
+        print("MIAM[",pogDB.name," parallel computation of histograms done !]")
+        print("MIAM[",pogDB.name," all histograms:",allHist.shape," ]")
+        np.save("../DB/"+pogDB.name+'_L_Hists_50bins',allHist)
+        print("MIAM[",pogDB.name," all histograms saved !]")
+    else:
+        print("")
+        print("[ --------------------------------------------------------]")
+        print("MIAM[",pogDB.name," lightness histogram found !]")
+
+

+ 150 - 0
_miamG/POGclusterPalette.py

@@ -0,0 +1,150 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, sys
+import matplotlib.pyplot as plt
+import numpy as np
+import scipy.stats
+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 MCHN
+
+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
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+
+
+def pCompPalette3(filename):
+    
+    # cut filename
+    path, name, ext = miam.utils.splitFileName(filename)
+
+    # read image
+    img = MIMG.Image.read(filename,exif=False)
+
+    # compute palette      
+    nbColors = 3
+    palette = MPAL.Palette.build(img, nbColors, fast=True, method='kmean-Lab',removeBlack=True)
+    # get colors
+    colors = palette.colors
+
+    #print("█",end='')
+    print("3.",end='')
+    sys.stdout.flush()
+
+    return colors
+
+def pCompPalette2(filename):
+    
+    # cut filename
+    path, name, ext = miam.utils.splitFileName(filename)
+
+    # read image
+    img = MIMG.Image.read(filename,exif=False)
+
+    # compute palette      
+    nbColors = 2
+    palette = MPAL.Palette.build(img, nbColors, fast=True, method='kmean-Lab',removeBlack=True)
+    # get colors
+    colors = palette.colors
+
+    #print("█",end='')
+    print("2.",end='')
+    sys.stdout.flush()
+
+    return colors
+
+if __name__ == '__main__':
+    print("MIAM[POG Cluster Palette]")
+
+    # ------------------------------------------------------------------------------------------
+    # what to do !
+    # ------------------------------------------------------------------------------------------
+    # config: configfile
+    jsonfile = "../DB/config_POG_DB.json"
+
+
+    # all palettes file
+    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"
+
+    # ------------------------------------------------------------------------------------------
+
+    # pog
+    pogDB = miam.imageDB.ImageDB.ImageDB(jsonConfigFile ="../DB/config_POG_DB.json")
+    pogDB.check(miam.imageDB.POGChecker.POGChecker(local=True))
+
+    print("MIAM[",pogDB.name,":(csvFileName:: ",pogDB.csvFileName,", imagePATH::",pogDB.imagePATH,")]")
+
+    # POG: compute Lightness Histograms
+    # ------------------------------------------------------------------------------------------
+    if not os.path.isfile(allPalettes_3colorsNoBlack):
+        print("MIAM[",pogDB.name," palette 3 colors not found !]")
+
+        nbCpu = mp.cpu_count()
+
+        print("MIAM[", nbCpu, "cpu cores]")
+        print("MIAM[",pogDB.name,"  number of images:",len(pogDB.db),"]")
+        print("MIAM[",pogDB.name," launch parallel computation of palettes (3) !]")
+
+        _pool = mp.Pool()
+        result = _pool.map(pCompPalette3, pogDB.db)
+        allColors = np.asarray(result)
+        print("")
+        print("[ ---------------------------------------------------------- ]")
+        print("MIAM[",pogDB.name," parallel computation of palettes (3) done !]")
+        print("MIAM[",pogDB.name," all palettes (3):",allColors.shape," ]")
+        np.save(allPalettes_3colorsNoBlack,allColors)
+        print("MIAM[",pogDB.name," all palettes saved !]")
+    else:
+        print("")
+        print("[ --------------------------------------------------------]")
+        print("MIAM[",pogDB.name," color palettes (3) found !]")
+
+    if not os.path.isfile(allPalettes_2colorsNoBlack):
+        print("MIAM[",pogDB.name," palette 2 colors not found !]")
+
+        nbCpu = mp.cpu_count()
+
+        print("MIAM[", nbCpu, "cpu cores]")
+        print("MIAM[",pogDB.name,"  number of images:",len(pogDB.db),"]")
+        print("MIAM[",pogDB.name," launch parallel computation of palettes (2) !]")
+
+        _pool = mp.Pool()
+        result = _pool.map(pCompPalette2, pogDB.db)
+        allColors = np.asarray(result)
+        print("")
+        print("[ ---------------------------------------------------------- ]")
+        print("MIAM[",pogDB.name," parallel computation of palettes (2) done !]")
+        print("MIAM[",pogDB.name," all palettes  (2):",allColors.shape," ]")
+        np.save(allPalettes_2colorsNoBlack,allColors)
+        print("MIAM[",pogDB.name," all palettes saved !]")
+    else:
+        print("")
+        print("[ --------------------------------------------------------]")
+        print("MIAM[",pogDB.name," color palettes (2) found !]")
+
+

+ 120 - 0
_miamG/WF_test_.py

@@ -0,0 +1,120 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, sys, math
+import numpy as np
+import easygui
+import colour
+
+# miam
+import miam.workflow.WFWorkflow as WF
+import miam.workflow.WFProcess as WP
+from miam.processing import NoOp, Duplicate,ExposureControl,TMO_Linear, TMO_CCTF
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def WF_test_00():
+
+    #                    (o) Root
+    #                     |
+    #                     v
+    #               [     o     ]
+    #               [    NoOp   ]
+    #               [     o     ]
+    #                     |
+    #                     v
+    #                    (_) Leaf
+    # process
+    wf = WF.WFWorkflow(name="test_00")
+    p1 = wf.addProcess(WP.WFProcess(name = 'NOP_01', process=NoOp.NoOp()))
+    p2 = wf.addProcess(WP.WFProcess(name = 'NOP_02', process=NoOp.NoOp()))
+    wf.connect(outputProcess = wf.getByName('NOP_01'),
+               inputProcess  = p2
+               )
+    wf.compile()
+
+
+def WF_test_01():
+
+    #                    (o) Root
+    #                     |
+    #                     v
+    #               [     o     ]
+    #               [  exposure ]
+    #               [     o     ]
+    #                     |
+    #                     v
+    #                    (_) Leaf
+    # process
+    wf = WF.WFWorkflow(name="test_01")
+
+    exposure = wf.addProcess(WP.WFProcess(name = 'exposure', process=ExposureControl.ExposureControl()).setParameters({'EV': +1}))
+
+    wf.compile()
+    wf.compute()    
+    wf.display()
+
+def WF_test_02():
+    # process
+    wf = WF.WFWorkflow(name="test_02")
+    duplicate = wf.addProcess(WP.WFProcess(name = 'duplicate', process=Duplicate.Duplicate()).setParameters({'nb': 2}))
+    exposureP1 = wf.addProcess(WP.WFProcess(name = 'exposure+1', process=ExposureControl.ExposureControl()).setParameters({'EV': +1}))
+    exposureM1 = wf.addProcess(WP.WFProcess(name = 'exposure-1', process=ExposureControl.ExposureControl()).setParameters({'EV': -1}))
+
+    wf.connect(outputProcess = duplicate, inputProcess  = exposureP1)
+    wf.connect(outputProcess = duplicate, inputProcess  = exposureM1)
+
+    wf.compile()
+    wf.compute()    
+    wf.display()
+
+def WF_test_03():
+
+    #                    (o) Root
+    #                     |
+    #                     v
+    #               [     o     ]
+    #               [ duplicate ]
+    #               [ o   |   o ]
+    #                /         \
+    #               /           \
+    #              v             v
+    #     [        o ]         [ o        ]          
+    #     [ exposure ]         [ TMO CCTF ]
+    #     [    o     ]         [    o     ]
+    #          |                    |
+    #          v                    v
+    #     [    o       ]           (_) Leaf
+    #     [ TMO linear ]
+    #     [     o      ]
+    #           |
+    #           v
+    #          (_) Leaf
+    # process
+    wf = WF.WFWorkflow(name="test_03")
+    duplicate = wf.addProcess(WP.WFProcess(name = 'duplicate', process=Duplicate.Duplicate()).setParameters({'nb': 2}))
+    exposure = wf.addProcess(WP.WFProcess(name = 'exposure', process=ExposureControl.ExposureControl()).setParameters({'auto': True, 'target': 0.5, 'EV': 0}))
+    tmo_linear = wf.addProcess(WP.WFProcess(name = 'tmo_linear', process=TMO_Linear.TMO_Linear()).setParameters({'min': 0.0, 'max': 1.0}))
+    tmo_cctf = wf.addProcess(WP.WFProcess(name = 'tmo_cctf', process=TMO_CCTF.TMO_CCTF()).setParameters({'function':'sRGB'}))
+
+    wf.setRoot(duplicate)
+
+    wf.connect(outputProcess = duplicate, inputProcess  = exposure)
+    wf.connect(outputProcess = exposure, inputProcess  = tmo_linear)
+    wf.connect(outputProcess = duplicate, inputProcess  = tmo_cctf)
+
+    wf.setLeaf(tmo_linear)
+    wf.setLeaf(tmo_cctf)
+              
+    wf.compile()
+
+    wf.compute()    
+    wf.display()
+
+def WF_JSON():
+    jsonFile = "../workflows/wf01.json"
+    wf = WF.WFWorkflow.readWorkflow(jsonFile)
+    wf.compute()
+    wf.display()

+ 70 - 0
_miamG/_miamG.py

@@ -1 +1,71 @@
 
+# import
+# ------------------------------------------------------------------------------------------
+import easygui, sys
+from multiprocessing import freeze_support
+# miam import
+import miamQT
+import WF_test_
+import myapp
+import miamResults4PublicationLIGHT
+import miamResults4PublicationPALETTE
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+def main():
+    # MIAM MAIN CHOICE
+    msg ="MIAM: main menu select action"
+    title = "MIAM - Remi Cozot (c) 2020"    
+    choices = [ "load image (SDR): display image, Lightness Histogram, Palette.",   # [0] load image (SDR): display image, Lightness Histogogram, Palette
+                "launch QT interafce."]                                             # [1] launch QT interafce
+
+    # take into account command line arguments
+    if len(sys.argv[1:])>=1:
+        # sys.argv[0]) == name of module
+        if (sys.argv[1]).isnumeric() : 
+            choice = choices[int(sys.argv[1])]
+            #  according to choice
+            print("MIAM:"+choice)
+            if choice == choices[0]: myapp.guiImage()
+            elif choice == choices[1]: miamQT.startGUI()
+            else:
+                if choice: print("MIAM:" + choice + " unknown !")
+                else: sys.exit(0)
+        elif 'help' in sys.argv[1]:
+            print("------            MIAM - Remi Cozot (c) 2020              ------")
+            print("----------------------------------------------------------------")
+            print("possible choices:")
+            for i, c in enumerate(choices):
+                print("python __miam.py ",i, ">",choices[i])
+            print("----------------------------------------------------------------")
+            sys.exit(0)
+        else:
+            choice = "error command line parameter: "+ sys.argv[1]
+
+    else: # no parameter in command line (interactive mode)
+        cont = True
+        while cont:
+            choice = easygui.choicebox(msg, title, choices)
+            if choice:
+                print("MIAM:"+choice)
+            else: sys.exit(0)
+
+            #  according to choice
+            if choice == choices[0]: myapp.guiImage()
+            elif choice == choices[1]:  miamQT.startGUI()
+
+            # continue or stop
+            msgRedo = "Do you want to continue?"
+            titleRedo = "Please Confirm"
+            cont =  easygui.ccbox(msgRedo, titleRedo)
+
+    # miamResults4PublicationPALETTE.clusterPalette()
+    # miamResults4PublicationLIGHT.clusterLightnessHist()
+    # myapp.guiSDR()
+# ------------------------------------------------------------------------------------------
+if __name__ == '__main__':
+    freeze_support()
+    main()
+# ------------------------------------------------------------------------------------------

+ 12 - 0
_miamG/_miamG.pyproj

@@ -21,6 +21,7 @@
     <EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
   </PropertyGroup>
   <ItemGroup>
+    <Compile Include="guiDisplayHDR.py" />
     <Compile Include="gui\guiController\MainWindowController.py" />
     <Compile Include="gui\guiController\__init__.py" />
     <Compile Include="gui\guiModel\ImageModel.py" />
@@ -31,6 +32,12 @@
     <Compile Include="gui\guiView\MainWindow.py" />
     <Compile Include="gui\guiView\__init__.py" />
     <Compile Include="gui\__init__.py" />
+    <Compile Include="highLevelFunc.py" />
+    <Compile Include="lightnessTMO_all.py" />
+    <Compile Include="localEQ_all.py" />
+    <Compile Include="miamQT.py" />
+    <Compile Include="miamResults4PublicationLIGHT.py" />
+    <Compile Include="miamResults4PublicationPALETTE.py" />
     <Compile Include="miam\aesthetics\Composition.py" />
     <Compile Include="miam\aesthetics\LightnessAesthetics.py" />
     <Compile Include="miam\aesthetics\Palette.py" />
@@ -93,6 +100,11 @@
     <Compile Include="miam\__init__.py">
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="myapp.py" />
+    <Compile Include="myQtApp.py" />
+    <Compile Include="POGclusterLightness.py" />
+    <Compile Include="POGclusterPalette.py" />
+    <Compile Include="WF_test_.py" />
     <Compile Include="_miamG.py" />
   </ItemGroup>
   <ItemGroup>

+ 55 - 0
_miamG/guiDisplayHDR.py

@@ -0,0 +1,55 @@
+# import
+# ------------------------------------------------------------------------------------------
+import matplotlib.pyplot as plt
+import numpy as np
+import easygui
+import os
+
+# miam import
+import miam.image.Image as MIMG
+import miam.processing.TMO_Lightness as TMO_L
+import miam.histogram.Histogram  as MHIST
+import miam.utils
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+
+if __name__ == '__main__':
+    pathImage = easygui.fileopenbox(msg="select HDR image.")
+    (path, name) =os.path.split(pathImage)
+    print("selected image:", pathImage, "name:", name)
+
+    # load image and remove zeros
+    img = MIMG.Image.readImage(pathImage)
+    img.name = name   
+    img = img.removeZeros().removeZeros(0.5)
+    img.name = name   
+    print("dynamic range (0.5%):",img.getDynamicRange( percentile = 0.0, mode="f-stops"),"f-stops")
+    hY = MHIST.Histogram.build(img,MIMG.channel.channel.Y,nbBins=50)
+
+    # tonemap
+    tmImg = img.process(TMO_L.TMO_Lightness())
+    tmImg.name = img.name+"Lightness_TMO"
+    htmL = MHIST.Histogram.build(tmImg,MIMG.channel.channel.L,nbBins=50)
+
+    # sve tone mapped image
+    tmImg.writeImage("../images/"+tmImg.name.split('.')[0]+"_Lightness_TMO")
+
+    # plot
+    fig, ax = plt.subplots(2,2)
+    img.plot(ax[0,0])
+    hY.plot(ax[0,1])
+    tmImg.plot(ax[1,0])
+    htmL.plot(ax[1,1])
+    plt.show(block=True)
+    
+    # just Y
+    #import miam.processing.ColorSpaceTransform as MCST
+    #Y = MCST.ColorSpaceTransform().compute(tmImg,dest='XYZ')
+    #plt.figure()
+    #plt.imshow(Y.colorData[:,:,1],cmap='gray')
+    #plt.show(block=True)

+ 25 - 0
_miamG/highLevelFunc.py

@@ -0,0 +1,25 @@
+import miam.utils
+import miam.image.Image as MIMG
+import miam.processing.TMO_Lightness as TMO_L
+import miam.processing.ContrastControl as PCC
+import imageio
+
+def tmo_Lightness_localEQ(hdrImageFilename):
+        (name, ext) = miam.utils.splitFileName(file)
+
+        # load image and remove zeros
+        img = MIMG.Image.readImage(srcPath+file).removeZeros().removeZeros(0.5) 
+
+        # tonemap
+        res = img.process(TMO_L.TMO_Lightness())
+      
+        # contrast control
+        imgLE = res.process(PCC.ContrastControl(),method='localEqualization', size=1500)
+
+        # fusion
+        alpha = 0.75
+        fusion = alpha*res+(1-alpha)*imgLE
+ 
+        # save 
+        imageio.imsave(name+"_Lightness_localEQ.jpg",fusion.colorData)
+        print("ok", end='\n')

+ 71 - 0
_miamG/lightnessTMO_all.py

@@ -0,0 +1,71 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os
+import multiprocessing as mp
+import matplotlib.pyplot as plt
+import numpy as np
+import easygui
+import colour
+
+# miam import
+import miam.image.Image as MIMG
+import miam.processing.TMO_Lightness as TMO_L
+import miam.utils
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def pfun(f):
+    path, name, ext = miam.utils.splitFileName(f)
+
+    current = mp.current_process()
+    print('core:', current.name,"(",current._identity,")","::",name)
+
+    # load image and remove zeros
+    img = MIMG.Image.readImage(f).removeZeros().removeZeros(0.5)
+    img.name = name   
+
+    # tonemap
+    tmImg = img.process(TMO_L.TMO_Lightness())
+    tmImg.name = img.name+"_Lightness_TMO"
+
+    # sve tone mapped image
+    tmImg.writeImage("../lightness_TMO/"+tmImg.name)
+
+    print('core:', current.name,"(",current._identity,")","::",tmImg.name,":: done n saved")
+
+    return None
+
+if __name__ == '__main__':
+
+    print("MIAM: lightness tone all hdr images")
+
+    nbCpu = mp.cpu_count()
+    print(" ---- found:", nbCpu, "cpu cores")
+
+    srcPath = "../../../photos/HDR-DB/HDR/"
+    hdrfiles = os.listdir(srcPath)
+    todo = []
+
+    respath = "../lightness_TMO/"
+    for h in hdrfiles:
+        path, name, ext = miam.utils.splitFileName(h)
+        jfile = respath+name+"_Lightness_TMO.json"
+        tmofile = respath+name+"_Lightness_TMO.jpg"
+        jfileOk = os.path.isfile(jfile)
+        tmofileOK = os.path.isfile(tmofile)
+        if ((not jfileOk) or (not tmofileOK)): todo.append(h)
+
+    listFiles = list(map(lambda x : srcPath+x, todo))
+
+
+    print(" ---- number of images:",len(listFiles))
+    for f in listFiles: print(" ---- file:", f)
+    print(" ---- launch tone mapping !")
+
+    _pool = mp.Pool()
+    result = _pool.map(pfun, listFiles)
+    print(" ---- tone mapping all done !")

+ 83 - 0
_miamG/localEQ_all.py

@@ -0,0 +1,83 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os
+import multiprocessing as mp
+import matplotlib.pyplot as plt
+import numpy as np
+import easygui
+import colour
+
+# miam import
+import miam.image.Image as MIMG
+import miam.processing.ContrastControl as PCC
+import miam.utils
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def pfun(f):
+    path, name, ext = miam.utils.splitFileName(f)
+
+    current = mp.current_process()
+    print('core:', current.name,"(",current._identity,")","::",name)
+
+    # load image and remove zeros
+    img = MIMG.Image.readImage(f)
+    img.name = name   
+
+    # tonemap
+    leqImg = img.process(PCC.ContrastControl(),method='localEqualization', size=1500)
+    leqImg.name = img.name+"_localEQ"
+
+    # save tone mapped image
+    leqImg.writeImage("../local_EQ/"+leqImg.name)
+
+    print('core:', current.name,"(",current._identity,")","::",leqImg.name,":: done n saved")
+
+    return None
+
+if __name__ == '__main__':
+
+    print("MIAM: local equalization of all images")
+
+    nbCpu = mp.cpu_count()
+    print(" ---- found:", nbCpu, "cpu cores")
+
+    srcPath = "../../../photos/HDR-DB/HDR/"
+    hdrfiles = os.listdir(srcPath)
+
+    todo = []
+
+    tmopath = "../lightness_TMO/"
+    leqpath = "../local_EQ/"
+    for h in hdrfiles:
+        path, name, ext = miam.utils.splitFileName(h)
+
+        tmofile = tmopath+name+"_Lightness_TMO.jpg"
+        leqfile = leqpath+name+"_Lightness_TMO"+"_localEQ.jpg"
+
+        tmofileOK = os.path.isfile(tmofile)
+        leqfileOK = os.path.isfile(leqfile)
+
+        #print("source:", h,
+        #      "tmofile::",tmofile,"::", tmofileOK,
+        #      "leqfile::",leqfile,"::", leqfileOK,
+        #      )
+
+
+        if (tmofileOK and (not leqfileOK)): todo.append(tmofile)
+
+    listFiles = todo
+
+
+    print(" ---- number of images:",len(listFiles))
+    for f in listFiles: print(" ---- file:", f)
+    print(" ---- launch local equalization !")
+
+    _pool = mp.Pool()
+    result = _pool.map(pfun, listFiles)
+    print(" ---- local equalize all done !")
+

+ 28 - 0
_miamG/miamQT.py

@@ -0,0 +1,28 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, sys, math
+import multiprocessing as mp
+import matplotlib.pyplot as plt
+import numpy as np
+import easygui
+import colour
+
+# import Qt
+from PyQt5.QtWidgets import QApplication
+
+# miam import
+
+# new import
+import gui.guiController.MainWindowController as MWC
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def startGUI():
+    app = QApplication(sys.argv)
+    # start MainWindowController
+    mwc = MWC.MainWindowController(app)
+    sys.exit(app.exec_())

+ 323 - 0
_miamG/miamResults4PublicationLIGHT.py

@@ -0,0 +1,323 @@
+# 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.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 
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+# --------------------------------------------> Cluster
+# --------------------------------------------> Palette
+
+
+def clusterLightnessHist():
+
+    # ------------------------------------------------------------------------------------------
+    # 
+    # ------------------------------------------------------------------------------------------
+    # config: configfile
+    jsonfile = "../DB/config_POG_DB.json"
+    # histogram files
+    # all lightness moments file
+    allLightness_Moments = "../DB/POG_DB_L_Moments.npy"
+    # all lightness histogram file
+    allLightness_50bins = "../DB/POG_DB_L_Hists_50bins.npy"
+    allLightness_100bins = "../DB/POG_DB_L_Hists_100bins.npy"
+    # clusters
+    centroids_L_Hists_50bins        = "../DB/POG_DB_centroids_L_Hists_50bins.npy"
+    assigments_L_Hists_50bins       = "../DB/POG_DB_assigments_L_Hists_50bins.npy"
+    assigmentsIdx_L_Hists_50bins    = "../DB/POG_DB_assigmentsIdx_L_Hists_50bins.npy"
+
+    distanceToCentroids = "../DB/POG_DB_dist_to_centroids_L_Hists_50bins.npy"
+    # ------------------------------------------------------------------------------------------
+    #  boolean to select what to do
+    # ------------------------------------------------------------------------------------------
+    display_StdMean =           True 
+    clusterHistograms =         False
+    computeDistToCentroids =    False
+    displayClusters =           True
+    distance1percent =          False
+    displayDistance =           True
+    displayBestPerClass =       True   
+    # pog
+    # ------------------------------------------------------------------------------------------
+    # loading POG
+    pogDB = miam.imageDB.ImageDB.ImageDB(jsonConfigFile =jsonfile)
+    pogDB.check(miam.imageDB.POGChecker.POGChecker(local=True))
+    print("MIAM[POG Cluster Lightness Histogram]")
+
+
+    # POG: display Lightness Moments
+    # ------------------------------------------------------------------------------------------
+    if display_StdMean:
+        # load files
+        allMoments = np.load(allLightness_Moments) 
+
+        # display
+        plt.figure("Lightness: standard deviations/mean")
+        plt.plot(allMoments[:,0],allMoments[:,1],'bo',markersize=2)
+        pc = MPC2D.PointCloud2D(allMoments[:,0],allMoments[:,1])
+        xx, yy = MPC2D.PointCloud2D.toXYarray(pc.contour(0.05))
+        plt.plot(xx,yy,'r')
+        plt.show(block=True)
+
+    # POG: compute cluster Histograms
+    # ------------------------------------------------------------------------------------------
+    if clusterHistograms:
+
+        print("MIAM[",pogDB.name," clustering Lightness launch !]")
+        allHists = np.load(allLightness_50bins)
+
+        # k-means
+        km = miam.classification.kmeans.kmeans(miam.math.Distance.Distance(miam.math.Distance.cosineDistance), 
+                                               miam.math.Normalize.Normalize(miam.math.Normalize.cosineNorm))
+        centroids,assigments,assigmentsIdx = km.kmeans(allHists, 5, 50, display = None)
+
+        print("MIAM[",pogDB.name," clustering done !]")
+        np.save(centroids_L_Hists_50bins,centroids)
+        np.save(assigments_L_Hists_50bins,assigments)
+        np.save(assigmentsIdx_L_Hists_50bins,assigmentsIdx)
+
+        print("MIAM[",pogDB.name," clustering save saved !]")
+
+    # POG: cluster analysis PART 1: distance to each centroids
+    # -----------------------------------------------------------------------------------------
+    if computeDistToCentroids:
+        # load files
+        allHists = np.load(allLightness_50bins)                                     # lightnesshsitograms
+        allMoments = np.load(allLightness_Moments)                                  # lightness moments mean, std, skewness
+        centroids = np.load(centroids_L_Hists_50bins, allow_pickle = True)          # centroids: 5 histograms
+        assigments = np.load(assigments_L_Hists_50bins, allow_pickle = True)        # assigments  
+        assigmentsIdx = np.load(assigmentsIdx_L_Hists_50bins, allow_pickle = True)  # assigments index: for each histograms index of class
+  
+        print("MIAM[",pogDB.name," compute fo each distance to all centroid !]")
+
+        # get data
+        L_mean = allMoments[:,0]
+        L_std  = allMoments[:,1]
+
+        # buid histogram objects
+        hCentroids = []
+        for cent in centroids:
+            c = MHIST.Histogram(cent,np.linspace(0,100,50+1),"hCentroid",MCH.channel.L)
+            hCentroids.append(c)
+
+        # distToCentroids
+        distToCentroids = []
+        # distance to centroids
+        for i, rawHist in enumerate(allHists):
+            # get raw image histogram and build Histogram Object
+            h = MHIST.Histogram(allHists[i],np.linspace(0,100,50+1),"h_"+str(i),MCH.channel.L)
+            distToCent = []
+            for j,hc in enumerate(hCentroids):
+                d = MHIST.Histogram.computeDistance(hc,h)
+                distToCent.append(d)
+            
+            distToCentroids.append(distToCent)
+
+        np.save(distanceToCentroids,distToCentroids)
+    # POG: cluster analysis PART 2: aesthetics class
+    # -----------------------------------------------------------------------------------------
+    if displayClusters:
+
+        # load files
+        allHists = np.load(allLightness_50bins)                                     # lightnesshsitograms
+        allMoments = np.load(allLightness_Moments)                                  # lightness moments mean, std, skewness
+        centroids = np.load(centroids_L_Hists_50bins, allow_pickle = True)          # centroids: 5 histograms
+        assigments = np.load(assigments_L_Hists_50bins, allow_pickle = True)        # assigments  
+        assigmentsIdx = np.load(assigmentsIdx_L_Hists_50bins, allow_pickle = True)  # assigments index: for each histograms index of class
+        distToCentroids = np.load(distanceToCentroids, allow_pickle = True)         # for each histograms/image distance to each cluster 
+
+        # get data
+        L_mean = allMoments[:,0]
+        L_std  = allMoments[:,1]
+
+        # --------------------------------------------
+        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 histograms
+        numberOfCluster =5
+        fig, ax = plt.subplots(1,1)
+        fig.suptitle("Centroids:"+str(numberOfCluster)+"/ Lightness Histograms ['b', 'g','r','c','m']")
+        for i,c in enumerate(centroids):
+            # create histograms object
+            histoCentroids = MHIST.Histogram(c,np.linspace(0,100,50+1),"class("+str(i)+")",MCH.channel.L)
+            # create image of palette
+            histoCentroids.plot(ax,color=colors[i], title=True)
+            #ax[1].plot(i*10,0,'o'+colors[i],markersize=10)
+            #ax[1].axis("off")
+                
+        plt.show(block=False)
+
+        # --------------------------------------------
+        plt.figure("Lightness: clusters")
+        colors = ['b', 'g','r','c','m','y','k']
+
+        for i,assigmentId in enumerate(assigmentsIdx):
+            print("assigmentId[",i,"].len:",len(assigmentId))
+            pc = MPC2D.PointCloud2D(L_mean[assigmentId],L_std[assigmentId])
+            # plot contour of clusters
+            xx, yy = MPC2D.PointCloud2D.toXYarray(pc.contour(0.1))
+            plt.plot(xx,yy,colors[i%len(colors)])
+            plt.plot(L_mean[assigmentId],L_std[assigmentId],colors[i%len(colors)]+'o', markersize=1)
+        plt.show(block=True)
+    # -----------------------------------------------------------------------------------------
+    if distance1percent:
+        # load files
+        allHists = np.load(allLightness_50bins)                                     # lightnesshsitograms
+        allMoments = np.load(allLightness_Moments)                                  # lightness moments mean, std, skewness
+        centroids = np.load(centroids_L_Hists_50bins, allow_pickle = True)          # centroids: 5 histograms
+        assigments = np.load(assigments_L_Hists_50bins, allow_pickle = True)        # assigments  
+        assigmentsIdx = np.load(assigmentsIdx_L_Hists_50bins, allow_pickle = True)  # assigments index: for each histograms index of class
+        distToCentroids = np.load(distanceToCentroids, allow_pickle = True)         # for each histograms/image distance to each cluster 
+
+        # get data
+        L_mean = allMoments[:,0]
+        L_std  = allMoments[:,1]
+
+        colors = ['b', 'g','r','c','m','y','k']
+        plt.figure("Lightness: clusters 1%")
+
+        for i, assigmentId in enumerate(assigmentsIdx):
+
+            p25 = int(len(assigmentId) * 0.01)
+            p100 = int(len(assigmentId) * 1.00)
+
+            dd = distToCentroids[assigmentId,i]
+
+            idxSorted = np.argsort(dd)#[::-1]
+
+            i25 = idxSorted[0:p25]
+            i100 = idxSorted[0:p100]
+
+            ii25 = [assigmentId[k] for k in i25]
+            ii100 = [assigmentId[k] for k in i100]
+
+            pc25 = MPC2D.PointCloud2D(L_mean[ii25],L_std[ii25])
+            pc100 = MPC2D.PointCloud2D(L_mean[ii100],L_std[ii100])
+
+            xx25, yy25 = MPC2D.PointCloud2D.toXYarray(pc25.contour(0.1))
+            xx100, yy100 = MPC2D.PointCloud2D.toXYarray(pc100.contour(0.1))
+
+            plt.plot(xx25, yy25, colors[i%len(colors)]+"-.")
+            plt.plot(xx100, yy100, colors[i%len(colors)])
+
+        plt.show(block=True)
+    # -----------------------------------------------------------------------------------------
+    if displayDistance:
+        print("MIAM[",pogDB.name," display distance !]")
+        # load files
+        allHists = np.load(allLightness_50bins)                                     # lightnesshsitograms
+        allMoments = np.load(allLightness_Moments)                                  # lightness moments mean, std, skewness
+        centroids = np.load(centroids_L_Hists_50bins, allow_pickle = True)          # centroids: 5 histograms
+        assigments = np.load(assigments_L_Hists_50bins, allow_pickle = True)        # assigments  
+        assigmentsIdx = np.load(assigmentsIdx_L_Hists_50bins, allow_pickle = True)  # assigments index: for each histograms index of class
+        distToCentroids = np.load(distanceToCentroids, allow_pickle = True)         # for each histograms/image distance to each cluster 
+
+        # get data
+        fig, ax = plt.subplots(1,5)
+        fig.suptitle('Distance to Histogram Class')
+        colors = ['b', 'g','r','c','m','y','k']
+        # sort
+        for i in range(5):
+            idxSorted = np.argsort(distToCentroids[:,i])#[::-1]
+
+            for j in range(5):
+                ax[i].plot((distToCentroids[idxSorted[0:1000],j]),colors[j%len(colors)]+'o', markersize=1)
+        plt.show(block=True)
+
+    # -----------------------------------------------------------------------------------------
+    if displayBestPerClass:
+        print("MIAM[display best image per class !]")
+        # load files
+        allHists = np.load(allLightness_50bins)                                     # lightnesshsitograms
+        allMoments = np.load(allLightness_Moments)                                  # lightness moments mean, std, skewness
+        centroids = np.load(centroids_L_Hists_50bins, allow_pickle = True)          # centroids: 5 histograms
+        assigments = np.load(assigments_L_Hists_50bins, allow_pickle = True)        # assigments  
+        assigmentsIdx = np.load(assigmentsIdx_L_Hists_50bins, allow_pickle = True)  # assigments index: for each histograms index of class
+        distToCentroids = np.load(distanceToCentroids, allow_pickle = True)         # for each histograms/image distance to each cluster
+
+        # get data
+        L_mean = allMoments[:,0]
+        L_std  = allMoments[:,1]
+
+        colors = ['b', 'g','r','c','m','y','k']
+
+        # for each class
+        for i in range(5):
+            # histogram of class
+            centroidHist = MHIST.Histogram(centroids[i,:],np.linspace(0,100,50+1),"",MCH.channel.L)
+            # contour of class
+            pc = MPC2D.PointCloud2D(L_mean[assigmentsIdx[i]],L_std[assigmentsIdx[i]])
+            xx, yy = MPC2D.PointCloud2D.toXYarray(pc.contour(0.1))
+
+            # sort image according to class distance
+            idxSorted = np.argsort(distToCentroids[:,i])
+
+            # for ten best image of the current class
+            for j in range(3):
+
+                imagefilename = pogDB.db[idxSorted[j]]
+                print("class(",i,"): best", j,">>",imagefilename)
+                img = MIMG.Image.read(imagefilename)
+                hist = MHIST.Histogram(allHists[idxSorted[j]],np.linspace(0,100,50+1),"",MCH.channel.L)
+
+                # create figure
+                fig, ax = plt.subplots(1,3)
+                fig.suptitle("find 'best' image per class")
+
+                centroidHist.plot(ax[0],colors[i%len(colors)])
+                hist.plot(ax[0],'k')
+                ax[0].set_title('image (black) & centroid histogram')
+
+                ax[1].plot(xx,yy,colors[i%len(colors)])
+                ax[1].plot(L_mean[idxSorted[j]],L_std[idxSorted[j]],'ko')
+                ax[1].set_title('image lighness mean and constrast (black)/ contour of class')
+
+                img.plot(ax[2])
+                ax[2].set_title('image')
+
+                plt.show(block=True)
+
+
+
+
+
+
+
+

+ 532 - 0
_miamG/miamResults4PublicationPALETTE.py

@@ -0,0 +1,532 @@
+# 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)

+ 139 - 0
_miamG/myQtApp.py

@@ -0,0 +1,139 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, sys, math
+import multiprocessing as mp
+import matplotlib.pyplot as plt
+import numpy as np
+import easygui
+import colour
+
+# import Qt
+from PyQt5.QtWidgets import QMainWindow, QAction, QApplication, QMenu
+from PyQt5.QtWidgets import QWidget, QLabel, QFileDialog 
+from PyQt5.QtWidgets import QHBoxLayout # QSlider
+from PyQt5.QtGui import QIcon, QPixmap, QImage
+from PyQt5 import QtCore
+
+# miam import
+import miam.image.Image as MIMG
+import miam.aesthetics.Palette as MPAL
+import miam.utils
+
+# new import
+import gui.guiView.ImageWidget as gIW
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+def getScreenSize():
+    app = QApplication(sys.argv)
+    screens = app.screens()
+
+    for s in screens:
+        n = s.name()
+        size = s.size()
+
+        x = size.width()
+        y = size.height()
+
+        print("screen(",n,"):",x,"x",y)
+
+    app.quit()
+
+    return None
+
+
+def testQt():
+    getScreenSize()
+    pass
+
+class QMainApp(QMainWindow):
+    
+    def __init__(self):
+        super().__init__()
+        
+        self.initUI()
+        
+    def initUI(self):         
+        
+        menubar = self.menuBar()
+        # file menu
+        fileMenu = menubar.addMenu('&File')
+
+        # Create Open action
+        openAction = QAction('&Open', self)        
+        openAction.setShortcut('Ctrl+N')
+        openAction.setStatusTip('Open image')
+        openAction.triggered.connect(self._open)
+        
+        fileMenu.addAction(openAction)
+
+        # Create Save action
+        saveAction = QAction('&Save', self)        
+        saveAction.setShortcut('Ctrl+S')
+        saveAction.setStatusTip('Save image')
+        saveAction.triggered.connect(self._save)
+        
+        fileMenu.addAction(saveAction)
+
+        # Create Quit action
+        quitAction = QAction('&Quit', self)        
+        quitAction.setShortcut('Alt+F4')
+        quitAction.setStatusTip('Quit')
+        quitAction.triggered.connect(self._quit)
+        
+        fileMenu.addAction(quitAction)
+
+        # status bar
+        self.statusBar().showMessage('Welcome to MIAM: Multidimensional Image Aesthetics Model!')
+
+        # geometry
+        base, ratio, scale= 1920, 16/9, 0.5
+        self.setGeometry(0, 0, math.floor(base*scale), math.floor(base/ratio*scale))
+
+        # title
+        self.setWindowTitle('miam')    
+
+        #
+        self.img0 = gIW.ImageWidget(None,filename= '../images/DSC01314-HDR.jpg', mother=self)
+        self.img1 = gIW.ImageWidget(None,filename= '../images/DSC01314.JPG', mother=self)
+        imgLayout = QHBoxLayout()
+        imgLayout.addWidget(self.img0)
+        imgLayout.addWidget(self.img1)
+
+        widget = QWidget()
+        widget.setLayout(imgLayout)
+        self.setCentralWidget(widget)
+
+        # show
+        self.show()
+
+    def _statusMessage(self, s): self.statusBar().showMessage(s)
+
+    def _open(self):
+        self._statusMessage('open!!')
+        fname = QFileDialog.getOpenFileName(self, 'Open file', '../images/')
+        print(fname[0])
+        self.centralWidget()._new(fname[0])
+
+    def _save(self):
+        self._statusMessage('save!!')
+
+    def _quit(self):
+        self._statusMessage('quit!!')
+        sys.exit()
+
+    def resizeEvent(self, event):
+
+        self.img0._resize()
+        self.img1._resize()
+        pass
+
+
+def qtTest2():
+    app = QApplication(sys.argv)
+    ex = QMainApp()
+    sys.exit(app.exec_())

+ 360 - 0
_miamG/myapp.py

@@ -0,0 +1,360 @@
+# import
+# ------------------------------------------------------------------------------------------
+import os, time
+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.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.aesthetics.Composition as MCMP
+
+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 
+
+# ------------------------------------------------------------------------------------------
+# MIAM project 2020
+# ------------------------------------------------------------------------------------------
+# author: remi.cozot@univ-littoral.fr
+# ------------------------------------------------------------------------------------------
+
+
+# --------------------------------------------> basic app
+def guiImage(filename=None):
+    if not filename:
+        filename = easygui.fileopenbox(msg="select image.")
+        print("MIAM[selected image:", filename,"]")
+
+    # paramters
+    nbColorInPalette =5
+    nbPointInCompo =10
+    # reading image
+    start = time.time()
+    image = MIMG.Image.readImage(filename, readExif=False)
+    end = time.time()
+    print("[read image: ........ ",int((end-start)*1000),"(ms)]")
+    # compute histogram
+
+    start = time.time()
+    histogram = MHIST.Histogram.build(image,MIMG.channel.channel.L,50).normalise(norm='dot')
+    end = time.time()
+    print("[compute histogram: . ",int((end-start)*1000),"(ms)]")
+
+    # compute palette
+    start = time.time()
+    palette = MPAL.Palette.build(image,nbColorInPalette,method='kmean-Lab', removeBlack=True)
+    imageOfPalette = palette.createImageOfPalette()    
+    end = time.time()
+    print("[compute palette: ... ",int((end-start)*1000),"(ms)]")    
+
+    # compute composition
+    start = time.time()
+    composition = MCMP.Composition.build(image,nbPoint =nbPointInCompo, nbZone=9)
+    end = time.time()
+    print("[compute composition: ",int((end-start)*1000),"(ms)]")
+
+
+    # display all elements
+    fig = plt.figure()
+
+    axHisto =   plt.subplot(233)
+    axPalette = plt.subplot(236)
+    axImage =   plt.subplot(131)
+    axCompo =   plt.subplot(132)
+
+    image.plot(axImage,title=False)
+    histogram.plot(axHisto,title=False)
+    imageOfPalette.plot(axPalette, title=False)
+    image.plot(axCompo,title=False)
+    composition.plot(axCompo,title=False, keepRawPoints = True)
+
+    axHisto.set_title("Histogram (Lightness)")
+    axPalette.set_title("Palette ("+str(nbColorInPalette)+" colors)")
+    axImage.set_title("Image")
+    axCompo.set_title("Composition ("+str(nbPointInCompo)+" points)")
+    fig.suptitle(image.name)
+
+
+    plt.show(block=True)
+
+def guiHDR():
+    pathImage = easygui.fileopenbox(msg="select HDR image.")
+    print("selected image:", pathImage)
+
+    # load image and remove zeros
+    img = MIMG.Image.readImage(pathImage).removeZeros().removeZeros(0.5)
+    ((minR,maxR),(minG,maxG),(minB,maxB)) = img.getMinMaxPerChannel()
+    # print min max per channel
+    print("(min/max): R:(",minR,"/",maxR,") - G:(",minG,"/",maxG,") -B:(",minB,"/",maxB,")")
+
+
+    # to XYZ
+    imgXYZ = MCST.ColorSpaceTransform().compute(img,dest='XYZ')
+    # print min max per channel
+    ((minX,maxX),(minY,maxY),(minZ,maxZ)) = imgXYZ.getMinMaxPerChannel()
+    print("(min/max): X:(",minX,"/",maxX,") - Y:(",minY,"/",maxY,") - Z:(",minZ,"/",maxZ,")")
+
+    # dynamic range
+    print("dynamic range (0.5%):",img.getDynamicRange( percentile = 0.25, mode="f-stops"),"f-stops/",
+          img.getDynamicRange( percentile = 0.25, mode="maxmin"),"(Ymax,Ymin)")
+    print("dynamic range (0):",img.getDynamicRange( percentile = 0, mode="f-stops"),"f-stops/",
+          img.getDynamicRange( percentile = 0, mode="maxmin"),"(Ymax,Ymin)")
+    # histogram
+    hRGB = MHIST.Histogram.build(img,MIMG.channel.channel.sG,nbBins=50)
+    hXYZ = MHIST.Histogram.build(imgXYZ,MIMG.channel.channel.Y,nbBins=50)
+
+    # plot
+    fig, ax = plt.subplots(1,3)
+    img.plot(ax[0])
+    hRGB.plot(ax[1])
+    hXYZ.plot(ax[2])
+    plt.show(block=True)
+
+# --------------------------------------------> Lightness HDR dataset
+def testDB_Huawei():
+    hDB = miam.imageDB.ImageDB_HDD.ImageDB_HDD(name= "HDR DataBase" ,csvFile="../DB/hdrHuawei_DB.csv", jsonConfigFile ="../DB/config_HDR_DB.json")
+    hDB.build(miam.imageDB.HwHDRBuilder.HwHDRBuilder(),src='HDR')
+    #hDB.build(miam.imageDB.HwHDRBuilder.HwHDRBuilder(),src='HTM')
+    #hDB.check()
+    hDB.buildHTMLPage()
+    
+# --------------------------------------------> Lightness TMO
+def guiLightnessTMO():
+    pathImage = easygui.fileopenbox(msg="select HDR image.")
+    print("selected image:", pathImage)
+
+    # load image and remove zeros
+    img = MIMG.Image.readImage(pathImage).removeZeros().removeZeros(0.5) #.resize((1920,None))
+
+    # tonemap
+    res = img.process(TMO_L.TMO_Lightness())
+
+    # contrast control
+    imgLE = res.process(PCC.ContrastControl(),method='localEqualization', size=1500)
+    imgLE.name += '_local equaliz.'
+    
+
+    alpha = 0.75
+    fusion = alpha*res+(1-alpha)*imgLE
+    fusion.name = 'fusion'
+
+    # histograms
+    #hHDR = MHIST.Histogram.build(img,MIMG.channel.channel.Y,nbBins=50)      # hdr image histogram
+    #hTMoL = MHIST.Histogram.build(res,MIMG.channel.channel.L,nbBins=50)     # TMo lightness histogram
+    #hLE = MHIST.Histogram.build(imgLE,MIMG.channel.channel.L,nbBins=50)     # TMo Lightness + local equalization histogram
+
+    # plot
+    fig, ax = plt.subplots(2,2)
+    img.plot(ax[0,0])   # hdr
+    res.plot(ax[0,1])   # lightness tone mapping
+
+    fusion.plot(ax[1,0])
+    imgLE.plot(ax[1,1])
+
+    plt.show(block=True)
+    imageio.imsave("testLightness_loalEQ.jpg",fusion.colorData)
+    #imageio.imsave("testLightness+stretch.jpg",imgCS.colorData)
+    #imageio.imsave("testLightness+equalization.jpg",imgGE.colorData)
+    pass
+
+def testLightnessTMO():
+    srcPath = "../../../photos/HDR-DB/HDR/"
+    listFiles = os.listdir(srcPath)
+    for file in listFiles:
+        print("fileName:", file , end='::')
+        (name, ext) = miam.utils.splitFileName(file)
+        print("loading", end='::')
+        # load image and remove zeros
+        img = MIMG.Image.readImage(srcPath+file).removeZeros().removeZeros(0.5) 
+        print("ok", end='::')
+        print("tone mapping", end='::')
+        # tonemap
+        res = img.process(TMO_L.TMO_Lightness())
+        print("ok", end='::')
+        print("post-processing", end='::')        
+        # contrast control
+        imgLE = res.process(PCC.ContrastControl(),method='localEqualization', size=1500)
+        print("ok", end='::')
+        print("fusion", end='::') 
+        # fusion
+        alpha = 0.75
+        fusion = alpha*res+(1-alpha)*imgLE
+        print("ok", end='::')
+        print("save", end='::') 
+        # save 
+        imageio.imsave(name+"_Lightness_localEQ.jpg",fusion.colorData)
+        print("ok", end='\n')
+
+# --------------------------------------------> Segmentation
+def testSegment(filename=None):
+    if not filename:
+        filename = easygui.fileopenbox(msg="select HDR image.")
+    
+        print("selected image:", filename)
+
+    # reading image
+    i0 = MIMG.Image.readImage(filename)
+    
+    # compute histogram
+    h0 = MHIST.Histogram.build(i0,MIMG.channel.channel.L,100).normalise(norm='probability')
+    print(h0)
+
+    res = h0.segmentPics(nbSegs=5)
+
+def testMask(filename=None):
+    if not filename:
+        filename = easygui.fileopenbox(msg="select HDR image.")
+    
+        print("selected image:", filename)
+
+    # reading image
+    i0 = MIMG.Image.readImage(filename)
+    
+    mask = i0.buildMaskByValue(MIMG.channel.channel.L, 0,50)
+
+    fig, ax = plt.subplots(nrows=1, ncols=2)
+    # +-----------------------------+-----------------------------+
+    # | [0]= i0                     | [1]=  mask                  | 
+    # +-----------------------------+-----------------------------+
+
+    i0.plot(ax[0])
+    mask.plot(ax[1])
+    plt.show(block=True)
+
+def testSegment2(filename=None):
+    if not filename:
+        filename = easygui.fileopenbox(msg="select an image.")
+    
+        print("selected image:", filename)
+        None
+    # reading image and compute histogram
+    i0 = MIMG.Image.readImage(filename)
+
+    if i0.type == MTYPE.imageType.HDR:
+        LorY = MIMG.channel.channel.Y
+        i0 = i0.removeZeros(0.5)
+    else:
+        LorY = MIMG.channel.channel.L
+
+    h0 = MHIST.Histogram.build(i0,LorY,100).normalise(norm='probability')
+
+    segmentBoundariesValue = h0.segmentPics(nbSegs=5)
+
+    # debug
+    print("segment boundaries value:", segmentBoundariesValue)
+    mask_i = []
+    for i in range(len(segmentBoundariesValue)-1):
+        mask = i0.buildMaskByValue(LorY,segmentBoundariesValue[i],segmentBoundariesValue[i+1])
+        mask_i.append(mask)
+    
+    # plot
+    fig, ax = plt.subplots(nrows=1, ncols=1)
+    # +-----------------------------+
+    # | [0]= i0                     | 
+    # +-----------------------------+
+    i0.plot(ax)
+    plt.show(block=False)
+
+    # plot
+    fig, ax = plt.subplots(nrows=len(segmentBoundariesValue)-1, ncols=1)
+    # +-----------------------------+
+    # | [i]=mask[i]                 | 
+    # +-----------------------------+
+    for i in range(len(segmentBoundariesValue)-1):
+        mask_i[i].plot(ax[i])
+    plt.show(block=True)
+
+# --------------------------------------------> Palette
+def testAddPalette(filename0=None, filename1=None):
+
+    # select images
+    if not filename0:
+        filename0 = easygui.fileopenbox(msg="select first image.")
+        print("selected image:", filename0)
+    if not filename1:
+        filename1 = easygui.fileopenbox(msg="select first image.")
+        print("selected image:", filename1)
+
+    # reading image
+    i0 = MIMG.Image.readImage(filename0)
+    i1 = MIMG.Image.readImage(filename1)
+
+    # compute palettes
+    p0 = MPAL.Palette.build(i0,5,method='kmean-Lab', removeBlack=True)
+    imageOfPalette0 = p0.createImageOfPalette()
+    p1 = MPAL.Palette.build(i1,5,method='kmean-Lab', removeBlack=True)
+    imageOfPalette1 = p1.createImageOfPalette()
+
+    # average palette
+    p01 = 0.5*(p0+p1)
+
+    fig, ax = plt.subplots(nrows=2, ncols=3)
+    # +-----------------------------+-----------------------------+-----------------------------+
+    # | [0,0]= i0                   | [0,1]=  i1                  | [0,2]= p01                  |
+    # +-----------------------------+-----------------------------+-----------------------------+
+    # | [1,0]= p0                   | [1,1]= p1                   | [1,2]=                      |
+    # +-----------------------------+-----------------------------+-----------------------------+
+    i0.plot(ax[0,0])
+    imageOfPalette0.plot(ax[1,0])
+
+    i1.plot(ax[0,1])
+    imageOfPalette1.plot(ax[1,1])
+
+    p01.createImageOfPalette().plot(ax[0,2])
+
+    plt.show(block=True)
+
+# --------------------------------------------> Compistion
+def estimateComposition(filename=None):
+    if not filename:
+        filename = easygui.fileopenbox(msg="select image.")
+        print("selected image:", filename)
+
+    # reading image
+    img = MIMG.Image.readImage(filename)
+
+    comp = MCMP.Composition.build(img,nbPoint =3, nbZone=9)
+
+    fig, ax = plt.subplots(nrows=1, ncols=2)
+    # +-----------------------------+-----------------------------+-----------------------------+
+    # | [0,0]= image                | [0,1]=  ssl map             | [0,2]=                      |
+    # +-----------------------------+-----------------------------+-----------------------------+
+    # | [1,0]=                      | [1,1]=                      | [1,2]=                      |
+    # +-----------------------------+-----------------------------+-----------------------------+
+    img.plot(ax[0])
+    comp.plot(ax[0],title=False)
+    ax[0].axis(False)
+
+    comp.plot(ax[1])
+
+    plt.show(block=True)
+    # load aesthetics classes
+    #centroidsAES = MLAC.LightnessAesthetics.readLightnessClasses('../../aestheticsClass/both/statsLY/'+'km_centroids_nbCluster5_nbBin50.npy')
+    #dists = centroidsAES.computeImageClass(i0)
+
+    #h0AES0 = centroidsAES.projectImage(i0,nbClass=range(0,1))
+    #h0AES01 = centroidsAES.projectImage(i0,nbClass=range(0,2))
+
+
+