Compare commits

...

4 Commits

6 changed files with 71 additions and 15 deletions

View File

@ -8,6 +8,7 @@ class DetectionData(Enum):
COORDINATES = 2
TRACK_ID = 3
USERLABELED = 4
SCORE = 5
class Tracks(Enum):
TRACKONE = 1

View File

@ -135,6 +135,16 @@ class ConsistencyWorker(QRunnable):
del detections[lowest_dist]
return detections
def find_last_userlabeled(startframe):
t1index = np.where((self.frames < startframe) & (self.userlabeled) & (self.tracks == 1))[0][-1]
t2index = np.where((self.frames < startframe) & (self.userlabeled) & (self.tracks == 2))[0][-1]
d1 = Detection(t1index, self.frames[t1index], self.tracks[t1index], self.positions[t1index],
self.orientations[t1index], self.lengths[t1index], self.userlabeled[t1index])
d2 = Detection(t1index, self.frames[t2index], self.tracks[t2index], self.positions[t2index],
self.orientations[t2index], self.lengths[t2index], self.userlabeled[t2index])
last_detections[1] = d1
last_detections[2] = d2
unique_frames = np.unique(self.frames)
steps = int((len(unique_frames) - self._startframe) // 100)
errors = 0
@ -142,6 +152,7 @@ class ConsistencyWorker(QRunnable):
progress = 0
self._stoprequest = False
last_detections = {1: None, 2: None, -1: None}
find_last_userlabeled(self._startframe)
for f in unique_frames[unique_frames >= self._startframe]:
if self._stoprequest:
@ -188,7 +199,7 @@ class ConsistencyWorker(QRunnable):
continue
if error and self._stoponerror:
self.signals.message.emit("Tracking stopped at frame %i.", f)
self.signals.message.emit(f"Tracking stopped at frame {f}.")
break
elif error:
continue
@ -559,8 +570,11 @@ class ConsistencyClassifier(QWidget):
self._messagebox.append("Error preparing data! Make sure that the first user-labeled frames contain both tracks!")
self.setEnabled(False)
return
max_startframe = np.min([t1_userlabeled[-1], t2_userlabeled[-1]])
min_startframe = np.max([t1_userlabeled[0], t2_userlabeled[0]])
max_startframe = np.min([t1_userlabeled[-1], t2_userlabeled[-1]]) -1
first_guess = np.max([t1_userlabeled[0], t2_userlabeled[0]])
while first_guess not in t1_userlabeled or first_guess not in t2_userlabeled:
first_guess += 1
min_startframe = first_guess + 1
self._maxframes = np.max(self._frames)
self._maxframeslabel.setText(str(self._maxframes))
self._startframe_spinner.setMinimum(min_startframe)

View File

@ -10,6 +10,7 @@ from fixtracks.utils.signals import DetectionSignals, DetectionViewSignals, Dete
from fixtracks.utils.enums import DetectionData, Tracks
from fixtracks.utils.trackingdata import TrackingData
class Detection(QGraphicsEllipseItem):
signals = DetectionSignals()
@ -138,10 +139,11 @@ class DetectionView(QWidget):
coordinates = self._data.coordinates(selection=True)
centercoordinates = self._data.centerOfGravity(selection=True)
userlabeled = self._data.selectedData("userlabeled")
scores = self._data.selectedData("confidence")
image_rect = self._pixmapitem.boundingRect() if self._pixmapitem is not None else QRectF(0,0,0,0)
for i, (id, f, t, l) in enumerate(zip(ids, frames, tracks, userlabeled)):
for i, (id, f, t, l, s) in enumerate(zip(ids, frames, tracks, userlabeled, scores)):
c = Tracks.fromValue(t).toColor()
if keypoint >= 0:
x = coordinates[i, keypoint, 0]
@ -155,7 +157,10 @@ class DetectionView(QWidget):
item.setData(DetectionData.ID.value, id)
item.setData(DetectionData.COORDINATES.value, coordinates[i, :, :])
item.setData(DetectionData.FRAME.value, f)
item.setData(DetectionData.USERLABELED.value, l)
# item.setData(DetectionData.USERLABELED.value, l)
item.setData(DetectionData.SCORE.value, s)
print(s)
print(item.data(DetectionData.SCORE.value))
item = self._scene.addItem(item)
def fit_image_to_view(self):
@ -214,7 +219,7 @@ def main():
view.setImage(img)
view.addDetections(bg_coords, bg_tracks, bg_ids, background_brush)
view.addDetections(focus_coords, focus_tracks, focus_ids, focus_brush)
view.addDetections(scnd_coords, scnd_tracks, scnd_ids, second_brush)
view.addDetections(scnd_coords, scnd_tracks, scnd_ids, second_brush)
window.setLayout(layout)
window.show()
app.exec()

View File

@ -52,7 +52,6 @@ class SelectionControls(QWidget):
quarterstepBackBtn.setStyleSheet(pushBtnStyle("darkgray"))
quarterstepBackBtn.clicked.connect(lambda: self.on_Back(quarterstep))
fwdBtn = QPushButton(">>|")
fwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
fwdBtn.setShortcut(Qt.Key.Key_Right)
@ -173,7 +172,7 @@ class SelectionControls(QWidget):
grid.setColumnStretch(0, 1)
grid.setColumnStretch(7, 1)
self.setLayout(grid)
self.setMaximumSize(QSize(500, 500))
# self.setMaximumSize(QSize(500, 500))
def setWindow(self, start:int=0, end:int=0):
self.startframe.setText(f"{start:.0f}")

View File

@ -94,7 +94,8 @@ class SkeletonWidget(QWidget):
i = s.data(DetectionData.ID.value)
t = s.data(DetectionData.TRACK_ID.value)
f = s.data(DetectionData.FRAME.value)
self._info_label.setText(f"Id {i}, track {t} on frame {f}, length {l:.1f} px")
sc = s.data(DetectionData.SCORE.value)
self._info_label.setText(f"Id {i}, track {t} on frame {f}, length {l:.1f} px, confidence {sc:.2f}")
else:
self._info_label.setText("")
@ -129,7 +130,7 @@ class SkeletonWidget(QWidget):
self._scene.setSceneRect(self._minx, self._miny, self._maxx - self._minx, self._maxy - self._miny)
self._view.fitInView(self._scene.sceneRect(), Qt.AspectRatioMode.KeepAspectRatio)
def addSkeleton(self, coords, detection_id, frame, track, brush, update=True):
def addSkeleton(self, coords, detection_id, frame, track, score, brush, update=True):
def check_extent(x, y, w, h):
if x == 0 and y == 0:
return
@ -157,12 +158,14 @@ class SkeletonWidget(QWidget):
item.setData(DetectionData.ID.value, detection_id)
item.setData(DetectionData.TRACK_ID.value, track)
item.setData(DetectionData.FRAME.value, frame)
item.setData(DetectionData.SCORE.value, score)
self._skeletons.append(item)
if update:
self.update()
def addSkeletons(self, coordinates:np.ndarray, detection_ids:np.ndarray,
frames:np.ndarray, tracks:np.ndarray, brush:QBrush):
frames:np.ndarray, tracks:np.ndarray, scores:np.ndarray,
brush:QBrush):
num_detections = 0 if coordinates is None else coordinates.shape[0]
logging.debug("SkeletonWidget: add %i Skeletons", num_detections)
if num_detections < 1:
@ -172,9 +175,10 @@ class SkeletonWidget(QWidget):
detection_ids = detection_ids[sorting]
frames = frames[sorting]
tracks = tracks[sorting]
scores = scores[sorting]
for i in range(num_detections):
self.addSkeleton(coordinates[i,:,:], detection_ids[i], frames[i],
tracks[i], brush=brush, update=False)
tracks[i], scores[i], brush=brush, update=False)
self.update()
# def addSkeleton(self, coords, detection_id, brush):

