Realcat
fix: eloftr
63f3cf2
raw
history blame
18.4 kB
# -*- coding: UTF-8 -*-
'''=================================================
@Project -> File pram -> viewer
@IDE PyCharm
@Author fx221@cam.ac.uk
@Date 05/03/2024 16:50
=================================================='''
import cv2
import numpy as np
import pypangolin as pangolin
from OpenGL.GL import *
import time
import threading
from colmap_utils.read_write_model import qvec2rotmat
from tools.common import resize_image_with_padding
from localization.frame import Frame
class Viewer:
default_config = {
'image_size_indoor': 0.1,
'image_line_width_indoor': 1,
'image_size_outdoor': 1,
'image_line_width_outdoor': 3,
'point_size_indoor': 1,
'point_size_outdoor': 1,
'image_width': 640,
'image_height': 480,
'viewpoint_x': 0,
'viewpoint_y': -1,
'viewpoint_z': -5,
'viewpoint_F': 512,
'scene': 'indoor',
}
def __init__(self, locMap, seg_color, config={}):
self.config = {**self.default_config, **config}
self.viewpoint_x = self.config['viewpoint_x']
self.viewpoint_y = self.config['viewpoint_y']
self.viewpoint_z = self.config['viewpoint_z']
self.viewpoint_F = self.config['viewpoint_F']
self.img_width = self.config['image_width']
self.img_height = self.config['image_height']
if self.config['scene'] == 'indoor':
self.image_size = self.config['image_size_indoor']
self.image_line_width = self.config['image_line_width_indoor']
self.point_size = self.config['point_size_indoor']
else:
self.image_size = self.config['image_size_outdoor']
self.image_line_width = self.config['image_line_width_outdoor']
self.point_size = self.config['point_size_outdoor']
self.viewpoint_z = -150
self.locMap = locMap
self.seg_colors = seg_color
# current camera pose
self.frame = None
self.Tcw = np.eye(4, dtype=float)
self.Twc = np.linalg.inv(self.Tcw)
self.gt_Tcw = None
self.gt_Twc = None
self.scene = None
self.current_vrf_id = None
self.reference_frame_ids = None
self.subMap = None
self.seg_point_clouds = None
self.point_clouds = None
self.start_seg_id = 1
self.stop = False
self.refinement = False
self.tracking = False
# time
self.time_feat = np.NAN
self.time_rec = np.NAN
self.time_loc = np.NAN
self.time_ref = np.NAN
# image
self.image_rec = None
def draw_3d_points_white(self):
if self.point_clouds is None:
return
point_size = self.point_size * 0.5
glColor4f(0.9, 0.95, 1.0, 0.6)
glPointSize(point_size)
pangolin.glDrawPoints(self.point_clouds)
def draw_seg_3d_points(self):
if self.seg_point_clouds is None:
return
for sid in self.seg_point_clouds.keys():
xyzs = self.seg_point_clouds[sid]
point_size = self.point_size * 0.5
bgr = self.seg_colors[sid + self.start_seg_id + 1]
glColor3f(bgr[2] / 255, bgr[1] / 255, bgr[0] / 255)
glPointSize(point_size)
pangolin.glDrawPoints(xyzs)
def draw_ref_3d_points(self, use_seg_color=False):
if self.reference_frame_ids is None:
return
ref_point3D_ids = []
for fid in self.reference_frame_ids:
pids = self.subMap.reference_frames[fid].point3D_ids
ref_point3D_ids.extend(list(pids))
ref_point3D_ids = np.unique(ref_point3D_ids).tolist()
point_size = self.point_size * 5
glPointSize(point_size)
glBegin(GL_POINTS)
for pid in ref_point3D_ids:
if pid not in self.subMap.point3Ds.keys():
continue
xyz = self.subMap.point3Ds[pid].xyz
rgb = self.subMap.point3Ds[pid].rgb
sid = self.subMap.point3Ds[pid].seg_id
if use_seg_color:
bgr = self.seg_colors[sid + self.start_seg_id + 1]
glColor3f(bgr[2] / 255, bgr[1] / 255, bgr[0] / 255)
else:
glColor3f(rgb[0] / 255, rgb[1] / 255, rgb[2] / 255)
glVertex3f(xyz[0], xyz[1], xyz[2])
glEnd()
def draw_vrf_frames(self):
if self.subMap is None:
return
w = self.image_size * 1.0
image_line_width = self.image_line_width * 1.0
h = w * 0.75
z = w * 0.6
for sid in self.subMap.seg_ref_frame_ids.keys():
frame_id = self.subMap.seg_ref_frame_ids[sid][0]
qvec = self.subMap.reference_frames[frame_id].qvec
tcw = self.subMap.reference_frames[frame_id].tvec
Rcw = qvec2rotmat(qvec)
twc = -Rcw.T @ tcw
Rwc = Rcw.T
Twc = np.column_stack((Rwc, twc))
Twc = np.vstack((Twc, (0, 0, 0, 1)))
glPushMatrix()
glMultMatrixf(Twc.T)
glLineWidth(image_line_width)
glColor3f(1, 0, 0)
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(w, h, z)
glVertex3f(0, 0, 0)
glVertex3f(w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(w, -h, z)
glEnd()
glPopMatrix()
def draw_current_vrf_frame(self):
if self.current_vrf_id is None:
return
qvec = self.subMap.reference_frames[self.current_vrf_id].qvec
tcw = self.subMap.reference_frames[self.current_vrf_id].tvec
Rcw = qvec2rotmat(qvec)
twc = -Rcw.T @ tcw
Rwc = Rcw.T
Twc = np.column_stack((Rwc, twc))
Twc = np.vstack((Twc, (0, 0, 0, 1)))
camera_line_width = self.image_line_width * 2
w = self.image_size * 2
h = w * 0.75
z = w * 0.6
glPushMatrix()
glMultMatrixf(Twc.T) # note the .T
glLineWidth(camera_line_width)
glColor3f(1, 0, 0)
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(w, h, z)
glVertex3f(0, 0, 0)
glVertex3f(w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(w, -h, z)
glEnd()
glPopMatrix()
def draw_current_frame(self, Tcw, color=(0, 1.0, 0)):
Twc = np.linalg.inv(Tcw)
camera_line_width = self.image_line_width * 2
w = self.image_size * 2
h = w * 0.75
z = w * 0.6
glPushMatrix()
glMultMatrixf(Twc.T) # not the .T
glLineWidth(camera_line_width)
glColor3f(color[0], color[1], color[2])
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(w, h, z)
glVertex3f(0, 0, 0)
glVertex3f(w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(w, -h, z)
glEnd()
glPopMatrix()
def draw_ref_frames(self):
if self.reference_frame_ids is None:
return
w = self.image_size * 1.5
image_line_width = self.image_line_width * 1.5
h = w * 0.75
z = w * 0.6
for fid in self.reference_frame_ids:
qvec = self.subMap.reference_frames[fid].qvec
tcw = self.subMap.reference_frames[fid].tvec
Rcw = qvec2rotmat(qvec)
twc = -Rcw.T @ tcw
Rwc = Rcw.T
Twc = np.column_stack((Rwc, twc))
Twc = np.vstack((Twc, (0, 0, 0, 1)))
glPushMatrix()
glMultMatrixf(Twc.T)
glLineWidth(image_line_width)
glColor3f(100 / 255, 140 / 255, 17 / 255)
glBegin(GL_LINES)
glVertex3f(0, 0, 0)
glVertex3f(w, h, z)
glVertex3f(0, 0, 0)
glVertex3f(w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, -h, z)
glVertex3f(0, 0, 0)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(-w, h, z)
glVertex3f(w, h, z)
glVertex3f(-w, -h, z)
glVertex3f(w, -h, z)
glEnd()
glPopMatrix()
def terminate(self):
lock = threading.Lock()
lock.acquire()
self.stop = True
lock.release()
def update_point_clouds(self):
# for fast drawing
seg_point_clouds = {}
point_clouds = []
for pid in self.subMap.point3Ds.keys():
sid = self.subMap.point3Ds[pid].seg_id
xyz = self.subMap.point3Ds[pid].xyz
if sid in seg_point_clouds.keys():
seg_point_clouds[sid].append(xyz.reshape(3, 1))
else:
seg_point_clouds[sid] = [xyz.reshape(3, 1)]
point_clouds.append(xyz.reshape(3, 1))
self.seg_point_clouds = seg_point_clouds
self.point_clouds = point_clouds
def update(self, curr_frame: Frame):
lock = threading.Lock()
lock.acquire()
# self.frame = curr_frame
self.current_vrf_id = curr_frame.reference_frame_id
self.reference_frame_ids = [self.current_vrf_id]
# self.reference_frame_ids = curr_frame.refinement_reference_frame_ids
# if self.reference_frame_ids is None:
# self.reference_frame_ids = [self.current_vrf_id]
self.subMap = self.locMap.sub_maps[curr_frame.matched_scene_name]
self.start_seg_id = self.locMap.scene_name_start_sid[curr_frame.matched_scene_name]
if self.scene is None or self.scene != curr_frame.matched_scene_name:
self.scene = curr_frame.matched_scene_name
self.update_point_clouds()
if curr_frame.qvec is not None:
Rcw = qvec2rotmat(curr_frame.qvec)
Tcw = np.column_stack((Rcw, curr_frame.tvec))
self.Tcw = np.vstack((Tcw, (0, 0, 0, 1)))
Rwc = Rcw.T
twc = -Rcw.T @ curr_frame.tvec
Twc = np.column_stack((Rwc, twc))
self.Twc = np.vstack((Twc, (0, 0, 0, 1)))
if curr_frame.gt_qvec is not None:
gt_Rcw = qvec2rotmat(curr_frame.gt_qvec)
gt_Tcw = np.column_stack((gt_Rcw, curr_frame.gt_tvec))
self.gt_Tcw = np.vstack((gt_Tcw, (0, 0, 0, 1)))
gt_Rwc = gt_Rcw.T
gt_twc = -gt_Rcw.T @ curr_frame.gt_tvec
gt_Twc = np.column_stack((gt_Rwc, gt_twc))
self.gt_Twc = np.vstack((gt_Twc, (0, 0, 0, 1)))
else:
self.gt_Tcw = None
self.gt_Twc = None
# update time
self.time_feat = curr_frame.time_feat
self.time_rec = curr_frame.time_rec
self.time_loc = curr_frame.time_loc
self.time_ref = curr_frame.time_ref
# update image
image_rec_inlier = np.hstack([curr_frame.image_rec, curr_frame.image_inlier])
image_rec_inlier = resize_image_with_padding(image=image_rec_inlier, nw=self.img_width * 2, nh=self.img_height)
image_matching = resize_image_with_padding(image=curr_frame.image_matching, nw=self.img_width * 2,
nh=self.img_height)
image_rec_matching_inliers = resize_image_with_padding(image=np.vstack([image_rec_inlier, image_matching]),
nw=self.img_width * 2, nh=self.img_height * 2)
self.image_rec = cv2.cvtColor(image_rec_matching_inliers, cv2.COLOR_BGR2RGB)
lock.release()
def run(self):
pangolin.CreateWindowAndBind("Map reviewer", 640, 480)
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
pangolin.CreatePanel("menu").SetBounds(pangolin.Attach(0),
pangolin.Attach(1),
pangolin.Attach(0),
# pangolin.Attach.Pix(-175),
pangolin.Attach.Pix(175),
# pangolin.Attach(1)
)
menu = pangolin.Var("menu")
menu.Tracking = (False, pangolin.VarMeta(toggle=True))
menu.FollowCamera = (True, pangolin.VarMeta(toggle=True))
menu.ShowPoints = (True, pangolin.VarMeta(toggle=True))
menu.ShowSegs = (False, pangolin.VarMeta(toggle=True))
menu.ShowRefSegs = (True, pangolin.VarMeta(toggle=True))
menu.ShowRefPoints = (False, pangolin.VarMeta(toggle=True))
menu.ShowVRFFrame = (True, pangolin.VarMeta(toggle=True))
menu.ShowAllVRFs = (False, pangolin.VarMeta(toggle=True))
menu.ShowRefFrames = (False, pangolin.VarMeta(toggle=True))
menu.Refinement = (self.refinement, pangolin.VarMeta(toggle=True))
menu.featTime = 'NaN'
menu.recTime = 'NaN'
menu.locTime = 'NaN'
menu.refTime = 'NaN'
menu.totalTime = 'NaN'
pm = pangolin.ProjectionMatrix(640, 480, self.viewpoint_F, self.viewpoint_F, 320, 240, 0.1,
10000)
# /camera position,viewpoint position,axis direction
mv = pangolin.ModelViewLookAt(self.viewpoint_x,
self.viewpoint_y,
self.viewpoint_z,
0, 0, 0,
# 0.0, -1.0, 0.0,
pangolin.AxisZ,
)
s_cam = pangolin.OpenGlRenderState(pm, mv)
# Attach bottom, Attach top, Attach left, Attach right,
scale = 0.42
d_img_rec = pangolin.Display('image_rec').SetBounds(pangolin.Attach(1 - scale),
pangolin.Attach(1),
pangolin.Attach(
1 - 0.3),
pangolin.Attach(1),
self.img_width / self.img_height
) # .SetLock(0, 1)
handler = pangolin.Handler3D(s_cam)
d_cam = pangolin.Display('3D').SetBounds(
pangolin.Attach(0), # bottom
pangolin.Attach(1), # top
pangolin.Attach.Pix(175), # left
# pangolin.Attach.Pix(0), # left
pangolin.Attach(1), # right
-640 / 480, # aspect
).SetHandler(handler)
d_img_rec_texture = pangolin.GlTexture(self.img_width * 2, self.img_height * 2, GL_RGB, False, 0, GL_RGB,
GL_UNSIGNED_BYTE)
while not pangolin.ShouldQuit() and not self.stop:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
# glClearColor(1.0, 1.0, 1.0, 1.0)
glClearColor(0.0, 0.0, 0.0, 1.0)
d_cam.Activate(s_cam)
if menu.FollowCamera:
s_cam.Follow(pangolin.OpenGlMatrix(self.Twc.astype(np.float32)), follow=True)
# pangolin.glDrawColouredCube()
if menu.ShowPoints:
self.draw_3d_points_white()
if menu.ShowRefPoints:
self.draw_ref_3d_points(use_seg_color=False)
if menu.ShowRefSegs:
self.draw_ref_3d_points(use_seg_color=True)
if menu.ShowSegs:
self.draw_seg_3d_points()
if menu.ShowAllVRFs:
self.draw_vrf_frames()
if menu.ShowRefFrames:
self.draw_ref_frames()
if menu.ShowVRFFrame:
self.draw_current_vrf_frame()
if menu.Refinement:
self.refinement = True
else:
self.refinement = False
if menu.Tracking:
self.tracking = True
else:
self.tracking = False
self.draw_current_frame(Tcw=self.Tcw)
if self.gt_Tcw is not None: # draw gt pose with color (0, 0, 1.0)
self.draw_current_frame(Tcw=self.gt_Tcw, color=(0., 0., 1.0))
d_img_rec.Activate()
glColor4f(1, 1, 1, 1)
if self.image_rec is not None:
d_img_rec_texture.Upload(self.image_rec, GL_RGB, GL_UNSIGNED_BYTE)
d_img_rec_texture.RenderToViewportFlipY()
time_total = 0
if self.time_feat != np.NAN:
menu.featTime = '{:.2f}s'.format(self.time_feat)
time_total = time_total + self.time_feat
if self.time_rec != np.NAN:
menu.recTime = '{:.2f}s'.format(self.time_rec)
time_total = time_total + self.time_rec
if self.time_loc != np.NAN:
menu.locTime = '{:.2f}s'.format(self.time_loc)
time_total = time_total + self.time_loc
if self.time_ref != np.NAN:
menu.refTime = '{:.2f}s'.format(self.time_ref)
time_total = time_total + self.time_ref
menu.totalTime = '{:.2f}s'.format(time_total)
time.sleep(50 / 1000)
pangolin.FinishFrame()