208 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			208 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								import bpy, os, sys, re, platform, subprocess
							 | 
						||
| 
								 | 
							
								import numpy as np
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class TLM_OIDN_Denoise:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    image_array = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    image_output_destination = ""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    denoised_array = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, oidnProperties, img_array, dirpath):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.oidnProperties = oidnProperties
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.image_array = img_array
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.image_output_destination = dirpath
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.check_binary()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def check_binary(self):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        oidnPath = self.oidnProperties.tlm_oidn_path
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if oidnPath != "":
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            file = oidnPath
							 | 
						||
| 
								 | 
							
								            filename, file_extension = os.path.splitext(file)
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								            if platform.system() == 'Windows':
							 | 
						||
| 
								 | 
							
								            
							 | 
						||
| 
								 | 
							
								                if(file_extension == ".exe"):
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                    pass
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                
							 | 
						||
| 
								 | 
							
								                    self.oidnProperties.tlm_oidn_path = os.path.join(self.oidnProperties.tlm_oidn_path,"oidnDenoise.exe")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
							 | 
						||
| 
								 | 
							
								                print("Please provide OIDN path")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def denoise(self):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for image in self.image_array:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if image not in self.denoised_array:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                image_path = os.path.join(self.image_output_destination, image)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                #Save to pfm
							 | 
						||
| 
								 | 
							
								                loaded_image = bpy.data.images.load(image_path, check_existing=False)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                width = loaded_image.size[0]
							 | 
						||
| 
								 | 
							
								                height = loaded_image.size[1]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                image_output_array = np.zeros([width, height, 3], dtype="float32")
							 | 
						||
| 
								 | 
							
								                image_output_array = np.array(loaded_image.pixels)
							 | 
						||
| 
								 | 
							
								                image_output_array = image_output_array.reshape(height, width, 4)
							 | 
						||
| 
								 | 
							
								                image_output_array = np.float32(image_output_array[:,:,:3])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                image_output_denoise_destination = image_path[:-4] + ".pfm"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                image_output_denoise_result_destination = image_path[:-4] + "_denoised.pfm"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                with open(image_output_denoise_destination, "wb") as fileWritePFM:
							 | 
						||
| 
								 | 
							
								                    self.save_pfm(fileWritePFM, image_output_array)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                #Denoise
							 | 
						||
| 
								 | 
							
								                if bpy.context.scene.TLM_SceneProperties.tlm_verbose:
							 | 
						||
| 
								 | 
							
								                    print("Loaded image: " + str(loaded_image))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                verbose = self.oidnProperties.tlm_oidn_verbose
							 | 
						||
| 
								 | 
							
								                affinity = self.oidnProperties.tlm_oidn_affinity
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if verbose:
							 | 
						||
| 
								 | 
							
								                    print("Denoiser search: " + bpy.path.abspath(self.oidnProperties.tlm_oidn_path))
							 | 
						||
| 
								 | 
							
								                    v = "3"
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    v = "0"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if affinity:
							 | 
						||
| 
								 | 
							
								                    a = "1"
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    a = "0"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                threads = str(self.oidnProperties.tlm_oidn_threads)
							 | 
						||
| 
								 | 
							
								                maxmem = str(self.oidnProperties.tlm_oidn_maxmem)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if platform.system() == 'Windows':
							 | 
						||
| 
								 | 
							
								                    oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
							 | 
						||
| 
								 | 
							
								                    pipePath = [oidnPath, '-f', 'RTLightmap', '-hdr', image_output_denoise_destination, '-o', image_output_denoise_result_destination, '-verbose', v, '-threads', threads, '-affinity', a, '-maxmem', maxmem]
							 | 
						||
| 
								 | 
							
								                elif platform.system() == 'Darwin':
							 | 
						||
| 
								 | 
							
								                    oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
							 | 
						||
| 
								 | 
							
								                    pipePath = [oidnPath + ' -f ' + ' RTLightmap ' + ' -hdr ' + image_output_denoise_destination + ' -o ' + image_output_denoise_result_destination + ' -verbose ' + v]
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    oidnPath = bpy.path.abspath(self.oidnProperties.tlm_oidn_path)
							 | 
						||
| 
								 | 
							
								                    oidnPath = oidnPath.replace(' ', '\\ ')
							 | 
						||
| 
								 | 
							
								                    image_output_denoise_destination = image_output_denoise_destination.replace(' ', '\\ ')
							 | 
						||
| 
								 | 
							
								                    image_output_denoise_result_destination = image_output_denoise_result_destination.replace(' ', '\\ ')
							 | 
						||
| 
								 | 
							
								                    pipePath = [oidnPath + ' -f ' + ' RTLightmap ' + ' -hdr ' + image_output_denoise_destination + ' -o ' + image_output_denoise_result_destination + ' -verbose ' + v]
							 | 
						||
