def fit_cube(max_iter          = 5000,
             resolution        = 4, 
             discontinuous     = False,
             repeats           = 1,
             log_interval      = 10, 
             display_interval  = None,
             display_res       = 512,
             out_dir           = '.',
             log_fn            = None,
             imgsave_interval  = None,
             imgsave_fn        = None):

    if out_dir:
        os.makedirs(out_dir, exist_ok=True)
    
    datadir = f'{pathlib.Path(__file__).absolute().parents[1]}/data'
    fn = 'cube_%s.npz' % ('d' if discontinuous else 'c')
    with np.load(f'{datadir}/{fn}') as f:
        pos_idx, vtxp, col_idx, vtxc = f.values()
    print("Mesh has %d triangles and %d vertices." % (pos_idx.shape[0], vtxp.shape[0]))
        
    # Transformation matrix input to TF graph.
    mtx_in = tf.placeholder(tf.float32, [4, 4])

    # Setup TF graph for reference.
    vtxw = np.concatenate([vtxp, np.ones([vtxp.shape[0], 1])], axis=1).astype(np.float32)
    pos_clip = tf.matmul(vtxw, mtx_in, transpose_b=True)[tf.newaxis, ...]
    rast_out, _ = dr.rasterize(pos_clip, pos_idx, resolution=[resolution, resolution], output_db=False)
    color, _ = dr.interpolate(vtxc[tf.newaxis, ...], rast_out, col_idx)
    color = dr.antialias(color, rast_out, pos_clip, pos_idx)

    # Optimized variables.
    vtxc_opt = tf.get_variable('vtxc', initializer=tf.zeros_initializer(), shape=vtxc.shape)
    vtxp_opt = tf.get_variable('vtxp', initializer=tf.zeros_initializer(), shape=vtxp.shape)

    # Optimization variable setters for initialization.
    vtxc_opt_in = tf.placeholder(tf.float32, vtxc.shape)
    vtxp_opt_in = tf.placeholder(tf.float32, vtxp.shape)
    opt_set = tf.group(tf.assign(vtxc_opt, vtxc_opt_in), tf.assign(vtxp_opt, vtxp_opt_in))

    # Setup TF graph for what we optimize result.
    vtxw_opt = tf.concat([vtxp_opt, tf.ones([vtxp.shape[0], 1], tf.float32)], axis=1)
    pos_clip_opt = tf.matmul(vtxw_opt, mtx_in, transpose_b=True)[tf.newaxis, ...]
    rast_out_opt, _ = dr.rasterize(pos_clip_opt, pos_idx, resolution=[resolution, resolution], output_db=False)
    color_opt, _ = dr.interpolate(vtxc_opt[tf.newaxis, ...], rast_out_opt, col_idx)
    color_opt = dr.antialias(color_opt, rast_out_opt, pos_clip_opt, pos_idx)

    # Image-space loss and optimizer.
    loss = tf.reduce_mean((color_opt - color)**2)
    lr_in = tf.placeholder(tf.float32, [])
    train_op = tf.train.AdamOptimizer(lr_in, 0.9, 0.999).minimize(loss, var_list=[vtxp_opt, vtxc_opt])

    # Setup TF graph for display.
    rast_out_disp, _ = dr.rasterize(pos_clip_opt, pos_idx, resolution=[display_res, display_res], output_db=False)
    color_disp, _ = dr.interpolate(vtxc_opt[tf.newaxis, ...], rast_out_disp, col_idx)
    color_disp = dr.antialias(color_disp, rast_out_disp, pos_clip_opt, pos_idx)
    rast_out_disp_ref, _ = dr.rasterize(pos_clip, pos_idx, resolution=[display_res, display_res], output_db=False)
    color_disp_ref, _ = dr.interpolate(vtxc[tf.newaxis, ...], rast_out_disp_ref, col_idx)
    color_disp_ref = dr.antialias(color_disp_ref, rast_out_disp_ref, pos_clip, pos_idx)

    # Geometric error calculation
    geom_loss = tf.reduce_mean(tf.reduce_sum((tf.abs(vtxp_opt) - .5)**2, axis=1)**0.5)

    # Open log file.
    log_file = open(out_dir + '/' + log_fn, 'wt') if log_fn else None

    # Repeats.
    for rep in range(repeats):

        # Optimize.
        ang = 0.0
        gl_avg = []
        util.init_uninitialized_vars()
        for it in range(max_iter + 1):
            # Initialize optimization.
            if it == 0:
                vtxp_init = np.random.uniform(-0.5, 0.5, size=vtxp.shape) + vtxp
                vtxc_init = np.random.uniform(0.0, 1.0, size=vtxc.shape)
                util.run(opt_set, {vtxc_opt_in: vtxc_init.astype(np.float32), vtxp_opt_in: vtxp_init.astype(np.float32)})

            # Learning rate ramp.
            lr = 1e-2
            lr = lr * max(0.01, 10**(-it*0.0005))

            # Random rotation/translation matrix for optimization.
            r_rot = util.random_rotation_translation(0.25)

            # Smooth rotation for display.
            a_rot = np.matmul(util.rotate_x(-0.4), util.rotate_y(ang))

            # Modelview and modelview + projection matrices.
            proj  = util.projection(x=0.4)
            r_mv  = np.matmul(util.translate(0, 0, -3.5), r_rot)
            r_mvp = np.matmul(proj, r_mv).astype(np.float32)
            a_mv  = np.matmul(util.translate(0, 0, -3.5), a_rot)
            a_mvp = np.matmul(proj, a_mv).astype(np.float32)
        
            # Run training and measure geometric error.
            gl_val, _ = util.run([geom_loss, train_op], {mtx_in: r_mvp, lr_in: lr})
            gl_avg.append(gl_val)

            # Print/save log.
            if log_interval and (it % log_interval == 0):
                gl_val, gl_avg = np.mean(np.asarray(gl_avg)), []
                s = ("rep=%d," % rep) if repeats > 1 else ""
                s += "iter=%d,err=%f" % (it, gl_val)
                print(s)
                if log_file:
                    log_file.write(s + "\n")

            # Show/save image.
            display_image = display_interval and (it % display_interval == 0)
            save_image = imgsave_interval and (it % imgsave_interval == 0)

            if display_image or save_image:
                ang = ang + 0.1
                img_o = util.run(color_opt,      {mtx_in: r_mvp})[0]
                img_b = util.run(color,          {mtx_in: r_mvp})[0]
                img_d = util.run(color_disp,     {mtx_in: a_mvp})[0]
                img_r = util.run(color_disp_ref, {mtx_in: a_mvp})[0]

                scl = display_res // img_o.shape[0]
                img_b = np.repeat(np.repeat(img_b, scl, axis=0), scl, axis=1)
                img_o = np.repeat(np.repeat(img_o, scl, axis=0), scl, axis=1)
                result_image = np.concatenate([img_o, img_b, img_d, img_r], axis=1)

            if display_image:
                util.display_image(result_image, size=display_res, title='%d / %d' % (it, max_iter))
            if save_image:
                util.save_image(out_dir + '/' + (imgsave_fn % it), result_image)

    # All repeats done.
    if log_file:
        log_file.close()
