diff --git a/README.md b/README.md index efed3c4..8e4dcec 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ If you leave away the ```--user``` the package will be installed system-wide. ## TrackingResults -Is a class that wraps around the *.h5 files written by DeppLabCut +Is a class that wraps around the *.h5 files written by DeepLabCut ## ImageMarker diff --git a/etrack/distance_calibration.py b/etrack/distance_calibration.py new file mode 100644 index 0000000..c859b9e --- /dev/null +++ b/etrack/distance_calibration.py @@ -0,0 +1,185 @@ +from cv2 import calibrationMatrixValues +import matplotlib.pyplot as plt +import numpy as np +import cv2 +import os +import sys +from IPython import embed + + +class DistanceCalibration: + + def __init__(self, file_name, x_0=95, y_0=185, cam_dist=1.36, width=1.35, height=0.805, width_pixel=1975, height_pixel=1375, checkerboard_width=0.24, checkerboard_height=0.18, + checkerboard_width_pixel=500, checkerboard_height_pixel=350, rectangle_width=0.024, rectangle_height=0.0225, rectangle_width_pixel=100, rectangle_height_pixel=90, + rectangle_count_width=9, rectangle_count_height=7) -> None: + # aktualisieren + """Calibration of the dimensions of the tank. Conversion of pixel into meter. Width refers to the "x-axis", height to the "y-axis" of the tank. + + Args: + file_name (_type_): _description_ + x_0 (int, optional): X-value of the "origin" of the tank. Defaults to 0. + y_0 (int, optional): Y-value of the "origin" of the tank. Defaults to 0. + cam_dist (int, optional): Distance of camera lense to tank floor. Defaults to 1.36. + width (int, optional): Width in meter from one lightened corner of the tank to the other. Defaults to 1.35. + heigth (int, optional): Height in meter from one lightened corner of the tank to the other. Defaults to 1.35. + width_pixel (int, optional): Width in pixel from one lightened corner of the tank to the other. Defaults to 1975. + height_pixel (int, optional): Heigth in pixel from one lightened corner of the tank to the other. Defaults to 1375. + rectangle_width (float, optional): Width of one black or corresponding white rectangle of the checkerboard. Defaults to 0.024. + rectangle_height (float, optional): Height of one black or corresponding white rectangle of the checkerboard. Defaults to 0.0225. + rectangle_count_width (int, optional): Number of black rectangles over the width of the whole checkerboard. Defaults to 9. + rectangle_count_height (int, optional): Number of black rectangles over the height of the whole checkerboard. Defaults to 7. + """ + + self._file_name = file_name + self._x_0 = x_0 + self._y_0 = y_0 + self._width_pix = width_pixel + self._height_pix = height_pixel + self._cam_dist = cam_dist + self._width = width + self._height = height + self._cb_width = checkerboard_width + self._cb_height = checkerboard_height + self._cb_width_pix = checkerboard_width_pixel + self._cb_height_pix = checkerboard_height_pixel + self._rect_width = rectangle_width + self._rect_height = rectangle_height + self._x_factor = self.width / self.width_pix # m/pix + self._y_factor = self.height / self.height_pix # m/pix + + # properties + @property + def x_0(self): + return self._x_0 + + @property + def y_0(self): + return self._y_0 + + @property + def cam_dist(self): + return self._cam_dist + + @property + def width(self): + return self._width + + @property + def height(self): + return self._height + + @property + def width_pix(self): + return self._width_pix + + @property + def height_pix(self): + return self._height_pix + + @property + def x_factor(self): + return self._x_factor + + @property + def y_factor(self): + return self._y_factor + + + def crop_movie(): + if not os.path.exists(filename): + raise IOError("file %s does not exist!" % filename) + video = cv2.VideoCapture() + video.open(filename) + frame_counter = 0 + success = True + frame = None + while success and frame_counter <= frame_number: # iterating until frame_counter == frame_number --> success (True) + print("Reading frame: %i" % frame_counter, end="\r") + success, frame = video.read() + frame_counter += 1 + if success: + self._fig.gca().imshow(frame) # plot wanted frame of video + else: + print("Could not read frame number %i either failed to open movie or beyond maximum frame number!" % frame_number) + return [] + plt.ion() # turn on interactive mode + plt.show(block=False) # block=False allows to continue interact in terminal while the figure is open + + self._task_index = -1 + if len(self._tasks) > 0: + self._next_task() + + while not self._tasks_done: + plt.pause(0.250) + if self._interrupt: + return [] + + self._fig.gca().set_title("All set and done!\n Window will close in 2s") + self._fig.canvas.draw() + plt.pause(2.0) + plt.close() + return [t.marker_positions for t in self._tasks] + + + def mark_checkerboard(self, filename, frame_number=10): + if not os.path.exists(filename): + raise IOError("file %s does not exist!" % filename) + video = cv2.VideoCapture() + video.open(filename) + frame_counter = 0 + success = True + frame = None + + x_0 = self._x_0 + y_0 = self._y_0 + width_pix = self._width_pix + height_pix = self._height_pix + + while success and frame_counter <= frame_number: # iterating until frame_counter == frame_number --> success (True) + print("Reading frame: %i" % frame_counter, end="\r") + success, frame = video.read() + frame_counter += 1 + width_mean = np.mean(frame,axis=1) + crop_width_mean = width_mean[x_0:width_pix] + + height_mean = np.mean(frame,axis=0) + crop_height_mean = height_mean[y_0:height_pix] +# HELLO, here you at + + embed() + quit() + if success: + self._fig.gca().imshow(frame) # plot wanted frame of video + else: + print("Could not read frame number %i either failed to open movie or beyond maximum frame number!" % frame_number) + return [] + plt.ion() # turn on interactive mode + plt.show(block=False) # block=False allows to continue interact in terminal while the figure is open + + self._task_index = -1 + if len(self._tasks) > 0: + self._next_task() + + while not self._tasks_done: + plt.pause(0.250) + if self._interrupt: + return [] + + self._fig.gca().set_title("All set and done!\n Window will close in 2s") + self._fig.canvas.draw() + plt.pause(2.0) + plt.close() + return [t.marker_positions for t in self._tasks] + + +if __name__ == "__main__": + vid2 = "/home/efish/etrack/videos/2022.03.28_3.mp4" + calibration_task = DistanceCalibration(vid2) + dc = DistanceCalibration(calibration_task) + dc.mark_checkerboard(vid2, 10) + + # print(sys.argv[0]) + # print (sys.argv[1]) + # vid1 = sys.argv[1] + + embed() \ No newline at end of file diff --git a/etrack/image_marker.py b/etrack/image_marker.py index 8ad7bad..82ca605 100644 --- a/etrack/image_marker.py +++ b/etrack/image_marker.py @@ -1,4 +1,6 @@ +from cv2 import calibrationMatrixValues import matplotlib.pyplot as plt +import numpy as np import cv2 import os import sys @@ -19,6 +21,19 @@ class ImageMarker: self._fig.canvas.mpl_connect('key_press_event', self._key_press_event) def mark_movie(self, filename, frame_number=0): + """ Interactive GUI to mark the corners of the tank. A specific frame of the video can be chosen. Returns marker positions. + + Args: + filename: Videofile + frame_number (int, optional): Number of a frame in the videofile. Defaults to 0. + + Raises: + IOError: File does not exist. + + Returns: + marker_positions: Marker positions of tank corners. + """ + if not os.path.exists(filename): raise IOError("file %s does not exist!" % filename) video = cv2.VideoCapture() @@ -26,17 +41,17 @@ class ImageMarker: frame_counter = 0 success = True frame = None - while success and frame_counter <= frame_number: + while success and frame_counter <= frame_number: # iterating until frame_counter == frame_number --> success (True) print("Reading frame: %i" % frame_counter, end="\r") success, frame = video.read() frame_counter += 1 if success: - self._fig.gca().imshow(frame) + self._fig.gca().imshow(frame) # plot wanted frame of video else: print("Could not read frame number %i either failed to open movie or beyond maximum frame number!" % frame_number) return [] - plt.ion() - plt.show(block=False) + plt.ion() # turn on interactive mode + plt.show(block=False) # block=False allows to continue interact in terminal while the figure is open self._task_index = -1 if len(self._tasks) > 0: @@ -50,6 +65,7 @@ class ImageMarker: self._fig.gca().set_title("All set and done!\n Window will close in 2s") self._fig.canvas.draw() plt.pause(2.0) + plt.close() return [t.marker_positions for t in self._tasks] def _key_press_event(self, event): @@ -141,11 +157,15 @@ class MarkerTask(): if __name__ == "__main__": tank_task = MarkerTask("tank limits", ["bottom left corner", "top left corner", "top right corner", "bottom right corner"], "Mark tank corners") feeder_task = MarkerTask("Feeder positions", list(map(str, range(1, 2))), "Mark feeder positions") - tasks = [tank_task, feeder_task] + tasks = [tank_task] # feeder_task] im = ImageMarker(tasks) - # vid1 = "2020.12.11_lepto48DLC_resnet50_boldnessDec11shuffle1_200000_labeled.mp4" - print(sys.argv[0]) - print (sys.argv[1]) - vid1 = sys.argv[1] - marker_positions = im.mark_movie(vid1, 10) - print(marker_positions) \ No newline at end of file + + vid1 = "/home/efish/efish_tracking/efish_tracking3-Xaver-2022-03-21/videos/2022.01.12_3DLC_resnet50_efish_tracking3Mar21shuffle1_300000_labeled.mp4" + marker_positions = im.mark_movie(vid1, 100) + print(marker_positions) + + # print(sys.argv[0]) + # print (sys.argv[1]) + # vid1 = sys.argv[1] + + embed() \ No newline at end of file