def save(data: np.ndarray, save_path: str, grayscale: bool = False, alpha: bool = False): """Saves the data to a specified path and handles all required extensions Args: img: The numpy RGB or Grayscale float image with range 0 to 1. save_path: The path the image is saved to. grayscale: True if the image is in grayscale, False if RGB. alpha: True if the image contains transparency, False if opaque """ hdr = _is_hdr(save_path) npy = os.path.splitext(save_path)[1] == ".npy" if hdr: pyexr.write(save_path, data) elif npy: np.save(save_path, data) else: asUint8 = (data * 255).astype(np.uint8) if alpha: if grayscale: print("ALPHA AND GRAYSCALE IS NOT FULLY SUPPORTED") proc = cv2.COLOR_RGBA2BGRA elif not alpha and grayscale: proc = cv2.COLOR_GRAY2BGR else: proc = cv2.COLOR_RGB2BGR toSave = cv2.cvtColor(asUint8, proc) cv2.imwrite(save_path, toSave)
def pcd2img(name, load_path, save_path, k, factor_path=None): """Convert point clouds to depth images. """ mask = IO.get(os.path.join(load_path, "%s/instance_segment.png" % name)) mask_bg = np.array(mask[:, :, 2] == 0, dtype=np.float32) depth_in = IO.get(os.path.join(load_path, "%s/depth.exr" % name)) depth_out = depth_in * mask_bg mask_vals = np.unique(mask[:, :, 2])[1:] for i in range(len(mask_vals)): pcd_i = IO.get( os.path.join(load_path, "%s/depth2pcd_pred_%d.pcd" % (name, i))) if factor_path is not None: with open( os.path.join(factor_path, "%s/scale_factor_%d.json" % (name, i))) as f: factors = json.loads(f.read()) if factors['normalize']: pcd_i *= float(factors['normalize_factor']) if factors['centering']: pcd_i += np.array(factors['center_position']) depth_i = project_to_image(k, pcd_i) mask_i = np.array(mask[:, :, 2] == mask_vals[i], dtype=np.float32) depth_out += depth_i * mask_i # write predicted depth image in exr depth_out = np.expand_dims(depth_out, -1).repeat(3, axis=2) pyexr.write(os.path.join(save_path, "%s/depth_pred.exr" % name), depth_out)
def visualize_fit( output_paths: Union[List[str], str], shape, sgs: np.ndarray, scale_down_by: float = 1, ): assert len(sgs.shape) == 2 assert sgs.shape[-1] == 7 assert len(shape) >= 2 shape = ( shape[0], shape[1], 3, ) output = np.zeros(shape) us, vs = np.meshgrid(np.linspace(0, 1, shape[1]), np.linspace(0, 1, shape[0])) # OK uvs = np.dstack([us, vs]) # q f theta = 2.0 * np.pi * uvs[..., 0] - (np.pi / 2) phi = np.pi * uvs[..., 1] d = np.dstack([ np.cos(theta) * np.sin(phi), np.cos(phi), np.sin(theta) * np.sin(phi) ]) for i in range(sgs.shape[0]): sg = sgs[i:i + 1] output = output + _evaluate(sg, d) if isinstance(output_paths, str): output_paths = [output_paths] for path in output_paths: curOut = output.copy() is_output_exr = os.path.splitext(path)[1] == ".exr" is_output_hdr = os.path.splitext(path)[1] == ".hdr" if is_output_exr: pyexr.write(path, curOut) continue if is_output_hdr: output_proc = curOut.astype(np.float32) else: output_proc = (EU.linearTosRGB(np.clip(curOut, 0.0, 1.0)) * 255).astype("uint8") cv2.imwrite(path, cv2.cvtColor(output_proc, cv2.COLOR_RGB2BGR)) return output
def filter(exr_filename, out_filename, channels): exr = pyexr.open(exr_filename) channel_data = {channel: exr.get(channel) for channel in channels} if len(channel_data) == 1: channel_data["default"] = channel_data.pop(channels[0]) pyexr.write(out_filename, channel_data)
def write_exr(path, data): pyexr.write(path, data, channel_names={ 'normal': ['X', 'Y', 'Z'], 'x': ['X', 'Y', 'Z'], 'view': ['X', 'Y', 'Z'] }, precision=pyexr.HALF)
def run(input_filename, output_filename): exr = pyexr.read(input_filename) height, width, channels = exr.shape nan_indices = np.concatenate( [np.argwhere(np.isinf(exr)), np.argwhere(np.isnan(exr))]) for index in nan_indices: exr[tuple(index)] = neighborhood_average(exr, index) pyexr.write(output_filename, exr) print(f"Removed {len(nan_indices)} nans")
def run(gt): grid = _make_grid(gt) pyexr.write("live-gt.exr", grid) grid = _srgb(grid) figure = plt.figure() axes = figure.add_subplot() axes.imshow(grid) axes.set_title("Gt Sampling") axes.set_xlabel("Phi") axes.set_ylabel("Theta") plt.show()
def visualize_depthmap(depthmap, output_path, flip=False): if isinstance(depthmap, np.ndarray): depthmap = depthmap.squeeze() elif isinstance(depthmap, torch.Tensor): depthmap = depthmap.squeeze().cpu().numpy() else: raise NotImplementedError if flip: depthmap = np.flip(depthmap, axis=1) rescaled = (255.0 / depthmap.max() * (depthmap - depthmap.min())).astype( np.uint8) im = Image.fromarray(rescaled) im.save(str(output_path) + '.png') pyexr.write(str(output_path) + '.exr', depthmap)
def validation_step(self, batch, batch_idx): prediction = self.forward(batch) for i in range(len(batch['name'])): output_vis_path = Path( "runs" ) / self.hparams.experiment / f"vis" / f'{(self.global_step // 1000):05d}' / batch[ 'name'][i] output_vis_path.mkdir(exist_ok=True, parents=True) depth_map = prediction[i].squeeze().cpu().numpy() pyexr.write(str(output_vis_path / "depth_map.exr"), depth_map) mse_loss = torch.nn.functional.mse_loss(prediction, batch['target'], reduction='mean') self.log('val_loss', mse_loss) return {'loss': mse_loss}
def writegen(file, data): if file.endswith('.float3'): return writeFloat(file, data) elif file.endswith('.flo'): return writeFlow(file, data) elif file.endswith('.ppm'): return writeImage(file, data) elif file.endswith('.pgm'): return writeImage(file, data) elif file.endswith('.png'): return writeImage(file, data) elif file.endswith('.jpg'): return writeImage(file, data) elif file.endswith('.pfm'): return writePFM(file, data) elif file.endswith('.exr'): return pyexr.write(file, data) #https://github.com/tvogels/pyexr else: raise Exception('don\'t know how to write %s' % file)
def crop_filename(source_filename, destination_filename, from_shape, to_shape, offset, keep_orig=False): exr = pyexr.open(source_filename) root_data = {} default = exr.get("default") assert default.shape[:2] == from_shape for channel, data in exr.get_all().items(): channel_data = data[offset[0]:offset[0] + to_shape[0], offset[1]:offset[1] + to_shape[1], :] root_data[channel] = channel_data pyexr.write(destination_filename, root_data)
def combine(data_sources): print(data_sources) scene = find_scene(data_sources) out_path = Path("./combined") if not out_path.exists(): out_path.mkdir() datasets = build_datasets(data_sources) for i, spp_set in enumerate(zip(*datasets)): combined = spp_set[0] for bounce in spp_set[1:]: combined += bounce exr_path = out_path / f"auto-{2**i:05d}spp.exr" print(f"Writing: {exr_path}") pyexr.write(str(exr_path), combined) write_report_json(out_path, scene)
def run(chunk_size, raw_path, renders_path): renders_path.mkdir(exist_ok=True, parents=True) parts_to_index = {} for iteration, chunk in enumerate( _chunker(valid_parts(raw_path), chunk_size)): iteration_root = renders_path / f"iteration-{iteration:04d}" iteration_root.mkdir(exist_ok=True) print("CREATING:", iteration, iteration_root) for i, parts in enumerate(chunk): pdf_path = build_pdf_path(raw_path, parts) pdf_exr = convert_rgb_to_single_channel(pdf_path) if np.all(pdf_exr == 0.): continue pyexr.write(str(iteration_root / f"pdf_{i:05d}.exr"), pdf_exr) photon_path = build_photon_path(raw_path, parts) grid = photon_reader.build_grid(photon_path, (10, 10)) grid.export_dat(iteration_root / f"photon-bundle_{i:05d}.dat")
def generate_zero_map(source_path, inferred_path, out_path): generated_map = zero_map( pyexr.read(str(source_path)), pyexr.read(str(inferred_path)), ) pyexr.write(str(out_path), generated_map)
def render_prt_ortho(out_path, folder_name, subject_name, shs, rndr, rndr_uv, im_size, angl_step=4, n_light=1, pitch=[0], yaw=(0, 360)): """ out_path: output path of the rendered images and baked textures. folder_name: input path subject_name: subject name shs: ??? rndr: ??? rndr_uv: ??? im_size: ??? angle_step: ??? n_light: ??? pitch: ??? """ cam = Camera(width=im_size, height=im_size) cam.ortho_ratio = 0.4 * (512 / im_size) # what does this mean? ###### range of the mesh visible is specified here # default: -100 ~ 100 cam.near = -100 cam.far = 100 ###### cam.sanity_check() # set path for obj, prt mesh_file = os.path.join(folder_name, subject_name + '.obj') if not os.path.exists(mesh_file): print('ERROR: obj file does not exist!!', mesh_file) return else: print('[HERE] will use obj file %s' % mesh_file) prt_file = os.path.join(folder_name, 'bounce', 'bounce0.txt') if not os.path.exists(prt_file): print('ERROR: prt file does not exist!!!', prt_file) return else: print('[HERE] will use prt file %s' % prt_file) face_prt_file = os.path.join(folder_name, 'bounce', 'face.npy') if args.use_prt: if not os.path.exists(face_prt_file): print('ERROR: face prt file does not exist!!!', prt_file) return else: print('[HERE] you have specified usr_prt.') print('[HERE] will use face_prt file %s' % face_prt_file) text_file = os.path.join(folder_name, subject_name + '.jpg') if not os.path.exists(text_file): text_file = os.path.join(folder_name, subject_name + '.png') if not os.path.exists(text_file): print('ERROR: dif file does not exist!!', text_file) return else: print('[HERE] will use texture file %s' % text_file) ### path setting done texture_image = cv2.imread(text_file) texture_image = cv2.cvtColor(texture_image, cv2.COLOR_BGR2RGB) vertices, faces, normals, faces_normals, textures, face_textures = load_obj_mesh( mesh_file, with_normal=True, with_texture=True) # vertices are of the shape [N_v, 3] vmin = vertices.min( 0 ) # so this has shape [3], and it denotes the min coord value in 3 dimensions. vmax = vertices.max(0) # up_axis is the axis that we are looking direction at! # but it seems to choose only from 1 and 2, i.e. y and z # up_axis = 1 if (vmax-vmin).argmax() == 1 else 2 up_axis = args.up_axis # always set to z # but there remains the problem of orientation (somehow the bikes are upside down) # I can confirm that orientation problem is caused by the generation of rotation matrices below # orientation is fixed below, by adding an additional a 180-degree rotations to the z axis. longest_axis = (vmax - vmin).argmax() # what is vmed? # this does scaling # why median not mean? vmed = np.median(vertices, 0) # the up_axis is set to have median as the mean of two farthes points. vmed[longest_axis] = 0.5 * (vmax[longest_axis] + vmin[longest_axis]) # this scales the up_axis to 180? # called 'y_scale' supposedly because renderpeople faces up # why 180 ??? # BECAUSE the near-far range is -100~100, so 180 takes 90% of the range!!! #y_scale = 180/(vmax[up_axis] - vmin[up_axis]) longest_scale = 180 / (vmax[longest_axis] - vmin[longest_axis]) # are these cameras? # these two lines normalizes the coordinates according to vmed and y_scale, by setting two normalization matrices. # original scaling was done by y_scale. # but for bikes, need to change to longest_axis scale. rndr.set_norm_mat(longest_scale, vmed) rndr_uv.set_norm_mat(longest_scale, vmed) tan, bitan = compute_tangent(vertices, faces, normals, textures, face_textures) ###### prt loading # this has a potential problem if the mesh is low-poly # a large area would have the same texture and the output would appear broken # using a all-one tensor instead gets rid of the prt effects prt = np.loadtxt(prt_file) # what does this do? print(prt.shape) # [???, 9] face_prt = np.load(face_prt_file) prt_mean = prt.mean() prt_var = ((prt - prt_mean)**2).mean() print('prt mean = %.8f, prt var = %.8f' % (prt_mean, prt_var)) #print(face_prt) #print('face_prt shape = ', face_prt.shape) # same as faces.shape if not args.use_prt: prt = np.random.randn(*(prt.shape)) * 0.01 + args.pm ###### rndr.set_mesh(vertices, faces, normals, faces_normals, textures, face_textures, prt, face_prt, tan, bitan) rndr.set_albedo(texture_image) rndr_uv.set_mesh(vertices, faces, normals, faces_normals, textures, face_textures, prt, face_prt, tan, bitan) rndr_uv.set_albedo(texture_image) os.makedirs(os.path.join(out_path, 'GEO', 'OBJ', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'PARAM', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'RENDER', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'MASK', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_RENDER', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_MASK', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_POS', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_NORMAL', subject_name), exist_ok=True) if not os.path.exists(os.path.join(out_path, 'val.txt')): f = open(os.path.join(out_path, 'val.txt'), 'w') f.close() # copy obj file cmd = 'cp %s %s' % (mesh_file, os.path.join(out_path, 'GEO', 'OBJ', subject_name)) print(cmd) os.system(cmd) for p in pitch: for y in tqdm(range(yaw[0], yaw[1], angl_step)): # y is the angle in degrees # y goes through 0~360 (integers) R = np.matmul(make_rotate(math.radians(p), 0, 0), make_rotate(0, math.radians(y), 0)) if up_axis == 2: R = np.matmul( R, make_rotate(math.radians(90), 0, math.radians(180))) rndr.rot_matrix = R rndr_uv.rot_matrix = R rndr.set_camera(cam) rndr_uv.set_camera(cam) for j in range(n_light): sh_id = random.randint(0, shs.shape[0] - 1) sh = shs[sh_id] sh_angle = 0.2 * np.pi * (random.random() - 0.5) sh = rotateSH(sh, make_rotate(0, sh_angle, 0).T) dic = { 'sh': sh, 'ortho_ratio': cam.ortho_ratio, 'scale': longest_scale, 'center': vmed, 'R': R } rndr.set_sh(sh) rndr.analytic = False rndr.use_inverse_depth = False rndr.display() out_all_f = rndr.get_color(0) out_mask = out_all_f[:, :, 3] out_all_f = cv2.cvtColor(out_all_f, cv2.COLOR_RGBA2BGR) np.save( os.path.join(out_path, 'PARAM', subject_name, '%d_%d_%02d.npy' % (y, p, j)), dic) cv2.imwrite( os.path.join(out_path, 'RENDER', subject_name, '%d_%d_%02d.jpg' % (y, p, j)), 255.0 * out_all_f) cv2.imwrite( os.path.join(out_path, 'MASK', subject_name, '%d_%d_%02d.png' % (y, p, j)), 255.0 * out_mask) rndr_uv.set_sh(sh) rndr_uv.analytic = False rndr_uv.use_inverse_depth = False rndr_uv.display() uv_color = rndr_uv.get_color(0) uv_color = cv2.cvtColor(uv_color, cv2.COLOR_RGBA2BGR) cv2.imwrite( os.path.join(out_path, 'UV_RENDER', subject_name, '%d_%d_%02d.jpg' % (y, p, j)), 255.0 * uv_color) if y == 0 and j == 0 and p == pitch[0]: uv_pos = rndr_uv.get_color(1) uv_mask = uv_pos[:, :, 3] cv2.imwrite( os.path.join(out_path, 'UV_MASK', subject_name, '00.png'), 255.0 * uv_mask) data = { 'default': uv_pos[:, :, :3] } # default is a reserved name pyexr.write( os.path.join(out_path, 'UV_POS', subject_name, '00.exr'), data) uv_nml = rndr_uv.get_color(2) uv_nml = cv2.cvtColor(uv_nml, cv2.COLOR_RGBA2BGR) cv2.imwrite( os.path.join(out_path, 'UV_NORMAL', subject_name, '00.png'), 255.0 * uv_nml)
#!/usr/bin/env python3 import os, sys import pyexr if len(sys.argv) != 3: print( "mergexr: Merge multiple EXRs into a single one with multiple channels." ) print("Usage: mergexr.py input_dir output_file") exit() dir = sys.argv[1] output = sys.argv[2] data = {} for dirpath, dirnames, filenames in os.walk(dir): for file in filenames: buffer_name, ext = os.path.splitext(file) if ext == '.exr': fullpath = os.path.join(dirpath, file) data[buffer_name] = pyexr.read(fullpath) pyexr.write(output, data)
# Initialize TF graph batch_size_tensor = tf.placeholder(tf.int32, shape=[]) optimizer = tf.train.AdamOptimizer(config["optimizer"]["learning_rate"], config["optimizer"]["beta1"], config["optimizer"]["beta2"], config["optimizer"]["epsilon"]) train_op, loss, input_tensor, output_tensor = make_graph() # Variables for saving/displaying image results resolution = 1024 img_shape = (resolution, resolution, target_fun.n_channels) half_dx = 0.5 / resolution xs = np.linspace(half_dx, 1-half_dx, resolution) xv, yv = np.meshgrid(xs, xs) xy = np.stack((xv.flatten(), yv.flatten())).transpose() gt = np.reshape(target_fun(xy), img_shape) exr.write("reference.exr", gt) # Enable XLA compiler (important for good TensorFlow performance) session_config = tf.ConfigProto() session_config.graph_options.optimizer_options.global_jit_level = tf.OptimizerOptions.ON_1 timer = time.perf_counter() # Run the network with tf.Session(config=session_config) as sess: PRINT_INTERVAL = 100 bench_result = { "tensorflow": [] } for batch_size in [2**14, 2**15, 2**16, 2**17, 2**18, 2**19, 2**20, 2**21]: N_ITERS = 1000
def main(args): start = time.time() if not os.path.exists(args.input): raise ValueError("input {} does not exist".format(args.input)) data_root = os.path.abspath(args.input) name = os.path.basename(data_root) tmpdir = tempfile.mkdtemp() os.symlink(data_root, os.path.join(tmpdir, name)) LOG.info("Loading model {}".format(args.checkpoint)) meta_params = ttools.Checkpointer.load_meta(args.checkpoint) LOG.info("Setting up dataloader") data_params = meta_params["data_params"] if args.spp: data_params["spp"] = args.spp data = sbmc.FullImagesDataset(tmpdir, **data_params) dataloader = DataLoader(data, batch_size=1, shuffle=False, num_workers=0) LOG.info("Denoising input with {} spp".format(data_params["spp"])) kpcn_mode = meta_params["kpcn_mode"] if kpcn_mode: LOG.info("Using [Bako2017] denoiser.") model = sbmc.KPCN(data.num_features) else: model = sbmc.Multisteps(data.num_features, data.num_global_features) model.train(False) device = "cpu" cuda = th.cuda.is_available() if cuda: LOG.info("Using CUDA") model.cuda() device = "cuda" checkpointer = ttools.Checkpointer(args.checkpoint, model, None) extras, meta = checkpointer.load_latest() LOG.info("Loading latest checkpoint {}".format( "failed" if meta is None else "success")) elapsed = (time.time() - start) * 1000 LOG.info("setup time {:.1f} ms".format(elapsed)) LOG.info("starting the denoiser") for scene_id, batch in enumerate(dataloader): for k in batch.keys(): batch[k] = batch[k].to(device) scene = os.path.basename(data.scenes[scene_id]) LOG.info(" scene {}".format(scene)) tile_sz = args.tile_size tile_pad = args.tile_pad batch_parts = _split_tiles(batch, max_sz=tile_sz, pad=tile_pad) out_radiance = th.zeros_like(batch["low_spp"]) if cuda: th.cuda.synchronize() start = time.time() for part, start_y, end_y, start_x, end_x, pad_ in batch_parts: with th.no_grad(): out_ = model(part) out_ = _pad(part, out_["radiance"], kpcn_mode) out_ = out_[..., pad_[0]:out_.shape[-2] - pad_[1], pad_[2]:out_.shape[-1] - pad_[3]] out_radiance[..., start_y:end_y, start_x:end_x] = out_ if cuda: th.cuda.synchronize() elapsed = (time.time() - start) * 1000 LOG.info(" denoising time {:.1f} ms".format(elapsed)) out_radiance = out_radiance[0, ...].cpu().numpy().transpose([1, 2, 0]) outdir = os.path.dirname(args.output) os.makedirs(outdir, exist_ok=True) pyexr.write(args.output, out_radiance) png = args.output.replace(".exr", ".png") skio.imsave(png, (np.clip(out_radiance, 0, 1) * 255).astype(np.uint8)) shutil.rmtree(tmpdir)
import pyexr import sys import numpy as np if len(sys.argv) != 4 and len(sys.argv) != 6 and len(sys.argv) != 7: print( "pure_color: Generate pure color EXRs(1/3/4 channels) with specific value and size." ) print( "Usage: pure_color.py width height channel_1 [channel_2 channel_3 [channel_4]]" ) exit() width = int(sys.argv[1]) height = int(sys.argv[2]) n_channel = len(sys.argv) - 3 value = np.zeros(n_channel) exr_name = "%dx%d" % (width, height) for i in range(n_channel): value[i] = float(sys.argv[i + 3]) exr_name += "_%.2f" % value[i] img = np.ones((height, width, n_channel)) * value exr_name += ".exr" if n_channel == 1: pyexr.write(exr_name, img, channel_names=['Y']) else: pyexr.write(exr_name, img)
import os, sys import glob import pyexr if len(sys.argv) < 3: print("exrmul: Multiply all EXRs specified or in a dir.") print("Usage: exrmul.py output_EXR {input_EXR_dir | input_EXRs...}") exit() output_name = sys.argv[1] path = sys.argv[2] exr_files = [] if os.path.isdir(path): exr_files = glob.glob(os.path.join(path, "*.exr")) else: for i in range(2, len(sys.argv)): exr_files.append(sys.argv[i]) output_exr = None for file in exr_files: if output_exr is None: output_exr = pyexr.read(file) else: output_exr *= pyexr.read(file) if output_exr.shape[2] == 1: pyexr.write(output_name, output_exr, channel_names=['Y']) else: pyexr.write(output_name, output_exr)
#!/usr/bin/env python3 import pyexr import sys import numpy as np if len(sys.argv) != 3: print( "clamp: Turn zero-value pixels into red, nonzero-value pixels into green." ) print("Usage: clamp.py input_file output_file") exit() img = pyexr.read(sys.argv[1]) size = img.shape[0:2] zero = np.zeros(size) is_zero = np.all(img == 0, 2) img_out = np.stack((is_zero, 1 - is_zero, zero), 2) n_zero = is_zero.sum() print(n_zero / (size[0] * size[1])) pyexr.write(sys.argv[2], img_out)
def bins2exr(data_dir, output, spp): batch_size = 1 data = sbmc.FullImagesDataset(data_dir, mode=sbmc.TilesDataset.RAW_MODE, spp=spp) if len(data.scenes) != 1: LOG.error("Expected a single scene, got %d", len(data.scenes)) raise RuntimeError("Invalid number of scenes in .bin folder.") im = data[0] os.makedirs(output, exist_ok=True) exr_data = {} half_spp = spp // 2 # Keys to features labels = data.tiles_dset.labels albedo_k = labels.index("albedo_first_r") diffuse_k = labels.index("diffuse_r") specular_k = labels.index("specular_r") normal_k = labels.index("normal_first_x") depth_k = labels.index("depth_first") visibility_k = labels.index("visibility") df = im['features'] diffuse_ = df[:, diffuse_k:diffuse_k + 3].transpose([2, 3, 1, 0]) specular_ = df[:, specular_k:specular_k + 3].transpose([2, 3, 1, 0]) specular_[specular_ < 0.0] = 0 diffuse_[diffuse_ < 0.0] = 0 radiance_ = diffuse_ + specular_ radiance_[radiance_ < 0.0] = 0 exr_data['color'] = radiance_.mean(-1) exr_data['colorA'] = radiance_[..., :half_spp].mean(-1) exr_data['colorB'] = radiance_[..., half_spp:].mean(-1) # MC estimate's variance = 1/n * var exr_data['colorVariance'] = radiance_.var(-1) / spp exr_data['diffuse'] = diffuse_.mean(-1) exr_data['diffuseA'] = diffuse_[..., :half_spp].mean(-1) exr_data['diffuseB'] = diffuse_[..., half_spp:].mean(-1) # MC estimate's variance = 1/n * var exr_data['diffuseVariance'] = diffuse_.var(-1) / spp exr_data['specular'] = specular_.mean(-1) exr_data['specularA'] = specular_[..., :half_spp].mean(-1) exr_data['specularB'] = specular_[..., half_spp:].mean(-1) # MC estimate's variance = 1/n * var exr_data['specularVariance'] = specular_.var(-1) / spp albedo_ = df[:, albedo_k:albedo_k + 3].transpose([2, 3, 1, 0]) exr_data['albedo'] = albedo_.mean(-1) exr_data['albedoA'] = albedo_[..., :half_spp].mean(-1) exr_data['albedoB'] = albedo_[..., half_spp:].mean(-1) exr_data['albedoVariance'] = albedo_.var(-1) / spp normal_ = df[:, normal_k:normal_k + 3].transpose([2, 3, 1, 0]) exr_data['normal'] = normal_.mean(-1) exr_data['normalA'] = normal_[..., :half_spp].mean(-1) exr_data['normalB'] = normal_[..., half_spp:].mean(-1) exr_data['normalVariance'] = normal_.var(-1) / spp depth_ = df[:, depth_k:depth_k + 1].transpose([2, 3, 1, 0]) depth_ = np.tile(depth_, [1, 1, 3, 1]) scene_radius = im["scene_radius"] depth_[depth_ < 0.0] = 0 depth_ /= scene_radius exr_data['depth'] = depth_.mean(-1) exr_data['depthA'] = depth_[..., :half_spp].mean(-1) exr_data['depthB'] = depth_[..., half_spp:].mean(-1) exr_data['depthVariance'] = depth_.var(-1) / spp for k in exr_data.keys(): LOG.debug(" %s %.2f --- %.2f (mean = %.2f)", k, exr_data[k].min(), exr_data[k].max(), exr_data[k].mean()) pyexr.write(os.path.join(output, k + ".exr"), exr_data[k])
def combine_renders(run_dir, combination_type='var', error_type=ErrorType.CUMULATIVE): run_dir = os.path.join(run_dir, "") # adds to the end '/' if needed out_dir = os.path.dirname(run_dir) print(f"Combining run with weighing heuristic: {combination_type}.") image_files = sorted([ filename for filename in os.listdir(run_dir) if re.search(r'^iteration[0-9]*\.exr$', filename) ]) image_sqr_files = sorted([ filename for filename in os.listdir(run_dir) if re.search(r'^iteration_sqr[0-9]*\.exr$', filename) ]) scene_name = Path(out_dir).parents[2].name gt_path = get_gt_path(scene_name) gt_image = pyexr.read(gt_path) final_image = None total_reciprocal_weight = 0.0 var_data=[] MrSE_data = [] MAPE_data = [] SMAPE_data = [] spp_data=[] total_spp = 0 for image_file, image_sqr_file in tqdm( zip(image_files, image_sqr_files), total=len(image_files) ): iteration = int( re.search(r'^iteration([0-9]*)\.exr$', image_file).group(1) ) # print('Processing iteration {}.'.format(iteration)) iteration_image, iteration_square_image, spp = load_iteration( os.path.join(run_dir, image_file), os.path.join(run_dir, image_sqr_file) ) image_shape = iteration_image.shape[:2] image_variance = spp / (spp - 1) * ( iteration_square_image / spp - (iteration_image / spp) ** 2 ) # image_variance = ski.filters.gaussian( # image_variance, sigma=3, multichannel=True # ) image_variance = np.clip(image_variance, 0, 2000) per_channel_variance = np.mean(image_variance, axis=(0,1)) max_variance = np.maximum(image_variance, per_channel_variance) # pyexr.write(os.path.join(out_dir, f'iteration_var{iteration}.exr'), image_variance) total_spp += spp spp_data.append(total_spp) # print('Iteration {} spp={}.'.format(iteration, spp)) var_data.append(aggregate(image_variance)) if iteration >= 4: # or iteration > 10: # print('Including iteration {}.'.format(iteration)) if combination_type == 'var': weight = per_channel_variance elif combination_type == 'max_var': weight = max_variance elif combination_type == 'uniform': weight = 1 / spp total_reciprocal_weight += 1.0 / weight if final_image is None: final_image = iteration_image / weight else: final_image += iteration_image / weight if final_image is not None and error_type == ErrorType.CUMULATIVE: combined_estimate = final_image / total_reciprocal_weight # out_path = os.path.join(out_dir, f'combined_{iteration:02d}' + '.exr') # if os.path.exists(out_path): # os.remove(out_path) # pyexr.write(out_path, combined_estimate.astype(np.float32)) MrSE_data.append(aggregate(MrSE(np.clip(combined_estimate, 0, 1), np.clip(gt_image, 0, 1)))) MAPE_data.append(aggregate(MAPE(combined_estimate, gt_image))) SMAPE_data.append(aggregate(SMAPE(combined_estimate, gt_image))) elif final_image is None or error_type == ErrorType.INDIVIDUAL: MrSE_data.append(aggregate(MrSE(np.clip(iteration_image, 0, 1), np.clip(gt_image, 0, 1)))) MAPE_data.append(aggregate(MAPE(iteration_image, gt_image))) SMAPE_data.append(aggregate(SMAPE(iteration_image, gt_image))) if len(var_data) <= 1: return {} json_dir = os.path.join(run_dir, "stats.json") total_elapsed_seconds = None mean_path_length = None elapsed_seconds = [] if os.path.exists(json_dir): with open(json_dir) as json_file: stats_json = json.load(json_file) for i in range(len(stats_json)): stats_json[i]['mean_pixel_variance']=float(var_data[i]) stats_json[i]['ttuv']=float(var_data[i]) * stats_json[i]['elapsed_seconds'] elapsed_seconds.append(stats_json[i]['total_elapsed_seconds']) last_stats = stats_json[-1] total_elapsed_seconds=last_stats['total_elapsed_seconds'] mean_path_length=last_stats['mean_path_length'] with open(json_dir, 'w') as json_file: json_file.write(json.dumps(stats_json, sort_keys=True, indent=4)) plot_filename = 'error.pdf' plot_file = os.path.join(out_dir, plot_filename) fig, ax = plt.subplots(figsize=(12, 9)) ax.set_axisbelow(True) ax.minorticks_on() ax.grid(which='major', axis='both', linestyle='-', linewidth='0.5') ax.grid(which='minor', axis='both', linestyle=':', linewidth='0.5') ax.semilogy(elapsed_seconds, var_data, base=10, label='Estimated VAR') ax.semilogy(elapsed_seconds, SMAPE_data, base=10, label='SMAPE') ax.semilogy(elapsed_seconds, MrSE_data, base=10, label='MRSE') ax.semilogy(elapsed_seconds, MAPE_data, base=10, label='MAPE') # ax.plot(var_data, label='Estimated VAR') # ax.plot(SMAPE_data, label='SMAPE') # ax.plot(MrSE_data, label='MRSE') # ax.set_yticks(var_data) ax.legend() fig.tight_layout() plt.savefig(plot_file, format=os.path.splitext(plot_filename)[-1][1:], dpi=fig.dpi) if final_image is None: print('No final image produced!') return final_image /= total_reciprocal_weight SMAPE_final = aggregate(SMAPE(final_image, gt_image)) MAPE_final = aggregate(MAPE(final_image, gt_image)) MrSE_final = aggregate(MrSE(np.clip(final_image, 0, 1), np.clip(gt_image, 0, 1))) print(f"{Fore.GREEN}MAPE={MAPE_final:.3f}, SMAPE={SMAPE_final:.3f}, MrSE={MrSE_final:.3f}{Style.RESET_ALL}") if total_elapsed_seconds and mean_path_length: print( f"{Fore.GREEN}" f"Total time: {total_elapsed_seconds:.3f}s, " f"Mean path length: {mean_path_length:.3f}." f"{Style.RESET_ALL}" ) out_path = os.path.join(out_dir, scene_name + '.exr') if os.path.exists(out_path): os.remove(out_path) pyexr.write(out_path, final_image.astype(np.float32)) return { 'MAPE': (elapsed_seconds, MAPE_data, MAPE_final), 'SMAPE': (elapsed_seconds, SMAPE_data, SMAPE_final), 'MrSE': (elapsed_seconds, MrSE_data, MrSE_final), }
def get_errors(run_dir, combination_type='var', error_type=ErrorType.CUMULATIVE, integrator='sdmm'): run_dir = os.path.join(run_dir, "") # adds to the end '/' if needed out_dir = os.path.dirname(run_dir) print(f"Combining run with weighing heuristic: {combination_type}.") rexp = r'^iteration_[0-9]*\.exr$' if integrator == 'ppg' else r'^iteration[0-9]*\.exr$' image_files = sorted([ filename for filename in os.listdir(run_dir) if re.search(rexp, filename) ]) json_dir = os.path.join(run_dir, "stats.json") scene_name = Path(out_dir).parents[2].name gt_path = get_gt_path(scene_name) gt_image = pyexr.read(gt_path) final_image = None total_reciprocal_weight = 0.0 var_data=[] MrSE_data = [] MAPE_data = [] SMAPE_data = [] spp_data=[] total_spp = 0 stats_json = None if not os.path.exists(json_dir): print('Cannot find stats.json.') return {} with open(json_dir) as json_file: stats_json = json.load(json_file) elapsed_seconds = [] var_data = [] spp_data = [] for i in range(len(stats_json)): elapsed_seconds.append(stats_json[i]['total_elapsed_seconds']) var_data.append(stats_json[i]['mean_pixel_variance']) spp_data.append(stats_json[i]['spp']) for iteration, image_file in tqdm(enumerate(image_files), total=len(image_files)): iteration_image = pyexr.read(os.path.join(run_dir, image_file)) var = var_data[iteration] spp = spp_data[iteration] total_spp += spp if combination_type == 'var': weight = var_data[iteration] elif combination_type == 'uniform': weight = 1 / spp if ( (integrator == 'ppg' and weight is not None) or (integrator == 'sdmm' and total_spp >= 40) ): total_reciprocal_weight += 1.0 / weight if final_image is None: final_image = iteration_image / weight else: final_image += iteration_image / weight if final_image is not None and error_type == ErrorType.CUMULATIVE: combined_estimate = final_image / total_reciprocal_weight MrSE_data.append(aggregate(MrSE(np.clip(combined_estimate, 0, 1), np.clip(gt_image, 0, 1)))) MAPE_data.append(aggregate(MAPE(combined_estimate, gt_image))) SMAPE_data.append(aggregate(SMAPE(combined_estimate, gt_image))) elif final_image is None or error_type == ErrorType.INDIVIDUAL: MrSE_data.append(aggregate(MrSE(np.clip(iteration_image, 0, 1), np.clip(gt_image, 0, 1)))) MAPE_data.append(aggregate(MAPE(iteration_image, gt_image))) SMAPE_data.append(aggregate(SMAPE(iteration_image, gt_image))) final_image /= total_reciprocal_weight out_path = os.path.join(out_dir, scene_name + '_test' + '.exr') if os.path.exists(out_path): os.remove(out_path) pyexr.write(out_path, final_image.astype(np.float32)) SMAPE_final = aggregate(SMAPE(final_image, gt_image)) MAPE_final = aggregate(MAPE(final_image, gt_image)) MrSE_final = aggregate(MrSE(np.clip(final_image, 0, 1), np.clip(gt_image, 0, 1))) if len(elapsed_seconds) > 0: print( f"{Fore.GREEN}" f"Total time: {elapsed_seconds[-1]:.3f}s, " f"MAPE: {MAPE_final:.3f}, " f"{Style.RESET_ALL}" ) return { 'MAPE': (elapsed_seconds, MAPE_data, MAPE_final), 'SMAPE': (elapsed_seconds, SMAPE_data, SMAPE_final), 'MrSE': (elapsed_seconds, MrSE_data, MrSE_final), }
if __name__ == "__main__": args = parser.parse_args() # load environment map HDR image and convert it from cube to # latitude-longitude mapping lum = cv2.imread(args.env_dir, -1)[..., ::-1] lum = cv2.resize(lum, (256, 128), interpolation=cv2.INTER_AREA) h, w, _ = lum.shape print(h, w) if args.cube_to_ll: lum = ConvertCubeMap2LL(lum, 1024) # read reflectance field reflectance_field, mask = ReadReflectanceField( args.ref_field, mask_path=args.ref_field_mask) mask = 1 - mask # read stage light directions and intensities intensities, directions = ReadLightsInfo(args.light_dirs, args.light_int) print("[INFO] Starting image relighting.") start = time.time() out = ImageRelighting(lum, directions, intensities)\ .relight(reflectance_field, mask) end = time.time() print("[INFO] Elapsed time to image relighting: ", end - start) # save image pyexr.write('out/{}.exr'.format(args.file_name), out)
#!/usr/bin/env python3 import pyexr import sys import numpy as np if len(sys.argv) != 3: print("average_channels: Average all channels into a single one.") print("Usage: average_channels.py input_file output_file") exit() rgb = pyexr.read(sys.argv[1]) y = np.average(rgb, 2) pyexr.write(sys.argv[2], y, channel_names=['Y'])
#!/usr/bin/env python3 import pyexr import sys # channel: 'R','G','B','A' if len(sys.argv) != 4: print("extract_channel_pyexr: Extract a channel as 'Y' into a new EXR.") print("Usage: extract_channel_pyexr.py input_file channel output_file") exit() r = pyexr.read(sys.argv[1], sys.argv[2]) pyexr.write(sys.argv[3], r, channel_names=['Y'])
def render_prt_ortho(out_path, folder_name, subject_name, tex_name, shs, rndr, rndr_uv, im_size, angl_step=4, n_light=1, pitch=[0]): cam = Camera(width=im_size, height=im_size) cam.ortho_ratio = 0.4 * (512 / im_size) cam.near = -100 cam.far = 100 cam.sanity_check() # set path for obj, prt mesh_file = os.path.join(folder_name, subject_name + '.obj') if not os.path.exists(mesh_file): print('ERROR: obj file does not exist!!', mesh_file) return prt_file = os.path.join(folder_name, 'bounce', 'bounce0.txt') if not os.path.exists(prt_file): print('ERROR: prt file does not exist!!!', prt_file) return face_prt_file = os.path.join(folder_name, 'bounce', 'face.npy') if not os.path.exists(face_prt_file): print('ERROR: face prt file does not exist!!!', prt_file) return text_file = os.path.join(folder_name, tex_name) if not os.path.exists(text_file): print('ERROR: dif file does not exist!!', text_file) return texture_image = cv2.imread(text_file) texture_image = cv2.cvtColor(texture_image, cv2.COLOR_BGR2RGB) vertices, faces, normals, faces_normals, textures, face_textures = load_obj_mesh( mesh_file, with_normal=True, with_texture=True) vmin = vertices.min(0) vmax = vertices.max(0) up_axis = 1 if (vmax - vmin).argmax() == 1 else 2 vmed = np.median(vertices, 0) vmed[up_axis] = 0.5 * (vmax[up_axis] + vmin[up_axis]) y_scale = 180 / (vmax[up_axis] - vmin[up_axis]) rndr.set_norm_mat(y_scale, vmed) rndr_uv.set_norm_mat(y_scale, vmed) tan, bitan = compute_tangent(vertices, faces, normals, textures, face_textures) prt = np.loadtxt(prt_file) face_prt = np.load(face_prt_file) rndr.set_mesh(vertices, faces, normals, faces_normals, textures, face_textures, prt, face_prt, tan, bitan) rndr.set_albedo(texture_image) rndr_uv.set_mesh(vertices, faces, normals, faces_normals, textures, face_textures, prt, face_prt, tan, bitan) rndr_uv.set_albedo(texture_image) os.makedirs(os.path.join(out_path, 'GEO', 'OBJ', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'PARAM', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'RENDER', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'MASK', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_RENDER', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_MASK', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_POS', subject_name), exist_ok=True) os.makedirs(os.path.join(out_path, 'UV_NORMAL', subject_name), exist_ok=True) if not os.path.exists(os.path.join(out_path, 'val.txt')): f = open(os.path.join(out_path, 'val.txt'), 'w') f.close() # copy obj file cmd = 'cp %s %s' % (mesh_file, os.path.join(out_path, 'GEO', 'OBJ', subject_name)) print(cmd) os.system(cmd) for p in pitch: for y in tqdm(range(0, 360, angl_step)): R = np.matmul(make_rotate(math.radians(p), 0, 0), make_rotate(0, math.radians(y), 0)) if up_axis == 2: R = np.matmul(R, make_rotate(math.radians(90), 0, 0)) rndr.rot_matrix = R rndr_uv.rot_matrix = R rndr.set_camera(cam) rndr_uv.set_camera(cam) for j in range(n_light): sh_id = random.randint(0, shs.shape[0] - 1) sh = shs[sh_id] sh_angle = 0.2 * np.pi * (random.random() - 0.5) sh = rotateSH(sh, make_rotate(0, sh_angle, 0).T) dic = { 'sh': sh, 'ortho_ratio': cam.ortho_ratio, 'scale': y_scale, 'center': vmed, 'R': R } rndr.set_sh(sh) rndr.analytic = False rndr.use_inverse_depth = False rndr.display() out_all_f = rndr.get_color(0) out_mask = out_all_f[:, :, 3] out_all_f = cv2.cvtColor(out_all_f, cv2.COLOR_RGBA2BGR) np.save( os.path.join(out_path, 'PARAM', subject_name, '%d_%d_%02d.npy' % (y, p, j)), dic) cv2.imwrite( os.path.join(out_path, 'RENDER', subject_name, '%d_%d_%02d.jpg' % (y, p, j)), 255.0 * out_all_f) cv2.imwrite( os.path.join(out_path, 'MASK', subject_name, '%d_%d_%02d.png' % (y, p, j)), 255.0 * out_mask) rndr_uv.set_sh(sh) rndr_uv.analytic = False rndr_uv.use_inverse_depth = False rndr_uv.display() uv_color = rndr_uv.get_color(0) uv_color = cv2.cvtColor(uv_color, cv2.COLOR_RGBA2BGR) cv2.imwrite( os.path.join(out_path, 'UV_RENDER', subject_name, '%d_%d_%02d.jpg' % (y, p, j)), 255.0 * uv_color) if y == 0 and j == 0 and p == pitch[0]: uv_pos = rndr_uv.get_color(1) uv_mask = uv_pos[:, :, 3] cv2.imwrite( os.path.join(out_path, 'UV_MASK', subject_name, '00.png'), 255.0 * uv_mask) data = { 'default': uv_pos[:, :, :3] } # default is a reserved name pyexr.write( os.path.join(out_path, 'UV_POS', subject_name, '00.exr'), data) uv_nml = rndr_uv.get_color(2) uv_nml = cv2.cvtColor(uv_nml, cv2.COLOR_RGBA2BGR) cv2.imwrite( os.path.join(out_path, 'UV_NORMAL', subject_name, '00.png'), 255.0 * uv_nml)
def generate_render_target( self, config_path: str, render_target: str = "low_spp", device: str = "gpu_multi", mitsuba_variant: Optional[str] = None, base_spp_level: int = 4, ) -> Dict[str, List[np.ndarray]]: """Generate a render target for a given config and render target. Args: config_path (str): The config path to use render_target (str, optional): Which render target to use. Defaults to "low_spp". device (str, optional): The device to run it on => renderer type. Defaults to "gpu_multi". mitsuba_variant (Optional[str], optional): Overrides the mitsuba variant. Defaults to None. base_spp_level (int, optional): The base spp level for each pass in the scene. Defaults to 4. Returns: Dict[str, List[np.ndarray]]: A dict of all the final renders for each spp levels. """ render_enum: RendererEnum = RendererEnum.from_str(device) renderer: RendererEnv = RendererEnv( mitsuba_variant=render_enum.default_variant() if mitsuba_variant is None else mitsuba_variant, renderer_type=render_enum, ) config: Dict = load_json(config_path) folder_out: Optional[str] = config.get("folder_out") os.makedirs(folder_out, exist_ok=True) render_targets: Optional[Dict[str, Dict]] = config.get("render_targets") if not isinstance(folder_out, str) or render_targets is None: raise ValueError( "Config is not well formatted, missing folder_out path and/or render_targets", ) target_dict: Optional[Dict[str, int]] = render_targets.get(render_target) if target_dict is None: raise ValueError( f"There is no target for render with key: {render_target}") results_dict: Dict[str, List[np.ndarray]] = {} scene_path: str = config.get("scene_path") if not isinstance(scene_path, str): raise ValueError("There is no proper scene_path specified") renderer.load_scene(scene_path=scene_path, scene_id="scene_gen") for spp_level, n_renders in tqdm(target_dict.items()): logger.info(f"Starting renders for spp level: {spp_level}") curr_folder: str = os.path.join( folder_out, f"render_{spp_level}", ) os.makedirs(curr_folder, exist_ok=True) results_dict[spp_level] = [] spp_level_int: int = int(spp_level) for i in range(n_renders): res: List[np.ndarray] = renderer.render( scene_id="scene_gen", n_pass=spp_level_int // base_spp_level, ) results_dict[spp_level].append(res) for k, r in enumerate(res): pyexr.write( os.path.join( curr_folder, f"spp_{i}th_{k}.exr", ), r, ) return results_dict
print("Saving mask to", dir + "mask.png") with open(dir + "mask.png", "wb") as f_mask: w = png.Writer(width, height, greyscale=True, bitdepth=1) w.write(f_mask, img_mask) print("Saving albedo to", dir + "albedo.png") with open(dir + "albedo.png", "wb") as f_albedo: w = png.Writer(width, height) w.write(f_albedo, img_albedos) print("Saving shading to", dir + "shading.png") with open(dir + "shading.png", "wb") as f_shading: w = png.Writer(width, height) w.write(f_shading, img_shading_png) print("Saving depth to", dir + "depth.exr") pyexr.write(dir + "depth.exr", img_depth.astype(np.float32)) print("Saving shading", img_shading.shape, "to", dir + "shading.exr") pyexr.write(dir + "shading.exr", img_shading.astype(np.float32), channel_names=['R', 'G', 'B']) print("Saving normals", img_shading.shape, "to", dir + "normals.exr") pyexr.write(dir + "normals.exr", img_normals.astype(np.float32), channel_names=['R', 'G', 'B']) print("Done!")