def fit_earth(max_iter=20000,
              log_interval=10,
              display_interval=None,
              display_res=1024,
              enable_mip=True,
              res=512,
              ref_res=4096,
              lr_base=1e-2,
              lr_ramp=0.1,
              out_dir='.',
              log_fn=None,
              texsave_interval=None,
              texsave_fn=None,
              imgsave_interval=None,
              imgsave_fn=None):

    if out_dir:
        os.makedirs(out_dir, exist_ok=True)

    # Mesh and texture adapted from "3D Earth Photorealistic 2K" model at
    # https://www.turbosquid.com/3d-models/3d-realistic-earth-photorealistic-2k-1279125
    datadir = f'{pathlib.Path(__file__).absolute().parents[1]}/data'
    with np.load(f'{datadir}/earth.npz') as f:
        pos_idx, pos, uv_idx, uv, tex = f.values()
    tex = tex.astype(np.float32) / 255.0
    max_mip_level = 9  # Texture is a 4x3 atlas of 512x512 maps.
    print("Mesh has %d triangles and %d vertices." %
          (pos_idx.shape[0], pos.shape[0]))

    # Transformation matrix input to TF graph.
    mtx_in = tf.placeholder(tf.float32, [4, 4])

    # Learned texture.
    tex_var = tf.get_variable('tex',
                              initializer=tf.constant_initializer(0.2),
                              shape=tex.shape)

    # Setup TF graph for reference rendering in high resolution.
    pos_clip = tf.matmul(pos, mtx_in, transpose_b=True)[tf.newaxis, ...]
    rast_out, rast_out_db = dr.rasterize(pos_clip, pos_idx, [ref_res, ref_res])
    texc, texd = dr.interpolate(uv[tf.newaxis, ...],
                                rast_out,
                                uv_idx,
                                rast_db=rast_out_db,
                                diff_attrs='all')
    color = dr.texture(tex[np.newaxis],
                       texc,
                       texd,
                       filter_mode='linear-mipmap-linear',
                       max_mip_level=max_mip_level)
    color = color * tf.clip_by_value(rast_out[..., -1:], 0,
                                     1)  # Mask out background.

    # Reduce the reference to correct size.
    while color.shape[1] > res:
        color = util.bilinear_downsample(color)

    # TF Graph for rendered candidate.
    if enable_mip:
        # With mipmaps.
        rast_out_opt, rast_out_db_opt = dr.rasterize(pos_clip, pos_idx,
                                                     [res, res])
        texc_opt, texd_opt = dr.interpolate(uv[tf.newaxis, ...],
                                            rast_out_opt,
                                            uv_idx,
                                            rast_db=rast_out_db_opt,
                                            diff_attrs='all')
        color_opt = dr.texture(tex_var[np.newaxis],
                               texc_opt,
                               texd_opt,
                               filter_mode='linear-mipmap-linear',
                               max_mip_level=max_mip_level)
    else:
        # No mipmaps: no image-space derivatives anywhere.
        rast_out_opt, _ = dr.rasterize(pos_clip,
                                       pos_idx, [res, res],
                                       output_db=False)
        texc_opt, _ = dr.interpolate(uv[tf.newaxis, ...], rast_out_opt, uv_idx)
        color_opt = dr.texture(tex_var[np.newaxis],
                               texc_opt,
                               filter_mode='linear')
    color_opt = color_opt * tf.clip_by_value(rast_out_opt[..., -1:], 0,
                                             1)  # Mask out background.

    # Measure only relevant portions of texture when calculating texture PSNR.
    loss = tf.reduce_mean((color - color_opt)**2)
    texmask = np.zeros_like(tex)
    tr = tex.shape[1] // 4
    texmask[tr + 13:2 * tr - 13, 25:-25, :] += 1.0
    texmask[25:-25, tr + 13:2 * tr - 13, :] += 1.0
    texloss = (tf.reduce_sum(texmask * (tex - tex_var)**2) /
               np.sum(texmask))**0.5  # RMSE within masked area.

    # Training driven by image-space loss.
    lr_in = tf.placeholder(tf.float32, [])
    train_op = tf.train.AdamOptimizer(lr_in, 0.9,
                                      0.99).minimize(loss, var_list=[tex_var])

    # Open log file.
    log_file = open(out_dir + '/' + log_fn, 'wt') if log_fn else None

    # Render.
    ang = 0.0
    util.init_uninitialized_vars()
    texloss_avg = []
    for it in range(max_iter + 1):
        lr = lr_base * lr_ramp**(float(it) / float(max_iter))

        # Random rotation/translation matrix for optimization.
        r_rot = util.random_rotation_translation(0.25)

        # Smooth rotation for display.
        ang = ang + 0.01
        a_rot = np.matmul(util.rotate_x(-0.4), util.rotate_y(ang))
        dist = np.random.uniform(0.0, 48.5)

        # Modelview and modelview + projection matrices.
        proj = util.projection(x=0.4, n=1.0, f=200.0)
        r_mv = np.matmul(util.translate(0, 0, -1.5 - dist), r_rot)
        r_mvp = np.matmul(proj, r_mv).astype(np.float32)
        a_mv = np.matmul(util.translate(0, 0, -3.5), a_rot)
        a_mvp = np.matmul(proj, a_mv).astype(np.float32)

        # Run training and measure texture-space RMSE loss.
        texloss_val, _ = util.run([texloss, train_op], {
            mtx_in: r_mvp,
            lr_in: lr
        })
        texloss_avg.append(texloss_val)

        # Print/save log.
        if log_interval and (it % log_interval == 0):
            texloss_val, texloss_avg = np.mean(np.asarray(texloss_avg)), []
            psnr = -10.0 * np.log10(texloss_val**
                                    2)  # PSNR based on average RMSE.
            s = "iter=%d,loss=%f,psnr=%f" % (it, texloss_val, psnr)
            print(s)
            if log_file:
                log_file.write(s + '\n')

        # Show/save result images/textures.
        display_image = display_interval and (it % display_interval) == 0
        save_image = imgsave_interval and (it % imgsave_interval) == 0
        save_texture = texsave_interval and (it % texsave_interval) == 0

        if display_image or save_image:
            result_image = util.run(color_opt, {mtx_in: a_mvp})[0]
        if display_image:
            util.display_image(result_image,
                               size=display_res,
                               title='%d / %d' % (it, max_iter))
        if save_image:
            util.save_image(out_dir + '/' + (imgsave_fn % it), result_image)
        if save_texture:
            util.save_image(out_dir + '/' + (texsave_fn % it),
                            util.run(tex_var)[::-1])

    # Done.
    if log_file:
        log_file.close()
