[merger] move code to merger class

This commit is contained in:
Jan Grewe 2025-01-17 15:07:11 +01:00
parent 9946c4c72a
commit f2f1741a77

View File

@ -14,6 +14,7 @@ class ProducerSignals(QObject):
# start = pyqtSignal(float)
# running = pyqtSignal()
progress = pyqtSignal(float)
progress2 = pyqtSignal((str, float, float))
class ImageReader(QRunnable):
@ -97,6 +98,9 @@ class Merger(QRunnable):
self._right_cut = right_cut
self._result = None
self._stopRequest = False
self._merged = None
self._current_task = ""
self._mergeprogress = 0.0
for df in [self._left_data, self._right_data]:
if not self.check_dataframe(df):
self.signals.error.emit("Merger.__init__: Error checking DataFrame structure!")
@ -132,166 +136,6 @@ class Merger(QRunnable):
numpy.ndarray
2D array, Coordinates of the bounding box for each detection. Shape: (num_detections, 4) x1, y1, x2, y2
"""
key_columns = [c for c in df.columns if "key_" in c]
box_columns = [c for c in df.columns if "box_" in c]
num_detections = len(df)
num_keypoints = len(key_columns)
dimensions = 2
keypoints = np.empty((num_detections, num_keypoints, dimensions))
visibility = np.empty((num_detections, num_keypoints))
boxcoordinates = np.empty((num_detections, 4))
for i, row in df.iterrows():
for j, k in enumerate(key_columns):
key_data = row[k]
l = list(map(float, list(key_data[1:-1].split(","))))
keypoints[i, j, :] = l
for j, b in enumerate(box_columns):
boxcoordinates[i, j] = row[b]
if isinstance(row["visible"], str):
vis = list(map(float, row["visible"][1:-1].split()))
visibility[i, :] = vis
else:
visibility[i, :] = row["visible"]
return keypoints, visibility, boxcoordinates
def sort_detections(self, keypoints, threshold, left=True):
"""Categorize the detections into those that are easy (not in the visual overlap zone) and those that are tricky, i.e. right across the threshold.
Detections beyond threshold can be discarded, those across the threshold need to be treated separately.
Parameters
----------
keypoints : np.ndarray
3d array of keypoint coordinates (num detections, num keypoints, (x,y))
threshold : int
the threshold line at which the data should be merged
left : bool, optional
whether or not the data is from the left side, controls how the threshold is interpreted, by default True
Returns
-------
np.ndarray
The indices of the easy detections
np.ndarray
The tricky detections
"""
if left:
easyindeces = np.where(np.all(keypoints[:,:,0] < threshold, axis=1))[0]
trickyindices = np.where(np.any((keypoints[:,:,0] >= threshold) &
(keypoints[:,:,0] < threshold), axis=1))[0]
else:
easyindeces = np.where(np.all(keypoints[:,:,0] >= threshold, axis=1))[0]
trickyindices = np.where(np.any((keypoints[:,:,0] < threshold) &
(keypoints[:,:,0] >= threshold), axis=1))[0]
return easyindeces, trickyindices
@pyqtSlot()
def stop_request(self):
self._stopRequest = True
@pyqtSlot()
def run(self):
max_frames = len(self._left_data) + len(self._right_data)
logging.debug("Cutting left detections to limit %i", self.left_cut)
self.signals.progress.emit(0.1)
lkeypoints, lquality, lbox = self.to_numpy(self._left_data)
self.signals.progress.emit(0.2)
lframes = self._left_data.frame.values
led, ltd = self.sort_detections(lkeypoints, self.left_cut, left=True)
self.signals.progress.emit(0.3)
logging.debug("Cutting right detections to limit %i", self._right_cut_cut)
rkeypoints, rquality, rbox = self.to_numpy(self.right_data)
rframes = self.right_data.frame.values
red, rtd = self.sort_detections(rkeypoints, self.right_cut, left=False)
rkeypoints[:, :, 0] += (self.left_cut - self.right_cut)
# here we need to decide what to do with these data points, trust the left, or trust the right perspective?
# we could also discard them. unless it is a lot of data points, not much harm will be done...
# next step after handling the tricky ones is to export the data again to pandas? nixtrack?
# 1. the right coordinates have to adapted! x - right_threshold + left_threshold!
embed()
exit()
# logging.debug("Merger: running merge for %i frames", max_frames)
# self._stopRequest = False
# max_frames = max(self._left_data.frame.max(), self._right_data.frame.max())
# step = max_frames // 100
# self._result = pd.DataFrame(columns=self._left_data.columns)
# for frame in range(max_frames):
# if self._stopRequest:
# break
# lf = self._left_data[self._left_data.frame == frame]
# rf = self._right_data[self._right_data.frame == frame]
# merge_frame(lf, rf, self._left_cut, self._right_cut, self._result)
# if frame % step == 0:
# self.signals.progress.emit(frame/max_frames)
# time.sleep(0.01)
self._signals.finished.emit(True and (not self._stopRequest))
@property
def signals(self):
return self._signals
@property
def result(self):
return self._result
def merge_frames(left, right, leftcut, rightcut, destination):
# for
pass
def check_frame(frame, cut, left=True):
"""checks whether the detected object is (partially) in the overlapping zone of the two cameras.
A frame is 'ok' if the box is not in the danger zone.
Parameters
----------
frame : pd.Series,
a row of the DataFrame
cut : int
The cut x-position
left : bool, optional
whether we are looking at the right or left frame, by default True
Returns
-------
bool
whether or not the
"""
if left:
return not (frame.box_x1 > cut or frame.box_x2 > cut) # any of the box coordinates is beyond the cut
else:
return not (frame.box_x1 < cut or frame.box_x2 < cut)
def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut: int, right_cut: int) ->pd.DataFrame:
"""Merge the key-point detections based on the left and right video. Key-points with x-coordinates beyond each of the limits (left and right cut) are discarded.
How to merge the detections WITHIN one of the fish detections???
Parameters
----------
left_data : pd.DataFrame
Detections based on the left video
right_data : pd.DataFrame
Detections based on the right video.
left_cut : int
Where to cut off and discard the detected key points.
right_cut : int
Where to cut off and discard the detected key points.
Returns
-------
pd.DataFrame
merged detections of left and right data
"""
def check_dataframe(df):
return True
def to_numpy(df):
logging.info("Converting to numpy ...")
key_columns = [c for c in df.columns if "key_" in c]
box_columns = [c for c in df.columns if "box_" in c]
@ -314,10 +158,10 @@ def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut:
visibility[i, :] = vis
else:
visibility[i, :] = row["visible"]
logging.debug("Converting to numpy done!")
logging.info("Converting to numpy done!")
return keypoints, visibility, boxcoordinates
def sort_detections(keypoints, threshold, left=True):
def sort_detections(self, keypoints, threshold, left=True):
"""Categorize the detections into those that are easy (not in the visual overlap zone) and those that are tricky, i.e. right across the threshold.
Detections beyond threshold are ignored, those across the threshold need to be treated separately.
@ -348,7 +192,8 @@ def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut:
(keypoints[:,:,0] >= threshold), axis=1))[0]
return easyindeces, trickyindices
def select_and_transform(df, keypoints, boxes, quality, frames, valid_detections, left_threshold=None, right_threshold=None):
def select_and_transform(self, df, keypoints, boxes, quality, frames, valid_detections,
left_threshold=None, right_threshold=None):
keypoints = keypoints[valid_detections, :, :]
boxes = boxes[valid_detections, :]
quality = quality[valid_detections, :]
@ -360,8 +205,8 @@ def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut:
return df, keypoints, quality, boxes, frames
def to_dataframe(old_left, old_right, lkeypoints, rkeypoints, lboxes, rboxes, lqualities, rqualities, lframes, rframes):
def to_dataframe(self, old_left, old_right, lkeypoints, rkeypoints, lboxes, rboxes,
lqualities, rqualities, lframes, rframes):
frames = np.concatenate([lframes, rframes])
sorting = np.argsort(frames)
frames = frames[sorting]
@ -391,31 +236,53 @@ def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut:
df = pd.DataFrame(d)
return df
def save(self, filename):
if self._merged is None:
logging.error("Saving/pickling merged dataFrame is None!")
return
logging.info("Saving/pickling merged file to %s" % filename)
with open(filename, 'rb') as f:
pickle.dump(self._merged, f)
@pyqtSlot()
def stop_request(self):
self._stopRequest = True
logging.info("Cutting left detections to limit %i", left_cut)
if not check_dataframe(left_data) or not check_dataframe(right_data):
@pyqtSlot()
def run(self):
logging.info("Cutting left detections to limit %i", self._left_cut)
self.signals.progress2.emit("Merging", self._mergeprogress, 0.)
if not self.check_dataframe(self._left_data) or not self.check_dataframe(self._right_data):
logging.error("Left or right dataframe structure does not match my expectations")
return None
logging.info("Converting to numpy %i", left_cut)
lkeypoints, lquality, lbox = to_numpy(left_data)
rkeypoints, rquality, rbox = to_numpy(right_data)
lframes = left_data.frame.values
rframes = right_data.frame.values
logging.info("Converting to numpy... %s", "Left camera")
lkeypoints, lquality, lbox = self.to_numpy(self._left_data)
logging.info("Converting to numpy... %s", "Right camera")
rkeypoints, rquality, rbox = self.to_numpy(self._right_data)
lframes = self._left_data.frame.values
rframes = self._right_data.frame.values
logging.info("Filtering detections")
left_easy, _ = sort_detections(lkeypoints, left_cut, left=True)
right_easy, _ = sort_detections(rkeypoints, right_cut, left=False)
left_easy, _ = self.sort_detections(lkeypoints, self._left_cut, left=True)
right_easy, _ = self.sort_detections(rkeypoints, self._right_cut, left=False)
logging.info("Merging and transformation")
ldf, lkeypoints, lquality, lboxes, lframes = select_and_transform(left_data, lkeypoints, lbox, lquality, lframes, left_easy)
rdf, rkeypoints, rquality, rboxes, rframes = select_and_transform(right_data, rkeypoints, rbox, rquality, rframes, right_easy, left_cut, right_cut)
export_df = to_dataframe(ldf, rdf, lkeypoints, rkeypoints, lboxes, rboxes, lquality, rquality, lframes, rframes)
filename = "test.pkl"
logging.info("Saving/pickling merged file to %s" % filename)
with open(filename, 'rb') as f:
pickle.dump(export_df, f)
ldf, lkeypoints, lquality, lboxes, lframes = self.select_and_transform(self._left_data, lkeypoints, lbox,
lquality, lframes, left_easy)
rdf, rkeypoints, rquality, rboxes, rframes = self.select_and_transform(self._right_data, rkeypoints, rbox,
rquality, rframes, right_easy,
self._left_cut, self._right_cut)
self._merged = self.to_dataframe(ldf, rdf, lkeypoints, rkeypoints, lboxes, rboxes, lquality, rquality,
lframes, rframes)
logging.info("Merging done!")
self._signals.finished.emit(True and (not self._stopRequest))
@property
def signals(self):
return self._signals
@property
def result(self):
return self._result
def main():
@ -423,7 +290,9 @@ def main():
left = pd.read_csv("../data/left_tracks.csv", sep=";", index_col=0)
logging.info("Loading data right")
right = pd.read_csv("../data/right_tracks.csv", sep=";", index_col=0)
merge_detections(left, right, 2000, 300)
# merge_detections(left, right, 2000, 300)
merger = Merger(left, right, 2000, 300 )
merger.run()
if __name__ == "__main__":