View File

@ -55,12 +55,23 @@ class FixTracks(QWidget):
self._keypointcombo = QComboBox()
self._keypointcombo.currentIndexChanged.connect(self.on_keypointSelected)
self._gotoframe = QSpinBox()
self._gotoframe.setSingleStep(1)
self._gotobtn = QPushButton("go!")
self._gotobtn.setToolTip("Jump to a given frame")
self._gotobtn.clicked.connect(self.on_goto)
combo_layout = QHBoxLayout()
combo_layout.addWidget(QLabel("Window width:"))
combo_layout.addWidget(self._windowspinner)
combo_layout.addWidget(QLabel("frames"))
combo_layout.addItem(QSpacerItem(10, 10, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed))
combo_layout.addWidget(QLabel("Keypoint:"))
combo_layout.addWidget(self._keypointcombo)
combo_layout.addItem(QSpacerItem(10, 10, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed))
combo_layout.addWidget(QLabel("Jump to frame:"))
combo_layout.addWidget(self._gotoframe)
combo_layout.addWidget(self._gotobtn)
combo_layout.addItem(QSpacerItem(100, 10, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed))
timelinebox = QVBoxLayout()
@ -159,15 +170,19 @@ class FixTracks(QWidget):
self._detectionView.setImage(img)
def update(self):
kp = self._keypointcombo.currentText().lower()
if len(kp) == 0:
return
kpi = -1 if "center" in kp else int(kp)
start_frame = self._currentWindowPos
stop_frame = start_frame + self._currentWindowWidth
self._timeline.setWindow(start_frame / self._maxframes,
self._currentWindowWidth/self._maxframes)
logging.debug("Tracks:update: Updating View for detection range %i, %i frames", start_frame, stop_frame)
self._data.setSelectionRange("frame", start_frame, stop_frame)
self._controls_widget.setWindow(start_frame, stop_frame)
kp = self._keypointcombo.currentText().lower()
kpi = -1 if "center" in kp else int(kp)
self._detectionView.updateDetections(kpi)
@property
@ -210,6 +225,7 @@ class FixTracks(QWidget):
self._currentWindowPos = 0
self._currentWindowWidth = self._windowspinner.value()
self._maxframes = np.max(self._data["frame"])
self._gotoframe.setMaximum(self._maxframes)
self.populateKeypointCombo(self._data.numKeypoints())
self._timeline.setData(self._data)
# self._timeline.setWindow(self._currentWindowPos / self._maxframes,
@ -333,11 +349,22 @@ class FixTracks(QWidget):
self._timeline.setWindowWidth(self._currentWindowWidth / self._maxframes)
self._controls_widget.setSelectedTracks(None)
def on_goto(self):
target = self._gotoframe.value()
if target > self._maxframes - self._currentWindowWidth:
target = self._maxframes - self._currentWindowWidth
logging.info("Jump to frame %i", target)
self._currentWindowPos = target
self._timeline.setWindow(self._currentWindowPos / self._maxframes,
self._currentWindowWidth / self._maxframes)
self.update()
def on_detectionsSelected(self, detections):
logging.debug("Tracks: %i Detections selected", len(detections))
tracks = np.zeros(len(detections), dtype=int)
ids = np.zeros_like(tracks)
frames = np.zeros_like(tracks)
scores = np.zeros_like(tracks)
coordinates = None
if len(detections) > 0:
c = detections[0].data(DetectionData.COORDINATES.value)
@ -348,15 +375,21 @@ class FixTracks(QWidget):
ids[i] = d.data(DetectionData.ID.value)
frames[i] = d.data(DetectionData.FRAME.value)
coordinates[i, :, :] = d.data(DetectionData.COORDINATES.value)
scores[i] = d.data(DetectionData.SCORE.value)
print(scores[i])
self._data.setSelection(ids)
self._controls_widget.setSelectedTracks(tracks)
self._skeleton.clear()
self._skeleton.addSkeletons(coordinates, ids, frames, tracks, QBrush(QColor(10, 255, 65, 255)))
self._skeleton.addSkeletons(coordinates, ids, frames, tracks, scores, QBrush(QColor(10, 255, 65, 255)))
def moveWindow(self, stepsize):
logging.info("Tracks.moveWindow: move window with stepsize %.2f", stepsize)
self._manualmove = True
new_start_frame = self._currentWindowPos + np.round(stepsize * self._currentWindowWidth)
if new_start_frame < 0:
new_start_frame = 0
elif new_start_frame + self._currentWindowWidth > self._maxframes:
new_start_frame = self._maxframes - self._currentWindowWidth
self._currentWindowPos = new_start_frame
self._controls_widget.setSelectedTracks(None)
self.update()