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)) |