def fit_env_phong(max_iter=1000,
                  log_interval=10,
                  display_interval=None,
                  display_res=1024,
                  res=1024,
                  lr_base=1e-2,
                  lr_ramp=1.0,
                  out_dir='.',
                  log_fn=None,
                  imgsave_interval=None,
                  imgsave_fn=None):

    if out_dir:
        os.makedirs(out_dir, exist_ok=True)

    # Texture adapted from https://github.com/WaveEngine/Samples/tree/master/Materials/EnvironmentMap/Content/Assets/CubeMap.cubemap
    datadir = f'{pathlib.Path(__file__).absolute().parents[1]}/data'
    with np.load(f'{datadir}/envphong.npz') as f:
        pos_idx, pos, normals, env = f.values()
    env = env.astype(np.float32) / 255.0
    print("Mesh has %d triangles and %d vertices." %
          (pos_idx.shape[0], pos.shape[0]))

    # Target Phong parameters.
    phong_rgb = np.asarray([1.0, 0.8, 0.6], np.float32)
    phong_exp = 25.0

    # Inputs to TF graph.
    mtx_in = tf.placeholder(tf.float32, [4, 4])
    invmtx_in = tf.placeholder(tf.float32, [4, 4])  # Inverse.
    campos_in = tf.placeholder(tf.float32,
                               [3])  # Camera position in world space.
    lightdir_in = tf.placeholder(tf.float32, [3])  # Light direction.

    # Learned variables: environment maps, phong color, phong exponent.
    env_var = tf.get_variable('env_var',
                              initializer=tf.constant_initializer(0.5),
                              shape=env.shape)
    phong_var_raw = tf.get_variable('phong_var',
                                    initializer=tf.random_uniform_initializer(
                                        0.0, 1.0),
                                    shape=[4])  # R, G, B, exp.
    phong_var = phong_var_raw * [1.0, 1.0, 1.0, 10.0
                                 ]  # Faster learning rate for the exponent.

    # Transform and rasterize.
    viewvec = pos[..., :3] - campos_in[
        np.newaxis, np.newaxis, :]  # View vectors at vertices.
    reflvec = viewvec - 2.0 * normals[tf.newaxis, ...] * tf.reduce_sum(
        normals[tf.newaxis, ...] * viewvec, axis=-1,
        keepdims=True)  # Reflection vectors at vertices.
    reflvec = reflvec / tf.reduce_sum(reflvec**2, axis=-1,
                                      keepdims=True)**0.5  # Normalize.
    pos_clip = tf.matmul(pos, mtx_in, transpose_b=True)[tf.newaxis, ...]
    rast_out, rast_out_db = dr.rasterize(pos_clip, pos_idx, [res, res])
    refl, refld = dr.interpolate(
        reflvec, rast_out, pos_idx, rast_db=rast_out_db,
        diff_attrs='all')  # Interpolated reflection vectors.

    # Phong light.
    refl = refl / tf.reduce_sum(refl**2, axis=-1,
                                keepdims=True)**0.5  # Normalize.
    ldotr = tf.reduce_sum(-lightdir_in * refl, axis=-1,
                          keepdims=True)  # L dot R.

    # Reference color. No need for AA because we are not learning geometry.
    env = np.stack(env)[:, ::-1]
    color = dr.texture(env[np.newaxis, ...],
                       refl,
                       refld,
                       filter_mode='linear-mipmap-linear',
                       boundary_mode='cube')
    color = tf.reduce_sum(tf.stack(color), axis=0)
    color = color + phong_rgb * tf.maximum(0.0, ldotr)**phong_exp  # Phong.
    color = tf.maximum(
        color,
        1.0 - tf.clip_by_value(rast_out[..., -1:], 0, 1))  # White background.

    # Candidate rendering same up to this point, but uses learned texture and Phong parameters instead.
    color_opt = dr.texture(env_var[tf.newaxis, ...],
                           refl,
                           uv_da=refld,
                           filter_mode='linear-mipmap-linear',
                           boundary_mode='cube')
    color_opt = tf.reduce_sum(tf.stack(color_opt), axis=0)
    color_opt = color_opt + phong_var[:3] * tf.maximum(
        0.0, ldotr)**phong_var[3]  # Phong.
    color_opt = tf.maximum(
        color_opt,
        1.0 - tf.clip_by_value(rast_out[..., -1:], 0, 1))  # White background.

    # Training.
    loss = tf.reduce_mean((color - color_opt)**2)  # L2 pixel loss.
    lr_in = tf.placeholder(tf.float32, [])
    train_op = tf.train.AdamOptimizer(lr_in, 0.9, 0.99).minimize(
        loss, var_list=[env_var, phong_var_raw])

    # Open log file.
    log_file = open(out_dir + '/' + log_fn, 'wt') if log_fn else None

    # Render.
    ang = 0.0
    util.init_uninitialized_vars()
    imgloss_avg, phong_avg = [], []
    for it in range(max_iter + 1):
        lr = lr_base * lr_ramp**(float(it) / float(max_iter))

        # Random rotation/translation matrix for optimization.
        r_rot = util.random_rotation_translation(0.25)

        # Smooth rotation for display.
        ang = ang + 0.01
        a_rot = np.matmul(util.rotate_x(-0.4), util.rotate_y(ang))

        # Modelview and modelview + projection matrices.
        proj = util.projection(x=0.4, n=1.0, f=200.0)
        r_mv = np.matmul(util.translate(0, 0, -3.5), r_rot)
        r_mvp = np.matmul(proj, r_mv).astype(np.float32)
        a_mv = np.matmul(util.translate(0, 0, -3.5), a_rot)
        a_mvp = np.matmul(proj, a_mv).astype(np.float32)

        # Solve camera positions.
        a_campos = np.linalg.inv(a_mv)[:3, 3]
        r_campos = np.linalg.inv(r_mv)[:3, 3]

        # Random light direction.
        lightdir = np.random.normal(size=[3])
        lightdir /= np.linalg.norm(lightdir) + 1e-8

        # Run training and measure image-space RMSE loss.
        imgloss_val, phong_val, _ = util.run(
            [loss, phong_var, train_op], {
                mtx_in: r_mvp,
                invmtx_in: np.linalg.inv(r_mvp),
                campos_in: r_campos,
                lightdir_in: lightdir,
                lr_in: lr
            })
        imgloss_avg.append(imgloss_val**0.5)
        phong_avg.append(phong_val)

        # Print/save log.
        if log_interval and (it % log_interval == 0):
            imgloss_val, imgloss_avg = np.mean(
                np.asarray(imgloss_avg, np.float32)), []
            phong_val, phong_avg = np.mean(np.asarray(phong_avg, np.float32),
                                           axis=0), []
            phong_rgb_rmse = np.mean((phong_val[:3] - phong_rgb)**2)**0.5
            phong_exp_rel_err = np.abs(phong_val[3] - phong_exp) / phong_exp
            s = "iter=%d,phong_rgb_rmse=%f,phong_exp_rel_err=%f,img_rmse=%f" % (
                it, phong_rgb_rmse, phong_exp_rel_err, imgloss_val)
            print(s)
            if log_file:
                log_file.write(s + '\n')

        # Show/save result image.
        display_image = display_interval and (it % display_interval == 0)
        save_image = imgsave_interval and (it % imgsave_interval == 0)

        if display_image or save_image:
            result_image = util.run(
                color_opt, {
                    mtx_in: a_mvp,
                    invmtx_in: np.linalg.inv(a_mvp),
                    campos_in: a_campos,
                    lightdir_in: lightdir
                })[0]
        if display_image:
            util.display_image(result_image,
                               size=display_res,
                               title='%d / %d' % (it, max_iter))
        if save_image:
            util.save_image(out_dir + '/' + (imgsave_fn % it), result_image)

    # Done.
    if log_file:
        log_file.close()
