//  [python]
def validate_image(self, idx=-1, resolution_level=-1):
        if idx < 0:
            idx = np.random.randint(self.dataset.n_images)
        print('Validate: iter: {}, camera: {}'.format(self.iter_step, idx))

        if resolution_level < 0:
            resolution_level = self.val_render_resolution_level        
        pixels, radii, orient_angle, cam_intr_0, cam_pose_0 = self.dataset.gen_rays_at(idx, resolution_level=resolution_level)
        # print('before cam model', cam_intr_0.shape, cam_pose_0.shape)
        if self.camera_model is not None:
            cam_intr_, cam_pose_ = self.camera_model(torch.tensor([idx]), cam_intr_0, cam_pose_0)
            cam_intr_ = cam_intr_[0]
            cam_pose_ = cam_pose_[0]
        else:
            cam_intr_ = cam_intr_0
            cam_pose_ = cam_pose_0

        cam_intr = cam_intr_.detach()
        cam_extr = torch.linalg.inv(cam_pose_.detach())

        p = torch.matmul(torch.linalg.inv(cam_intr_)[None, None, :3, :3], pixels[:, :, :, None]).squeeze()  # W, H, 3
        rays_d = p / torch.norm(p, 2, dim=-1, keepdim=True)  # W, H, 3
        rays_d = torch.matmul(cam_pose_[None, None, :3, :3], rays_d[:, :, :, None]).squeeze()  # W, H, 3
        rays_o = cam_pose_[None, None, :3, 3].expand(rays_d.shape)  # W, H, 3

        H, W, _ = rays_o.shape

        rays_o = rays_o.transpose(0, 1).reshape(-1, 3).split(self.batch_size)
        rays_d = rays_d.transpose(0, 1).reshape(-1, 3).split(self.batch_size)
        
        radii = radii.reshape(-1, 1).split(self.batch_size)
        orient_angle = orient_angle.reshape(-1, 3).split(self.batch_size)

        out_rgb_fine = []
        out_orient_fine = []
        out_normal_fine = []
        out_normal_hair_fine = []
        
        for rays_o_batch, rays_d_batch, radii_batch, orient_angle_batch in zip(rays_o, rays_d, radii, orient_angle):
            near, far = self.dataset.near_far_from_sphere(rays_o_batch, rays_d_batch)
            background_rgb = torch.ones([1, 3]) if self.use_white_bkgd else None

            render_out = self.renderer.render(rays_o_batch,
                                              rays_d_batch,
                                              radii_batch,
                                              near,
                                              far,
                                              cos_anneal_ratio=self.get_cos_anneal_ratio(),
                                              background_rgb=background_rgb)

            color_fine = render_out['color_fine'].detach().cpu().numpy()


            def feasible(key): return (key in render_out) and (render_out[key] is not None)

            if feasible('color_fine'):
                out_rgb_fine.append(color_fine)

            if self.orient_weight:
                if feasible('sampled_orient_fine'):
                    # Project orientations into camera
                    orient_angle_fine = project_orient_to_camera(orient_3d=render_out['sampled_orient_fine'], org_3d=render_out['pts_fine'], cam_intr=cam_intr, cam_extr=cam_extr)
                    
                    orient_cos_fine = orient_angle_fine.cos()
                    orient_fine_cam = torch.cat(
                        [
                            orient_cos_fine * (orient_cos_fine >= 0),
                            orient_angle_fine.sin(),
                            orient_cos_fine.abs() * (orient_cos_fine < 0)
                        ],
                        dim=1
                    )
                    out_orient_fine.append(orient_fine_cam.cpu().numpy())                        
        
            if feasible('gradients_head') and feasible('weights'):
                n_samples = self.renderer.n_samples + self.renderer.n_importance
                normals = render_out['gradients_head'] * render_out['weights'][:, :n_samples, None]
                if feasible('inside_sphere'):
                    normals = normals * render_out['inside_sphere'][..., None]

                normals = normals.sum(dim=1).detach().cpu().numpy()
                out_normal_fine.append(normals)

            if feasible('gradients_hair') and feasible('weights'):
                n_samples = self.renderer.n_samples + self.renderer.n_importance
                normals_hair = render_out['gradients_hair'] * render_out['weights'][:, :n_samples, None]
                if feasible('inside_sphere'):
                    normals_hair = normals_hair * render_out['inside_sphere'][..., None]

                normals_hair = normals_hair.sum(dim=1).detach().cpu().numpy()
                out_normal_hair_fine.append(normals_hair)  
                
            del render_out

        img_fine = None
        orient_fine = None
        
        if out_rgb_fine:
            img_fine = (np.concatenate(out_rgb_fine, axis=0).reshape([H, W, 3, -1]) * 255).clip(0, 255)
        if self.orient_weight:     
            if out_orient_fine:
                orient_fine = (np.concatenate(out_orient_fine, axis=0).reshape([H, W, 3, -1]) * 255).clip(0, 255)
        
        normal_img = None
        if out_normal_fine:
            normal_img = np.concatenate(out_normal_fine, axis=0)
            rot = np.linalg.inv(self.dataset.pose_all[idx, :3, :3].detach().cpu().numpy())
            normal_img = (np.matmul(rot[None, :, :], normal_img[:, :, None])
                          .reshape([H, W, 3, -1]) * 128 + 128).clip(0, 255)
        normal_hair_img = None
        if out_normal_hair_fine:
            normal_hair_img = np.concatenate(out_normal_hair_fine, axis=0)
            rot = np.linalg.inv(self.dataset.pose_all[idx, :3, :3].detach().cpu().numpy())
            normal_hair_img = (np.matmul(rot[None, :, :], normal_hair_img[:, :, None])
                               .reshape([H, W, 3, -1]) * 128 + 128).clip(0, 255)
            
        os.makedirs(os.path.join(self.base_exp_dir, 'renders_fine'), exist_ok=True)
        os.makedirs(os.path.join(self.base_exp_dir, 'normals'), exist_ok=True)


        if self.orient_weight: 
            os.makedirs(os.path.join(self.base_exp_dir, 'orients_fine'), exist_ok=True)
            os.makedirs(os.path.join(self.base_exp_dir, 'orients_masked_fine'), exist_ok=True)
        os.makedirs(os.path.join(self.base_exp_dir, 'normals_hair'), exist_ok=True)

        for i in range(img_fine.shape[-1]):
            if out_rgb_fine:
                cv.imwrite(os.path.join(self.base_exp_dir,
                                        'renders_fine',
                                        '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)),
                           np.concatenate([img_fine[..., i],
                                           self.dataset.image_at(idx, resolution_level=resolution_level)]))
            if self.orient_weight: 
                if out_orient_fine:
                    confs = self.dataset.orient_confs_at(idx, resolution_level=resolution_level)
                    orients_gt = self.dataset.orient_at(idx, resolution_level=resolution_level)
                    cv.imwrite(os.path.join(self.base_exp_dir,
                                            'orients_fine',
                                            '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)),
                               np.concatenate([orient_fine[..., i], orients_gt]))

                    # Masked orients
                    orient_fine[..., i] = (orient_fine[..., i] * confs).round().astype('uint8')
                    orients_gt = (orients_gt * confs).round().astype('uint8')
                    cv.imwrite(os.path.join(self.base_exp_dir,
                                            'orients_masked_fine',
                                            '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)),
                               np.concatenate([orient_fine[..., i], orients_gt]))
            if out_normal_fine:
                cv.imwrite(os.path.join(self.base_exp_dir,
                                        'normals',
                                        '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)),
                           normal_img[..., i])

            if out_normal_hair_fine:
                cv.imwrite(os.path.join(self.base_exp_dir,
                                        'normals_hair',
                                        '{:0>8d}_{}_{}.png'.format(self.iter_step, i, idx)),
                           normal_hair_img[..., i])