|
@@ -14,101 +14,19 @@
|
|
|
# hdrCore project 2020
|
|
|
# author: remi.cozot@univ-littoral.fr
|
|
|
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# --- VERSION TRACKING --------------------------------------------------------
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (1): DEBUG
|
|
|
-# HDRImageViewer doesn't open
|
|
|
-# add time.sleep() in HDRviewerController.displayFile(...)
|
|
|
-# ---- Rémi Cozot, June 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (2): Prevent Freezing
|
|
|
-# Add multithreading in:
|
|
|
-# i - processpipe processing (except for export and display)
|
|
|
-# ii - loading images
|
|
|
-# ---- Rémi Cozot, July 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (3): Prevent Freezing and speed up
|
|
|
-# Add multithreading in:
|
|
|
-# i - processpipe processing for HDR display
|
|
|
-# ii - processpipe procssing export single image to vesaHDR1000
|
|
|
-# ---- Rémi Cozot, July 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (4): Fix ev value and accuracy in color editor
|
|
|
-# ---- Rémi Cozot, July 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (5): Fix Y curve plot
|
|
|
-# ---- Rémi Cozot, July 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
-# (6): Ability to export SDR (.jpg) image to HDR (tone expansion).
|
|
|
-# ---- Rémi Cozot, July 2021
|
|
|
-# -----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
# -----------------------------------------------------------------------------
|
|
|
# --- Package hdrGUI ---------------------------------------------------------
|
|
|
# -----------------------------------------------------------------------------
|
|
|
"""
|
|
|
-package hdrGUI consists of the classes for GUI:
|
|
|
-(1) controller classes:
|
|
|
- class GalleryMode(enum.Enum)
|
|
|
- class ImageWidgetController
|
|
|
- class ImageGalleryController()
|
|
|
- class AppController(object)
|
|
|
- class MultiDockController()
|
|
|
- class EditImageController
|
|
|
- class ImageInfoController
|
|
|
- class AdvanceSliderController()
|
|
|
- class ToneCurveController()
|
|
|
- class LightnessMaskController()
|
|
|
- class HDRviewerController()
|
|
|
- class LchColorSelectorController()
|
|
|
- class GeometryController()
|
|
|
-(2) model classes:
|
|
|
- class ImageWidgetModel(object)
|
|
|
- class ImageGalleryModel
|
|
|
- class AppModel(object)
|
|
|
- class EditImageModel(object)
|
|
|
- class AdvanceSliderModel()
|
|
|
- class ToneCurveModel()
|
|
|
- class LightnessMaskModel()
|
|
|
- class ImageInfoModel(object)
|
|
|
- class HDRviewerModel(object)
|
|
|
- class ImageQualityModel(object)
|
|
|
- class LchColorSelectorModel(object)
|
|
|
- class GeometryModel(object)
|
|
|
-(3) view classes:
|
|
|
- class ImageWidgetView(QWidget)
|
|
|
- class FigureWidget(FigureCanvas)
|
|
|
- class ImageGalleryView(QSplitter)
|
|
|
- class AppView(QMainWindow)
|
|
|
- class ImageInfoView(QSplitter)
|
|
|
- class AdvanceLineEdit(object)
|
|
|
- class AdvanceCheckBox(object)
|
|
|
- class EditImageView(QSplitter)
|
|
|
- class MultiDockView(QDockWidget)
|
|
|
- class AdvanceSliderView(QFrame)
|
|
|
- class ToneCurveView(QFrame)
|
|
|
- class LightnessMaskView(QGroupBox)
|
|
|
- class HDRviewerView(QFrame)
|
|
|
- class ImageQualityView(QScrollArea)
|
|
|
- class LchColorSelectorView(QFrame)
|
|
|
- class GeometryView(QFrame)
|
|
|
-(4) Qt multi threading classes:
|
|
|
- class RequestCompute(object)
|
|
|
- class RunCompute(QRunnable)
|
|
|
- class RequestLoadImage(object)
|
|
|
- class RunLoadImage(QRunnable)
|
|
|
- class pCompute(object)
|
|
|
- class pRun(QRunnable)
|
|
|
+package hdrGUI consists of the classes for GUI.
|
|
|
"""
|
|
|
# -----------------------------------------------------------------------------
|
|
|
# --- Import ------------------------------------------------------------------
|
|
|
# -----------------------------------------------------------------------------
|
|
|
|
|
|
-import enum, sys, subprocess, copy, colour, time, os, shutil, datetime
|
|
|
+import enum, sys, subprocess, copy, colour, time, os, shutil, datetime, ctypes
|
|
|
import numpy as np
|
|
|
# pyQT5 import
|
|
|
from PyQt5.QtWidgets import QFileDialog, QApplication
|
|
@@ -116,8 +34,14 @@ from PyQt5.QtWidgets import QMessageBox
|
|
|
|
|
|
from . import model, view, thread
|
|
|
import hdrCore.image, hdrCore.processing, hdrCore.utils
|
|
|
+import hdrCore.coreC
|
|
|
import preferences.preferences as pref
|
|
|
|
|
|
+# zj add for semi-auto curve
|
|
|
+import torch
|
|
|
+from hdrCore.net import Net
|
|
|
+from torch.autograd import Variable
|
|
|
+
|
|
|
# -----------------------------------------------------------------------------
|
|
|
# --- package methods ---------------------------------------------------------
|
|
|
# -----------------------------------------------------------------------------
|
|
@@ -301,7 +225,9 @@ class ImageGalleryController():
|
|
|
return (nb*nbImagePage), ((nb+1)*nbImagePage)
|
|
|
|
|
|
def getFilenamesOfCurrentPage(self): return self.model.getFilenamesOfCurrentPage()
|
|
|
+
|
|
|
def getProcessPipeById(self,i) : return self.model.getProcessPipeById(i)
|
|
|
+
|
|
|
def getProcessPipes(self): return self.model.processPipes
|
|
|
# -----------------------------------------------------------------------------
|
|
|
# --- Class AppController -----------------------------------------------------
|
|
@@ -316,17 +242,16 @@ class AppController(object):
|
|
|
model
|
|
|
|
|
|
Methods:
|
|
|
- callBackInfo
|
|
|
- callBackSelectDir
|
|
|
- callBackSave
|
|
|
- callBackQuit
|
|
|
- callBackDisplayHDR
|
|
|
- callBackEndDisplay
|
|
|
- callBackCloseDisplayHDR
|
|
|
- callBackCompareRawEditedHDR
|
|
|
- callBackExportHDR
|
|
|
- callBackEndExportHDR
|
|
|
- callBackExportAllHDR
|
|
|
+ callBackSelectDir(self)
|
|
|
+ callBackSave(self)
|
|
|
+ callBackDisplayHDR(self)
|
|
|
+ callBackEndDisplay(self, img)
|
|
|
+ callBackCloseDisplayHDR(self)
|
|
|
+ callBackCompareRawEditedHDR(self)
|
|
|
+ callBackExportHDR(self)
|
|
|
+ callBackEndExportHDR(self, img)
|
|
|
+ callBackExportAllHDR(self)
|
|
|
+ callBackEndAllExportHDR(self, img)
|
|
|
|
|
|
"""
|
|
|
|
|
@@ -339,50 +264,37 @@ class AppController(object):
|
|
|
self.hdrDisplay = HDRviewerController(self)
|
|
|
self.view = view.AppView(self, HDRcontroller = self.hdrDisplay)
|
|
|
self.model = model.AppModel(self)
|
|
|
+
|
|
|
+ self.dirName = None
|
|
|
+ self.imagesName = []
|
|
|
|
|
|
self.view.show()
|
|
|
-
|
|
|
- def callBackPython(self):
|
|
|
- if pref.verbose: print(" [CONTROL] >> AppController.callBackPython()")
|
|
|
- pref.computation = pref.target[0]
|
|
|
-
|
|
|
- def callBackNumba(self):
|
|
|
- if pref.verbose: print(" [CONTROL] >> AppController.callBackNumba()")
|
|
|
- pref.computation = pref.target[1]
|
|
|
-
|
|
|
- def callBackCuda(self):
|
|
|
- if pref.verbose: print(" [CONTROL] >> AppController.callBackCuda()")
|
|
|
- pref.computation = pref.target[2]
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
|
|
|
def callBackSelectDir(self):
|
|
|
+ """Callback of export HDR menu: open file dialog, store image filenames (self.imagesName), set directory to model
|
|
|
+ """
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackSelectDir()")
|
|
|
- if not self.view.assessmentRunning():
|
|
|
- dirName = QFileDialog.getExistingDirectory(None, 'Select Directory', self.model.directory)
|
|
|
- if dirName != "":
|
|
|
- # save current images (metadata)
|
|
|
- self.view.imageGalleryController.save()
|
|
|
- # get images in the selected directory
|
|
|
- self.view.imageGalleryController.setImages(self.model.setDirectory(dirName))
|
|
|
- self.hdrDisplay.displaySplash()
|
|
|
-
|
|
|
- else: self.view.statusBar().showMessage('stop assessment before')
|
|
|
+ dirName = QFileDialog.getExistingDirectory(None, 'Select Directory', self.model.directory)
|
|
|
+ if dirName != "":
|
|
|
+ # save current images (metadata)
|
|
|
+ self.view.imageGalleryController.save()
|
|
|
+ # get images in the selected directory
|
|
|
+ self.imagesName = []; self.imagesName = list(self.model.setDirectory(dirName))
|
|
|
|
|
|
+ self.view.imageGalleryController.setImages(self.imagesName)
|
|
|
+ self.hdrDisplay.displaySplash()
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackSave(self): self.view.imageGalleryController.save()
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackQuit(self):
|
|
|
if pref.verbose: print(" [CB] >> AppController.callBackQuit()")
|
|
|
- if not self.view.assessmentRunning():
|
|
|
- self.view.imageGalleryController.save()
|
|
|
- self.hdrDisplay.close()
|
|
|
- sys.exit()
|
|
|
- else:
|
|
|
- okCancel = okCancelBox('uHDR: WARNING', 'closing now, assessment results will be lost!')
|
|
|
- if okCancel==QMessageBox.Ok:
|
|
|
- self.view.imageGalleryController.save()
|
|
|
- self.hdrDisplay.close()
|
|
|
- sys.exit()
|
|
|
-
|
|
|
+ self.view.imageGalleryController.save()
|
|
|
+ self.hdrDisplay.close()
|
|
|
+ sys.exit()
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackDisplayHDR(self):
|
|
|
+
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackDisplayHDR()")
|
|
|
|
|
|
selectedProcessPipe = self.view.imageGalleryController.model.getSelectedProcessPipe()
|
|
@@ -404,17 +316,16 @@ class AppController(object):
|
|
|
processpipe = copy.deepcopy(selectedProcessPipe)
|
|
|
|
|
|
# set size to display size
|
|
|
- size = self.hdrDisplay.model.displayModel['shape']
|
|
|
+ size = pref.getDisplayShape()
|
|
|
img = img.process(hdrCore.processing.resize(),size=(None, size[1]))
|
|
|
|
|
|
# set image to process-pipe
|
|
|
processpipe.setImage(img)
|
|
|
|
|
|
- # star parallel computation
|
|
|
- nbWidth, nbHeight = 3,3
|
|
|
- thread.pCompute(self.callBackEndDisplay, processpipe,nbWidth,nbHeight, toneMap=False, progress=self.view.statusBar().showMessage)
|
|
|
+ thread.cCompute(self.callBackEndDisplay, processpipe, toneMap=False, progress=self.view.statusBar().showMessage)
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ def callBackEndDisplay(self, img):
|
|
|
|
|
|
- def callBackEndDisplay(self, img, addParams=None):
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackEndDisplay()")
|
|
|
|
|
|
# turn off: autoResize
|
|
@@ -424,16 +335,15 @@ class AppController(object):
|
|
|
|
|
|
# clip, scale
|
|
|
img = img.process(hdrCore.processing.clip())
|
|
|
- img.colorData = img.colorData*hdrCore.utils.HDRdisplay['vesaDisplayHDR1000']['scaling']
|
|
|
+ img.colorData = img.colorData*pref.getDisplayScaling()
|
|
|
|
|
|
colour.write_image(img.colorData,"temp.hdr", method='Imageio') # local copy for display
|
|
|
self.hdrDisplay.displayFile("temp.hdr")
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackCloseDisplayHDR(self):
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackCloseDisplayHDR()")
|
|
|
- if not self.view.assessmentRunning(): self.hdrDisplay.displaySplash()
|
|
|
- else: self.view.statusBar().showMessage('stop assessment before')
|
|
|
-
|
|
|
+ self.hdrDisplay.displaySplash()
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackCompareRawEditedHDR(self):
|
|
|
"""
|
|
|
Callback of compare raw/edited HDR menu
|
|
@@ -443,61 +353,60 @@ class AppController(object):
|
|
|
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackCompareOriginalInputHDR()")
|
|
|
|
|
|
- if not self.view.assessmentRunning():
|
|
|
- # process real size image
|
|
|
- # get selected process pipe
|
|
|
- selectedProcessPipe = self.view.imageGalleryController.model.getSelectedProcessPipe()
|
|
|
-
|
|
|
- if selectedProcessPipe: # check if a process pipe is selected
|
|
|
-
|
|
|
- # read original image
|
|
|
- img = hdrCore.image.Image.read(selectedProcessPipe.originalImage.path+'/'+selectedProcessPipe.originalImage.name)
|
|
|
-
|
|
|
- # resize
|
|
|
- screenY, screenX = self.hdrDisplay.model.displayModel['shape']
|
|
|
- imgY, imgX,_ = img.shape
|
|
|
-
|
|
|
- marginY = int((screenY - imgY/2)/2)
|
|
|
- marginX = int(marginY/4)
|
|
|
- imgXp = int((screenX - 3*marginX)/2)
|
|
|
- img = img.process(hdrCore.processing.resize(),size=(None,imgXp))
|
|
|
- imgY, imgX, _ = img.shape
|
|
|
-
|
|
|
- # original image after resize
|
|
|
- ori = copy.deepcopy(img)
|
|
|
-
|
|
|
- # build process pipe from selected one them compute
|
|
|
- pp = hdrCore.processing.ProcessPipe()
|
|
|
- hdrCore.processing.ProcessPipe.autoResize = False # stop autoResize
|
|
|
- params= []
|
|
|
- for p in selectedProcessPipe.processNodes:
|
|
|
- pp.append(copy.deepcopy(p.process),paramDict=None, name=copy.deepcopy(p.name))
|
|
|
- params.append({p.name:p.params})
|
|
|
- img.metadata.metadata['processpipe'] = params
|
|
|
- pp.setImage(img)
|
|
|
- pp.compute()
|
|
|
- res = pp.getImage(toneMap=False)
|
|
|
- res = res.process(hdrCore.processing.clip())
|
|
|
- imgYres, imgXres, _ = res.colorData.shape
|
|
|
-
|
|
|
- hdrCore.processing.ProcessPipe.autoResize = True # return to autoResize
|
|
|
-
|
|
|
- # make comparison image
|
|
|
- oriColorData = ori.colorData*self.hdrDisplay.model.displayModel['scaling']
|
|
|
- resColorData = res.colorData*self.hdrDisplay.model.displayModel['scaling']
|
|
|
- display = np.ones((screenY,screenX,3))*0.2
|
|
|
- marginY = int((screenY - imgY)/2)
|
|
|
- marginYres = int((screenY - imgYres)/2)
|
|
|
-
|
|
|
- display[marginY:marginY+imgY, marginX:marginX+imgX,:] = oriColorData
|
|
|
- display[marginYres:marginYres+imgYres, 2*marginX+imgX:2*marginX+imgX+imgXres,:] = resColorData
|
|
|
+ # process real size image
|
|
|
+ # get selected process pipe
|
|
|
+ selectedProcessPipe = self.view.imageGalleryController.model.getSelectedProcessPipe()
|
|
|
+
|
|
|
+ if selectedProcessPipe: # check if a process pipe is selected
|
|
|
+
|
|
|
+ # read original image
|
|
|
+ img = hdrCore.image.Image.read(selectedProcessPipe.originalImage.path+'/'+selectedProcessPipe.originalImage.name)
|
|
|
+
|
|
|
+ # resize
|
|
|
+ screenY, screenX = pref.getDisplayShape()
|
|
|
+
|
|
|
+ imgY, imgX,_ = img.shape
|
|
|
+
|
|
|
+ marginY = int((screenY - imgY/2)/2)
|
|
|
+ marginX = int(marginY/4)
|
|
|
+ imgXp = int((screenX - 3*marginX)/2)
|
|
|
+ img = img.process(hdrCore.processing.resize(),size=(None,imgXp))
|
|
|
+ imgY, imgX, _ = img.shape
|
|
|
+
|
|
|
+ # original image after resize
|
|
|
+ ori = copy.deepcopy(img)
|
|
|
+
|
|
|
+ # build process pipe from selected one them compute
|
|
|
+ pp = hdrCore.processing.ProcessPipe()
|
|
|
+ hdrCore.processing.ProcessPipe.autoResize = False # stop autoResize
|
|
|
+ params= []
|
|
|
+ for p in selectedProcessPipe.processNodes:
|
|
|
+ pp.append(copy.deepcopy(p.process),paramDict=None, name=copy.deepcopy(p.name))
|
|
|
+ params.append({p.name:p.params})
|
|
|
+ img.metadata.metadata['processpipe'] = params
|
|
|
+ pp.setImage(img)
|
|
|
+
|
|
|
+ res = hdrCore.coreC.coreCcompute(img, pp)
|
|
|
+ res = res.process(hdrCore.processing.clip())
|
|
|
|
|
|
- # save as compOrigFinal.hdr
|
|
|
- colour.write_image(display,'compOrigFinal.hdr', method='Imageio')
|
|
|
- self.hdrDisplay.displayFile('compOrigFinal.hdr')
|
|
|
- else:
|
|
|
- self.view.statusBar().showMessage('stop assessment before')
|
|
|
+ imgYres, imgXres, _ = res.colorData.shape
|
|
|
+
|
|
|
+ hdrCore.processing.ProcessPipe.autoResize = True # return to autoResize
|
|
|
+
|
|
|
+ # make comparison image
|
|
|
+ oriColorData = ori.colorData*pref.getDisplayScaling()
|
|
|
+ resColorData = res.colorData*pref.getDisplayScaling()
|
|
|
+ display = np.ones((screenY,screenX,3))*0.2
|
|
|
+ marginY = int((screenY - imgY)/2)
|
|
|
+ marginYres = int((screenY - imgYres)/2)
|
|
|
|
|
|
+ display[marginY:marginY+imgY, marginX:marginX+imgX,:] = oriColorData
|
|
|
+ display[marginYres:marginYres+imgYres, 2*marginX+imgX:2*marginX+imgX+imgXres,:] = resColorData
|
|
|
+
|
|
|
+ # save as compOrigFinal.hdr
|
|
|
+ colour.write_image(display,'compOrigFinal.hdr', method='Imageio')
|
|
|
+ self.hdrDisplay.displayFile('compOrigFinal.hdr')
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackExportHDR(self):
|
|
|
"""
|
|
|
Callback of export HDR menu
|
|
@@ -509,12 +418,15 @@ class AppController(object):
|
|
|
|
|
|
selectedProcessPipe = self.view.imageGalleryController.model.getSelectedProcessPipe()
|
|
|
|
|
|
+
|
|
|
if selectedProcessPipe:
|
|
|
# select dir where to save export
|
|
|
self.dirName = QFileDialog.getExistingDirectory(None, 'Select Directory where to export HDR file', self.model.directory)
|
|
|
|
|
|
- self.view.statusBar().showMessage('exporting HDR image (HDR vesa 1000), full size image computation: start, please wait !')
|
|
|
+ # show export message
|
|
|
+ self.view.statusBar().showMessage('exporting HDR image ('+pref.getHDRdisplay()['tag']+'), full size image computation: start, please wait !')
|
|
|
self.view.statusBar().repaint()
|
|
|
+
|
|
|
# save current processpipe metada
|
|
|
originalImage = copy.deepcopy(selectedProcessPipe.originalImage)
|
|
|
originalImage.metadata.metadata['processpipe'] = selectedProcessPipe.toDict()
|
|
@@ -531,43 +443,107 @@ class AppController(object):
|
|
|
# set image to process-pipe
|
|
|
processpipe.setImage(img)
|
|
|
|
|
|
- # star parallel computation
|
|
|
- nbWidth, nbHeight = 3,3
|
|
|
- thread.pCompute(self.callBackEndExportHDR, processpipe,nbWidth,nbHeight, toneMap=False, progress=self.view.statusBar().showMessage, meta=copy.deepcopy(img.metadata) )
|
|
|
-
|
|
|
- def callBackEndExportHDR(self, img, meta):
|
|
|
+ thread.cCompute(self.callBackEndExportHDR, processpipe, toneMap=False, progress=self.view.statusBar().showMessage)
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ def callBackEndExportHDR(self, img):
|
|
|
# turn off: autoResize
|
|
|
hdrCore.processing.ProcessPipe.autoResize = True
|
|
|
|
|
|
- self.view.statusBar().showMessage('exporting HDR image (HDR vesa 1000), full size image computation: done !')
|
|
|
+ self.view.statusBar().showMessage('exporting HDR image ('+pref.getHDRdisplay()['tag']+'), full size image computation: done !')
|
|
|
|
|
|
# clip, scale
|
|
|
img = img.process(hdrCore.processing.clip())
|
|
|
- img.colorData = img.colorData*hdrCore.utils.HDRdisplay['vesaDisplayHDR1000']['scaling']
|
|
|
+ img.colorData = img.colorData*pref.getDisplayScaling()
|
|
|
|
|
|
if self.dirName:
|
|
|
- pathExport = os.path.join(self.dirName, img.name[:-4]+hdrCore.utils.HDRdisplay['vesaDisplayHDR1000']['post']+'.hdr')
|
|
|
+ pathExport = os.path.join(self.dirName, img.name[:-4]+pref.getHDRdisplay()['post']+'.hdr')
|
|
|
img.type = hdrCore.image.imageType.HDR
|
|
|
- img.metadata = meta
|
|
|
img.metadata.metadata['processpipe'] = None
|
|
|
- img.metadata.metadata['display'] =hdrCore.utils.HDRdisplay['vesaDisplayHDR1000']['tag']
|
|
|
+ img.metadata.metadata['display'] = pref.getHDRdisplay()['tag']
|
|
|
|
|
|
img.write(pathExport)
|
|
|
|
|
|
colour.write_image(img.colorData,"temp.hdr", method='Imageio') # local copy for display
|
|
|
self.hdrDisplay.displayFile("temp.hdr")
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def callBackExportAllHDR(self):
|
|
|
if pref.verbose: print(" [CONTROL] >> AppController.callBackExportAllHDR()")
|
|
|
|
|
|
- processPipes = self.view.imageGalleryController.getProcessPipes()
|
|
|
+ self.processPipes = self.view.imageGalleryController.getProcessPipes()
|
|
|
|
|
|
# select dir where to save export
|
|
|
- dirName = QFileDialog.getExistingDirectory(None, 'Select Directory where to export HDR file', self.model.directory)
|
|
|
- self.view.statusBar().showMessage('exporting HDR vesa 1000 images ... please wait')
|
|
|
+ self.dirName = QFileDialog.getExistingDirectory(None, 'Select Directory where to export HDR file', self.model.directory)
|
|
|
+ self.view.statusBar().showMessage('exporting '+str(len(self.processPipes))+' HDR images ... please wait')
|
|
|
self.view.statusBar().repaint()
|
|
|
+ self.imageToExport = len(self.processPipes) ; self.imageExportDone = 0
|
|
|
+
|
|
|
+ pp = self.processPipes[0]
|
|
|
+
|
|
|
+ # save current processpipe metada
|
|
|
+ originalImage = copy.deepcopy(pp.originalImage)
|
|
|
+ originalImage.metadata.metadata['processpipe'] = pp.toDict()
|
|
|
+ originalImage.metadata.save()
|
|
|
+
|
|
|
+ # load full size image
|
|
|
+ img = hdrCore.image.Image.read(originalImage.path+'/'+originalImage.name)
|
|
|
+
|
|
|
+ # turn off: autoResize
|
|
|
+ hdrCore.processing.ProcessPipe.autoResize = False
|
|
|
+ # make a copy of selectedProcessPipe
|
|
|
+ processpipe = copy.deepcopy(pp)
|
|
|
+
|
|
|
+ # set image to process-pipe
|
|
|
+ processpipe.setImage(img)
|
|
|
+
|
|
|
+ thread.cCompute(self.callBackEndAllExportHDR, processpipe, toneMap=False, progress=self.view.statusBar().showMessage)
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ def callBackEndAllExportHDR(self, img):
|
|
|
+ # last image ?
|
|
|
+ self.imageExportDone +=1
|
|
|
+
|
|
|
+ self.view.statusBar().showMessage('exporting HDR images ('+pref.getHDRdisplay()['tag']+'):'+str(int(100*self.imageExportDone/self.imageToExport))+'% done !')
|
|
|
|
|
|
- for pp_i in processPipes: res = pp_i.export(dirName, size=None, to=hdrCore.utils.HDRdisplay['vesaDisplayHDR1000'], progress = None)
|
|
|
+ # clip, scale
|
|
|
+ img = img.process(hdrCore.processing.clip())
|
|
|
+ img.colorData = img.colorData*pref.getDisplayScaling()
|
|
|
+
|
|
|
+ if self.dirName:
|
|
|
+ pathExport = os.path.join(self.dirName, img.name[:-4]+pref.getHDRdisplay()['post']+'.hdr')
|
|
|
+ img.type = hdrCore.image.imageType.HDR
|
|
|
+ img.metadata.metadata['processpipe'] = None
|
|
|
+ img.metadata.metadata['display'] = pref.getHDRdisplay()['tag']
|
|
|
+
|
|
|
+ img.write(pathExport)
|
|
|
+
|
|
|
+ if self.imageExportDone == self.imageToExport :
|
|
|
+ # turn off: autoResize
|
|
|
+ hdrCore.processing.ProcessPipe.autoResize = True
|
|
|
+ else:
|
|
|
+ pp = self.processPipes[self.imageExportDone]
|
|
|
+
|
|
|
+ if not pp:
|
|
|
+ img = hdrCore.image.Image.read(self.imagesName[self.imageExportDone], thumb=True)
|
|
|
+ pp = model.EditImageModel.buildProcessPipe()
|
|
|
+ pp.setImage(img)
|
|
|
+
|
|
|
+
|
|
|
+ # save current processpipe metada
|
|
|
+ originalImage = copy.deepcopy(pp.originalImage)
|
|
|
+ originalImage.metadata.metadata['processpipe'] = pp.toDict()
|
|
|
+ originalImage.metadata.save()
|
|
|
+
|
|
|
+ # load full size image
|
|
|
+ img = hdrCore.image.Image.read(originalImage.path+'/'+originalImage.name)
|
|
|
+
|
|
|
+ # turn off: autoResize
|
|
|
+ hdrCore.processing.ProcessPipe.autoResize = False
|
|
|
+ # make a copy of selectedProcessPipe
|
|
|
+ processpipe = copy.deepcopy(pp)
|
|
|
+
|
|
|
+ # set image to process-pipe
|
|
|
+ processpipe.setImage(img)
|
|
|
+
|
|
|
+ thread.cCompute(self.callBackEndAllExportHDR, processpipe, toneMap=False, progress=self.view.statusBar().showMessage)
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
# --- class MultiDockController() ----------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
@@ -578,25 +554,20 @@ class MultiDockController():
|
|
|
self.parent = parent
|
|
|
self.view = view.MultiDockView(self, HDRcontroller)
|
|
|
self.model = None
|
|
|
-
|
|
|
-
|
|
|
+ # ---------------------------------------------------------------------------------------
|
|
|
def activateEDIT(self): self.switch(0)
|
|
|
def activateINFO(self): self.switch(1)
|
|
|
- def activateIQA(self): self.switch(2)
|
|
|
-
|
|
|
+ def activateMIAM(self): self.switch(2)
|
|
|
+ # ---------------------------------------------------------------------------------------
|
|
|
def switch(self,nb):
|
|
|
if pref.verbose: print(" [CONTROL] >> MultiDockController.switch()")
|
|
|
-
|
|
|
- if not self.assessmentRunning(): self.view.switch(nb)
|
|
|
- else: self.parent.statusBar().showMessage('stop assessment before switching dock')
|
|
|
-
|
|
|
+ self.view.switch(nb)
|
|
|
+ # --------------------------------------------------------------------------------------
|
|
|
def setProcessPipe(self, processPipe):
|
|
|
if pref.verbose: print(" [CONTROL] >> MultiDockController.setProcessPipe(",processPipe.getImage().name,")")
|
|
|
|
|
|
return self.view.setProcessPipe(processPipe)
|
|
|
-
|
|
|
- def assessmentRunning(self):
|
|
|
- return self.view.childControllers[2].assessmentRunning()
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
class EditImageController:
|
|
@@ -611,7 +582,7 @@ class EditImageController:
|
|
|
|
|
|
self.view = view.EditImageView(self)
|
|
|
self.model = model.EditImageModel(self)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def setProcessPipe(self, processPipe):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.setProcessPipe(",")")
|
|
|
|
|
@@ -629,14 +600,16 @@ class EditImageController:
|
|
|
return True
|
|
|
else:
|
|
|
return False
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ def getProcessPipe(self) : return self.model.getProcessPipe()
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def buildView(self,processPipe=None):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.buildView(",")")
|
|
|
|
|
|
""" called when MultiDockController recall a controller/view """
|
|
|
self.view = view.EditImageView(self, build=True)
|
|
|
if processPipe: self.setProcessPipe(processPipe)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def autoExposure(self):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.autoExposure(",")")
|
|
|
if self.model.processpipe:
|
|
@@ -649,35 +622,35 @@ class EditImageController:
|
|
|
|
|
|
qPixmap = self.view.setImage(img)
|
|
|
self.parent.controller.parent.controller.view.imageGalleryController.setProcessPipeWidgetQPixmap(qPixmap)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeExposure(self,value):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeExposure(",value,")")
|
|
|
if self.model.processpipe: self.model.changeExposure(value)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeContrast(self,value):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeContrast(",value,")")
|
|
|
if self.model.processpipe: self.model.changeContrast(value)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeToneCurve(self,controlPoints):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeToneCurve("")")
|
|
|
if self.model.processpipe: self.model.changeToneCurve(controlPoints)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeLightnessMask(self, maskValues):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeLightnessMask(",maskValues,")")
|
|
|
if self.model.processpipe: self.model.changeLightnessMask(maskValues)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeSaturation(self,value):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeSaturation(",value,")")
|
|
|
if self.model.processpipe: self.model.changeSaturation(value)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeColorEditor(self,values, idName):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeColorEditor(",values,")")
|
|
|
if self.model.processpipe: self.model.changeColorEditor(values, idName)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def changeGeometry(self,values):
|
|
|
if pref.verbose: print(" [CONTROL] >> EditImageController.changeGeometry(",values,")")
|
|
|
if self.model.processpipe: self.model.changeGeometry(values)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def updateImage(self,imgTM):
|
|
|
"""
|
|
|
updateImage: called when process-pipe computation is done
|
|
@@ -689,9 +662,14 @@ class EditImageController:
|
|
|
self.parent.controller.parent.controller.view.imageGalleryController.setProcessPipeWidgetQPixmap(qPixmap)
|
|
|
self.view.plotToneCurve()
|
|
|
|
|
|
+ # if aesthetics model > notify required update
|
|
|
+
|
|
|
+
|
|
|
if self.previewHDR and self.model.autoPreviewHDR:
|
|
|
self.controllerHDR.callBackUpdate()
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
class ImageInfoController:
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
@@ -702,133 +680,25 @@ class ImageInfoController:
|
|
|
self.model = model.ImageInfoModel(self)
|
|
|
|
|
|
self.callBackActive = True
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def setProcessPipe(self, processPipe):
|
|
|
if pref.verbose: print(" [CONTROL] >> ImageInfoController.setProcessPipe(",processPipe.getImage().name,")")
|
|
|
self.model.setProcessPipe(processPipe)
|
|
|
- #### self.view.setImage(processPipe.getImage())
|
|
|
self.view.setProcessPipe(processPipe)
|
|
|
return True
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def buildView(self,processPipe=None):
|
|
|
if pref.verbose: print(" [CONTROL] >> ImageInfoController.buildView()")
|
|
|
|
|
|
""" called when MultiDockController recall a controller/view """
|
|
|
self.view = view.ImageInfoView(self)
|
|
|
if processPipe: self.setProcessPipe(processPipe)
|
|
|
-
|
|
|
- def useCaseChange(self,useCaseClass,useCase, on_off):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageInfoController.useCaseChange(",useCaseClass,",", useCase,",", on_off,")")
|
|
|
- self.model.changeUseCase(useCaseClass,useCase, on_off)
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ def metadataChange(self,metaGroup,metaTag, on_off):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> ImageInfoController.useCaseChange(",metaGroup,",", metaTag,",", on_off,")")
|
|
|
+ self.model.changeMeta(metaGroup,metaTag, on_off)
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
-class ImageQualityController:
|
|
|
- def __init__(self, parent=None, HDRcontroller = None):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.__init__()")
|
|
|
-
|
|
|
- self.parent = parent
|
|
|
- self.model = model.ImageQualityModel(self)
|
|
|
- self.view = view.ImageQualityView(self)
|
|
|
-
|
|
|
- self.HDRcontroller = HDRcontroller
|
|
|
-
|
|
|
- self.running = False
|
|
|
- self.callBackActive = True
|
|
|
-
|
|
|
- def assessmentRunning(self): return self.running
|
|
|
-
|
|
|
- def setProcessPipe(self, processPipe):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.setProcessPipe(",processPipe.getImage().name,")")
|
|
|
-
|
|
|
- pass
|
|
|
-
|
|
|
- def buildView(self,processPipe=None):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.buildView()")
|
|
|
- self.view = view.ImageQualityView(self)
|
|
|
- if processPipe: self.setProcessPipe(processPipe)
|
|
|
-
|
|
|
- def startStop(self):
|
|
|
-
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.startStop(",")")
|
|
|
- self.running = not self.running
|
|
|
-
|
|
|
- if self.running:
|
|
|
-
|
|
|
- if not self.model.userName:
|
|
|
- messageBox("uHDR: WARNING", "you must enter your name/pseudo!")
|
|
|
- self.running = False
|
|
|
-
|
|
|
- else:
|
|
|
-
|
|
|
- # start assessment: create vesaDisplayHDR1000 export images
|
|
|
- imgGalController = self.parent.controller.parent.imageGalleryController
|
|
|
- status = self.parent.controller.parent.statusBar()
|
|
|
- processPipes = imgGalController.getProcessPipes()
|
|
|
-
|
|
|
- if len(processPipes)==0:
|
|
|
- messageBox("uHDR: WARNING", "you must select the directory with images to assess!")
|
|
|
- self.running = False
|
|
|
-
|
|
|
- else:
|
|
|
-
|
|
|
- localCopies = []
|
|
|
-
|
|
|
- status.showMessage("exporting HDR images")
|
|
|
- status.repaint()
|
|
|
-
|
|
|
- for i,pp_i in enumerate(processPipes):
|
|
|
-
|
|
|
- res = pp_i.export(None, size=None, to=hdrCore.utils.HDRdisplay['vesaDisplayHDR1000'], progress = None)
|
|
|
- destFile = "temp_"+str(i)+".hdr"
|
|
|
- colour.write_image(res.colorData,destFile, method='Imageio') # local copy for display
|
|
|
- localCopies.append(destFile)
|
|
|
-
|
|
|
- # start assessment
|
|
|
- self.model.processPipes = processPipes #
|
|
|
- self.model.setImages(localCopies) # send data to model
|
|
|
- self.model.start()
|
|
|
- self.model.next() # start
|
|
|
- else:
|
|
|
- # stop assessment: save score, remove local copies
|
|
|
- self.model.save()
|
|
|
- self.model.resetImages()
|
|
|
- for localFile in self.model.localImageNames: os.remove(localFile)
|
|
|
-
|
|
|
- def next(self):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.next(",")")
|
|
|
- if self.assessmentRunning():
|
|
|
- q = self.model.next()
|
|
|
- self.setValues(q)
|
|
|
-
|
|
|
- def previous(self):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.previous(",")")
|
|
|
- if self.assessmentRunning():
|
|
|
- q = self.model.previous()
|
|
|
- self.setValues(q)
|
|
|
-
|
|
|
- def pseudo(self, name):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.pseudo(",name,")")
|
|
|
-
|
|
|
- if self.callBackActive:
|
|
|
- self.model.setPseudo(name)
|
|
|
-
|
|
|
- def score(self, label, value):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.score(",label,",", value,")")
|
|
|
-
|
|
|
- if self.callBackActive:
|
|
|
- self.model.setScore(label,value)
|
|
|
-
|
|
|
- def artifact(self, label, value):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.artifact(",label,",", value,")")
|
|
|
-
|
|
|
- if self.callBackActive:
|
|
|
- self.model.setArtifact(label,value)
|
|
|
-
|
|
|
- def setValues(self,q):
|
|
|
- if pref.verbose: print(" [CONTROL] >> ImageQualityController.setValues(",q,")")
|
|
|
-
|
|
|
- self.callBackActive = False
|
|
|
- self.view.setValues(q)
|
|
|
- self.callBackActive = True
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
class AdvanceSliderController():
|
|
|
def __init__(self, parent,name, defaultValue, range, step,callBackValueChange=None,callBackAutoPush= None):
|
|
@@ -845,7 +715,7 @@ class AdvanceSliderController():
|
|
|
self.callBackActive = True
|
|
|
self.callBackValueChange = callBackValueChange
|
|
|
self.callBackAutoPush = callBackAutoPush
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def sliderChange(self):
|
|
|
|
|
|
value = self.view.slider.value()*self.step
|
|
@@ -855,29 +725,31 @@ class AdvanceSliderController():
|
|
|
self.model.value = value
|
|
|
self.view.editValue.setText(str(value))
|
|
|
if self.callBackActive and self.callBackValueChange: self.callBackValueChange(value)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def setValue(self, value, callBackActive = True):
|
|
|
if pref.verbose: print(" [CONTROL] >> AdvanceSliderController.setValue(",value,") ")
|
|
|
|
|
|
""" set value value in 'model' range"""
|
|
|
self.callBackActive = callBackActive
|
|
|
- self.view.slider.setValue(value/self.step)
|
|
|
+ self.view.slider.setValue(int(value/self.step))
|
|
|
self.view.editValue.setText(str(value))
|
|
|
- self.model.setValue(value)
|
|
|
+ self.model.setValue(int(value))
|
|
|
|
|
|
self.callBackActive = True
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def reset(self):
|
|
|
if pref.verbose : print(" [CB] >> AdvanceSliderController.reset(",") ")
|
|
|
|
|
|
self.setValue(self.defaultValue,callBackActive = False)
|
|
|
if self.callBackValueChange: self.callBackValueChange(self.defaultValue)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def auto(self):
|
|
|
if pref.verbose: print(" [CB] >> AdvanceSliderController.auto(",") ")
|
|
|
|
|
|
if self.callBackAutoPush: self.callBackAutoPush()
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
+# --- class AdvanceSliderController --------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
class ToneCurveController():
|
|
|
def __init__(self, parent):
|
|
|
|
|
@@ -889,8 +761,14 @@ class ToneCurveController():
|
|
|
# tone curve display control
|
|
|
self.showInput =False
|
|
|
self.showbefore = False
|
|
|
- self.showAfter = True
|
|
|
-
|
|
|
+ self.showAfter = False
|
|
|
+ self.showOutput = True
|
|
|
+
|
|
|
+ # zj add semi-auto curve
|
|
|
+ # machine learning network and weight file
|
|
|
+ self.weightFile = 'MSESig505_0419.pth'
|
|
|
+ self.networkModel = None
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def sliderChange(self, key, value):
|
|
|
if pref.verbose: print(" [CB] >> ToneCurveController.sliderChange(",key,",",value,")[callBackActive:",self.callBackActive,"] ")
|
|
|
|
|
@@ -902,23 +780,23 @@ class ToneCurveController():
|
|
|
|
|
|
self.callBackActive = False
|
|
|
|
|
|
- self.view.sliderShadows.setValue(newValues["shadows"][1])
|
|
|
+ self.view.sliderShadows.setValue(int(newValues["shadows"][1]))
|
|
|
self.view.editShadows.setText(str(newValues["shadows"][1]))
|
|
|
|
|
|
- self.view.sliderBlacks.setValue(newValues["blacks"][1])
|
|
|
+ self.view.sliderBlacks.setValue(int(newValues["blacks"][1]))
|
|
|
self.view.editBlacks.setText(str(newValues["blacks"][1]))
|
|
|
|
|
|
- self.view.sliderMediums.setValue(newValues["mediums"][1])
|
|
|
+ self.view.sliderMediums.setValue(int(newValues["mediums"][1]))
|
|
|
self.view.editMediums.setText(str(newValues["mediums"][1]))
|
|
|
|
|
|
- self.view.sliderWhites.setValue(newValues["whites"][1])
|
|
|
+ self.view.sliderWhites.setValue(int(newValues["whites"][1]))
|
|
|
self.view.editWhites.setText(str(newValues["whites"][1]))
|
|
|
|
|
|
- self.view.sliderHighlights.setValue(newValues["highlights"][1])
|
|
|
+ self.view.sliderHighlights.setValue(int(newValues["highlights"][1]))
|
|
|
self.view.editHighlights.setText(str(newValues["highlights"][1]))
|
|
|
|
|
|
self.callBackActive = True
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def setValues(self, valuesDict,callBackActive = False):
|
|
|
if pref.verbose: print(" [CONTROL] >> ToneCurveController.setValue(",valuesDict,") ")
|
|
|
|
|
@@ -927,23 +805,58 @@ class ToneCurveController():
|
|
|
self.model.setValues(valuesDict)
|
|
|
points = self.model.evaluate()
|
|
|
|
|
|
- self.view.sliderShadows.setValue(valuesDict["shadows"][1])
|
|
|
+ self.view.sliderShadows.setValue(int(valuesDict["shadows"][1]))
|
|
|
self.view.editShadows.setText(str(valuesDict["shadows"][1]))
|
|
|
|
|
|
- self.view.sliderBlacks.setValue(valuesDict["blacks"][1])
|
|
|
+ self.view.sliderBlacks.setValue(int(valuesDict["blacks"][1]))
|
|
|
self.view.editBlacks.setText(str(valuesDict["blacks"][1]))
|
|
|
|
|
|
- self.view.sliderMediums.setValue(valuesDict["mediums"][1])
|
|
|
+ self.view.sliderMediums.setValue(int(valuesDict["mediums"][1]))
|
|
|
self.view.editMediums.setText(str(valuesDict["mediums"][1]))
|
|
|
|
|
|
- self.view.sliderWhites.setValue(valuesDict["whites"][1])
|
|
|
+ self.view.sliderWhites.setValue(int(valuesDict["whites"][1]))
|
|
|
self.view.editWhites.setText(str(valuesDict["whites"][1]))
|
|
|
|
|
|
- self.view.sliderHighlights.setValue(valuesDict["highlights"][1])
|
|
|
+ self.view.sliderHighlights.setValue(int(valuesDict["highlights"][1]))
|
|
|
self.view.editHighlights.setText(str(valuesDict["highlights"][1]))
|
|
|
|
|
|
self.callBackActive = True
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
+ # zj add for semi-auto curve begin
|
|
|
+ def autoCurve(self):
|
|
|
+ processPipe = self.parent.controller.model.getProcessPipe()
|
|
|
+ if processPipe != None :
|
|
|
+ idExposure = processPipe.getProcessNodeByName("tonecurve")
|
|
|
+ bins = np.linspace(0,1,50+1)
|
|
|
+
|
|
|
+ imageBeforeColorData = processPipe.processNodes[idExposure-1].outputImage.colorData
|
|
|
+ imageBeforeColorData[imageBeforeColorData>1]=1
|
|
|
+ imageBeforeY = colour.sRGB_to_XYZ(imageBeforeColorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
+ nphistBefore = np.histogram(imageBeforeY, bins)[0]
|
|
|
+ nphistBefore = nphistBefore/np.amax(nphistBefore)
|
|
|
|
|
|
+ npImgHistCumuNorm = np.empty_like(nphistBefore)
|
|
|
+ npImgHistCumu = np.cumsum(nphistBefore)
|
|
|
+ npImgHistCumuNorm = npImgHistCumu/np.max(npImgHistCumu)
|
|
|
+
|
|
|
+ #predict keypoint value
|
|
|
+ if self.networkModel == None:
|
|
|
+ self.networkModel = Net(50,5)
|
|
|
+ self.networkModel.load_state_dict(torch.load(self.weightFile))
|
|
|
+ self.networkModel.eval()
|
|
|
+
|
|
|
+ with torch.no_grad():
|
|
|
+ x = Variable(torch.FloatTensor([npImgHistCumuNorm.tolist(),]), requires_grad=True)
|
|
|
+ y_predict = self.networkModel(x)
|
|
|
+
|
|
|
+ kpc = (y_predict[0]*100).tolist()
|
|
|
+ kpcDict = {'start':[0.0,0.0], 'shadows': [10.0,kpc[0]], 'blacks': [30.0,kpc[1]], 'mediums': [50.0,kpc[2]], 'whites': [70.0,kpc[3]], 'highlights': [90.0,kpc[4]], 'end': [100.0,100.0]}
|
|
|
+ self.setValues(kpcDict,callBackActive = True)
|
|
|
+ self.parent.controller.changeToneCurve(kpcDict)
|
|
|
+
|
|
|
+ # zj add for semi-auto curve end
|
|
|
+
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def reset(self, key):
|
|
|
if pref.verbose: print(" [CONTROL] >> ToneCurveController.reset(",key,") ")
|
|
|
|
|
@@ -952,50 +865,64 @@ class ToneCurveController():
|
|
|
self.setValues(controls,callBackActive = False)
|
|
|
|
|
|
self.parent.controller.changeToneCurve(controls)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def plotCurve(self):
|
|
|
- self.view.curve.plot([0,100],[0,100],'r--', clear=True)
|
|
|
- self.view.curve.plot([20,20],[0,100],'r--', clear=False)
|
|
|
- self.view.curve.plot([40,40],[0,100],'r--', clear=False)
|
|
|
- self.view.curve.plot([60,60],[0,100],'r--', clear=False)
|
|
|
- self.view.curve.plot([80,80],[0,100],'r--', clear=False)
|
|
|
-
|
|
|
- processPipe = self.parent.controller.model.getProcessPipe()
|
|
|
- idExposure = processPipe.getProcessNodeByName("tonecurve")
|
|
|
-
|
|
|
- bins = np.linspace(0,1,50+1)
|
|
|
-
|
|
|
- if self.showInput:
|
|
|
- imageInput = copy.deepcopy(processPipe.getInputImage())
|
|
|
- if imageInput.linear: imageInputColorData =colour.cctf_encoding(imageInput.colorData, function='sRGB')
|
|
|
- else: imageInputColorData = imageInput.colorData
|
|
|
- imageInputColorData[imageInputColorData>1]=1
|
|
|
- imageInputY = colour.sRGB_to_XYZ(imageInputColorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
- nphistInput = np.histogram(imageInputY, bins)[0]
|
|
|
- nphistInput = nphistInput/np.amax(nphistInput)
|
|
|
- self.view.curve.plot(bins[:-1]*100,nphistInput*100,'k--', clear=False)
|
|
|
-
|
|
|
- if self.showbefore:
|
|
|
- imageBeforeColorData = processPipe.processNodes[idExposure-1].outputImage.colorData
|
|
|
- imageBeforeColorData[imageBeforeColorData>1]=1
|
|
|
- imageBeforeY = colour.sRGB_to_XYZ(imageBeforeColorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
- nphistBefore = np.histogram(imageBeforeY, bins)[0]
|
|
|
- nphistBefore = nphistBefore/np.amax(nphistBefore)
|
|
|
- self.view.curve.plot(bins[:-1]*100,nphistBefore*100,'b--', clear=False)
|
|
|
-
|
|
|
- if self.showAfter:
|
|
|
- imageAftercolorData = processPipe.processNodes[idExposure].outputImage.colorData
|
|
|
- imageAftercolorData[imageAftercolorData>1]=1
|
|
|
- imageAfterY = colour.sRGB_to_XYZ(imageAftercolorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
- nphistAfter = np.histogram(imageAfterY, bins)[0]
|
|
|
- nphistAfter =nphistAfter/np.amax(nphistAfter)
|
|
|
- self.view.curve.plot(bins[:-1]*100,nphistAfter*100,'b', clear=False)
|
|
|
-
|
|
|
- controlPointCoordinates= np.asarray(list(self.model.control.values()))
|
|
|
- self.view.curve.plot(controlPointCoordinates[1:-1,0],controlPointCoordinates[1:-1,1],'ro', clear=False)
|
|
|
- points = np.asarray(self.model.curve.evalpts)
|
|
|
- x = points[:,0]
|
|
|
- self.view.curve.plot(points[x<100,0],points[x<100,1],'r',clear=False)
|
|
|
+ try:
|
|
|
+ self.view.curve.plot([0,100],[0,100],'r--', clear=True)
|
|
|
+ self.view.curve.plot([20,20],[0,100],'r--', clear=False)
|
|
|
+ self.view.curve.plot([40,40],[0,100],'r--', clear=False)
|
|
|
+ self.view.curve.plot([60,60],[0,100],'r--', clear=False)
|
|
|
+ self.view.curve.plot([80,80],[0,100],'r--', clear=False)
|
|
|
+
|
|
|
+ processPipe = self.parent.controller.model.getProcessPipe()
|
|
|
+ idExposure = processPipe.getProcessNodeByName("tonecurve")
|
|
|
+
|
|
|
+ bins = np.linspace(0,1,50+1)
|
|
|
+
|
|
|
+ if self.showInput:
|
|
|
+ imageInput = copy.deepcopy(processPipe.getInputImage())
|
|
|
+ if imageInput.linear: imageInputColorData =colour.cctf_encoding(imageInput.colorData, function='sRGB')
|
|
|
+ else: imageInputColorData = imageInput.colorData
|
|
|
+ imageInputColorData[imageInputColorData>1]=1
|
|
|
+ imageInputY = colour.sRGB_to_XYZ(imageInputColorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
+ nphistInput = np.histogram(imageInputY, bins)[0]
|
|
|
+ nphistInput = nphistInput/np.amax(nphistInput)
|
|
|
+ self.view.curve.plot(bins[:-1]*100,nphistInput*100,'k--', clear=False)
|
|
|
+
|
|
|
+ if self.showbefore:
|
|
|
+ imageBeforeColorData = processPipe.processNodes[idExposure-1].outputImage.colorData
|
|
|
+ imageBeforeColorData[imageBeforeColorData>1]=1
|
|
|
+ imageBeforeY = colour.sRGB_to_XYZ(imageBeforeColorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
+ nphistBefore = np.histogram(imageBeforeY, bins)[0]
|
|
|
+ nphistBefore = nphistBefore/np.amax(nphistBefore)
|
|
|
+ self.view.curve.plot(bins[:-1]*100,nphistBefore*100,'b--', clear=False)
|
|
|
+
|
|
|
+ if self.showAfter:
|
|
|
+ imageAftercolorData = processPipe.processNodes[idExposure].outputImage.colorData
|
|
|
+ imageAftercolorData[imageAftercolorData>1]=1
|
|
|
+ imageAfterY = colour.sRGB_to_XYZ(imageAftercolorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
+ nphistAfter = np.histogram(imageAfterY, bins)[0]
|
|
|
+ nphistAfter =nphistAfter/np.amax(nphistAfter)
|
|
|
+ self.view.curve.plot(bins[:-1]*100,nphistAfter*100,'b', clear=False)
|
|
|
+
|
|
|
+ if self.showOutput:
|
|
|
+ imageAftercolorData = processPipe.getImage(toneMap=True).colorData
|
|
|
+ imageAftercolorData[imageAftercolorData>1]=1
|
|
|
+ imageAfterY = colour.sRGB_to_XYZ(imageAftercolorData, apply_cctf_decoding=False)[:,:,1]
|
|
|
+ nphistAfter = np.histogram(imageAfterY, bins)[0]
|
|
|
+ nphistAfter =nphistAfter/np.amax(nphistAfter)
|
|
|
+ self.view.curve.plot(bins[:-1]*100,nphistAfter*100,'b', clear=False)
|
|
|
+
|
|
|
+ controlPointCoordinates= np.asarray(list(self.model.control.values()))
|
|
|
+ self.view.curve.plot(controlPointCoordinates[1:-1,0],controlPointCoordinates[1:-1,1],'ro', clear=False)
|
|
|
+ points = np.asarray(self.model.curve.evalpts)
|
|
|
+ x = points[:,0]
|
|
|
+ self.view.curve.plot(points[x<100,0],points[x<100,1],'r',clear=False)
|
|
|
+ except:
|
|
|
+ time.sleep(0.5)
|
|
|
+ self.plotCurve()
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
class LightnessMaskController():
|
|
|
def __init__(self, parent):
|
|
@@ -1006,13 +933,13 @@ class LightnessMaskController():
|
|
|
self.view = view.LightnessMaskView(self)
|
|
|
|
|
|
self.callBackActive = True
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def maskChange(self,key, on_off):
|
|
|
if pref.verbose: print(" [CB] >> MaskLightnessController.maskChange(",key,",",on_off,")[callBackActive:",self.callBackActive,"] ")
|
|
|
|
|
|
maskState = self.model.maskChange(key, on_off)
|
|
|
self.parent.controller.changeLightnessMask(maskState)
|
|
|
-
|
|
|
+ # -----------------------------------------------------------------------------
|
|
|
def setValues(self, values,callBackActive = False):
|
|
|
if pref.verbose: print(" [CONTROL] >> LightnessMaskController.setValue(",values,") ")
|
|
|
|
|
@@ -1028,6 +955,8 @@ class LightnessMaskController():
|
|
|
|
|
|
self.callBackActive = True
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
class HDRviewerController():
|
|
|
def __init__(self, parent):
|
|
|
if pref.verbose: print(" [CONTROL] >> HDRviewerController.__init__(",")")
|
|
@@ -1132,6 +1061,8 @@ class HDRviewerController():
|
|
|
subprocess.run(['taskkill', '/F', '/T', '/IM', "HDRImageViewer*"],capture_output=False)
|
|
|
self.viewerProcess = None
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
+# ---- Class LchColorSelectorController ----------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
class LchColorSelectorController:
|
|
|
def __init__(self, parent, idName = None):
|
|
|
if pref.verbose: print(" [CONTROL] >> LchColorSelectorController.__init__(",") ")
|
|
@@ -1181,8 +1112,8 @@ class LchColorSelectorController:
|
|
|
self.callBackActive = callBackActive
|
|
|
# slider hue selection
|
|
|
v = values['selection']['hue'] if 'hue' in values['selection'].keys() else (0,360)
|
|
|
- self.view.sliderHueMin.setValue(v[0])
|
|
|
- self.view.sliderHueMax.setValue(v[1])
|
|
|
+ self.view.sliderHueMin.setValue(int(v[0]))
|
|
|
+ self.view.sliderHueMax.setValue(int(v[1]))
|
|
|
|
|
|
# slider chroma selection
|
|
|
v = values['selection']['chroma'] if 'chroma' in values['selection'].keys() else (0,100)
|
|
@@ -1191,39 +1122,64 @@ class LchColorSelectorController:
|
|
|
|
|
|
# slider lightness
|
|
|
v = values['selection']['lightness'] if 'lightness' in values['selection'].keys() else (0,100)
|
|
|
- self.view.sliderLightMin.setValue(v[0]*3)
|
|
|
- self.view.sliderLightMax.setValue(v[1]*3)
|
|
|
+ self.view.sliderLightMin.setValue(int(v[0]*3))
|
|
|
+ self.view.sliderLightMax.setValue(int(v[1]*3))
|
|
|
|
|
|
# hue shift editor
|
|
|
v = values['edit']['hue'] if 'hue' in values['edit'].keys() else 0
|
|
|
- self.view.sliderHueShift.setValue(v)
|
|
|
+ self.view.sliderHueShift.setValue(int(v))
|
|
|
self.view.valueHueShift.setText(str(v))
|
|
|
|
|
|
# exposure editor
|
|
|
- v = values['edit']['exposure'] if 'exposure' in values['edit'].keys() else 0
|
|
|
- self.view.sliderExposure.setValue(v*30)
|
|
|
+ v : int = values['edit']['exposure'] if 'exposure' in values['edit'].keys() else 0
|
|
|
+ self.view.sliderExposure.setValue(int(v*30))
|
|
|
self.view.valueExposure.setText(str(v))
|
|
|
|
|
|
# contrast editor
|
|
|
- v = values['edit']['contrast'] if 'contrast' in values['edit'].keys() else 0
|
|
|
- self.view.sliderContrast.setValue(v)
|
|
|
+ v : int = values['edit']['contrast'] if 'contrast' in values['edit'].keys() else 0
|
|
|
+ self.view.sliderContrast.setValue(int(v))
|
|
|
self.view.valueContrast.setText(str(v))
|
|
|
|
|
|
# saturation editor
|
|
|
- v = values['edit']['saturation'] if 'saturation' in values['edit'].keys() else 0
|
|
|
- self.view.sliderSaturation.setValue(v)
|
|
|
+ v : int = values['edit']['saturation'] if 'saturation' in values['edit'].keys() else 0
|
|
|
+ self.view.sliderSaturation.setValue(int(v))
|
|
|
self.view.valueSaturation.setText(str(v))
|
|
|
|
|
|
# mask
|
|
|
- v = values['mask'] if 'mask' in values.keys() else False
|
|
|
+ v : bool = values['mask'] if 'mask' in values.keys() else False
|
|
|
self.view.checkboxMask.setChecked(values['mask'])
|
|
|
|
|
|
self.model.setValues(values)
|
|
|
|
|
|
self.callBackActive = True
|
|
|
+
|
|
|
+ # -----
|
|
|
+ def resetSelection(self):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> LchColorSelectorController.resetSelection(",") ")
|
|
|
+
|
|
|
+ default = copy.deepcopy(self.model.default)
|
|
|
+ current = copy.deepcopy(self.model.getValues())
|
|
|
+
|
|
|
+ current['selection'] = default['selection']
|
|
|
+
|
|
|
+ self.setValues(current,callBackActive = True)
|
|
|
+ self.callBackActive = True
|
|
|
+
|
|
|
+ def resetEdit(self):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> LchColorSelectorController.resetEdit(",") ")
|
|
|
+
|
|
|
+ default = copy.deepcopy(self.model.default)
|
|
|
+ current = copy.deepcopy(self.model.getValues())
|
|
|
+
|
|
|
+ current['edit'] = default['edit']
|
|
|
+
|
|
|
+ self.setValues(current,callBackActive = True)
|
|
|
+ self.callBackActive = True
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+# ---- Class LchColorSelectorController ----------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
class GeometryController:
|
|
|
- def __init__(self, parent, ):
|
|
|
+ def __init__(self, parent ):
|
|
|
if pref.verbose: print(" [CONTROL] >> GeometryController.__init__(",") ")
|
|
|
self.parent = parent
|
|
|
self.model = model.GeometryModel(self)
|
|
@@ -1247,19 +1203,42 @@ class GeometryController:
|
|
|
|
|
|
self.callBackActive = callBackActive
|
|
|
|
|
|
- self.view.sliderCroppingVerticalAdjustement.setValue(up)
|
|
|
- self.view.sliderRotation.setValue(rotation*6)
|
|
|
+ self.view.sliderCroppingVerticalAdjustement.setValue(int(up))
|
|
|
+ self.view.sliderRotation.setValue(int(rotation*6))
|
|
|
|
|
|
self.model.setValues(values)
|
|
|
|
|
|
self.callBackActive = True
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+# ---- Class AestheticsImageController -----------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+class ImageAestheticsController:
|
|
|
+ def __init__(self, parent=None, HDRcontroller = None):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> AestheticsImageController.__init__(",")")
|
|
|
+
|
|
|
+ self.parent = parent
|
|
|
+ self.model = model.ImageAestheticsModel(self)
|
|
|
+ self.view = view.ImageAestheticsView(self)
|
|
|
+ # --------------------------------------------------------------------------------------
|
|
|
+ def buildView(self,processPipe=None):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> AestheticsImageController.buildView()")
|
|
|
+
|
|
|
+ # called when MultiDockController recall a controller/view
|
|
|
+ self.view = view.ImageAestheticsView(self)
|
|
|
+ if processPipe: self.setProcessPipe(processPipe)
|
|
|
+ # --------------------------------------------------------------------------------------
|
|
|
+ def setProcessPipe(self, processPipe):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> AestheticsImageController.setProcessPipe()")
|
|
|
|
|
|
+ self.model.setProcessPipe(processPipe)
|
|
|
+ self.view.setProcessPipe(processPipe, self.model.getPaletteImage())
|
|
|
+
|
|
|
+ return True
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
-# message widget functions
|
|
|
+# --- message widget functions -------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
-
|
|
|
def messageBox(title, text):
|
|
|
msg = QMessageBox()
|
|
|
msg.setText(text)
|
|
@@ -1268,6 +1247,7 @@ def messageBox(title, text):
|
|
|
msg.setStandardButtons(QMessageBox.Ok)
|
|
|
msg.setEscapeButton(QMessageBox.Close)
|
|
|
msg.exec_()
|
|
|
+# -----------------------------------------------------------------------------
|
|
|
def okCancelBox(title, text):
|
|
|
msg = QMessageBox()
|
|
|
msg.setText(text)
|
|
@@ -1276,4 +1256,26 @@ def okCancelBox(title, text):
|
|
|
msg.setEscapeButton(QMessageBox.Close)
|
|
|
return msg.exec_()
|
|
|
# ------------------------------------------------------------------------------------------
|
|
|
+# ---- Class ColorEditorsAutoController ----------------------------------------------------
|
|
|
+# ------------------------------------------------------------------------------------------
|
|
|
+class ColorEditorsAutoController:
|
|
|
+ def __init__(self, parent, controlledColorEditors, stepName ):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> ColorEditorsAutoController.__init__(",") ")
|
|
|
+
|
|
|
+ self.parent = parent
|
|
|
+ self.controlled = controlledColorEditors
|
|
|
+ self.stepName =stepName
|
|
|
+
|
|
|
+ self.model = model.ColorEditorsAutoModel(self, stepName,len(controlledColorEditors), removeBlack= True)
|
|
|
+ self.view = view.ColorEditorsAutoView(self)
|
|
|
+
|
|
|
+ self.callBackActive = True
|
|
|
+ # callbacks
|
|
|
+ def auto(self):
|
|
|
+ if pref.verbose: print(" [CONTROL] >> ColorEditorsAutoController.auto(",") ")
|
|
|
+ for ce in self.controlled: ce.resetSelection(); ce.resetEdit()
|
|
|
+ values = self.model.compute()
|
|
|
+
|
|
|
+ if values != None:
|
|
|
+ for i,v in enumerate(values): self.controlled[i].setValues(v, callBackActive = False)
|
|
|
|