| 
								 | 
							
								                    
							 | 
						||
| 
								 | 
							
								                if not verbose:
							 | 
						||
| 
								 | 
							
								                    denoisePipe = subprocess.Popen(pipePath, stdout=subprocess.PIPE, stderr=None, shell=True)
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    denoisePipe = subprocess.Popen(pipePath, shell=True)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                denoisePipe.communicate()[0]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if platform.system() != 'Windows':
							 | 
						||
| 
								 | 
							
								                    image_output_denoise_result_destination = image_output_denoise_result_destination.replace('\\', '')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                with open(image_output_denoise_result_destination, "rb") as f:
							 | 
						||
| 
								 | 
							
								                    denoise_data, scale = self.load_pfm(f)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                ndata = np.array(denoise_data)
							 | 
						||
| 
								 | 
							
								                ndata2 = np.dstack((ndata, np.ones((width,height))))
							 | 
						||
| 
								 | 
							
								                img_array = ndata2.ravel()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                loaded_image.pixels = img_array
							 | 
						||
| 
								 | 
							
								                loaded_image.filepath_raw = image_output_denoise_result_destination = image_path[:-10] + "_denoised.hdr"
							 | 
						||
| 
								 | 
							
								                loaded_image.file_format = "HDR"
							 | 
						||
| 
								 | 
							
								                loaded_image.save()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                self.denoised_array.append(image)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                print(image_path)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def clean(self):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        self.denoised_array.clear()
							 | 
						||
| 
								 | 
							
								        self.image_array.clear()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for file in self.image_output_destination:
							 | 
						||
| 
								 | 
							
								                if file.endswith("_baked.hdr"):
							 | 
						||
| 
								 | 
							
								                    baked_image_array.append(file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #self.image_output_destination
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #Clean temporary files here..
							 | 
						||
| 
								 | 
							
								        #...pfm
							 | 
						||
| 
								 | 
							
								        #...denoised.hdr
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def load_pfm(self, file, as_flat_list=False):
							 | 
						||
| 
								 | 
							
								        #start = time()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        header = file.readline().decode("utf-8").rstrip()
							 | 
						||
| 
								 | 
							
								        if header == "PF":
							 | 
						||
| 
								 | 
							
								            color = True
							 | 
						||
| 
								 | 
							
								        elif header == "Pf":
							 | 
						||
| 
								 | 
							
								            color = False
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            raise Exception("Not a PFM file.")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        dim_match = re.match(r"^(\d+)\s(\d+)\s$", file.readline().decode("utf-8"))
							 | 
						||
| 
								 | 
							
								        if dim_match:
							 | 
						||
| 
								 | 
							
								            width, height = map(int, dim_match.groups())
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            raise Exception("Malformed PFM header.")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        scale = float(file.readline().decode("utf-8").rstrip())
							 | 
						||
| 
								 | 
							
								        if scale < 0:  # little-endian
							 | 
						||
| 
								 | 
							
								            endian = "<"
							 | 
						||
| 
								 | 
							
								            scale = -scale
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            endian = ">"  # big-endian
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = np.fromfile(file, endian + "f")
							 | 
						||
| 
								 | 
							
								        shape = (height, width, 3) if color else (height, width)
							 | 
						||
| 
								 | 
							
								        if as_flat_list:
							 | 
						||
| 
								 | 
							
								            result = data
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            result = np.reshape(data, shape)
							 | 
						||
| 
								 | 
							
								        #print("PFM import took %.3f s" % (time() - start))
							 | 
						||
| 
								 | 
							
								        return result, scale
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def save_pfm(self, file, image, scale=1):
							 | 
						||
| 
								 | 
							
								        #start = time()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if image.dtype.name != "float32":
							 | 
						||
| 
								 | 
							
								            raise Exception("Image dtype must be float32 (got %s)" % image.dtype.name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if len(image.shape) == 3 and image.shape[2] == 3:  # color image
							 | 
						||
| 
								 | 
							
								            color = True
							 | 
						||
| 
								 | 
							
								        elif len(image.shape) == 2 or len(image.shape) == 3 and image.shape[2] == 1:  # greyscale
							 | 
						||
| 
								 | 
							
								            color = False
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            raise Exception("Image must have H x W x 3, H x W x 1 or H x W dimensions.")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        file.write(b"PF\n" if color else b"Pf\n")
							 | 
						||
| 
								 | 
							
								        file.write(b"%d %d\n" % (image.shape[1], image.shape[0]))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        endian = image.dtype.byteorder
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if endian == "<" or endian == "=" and sys.byteorder == "little":
							 | 
						||
| 
								 | 
							
								            scale = -scale
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        file.write(b"%f\n" % scale)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        image.tofile(file)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        #print("PFM export took %.3f s" % (time() - start))
							 |