raft update
This commit is contained in:
+54
-36
@@ -25,7 +25,7 @@ class Tracker:
|
|||||||
self.__frame_count = 0
|
self.__frame_count = 0
|
||||||
dis_preset = config_tracker["dis_preset"]
|
dis_preset = config_tracker["dis_preset"]
|
||||||
loop_closure_interval = config_tracker["loop_closure_interval"]
|
loop_closure_interval = config_tracker["loop_closure_interval"]
|
||||||
if not cuda:
|
if not self.cuda:
|
||||||
# DIS method - optimize for speed
|
# DIS method - optimize for speed
|
||||||
if dis_preset == 'ultrafast':
|
if dis_preset == 'ultrafast':
|
||||||
preset = cv2.DISOPTICAL_FLOW_PRESET_ULTRAFAST
|
preset = cv2.DISOPTICAL_FLOW_PRESET_ULTRAFAST
|
||||||
@@ -53,9 +53,10 @@ class Tracker:
|
|||||||
self.__lower_threshold = config_tracker["lower_threshold"] # error lower than threshold will close the loop
|
self.__lower_threshold = config_tracker["lower_threshold"] # error lower than threshold will close the loop
|
||||||
self.__upper_threshold = config_tracker["upper_threshold"] # error greater than threshold will add new reference frame
|
self.__upper_threshold = config_tracker["upper_threshold"] # error greater than threshold will add new reference frame
|
||||||
### RAFT
|
### RAFT
|
||||||
self.__raft_model = self.setup_simple_raft()
|
|
||||||
self.__raft_device = "cuda" if torch.cuda.is_available() else "cpu"
|
self.__raft_device = "cuda" if torch.cuda.is_available() else "cpu"
|
||||||
|
self.__raft_model = self.setup_simple_raft()
|
||||||
self.__raft_ref_frame = None
|
self.__raft_ref_frame = None
|
||||||
|
self.__raft_ref_tensor = None
|
||||||
|
|
||||||
|
|
||||||
def track(self, frame):
|
def track(self, frame):
|
||||||
@@ -232,61 +233,78 @@ class Tracker:
|
|||||||
self.__fine_flow_queue = []
|
self.__fine_flow_queue = []
|
||||||
self.__prev_fine_flow = None
|
self.__prev_fine_flow = None
|
||||||
self.__frame_count = 0
|
self.__frame_count = 0
|
||||||
|
self.__raft_ref_frame = None
|
||||||
|
self.__raft_ref_tensor = None
|
||||||
|
|
||||||
def getFrameQueueLength(self):
|
def getFrameQueueLength(self):
|
||||||
return len(self.__fine_base_frame_queue)
|
return len(self.__fine_base_frame_queue)
|
||||||
|
|
||||||
### RAFT ###
|
### RAFT ###
|
||||||
|
|
||||||
def preprocess(self,batch, resize=None):
|
|
||||||
"""
|
|
||||||
Preprocess image batch for RAFT model.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
batch: Tensor of shape (N, C, H, W)
|
|
||||||
resize: Optional tuple (height, width) to resize. If None, keeps original size.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Preprocessed tensor
|
|
||||||
"""
|
|
||||||
transform_list = [
|
|
||||||
T.ConvertImageDtype(torch.float32),
|
|
||||||
T.Normalize(mean=0.5, std=0.5), # map [0, 1] into [-1, 1]
|
|
||||||
]
|
|
||||||
|
|
||||||
if resize is not None:
|
|
||||||
transform_list.append(T.Resize(size=resize))
|
|
||||||
|
|
||||||
transforms = T.Compose(transform_list)
|
|
||||||
batch = transforms(batch)
|
|
||||||
return batch
|
|
||||||
|
|
||||||
def setup_simple_raft(self):
|
def setup_simple_raft(self):
|
||||||
"""
|
"""
|
||||||
Setup a simpler version using available models
|
Setup a simpler version using available models
|
||||||
"""
|
"""
|
||||||
model = raft_large(pretrained=True, progress=False).to('cuda')
|
# Load model and move to GPU
|
||||||
|
model = raft_large(pretrained=True, progress=False).to(self.__raft_device)
|
||||||
model = model.eval()
|
model = model.eval()
|
||||||
# Alternative: Use LiteFlowNet (lighter alternative)
|
|
||||||
print("RAFT loaded successfully")
|
print(f"RAFT model loaded on {self.__raft_device}")
|
||||||
return model
|
return model
|
||||||
|
|
||||||
|
def _preprocess_frame_to_tensor(self, frame, resize=None):
|
||||||
|
"""Efficiently convert numpy frame to RAFT-ready tensor"""
|
||||||
|
# Upload to device as uint8 first to save bandwidth
|
||||||
|
# permute returns a view, but from_numpy usually shares memory.
|
||||||
|
# Moving to GPU as uint8 is fast.
|
||||||
|
tensor = torch.from_numpy(frame).permute(2, 0, 1).to(self.__raft_device)
|
||||||
|
|
||||||
|
# Convert to float and normalize on device
|
||||||
|
tensor = tensor.float() / 255.0
|
||||||
|
|
||||||
|
# Resize if needed
|
||||||
|
if resize is not None:
|
||||||
|
tensor = T.Resize(resize)(tensor)
|
||||||
|
|
||||||
|
# Normalize to [-1, 1]
|
||||||
|
tensor = (tensor - 0.5) * 2.0
|
||||||
|
|
||||||
|
# Add batch dimension
|
||||||
|
tensor = tensor.unsqueeze(0)
|
||||||
|
|
||||||
|
# Keep in float32 - autocast will handle mixed precision during inference
|
||||||
|
return tensor
|
||||||
|
|
||||||
def track_raft(self, frame):
|
def track_raft(self, frame):
|
||||||
|
# No need to copy if we just read
|
||||||
|
# frame is expected to be (H, W, 3) or (H, W)
|
||||||
|
|
||||||
|
if frame.ndim == 2:
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
|
||||||
|
elif frame.shape[2] == 4:
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2RGB)
|
||||||
|
elif frame.shape[2] == 3:
|
||||||
|
# Assume BGR input from OpenCV
|
||||||
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
|
||||||
gray = frame.copy()
|
|
||||||
if self.__raft_ref_frame is None:
|
if self.__raft_ref_frame is None:
|
||||||
self.__raft_ref_frame = gray.copy()
|
self.__raft_ref_frame = frame # Keep reference for potential debug/CPU use
|
||||||
prev_frame = self.__raft_ref_frame
|
# Cache the processed tensor to avoid re-processing reference frame every time
|
||||||
|
self.__raft_ref_tensor = self._preprocess_frame_to_tensor(frame)
|
||||||
|
|
||||||
prev_tensor = torch.from_numpy(prev_frame.transpose(2, 0, 1).astype(np.float32) / 255.0)
|
prev_tensor = self.__raft_ref_tensor
|
||||||
curr_tensor = torch.from_numpy(gray.transpose(2, 0, 1).astype(np.float32) / 255.0)
|
curr_tensor = self._preprocess_frame_to_tensor(frame)
|
||||||
prev_tensor = self.preprocess(prev_tensor.unsqueeze(0), resize=None).to(self.__raft_device)
|
|
||||||
curr_tensor = self.preprocess(curr_tensor.unsqueeze(0), resize=None).to(self.__raft_device)
|
# Use autocast for automatic mixed precision (FP16 where supported, FP32 where needed)
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
|
if self.__raft_device == 'cuda':
|
||||||
|
with torch.amp.autocast('cuda'):
|
||||||
|
flow = self.__raft_model(prev_tensor, curr_tensor)
|
||||||
|
else:
|
||||||
flow = self.__raft_model(prev_tensor, curr_tensor)
|
flow = self.__raft_model(prev_tensor, curr_tensor)
|
||||||
predicted_flows = flow[-1]
|
predicted_flows = flow[-1]
|
||||||
|
|
||||||
flow_np = predicted_flows[0].cpu().numpy() # or .squeeze(0)
|
flow_np = predicted_flows[0].float().cpu().numpy() # Convert back to float32 for numpy
|
||||||
|
|
||||||
# Transpose to (H, W, 2) format expected by draw_arrows
|
# Transpose to (H, W, 2) format expected by draw_arrows
|
||||||
flow_np = flow_np.transpose(1, 2, 0) # (2, H, W) -> (H, W, 2)
|
flow_np = flow_np.transpose(1, 2, 0) # (2, H, W) -> (H, W, 2)
|
||||||
|
|||||||
Reference in New Issue
Block a user