[merger] move code to merger class
This commit is contained in:
parent
9946c4c72a
commit
f2f1741a77
@ -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.
|
||||
|
||||
@ -347,8 +191,9 @@ def merge_detections(left_data:pd.DataFrame, right_data: pd.DataFrame, left_cut:
|
||||
trickyindices = np.where(np.any((keypoints[:,:,0] < threshold) &
|
||||
(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):
|
||||
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("Filtering detections")
|
||||
left_easy, _ = sort_detections(lkeypoints, left_cut, left=True)
|
||||
right_easy, _ = sort_detections(rkeypoints, 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)
|
||||
@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... %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, _ = 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 = 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))
|
||||
|
||||
filename = "test.pkl"
|
||||
logging.info("Saving/pickling merged file to %s" % filename)
|
||||
with open(filename, 'rb') as f:
|
||||
pickle.dump(export_df, f)
|
||||
@property
|
||||
def signals(self):
|
||||
return self._signals
|
||||
|
||||
logging.info("Merging done!")
|
||||
@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__":
|
||||
|
Loading…
Reference in New Issue
Block a user