def fit_pose(max_iter=10000,
             repeats=1,
             log_interval=10,
             display_interval=None,
             display_res=512,
             lr_base=0.01,
             lr_falloff=1.0,
             nr_base=1.0,
             nr_falloff=1e-4,
             grad_phase_start=0.5,
             resolution=256,
             out_dir='.',
             log_fn=None,
             imgsave_interval=None,
             imgsave_fn=None):

    if out_dir:
        os.makedirs(out_dir, exist_ok=True)

    datadir = f'{pathlib.Path(__file__).absolute().parents[1]}/data'
    with np.load(f'{datadir}/cube_p.npz') as f:
        pos_idx, pos, col_idx, col = f.values()
    print("Mesh has %d triangles and %d vertices." %
          (pos_idx.shape[0], pos.shape[0]))

    # Transformation matrix input to TF graph.
    mtx_in = tf.placeholder(tf.float32, [4, 4])

    # Pose matrix input to TF graph.
    pose_in = tf.placeholder(tf.float32, [4])  # Quaternion.
    noise_in = tf.placeholder(tf.float32, [4])  # Mollification noise.

    # Setup TF graph for reference.
    mtx_total = tf.matmul(mtx_in, q_to_mtx_tf(pose_in))
    pos_clip = tf.matmul(pos, mtx_total, transpose_b=True)[tf.newaxis, ...]
    rast_out, _ = dr.rasterize(pos_clip,
                               pos_idx,
                               resolution=[resolution, resolution],
                               output_db=False)
    color, _ = dr.interpolate(col[tf.newaxis, ...], rast_out, col_idx)
    color = dr.antialias(color, rast_out, pos_clip, pos_idx)

    # Setup TF graph for optimization candidate.
    pose_var = tf.get_variable('pose',
                               initializer=tf.zeros_initializer(),
                               shape=[4])
    pose_var_in = tf.placeholder(tf.float32, [4])
    pose_set = tf.assign(pose_var, pose_var_in)
    pose_norm_op = tf.assign(
        pose_var,
        pose_var / tf.reduce_sum(pose_var**2)**0.5)  # Normalization operation.
    pose_total = q_mul_tf(pose_var, noise_in)
    mtx_total_opt = tf.matmul(mtx_in, q_to_mtx_tf(pose_total))
    pos_clip_opt = tf.matmul(pos, mtx_total_opt, transpose_b=True)[tf.newaxis,
                                                                   ...]
    rast_out_opt, _ = dr.rasterize(pos_clip_opt,
                                   pos_idx,
                                   resolution=[resolution, resolution],
                                   output_db=False)
    color_opt, _ = dr.interpolate(col[tf.newaxis, ...], rast_out_opt, col_idx)
    color_opt = dr.antialias(color_opt, rast_out_opt, pos_clip_opt, pos_idx)

    # Image-space loss.
    diff = (color_opt - color)**2  # L2 norm.
    diff = tf.tanh(5.0 *
                   tf.reduce_max(diff, axis=-1))  # Add some oomph to the loss.
    loss = tf.reduce_mean(diff)
    lr_in = tf.placeholder(tf.float32, [])
    train_op = tf.train.AdamOptimizer(lr_in, 0.9,
                                      0.999).minimize(loss,
                                                      var_list=[pose_var])

    # Open log file.
    log_file = open(out_dir + '/' + log_fn, 'wt') if log_fn else None

    # Repeats.
    for rep in range(repeats):

        # Optimize.
        util.init_uninitialized_vars()
        loss_best = np.inf
        pose_best = None
        for it in range(max_iter + 1):
            # Modelview + projection matrix.
            mvp = np.matmul(util.projection(x=0.4),
                            util.translate(0, 0, -3.5)).astype(np.float32)

            # Learning and noise rate scheduling.
            itf = 1.0 * it / max_iter
            lr = lr_base * lr_falloff**itf
            nr = nr_base * nr_falloff**itf

            # Noise input.
            if itf >= grad_phase_start:
                noise = q_unit()
            else:
                noise = q_scale(q_rnd(), nr)
                noise = q_mul(noise, q_rnd_S4())  # Orientation noise.

            # Initialize optimization.
            if it == 0:
                pose_target = q_rnd()
                util.run(pose_set, {pose_var_in: q_rnd()})
                util.run(pose_norm_op)
                util.run(loss, {
                    mtx_in: mvp,
                    pose_in: pose_target,
                    noise_in: noise
                })  # Pipecleaning pass.

            # Run gradient training step.
            if itf >= grad_phase_start:
                util.run(train_op, {
                    mtx_in: mvp,
                    pose_in: pose_target,
                    noise_in: noise,
                    lr_in: lr
                })
                util.run(pose_norm_op)

            # Measure image-space loss and update best found pose.
            loss_val = util.run(loss, {
                mtx_in: mvp,
                pose_in: pose_target,
                noise_in: noise,
                lr_in: lr
            })
            if loss_val < loss_best:
                pose_best = util.run(pose_total, {noise_in: noise})
                if loss_val > 0.0:
                    loss_best = loss_val
            else:
                # Return to best pose in the greedy phase.
                if itf < grad_phase_start:
                    util.run(pose_set, {pose_var_in: pose_best})

            # Print/save log.
            if log_interval and (it % log_interval == 0):
                err = q_angle_deg(util.run(pose_var), pose_target)
                ebest = q_angle_deg(pose_best, pose_target)
                s = "rep=%d,iter=%d,err=%f,err_best=%f,loss=%f,loss_best=%f,lr=%f,nr=%f" % (
                    rep, it, err, ebest, loss_val, loss_best, lr, nr)
                print(s)
                if log_file:
                    log_file.write(s + "\n")

            # Show/save image.
            display_image = display_interval and (it % display_interval == 0)
            save_image = imgsave_interval and (it % imgsave_interval == 0)

            if display_image or save_image:
                img_ref, img_opt = util.run([color, color_opt], {
                    mtx_in: mvp,
                    pose_in: pose_target,
                    noise_in: noise
                })
                img_best, = util.run([color_opt], {
                    mtx_in: mvp,
                    pose_in: pose_best,
                    noise_in: q_unit()
                })
                img_ref = img_ref[0]
                img_opt = img_opt[0]
                img_best = img_best[0]
                result_image = np.concatenate([img_ref, img_best, img_opt],
                                              axis=1)

            if display_image:
                util.display_image(result_image,
                                   size=display_res,
                                   title='(%d) %d / %d' % (rep, it, max_iter))
            if save_image:
                util.save_image(out_dir + '/' + (imgsave_fn % (rep, it)),
                                result_image)

    # All repeats done.
    if log_file:
        log_file.close()
Beispiel #5
0
import imageio
import logging
import os
import numpy as np
import tensorflow as tf
import nvdiffrast.tensorflow as dr

# Silence deprecation warnings and debug level logging
logging.getLogger('tensorflow').setLevel(logging.ERROR)
os.environ.setdefault('TF_CPP_MIN_LOG_LEVEL', '1')

pos = tf.convert_to_tensor(
    [[[-0.8, -0.8, 0, 1], [0.8, -0.8, 0, 1], [-0.8, 0.8, 0, 1]]],
    dtype=tf.float32)
col = tf.convert_to_tensor([[[1, 0, 0], [0, 1, 0], [0, 0, 1]]],
                           dtype=tf.float32)
tri = tf.convert_to_tensor([[0, 1, 2]], dtype=tf.int32)

rast, _ = dr.rasterize(pos, tri, resolution=[256, 256])
out, _ = dr.interpolate(col, rast, tri)

with tf.Session() as sess:
    img = sess.run(out)

img = img[0, ::-1, :, :]  # Flip vertically.
img = np.clip(np.rint(img * 255), 0,
              255).astype(np.uint8)  # Quantize to np.uint8

print("Saving to 'tri.png'.")
imageio.imsave('tri.png', img)