Giter Club home page Giter Club logo

deepfly3d's Introduction

Markerless Multi-view Motion Capture for Tethered Drosophila

Code style: black License: GPL v3 PyPI version

Alt text

DeepFly3D is a PyTorch and PyQT5 implementation of 2D-3D tethered Drosophila pose estimation. It aims to provide an interface for pose estimation and to permit further correction of 2D pose estimates, which are automatically converted to 3D pose.

DeepFly3D does not require a calibration pattern, it enforces geometric constraints using pictorial structures, which corrects most of the errors, and the remaining errors are automatically detected can be dealt manually with GUI.

We previously published our DeepFly3D work on eLife journal. You can read the publication here.

Table of Contents

Installing

Installing with pip

Create a new anaconda environment, and pip install nely-df3d package.

conda create -n df3d python=3.6
conda activate df3d
pip install nely-df3d

Odd CUDA Drivers

Only in case your cuda driver is not up-to-date, or is not supported by mainstream pytorch, additionally you might need to explicitly install cudatoolkit before pip installing nely-df3d:

conda install pytorch torchvision torchaudio cudatoolkit="YOUR_CUDA_VERSION" -c pytorch

For example with with RTX 3080 Ti GPU, you will need to do:

conda create -n df3d python=3.6
conda activate df3d
conda install pytorch torchvision cudatoolkit=11 -c pytorch-nightly
pip install nely-df3d

Installing from the source

DeepFly3D requires Python3, Anaconda environment and CUDA drivers for installation. It is only tested on Ubuntu and MacOS. First, clone the repository:

git clone https://github.com/NeLy-EPFL/DeepFly3D
cd DeepFly3D

Then, run create a conda environment with

conda create -n df3d python=3.6

which will create a new python environment. Then, activate the environment.

conda activate df3d

Once this is done you can install the df3d package with the following command,

pip install -e .

which uses the setup.py function to create the package.

Make sure you also have installed the CUDA drivers compatible with your GPU, otherwise it is not possible to make 2D predictions. You can check how to install CUDA drivers here: https://developer.nvidia.com/cuda-downloads

Data Structure

The inteded usage of DeepFly3D is through command-line-intarface (CLI). df3d-cli assumes there are videos or images in this format under the folder. if your path /your/image/path has images or videos, df3d-cli will run 2D pose estimation, calibration and triangulation and will save 2d pose, 3d pose and calibration parameters under the folder /your/image/path/df3d.

Idealy you would have images or videos under images/ folder, with the specific naming convention:

.
+-- images/
|   +-- camera_0_img_0.jpg
|   +-- camera_1_img_0.jpg
|   +-- camera_2_img_0.jpg
|   +-- camera_3_img_0.jpg
|   +-- camera_4_img_0.jpg
|   +-- camera_5_img_0.jpg
|   +-- camera_6_img_0.jpg
...

or

.
+-- images
|   +-- camera_0.mp4
|   +-- camera_1.mp4
|   +-- camera_2.mp4
|   +-- camera_3.mp4
|   +-- camera_4.mp4
|   +-- camera_5.mp4
|   +-- camera_6.mp4

In case of mp4 files, df3d will first expand them into images using ffmpeg. Please check the sample data for a real exampe: https://github.com/NeLy-EPFL/DeepFly3D/tree/master/sample/test

Basic Usage

The basic usage is like this.

df3d-cli /your/image/path \
         --order 0 1 2 3 4 5 6 

camera order stands for the selection of cameras. The default camera ordering (0 1 2 3 4 5 6) stands for this. In case you have some other order, then you need to tell which order.

Originally.

Then if you have the following order, your image

So for example, if your data looks like this, then your order should be 6 5 4 3 2 1 0. image

Advanced Usage

usage: df3d-cli [-h] [-v] [-vv] [-d] [--output-folder OUTPUT_FOLDER] [-r] [-f]
                [-o] [-n NUM_IMAGES_MAX]
                [-order [CAMERA_IDS [CAMERA_IDS ...]]] [--video-2d]
                [--video-3d] [--skip-pose-estimation]
                INPUT

DeepFly3D pose estimation

positional arguments:
  INPUT                 Without additional arguments, a folder containing
                        unlabeled images.

optional arguments:
  -h, --help            show this help message and exit
  -v, --verbose         Enable info output (such as progress bars)
  -vv, --verbose2       Enable debug output
  -d, --debug           Displays the argument list for debugging purposes
  --output-folder OUTPUT_FOLDER
                        The name of subfolder where to write results
  -r, --recursive       INPUT is a folder. Successively use its subfolders
                        named 'images/'
  -f, --from-file       INPUT is a text-file, where each line names a folder.
                        Successively use the listed folders.
  -o, --overwrite       Rerun pose estimation and overwrite existing pose
                        results
  -n NUM_IMAGES_MAX, --num-images-max NUM_IMAGES_MAX
                        Maximal number of images to process.
  -order [CAMERA_IDS [CAMERA_IDS ...]], --camera-ids [CAMERA_IDS [CAMERA_IDS ...]]
                        Ordering of the cameras provided as an ordered list of
                        ids. Example: 0 1 4 3 2 5 6.
  --video-2d            Generate pose2d videos
  --video-3d            Generate pose3d videos
  --skip-pose-estimation
                        Skip 2D and 3D pose estimation

Therefore, you can create advanced queries in df3d-cli, for example:

df3d-cli -f /path/to/text.txt    \  # process each line from the text file 
         -r                      \  # recursively search for images folder under each line of the text line
         --order 0 1 2 3 4 5 6   \  # set the camera order
         -n 100                  \  # process only the first 100 images 
         --output-folder results \  # write results under  /your/image/path/results instead of  /your/image/path/df3d
         --vv                    \  # will print agressivelly, for debugging purposes
         --skip-pose-estimation  \  # will not run 2d pose estimation, instead will do calibration, triangulation and will save results
         --video-2d              \  # will make 2d video for each folder 
         --video-3d              \  # will make 3d video for each folder

To test df3d-cli, you run it on a folder for only 100 images, make videos, and print agressivelly for debugging:

df3d-cli /path/to/images/ -n 100 -vv -order 0 1 2 3 4 5 6

Python Interface

Optionally, you can also use df3d on directly python.

from df3d.core import Core
from df3d import video

core = Core(input_folder='../sample/test/', num_images_max=100, output_subfolder='df3d_py', camera_ordering=[0,1,2,3,4,5,6])
core.pose2d_estimation()
core.calibrate_calc(min_img_id=0, max_img_id=100)

# save df3d_resultt  file under '../sample/test/df3d_py' 
core.save()

# make videos
video.make_pose2d_video(
    core.plot_2d, core.num_images, core.input_folder, core.output_folder
)
video.make_pose3d_video(
    core.get_points3d(),
    core.plot_2d,
    core.num_images,
    core.input_folder,
    core.output_folder,
)

In general following functions are available for Core module:

class Core:
    def __init__(self, input_folder, num_images_max):  # 9 lines
	def setup_cameras(self):  # 38 lines
    
    # attribute access
    @property def input_folder(self):  # 2 lines
    @property def output_folder(self):  # 2 lines
    @property def image_shape(self):  # 2 lines
    @property def number_of_joints(self):  # 3 lines
    def has_pose(self):  # 1 lines
    def has_heatmap(self):  # 1 lines
    def has_calibration(self):  # 4 lines
    
    # interactions with pose-estimation
    def update_camera_ordering(self, cidread2cid):  # 12 lines
    def pose2d_estimation(self):  # 14 lines
    def next_error(self, img_id):  # 1 lines
    def prev_error(self, img_id):  # 1 lines
    def calibrate_calc(self, min_img_id, max_img_id):  # 35 lines
    def nearest_joint(self, cam_id, img_id, x, y):  # 10 lines
    def move_joint(self, cam_id, img_id, joint_id, x, y):  # 10 lines

    def save_calibration(self):  # 3 lines
    def save_pose(self):  # 63 lines
    def save_corrections(self):  # 1 line
    
    # visualizations
    def plot_2d(self, cam_id, img_id, with_corrections=False, joints=[]):  # 33 lines
    def plot_heatmap(self, cam_id, img_id, joints=[]):  # 5 lines
    def get_image(self, cam_id, img_id):  # 4 lines
    
    # private helper methods
    def next_error_in_range(self, range_of_ids):  # 6 lines
    def get_joint_reprojection_error(self, img_id, joint_id, camNet):  # 11 lines
    def joint_has_error(self, img_id, joint_id):  # 4 lines
    def solve_bp_for_camnet(self, img_id, camNet):  # 29 lines

Videos

Using the flag --video-2d with df3d-cli will create the following video: Alt text

Using the flag --video-3d with df3d-cli will create the following video: Alt text

Output

df3d-cli saves results under df3d_result.pk file. You can read it using,

result_path = '../sample/test/df3d/df3d_result*.pkl'
d = pickle.load(open(glob.glob(pr_path)[0], 'rb'))

This will read a dictionary with the following keys:

d.keys()
>>> dict_keys([0, 1, 2, 3, 4, 5, 6, 'points3d', 'points2d', 'points3d_wo_procrustes', 'camera_ordering', 'heatmap_confidence'])

Points2D

Detected 2D keypoints are hold under d['points2d'], which is a 4 dimensional tensor.

d['points2d'].shape
>>> (7, 15, 38, 2) # [CAMERAS, TIMES, JOINTS, 2D]

You can read the corresponding 2D points from a particular camera from a particular time using,

row, column = d['points2d'][CAMERA, TIME, JOINT]

The points are in the (row, column) format.

You can also visualize which keypoints in results belongs to which keypoints on the animal:

import matplotlib.pyplot as plt

image_path = '../sample/test/camera_{cam_id}_img_{img_id}.jpg'
pr_path = '../sample/test/df3d/df3d_result*.pkl'

cam_id, time = 0, 0

plt.imshow(plt.imread(image_path.format(cam_id=0,img_id=0)))
plt.axis('off')
for joint_id in range(19):
    x, y = d['points2d'][cam_id, time][joint_id, 1] * 960, d['points2d'][cam_id, time][joint_id, 0] * 480
    plt.scatter(x, y, c='blue', s=5)
    plt.text(x, y, f'{i}', c='red')

Points3D

You can recalculate the 3D points, given the 2D points and the caibraiton parameters:

from pyba.CameraNetwork import CameraNetwork
import pickle
import glob

image_path = './sample/test/camera_{cam_id}_img_{img_id}.jpg'
pr_path = './sample/test/df3d/df3d_result*.pkl'

d = pickle.load(open(glob.glob(pr_path)[0], 'rb'))
points2d = d['points2d']

# df3d points2d are saved in normalized into [0,1], rescale them into image shape
camNet = CameraNetwork(points2d=points2d*[480, 960], calib=d, image_path=image_path)

points3d = camNet.triangulate()

Camera 0 corresponds to origin. It's camera center (not the translation vector) corresponds to 0 point.

image

Camera Ordering

The same camera ordering as given input using --order flag in cli.

d["camera_ordering"]
>>> array([0, 1, 2, 3, 4, 5, 6])

Heatmap Confidence

Stacked Hourglass confidence values for each joint predicted. Given an unnormalized posterior distribution heatmap H over the pixels, we take the argmax_{h, w} H for the final prediction and H[h, w] for the confidence level.

image

Calibration

df3d_result files also have the calculated calibration parameters for each camera. Each calibration section includes

  1. rotation matrix R
  2. translation vector tvec,
  3. intrinsic matrix intr,
  4. distortion parameters distort.
calib = {0: {'R': array([[ 0.90885957,  0.006461  , -0.41705219],
         [ 0.01010426,  0.99924554,  0.03750006],
         [ 0.41697983, -0.0382963 ,  0.90810859]]),
  'tvec': array([1.65191596e+00, 2.22582670e-02, 1.18353733e+02]),
  'intr': array([[1.60410e+04, 0.00000e+00, 2.40000e+02],
         [0.00000e+00, 1.59717e+04, 4.80000e+02],
         [0.00000e+00, 0.00000e+00, 1.00000e+00]]),
  'distort': array([0., 0., 0., 0., 0.])},
 1: {'R': array([[ 0.59137248,  0.02689833, -0.80594979],
         [-0.00894927,  0.9996009 ,  0.02679478],
         [ 0.80634887, -0.00863303,  0.59137718]]),
  'tvec': array([ 1.02706542e+00, -9.25820468e-02,  1.18251732e+02]),
  'intr': array([[1.60410e+04, 0.00000e+00, 2.40000e+02],
         [0.00000e+00, 1.59717e+04, 4.80000e+02],
         [0.00000e+00, 0.00000e+00, 1.00000e+00]]),
  'distort': array([0., 0., 0., 0., 0.])},
}

The coordinate system is compatible with OpenCV, where z-axis corresponds to axis going out of camera.

Running GUI

GUI is primarily used for correcting the false 2D pose estimation results in the 'Correction' mode. Your changes will be saved under df3d folder and will be used for the final df3d_result file.

Currently, you can only use GUI after running the df3d on the cli on the same folder.

After installing the dependencies we can initialize the GUI using the command line entry point:

Alt text

df3d ./data/test/ 15

The second argument sets the image folder, while the third argument sets the upper bound for the images, in case you only want to process the subset of images.

This should start the GUI:

Alt text

you can optionally remove /FULL/PATH_FOLDER and NUM_IMAGES, in which case pop-up apperas the select the folder.

After completing pose estimation in the cli, you can open the pose mode:

Alt text

Development

DeepFly3D consists of 3 pip packages:

The master branch of the DeepFly3D package is kept up-to-date with the last version of the pip package. Development is done under dev branch. Before pushing changes to the master branch, make sure all test cases are passing. You can run the tests using python test.py. Unittests make sure several scenarios can be processed using cli without failing.

References

You can cite our paper in case you find it useful.

@inproceedings{Gunel19DeepFly3D,
  author    = {Semih G{\"u}nel and
               Helge Rhodin and
               Daniel Morales and
               João Compagnolo and
               Pavan Ramdya and
               Pascal Fua},
  title     = {DeepFly3D, a deep learning-based approach for 3D limb and appendage tracking in tethered, adult Drosophila},
  bookTitle = {eLife},
  doi       = {10.7554/eLife.48571},
  year      = {2019}
}

Version History

Changes in 0.5

  • Major internal rewrite.

Changes in 0.4

  • Using the CLI, the output folder can be changed using the --output-folder flag
  • CLI and GUI now use the same pose estimation code, so changes will automatically propagate to both
  • Minor tweaks in the GUI layout, functionality kept unchanged

Changes in 0.3

  • Results are saved in df3d folder instead of the image folder.
  • Much faster startup time.
  • Cameras are automatically ordered using Regular Expressions.
  • CLI improvements. Now it includes 3D pose.

Changes in 0.2

  • Changing name from deepfly3d to df3d
  • Adding cli interface with df3d-cli
  • Removing specific dependencies for numpy and scipy
  • Removing L/R buttons, so you can see all the data at once
  • Removing the front camera
  • Faster startup time, less time spent on searching for the image folder
  • Better notebooks for plotting
  • Adding procrustes support. Now all the output is registere to template skeleton.
  • Bug fixes in CameraNetwork. Now calibration with arbitrary camera sequence is possible.

Extras:

deepfly3d's People

Contributors

dependabot[bot] avatar faymanns avatar jasper-tms avatar jonasfbraun avatar julien-h avatar ramdya avatar semihgunel avatar sibocw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

deepfly3d's Issues

Example JSON file with annotations?

Hello,
I want to try running DeepFly3D on our dataset.
We already have annotations, so I think we could convert it to your JSON format to train a network and try out DeepFly3D.

However, I can't seem to find any example of a JSON annotation file of the type that DeepFly3DAnnotation produces.

Do you have any examples that you could share, perhaps on the H36M dataset?

save df3d output to behavior

Currently the output of df3d is saved inside the images folder (behData>images>df3d). This makes it very annoying to access when all the videos are saved as individual images in that same images folder
The df3d folder should be saved instead inside of behData but outside of images.

Post hoc generation of 3d videos fails

df3d-cli -skip -3d /ramdya-nas/FA/191129_ABO/Fly1/001_coronal/behData/image
raises the following error

Traceback (most recent call last):
  File "/home/aymanns/.conda/envs/mydeepfly/bin/df3d-cli", line 11, in <module>
    load_entry_point('deepfly', 'console_scripts', 'df3d-cli')()
  File "/home/aymanns/DeepFly3D/deepfly/CLI/main.py", line 29, in main
    return run(args)
  File "/home/aymanns/DeepFly3D/deepfly/CLI/main.py", line 170, in run
    nothing_to_do = args.skip_estimation and (not args.vid2d) and (not args.vid3d)
AttributeError: 'Namespace' object has no attribute 'vid2d'

Do I need to provide initial camera calibration parameters?

Owing to the proposed "Pictorial structure based calibration", ideally I should just provide detected 2D as input and get the 3D structure if I am understanding the paper correctly.

Thus, if I get the 2D poses from df2d in the following structure (7 x 15 x 38 x 2), do I need to provide any other information (such as calib.pkl) in order for me to generate a 3D structure (15 x 38 x 3)? In other words, what information do I need to provide? Intrinsics, Extrinsics, or both? Or initial rough values for both?

Asking the above question in case I need to run on Human 3.6 M dataset, where I just have 2D detected poses from a 2D pose detector and nothing else.

Installation of PyQt5

This is not a DeepFly3D issue but I will document it here for future reference.
Running pip install . can cause an error when pip tries to install PyQt5.
The error message looks something like this:

    ERROR: Complete output from command /home/aymanns/.conda/envs/deepflyfront/bin/python /home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpmldfr5gc:
    ERROR: Querying qmake about your Qt installation...
    /usr/bin/qmake -query
    Traceback (most recent call last):
      File "/home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 64, in prepare_metadata_for_build_wheel
        hook = backend.prepare_metadata_for_build_wheel
    AttributeError: module 'sipbuild.api' has no attribute 'prepare_metadata_for_build_wheel'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "/home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 207, in <module>
        main()
      File "/home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 197, in main
        json_out['return_val'] = hook(**hook_input['kwargs'])
      File "/home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 67, in prepare_metadata_for_build_wheel
        config_settings)
      File "/home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 95, in _get_wheel_metadata_from_wheel
        whl_basename = backend.build_wheel(metadata_directory, config_settings)
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/sipbuild/api.py", line 51, in build_wheel
        project = AbstractProject.bootstrap('pep517')
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/sipbuild/abstract_project.py", line 82, in bootstrap
        project.setup(pyproject, tool, tool_description)
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 387, in setup
        self.apply_user_defaults(tool)
      File "project.py", line 62, in apply_user_defaults
        super().apply_user_defaults(tool)
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/pyqtbuild/project.py", line 86, in apply_user_defaults
        super().apply_user_defaults(tool)
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 202, in apply_user_defaults
        self.builder.apply_user_defaults(tool)
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/pyqtbuild/builder.py", line 76, in apply_user_defaults
        self._get_qt_configuration()
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/pyqtbuild/builder.py", line 431, in _get_qt_configuration
        for line in project.read_command_pipe([self.qmake, '-query']):
      File "/tmp/pip-build-env-mh0ik_qb/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 350, in read_command_pipe
        raise UserException("'{0}' failed returning {1}".format(cmd, rc))
    sipbuild.exceptions.UserException
    ----------------------------------------
ERROR: Command "/home/aymanns/.conda/envs/deepflyfront/bin/python /home/aymanns/.conda/envs/deepflyfront/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmpmldfr5gc" failed with error code 1 in /tmp/pip-install-zq8org3n/PyQt5

Front Branch: Index out of bounds exception when moving to next error in GUI

When you click on "next error" in the correction mode of the GUI the following index out of bounds
error is raise.
I suspect this only happens when no errors are detected but haven't tested it.

df3d /mnt/data/CLC/190703_SS42740-tdTomGC6fopt/Fly2/CO2xzGG/behData_002/images/ --output-folder df3d_2
/mnt/data/CLC/190703_SS42740-tdTomGC6fopt/Fly2/CO2xzGG/behData_002/images
(df3dfork) aymanns@upramdyapc1:~$ df3d /mnt/data/CLC/190703_SS42740-tdTomGC6fopt/Fly2/CO2xzGG/behData_002/images/ --output-folder df3d_2
/mnt/data/CLC/190703_SS42740-tdTomGC6fopt/Fly2/CO2xzGG/behData_002/images
Finished Belief Propagation
Finished Belief Propagation
Traceback (most recent call last):
  File "/home/aymanns/DeepFly3DFork/deepfly/gui.py", line 246, in onclick_next_error
    next_img = self.core.next_error(self.img_id)
  File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 181, in next_error
    return self.next_error_in_range(range(img_id + 1, self.max_img_id + 1))
  File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 537, in next_error_in_range
    if self.joint_has_error(img_id, joint_id):
  File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 568, in joint_has_error
    err_left = get_error(img_id, joint_id, self.camNetLeft)
  File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 553, in get_joint_reprojection_error
    [cam.points2d[img_id, joint_id, :] for cam in visible_cameras]
  File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 553, in <listcomp>
    [cam.points2d[img_id, joint_id, :] for cam in visible_cameras]
IndexError: index 150 is out of bounds for axis 0 with size 150
Aborted (core dumped)

Automatically pull image size from image files

Currently there's a value image_shape in config.py that users have to set based on the size of their images. This is suboptimal. The image shape should just be read from the images themselves so users don't have to remember to set this, and so that users changing between working on datasets with different image sizes don't have to change this manually each time they swap what they're working on.

Naming convention of files

Currently the pose and prediction output files saved in the sub-folder are include the path to the directory in their name. This can lead to duplication of files when you work on the same data from different machines. For instance when a NAS is mounted in different locations as in the example below. The output sub-folder contains the following files:

-rwxr-xr-x 1 root root     3025 Feb  5 17:11 calib.pkl
-rwxr-xr-x 1 root root      184 Feb  5 16:57 cam_order.npy
-rwxr-xr-x 1 root root    13837 Feb  5 17:32 pose_corr_-mnt-data-CLC-190703_SS42740-tdTomGC6fopt-Fly2-CO2xzGG-behData_002-images-df3d_2.pkl
-rwxr-xr-x 1 root root 38453066 Feb  5 17:32 pose_result__mnt_data_CLC_190703_SS42740-tdTomGC6fopt_Fly2_CO2xzGG_behData_002_images.pkl
-rwxr-xr-x 1 root root 38453066 Dec 11 11:19 pose_result__mnt_NAS_CLC_190703_SS42740-tdTomGC6fopt_Fly2_CO2xzGG_behData_002_images.pkl
-rwxr-xr-x 1 root root  9047200 Dec 11 11:13 preds_-mnt-NAS-CLC-190703_SS42740-tdTomGC6fopt-Fly2-CO2xzGG-behData_002-images.pkl

I suggest we drop that part of the name and simply save them as preds.pkl and pose_result.pkl.
To ensure backwards compatibility we can glob for preds*.pkl and pose_result*.pkl and choose the file modified last.

error with visualizing test data

Hello,
I am using the most recent DeepFly3D (commit 6764e08). I am trying to run the visualization block of code as specified in the docs. That is:

import matplotlib.pyplot as plt
from deepfly.GUI.CameraNetwork import CameraNetwork
camNet = CameraNetwork(image_folder=image_folder)
image_folder = './data/test/df3d'

plt.imshow(camNet[1].plot_2d())

Running this block of code results in the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-5-aed64e215871> in <module>
      4 image_folder = './data/test/df3d'
      5 camNet = CameraNetwork(image_folder=image_folder, 
----> 6                        output_folder=image_folder)
      7 
      8 

~/src/DeepFly3D/deepfly/GUI/CameraNetwork.py in __init__(self, image_folder, output_folder, calibration, num_images, num_joints, image_shape, heatmap_shape, cam_id_list, cid2cidread, heatmap, pred, cam_list, hm_path, pred_path)
    104 
    105             for cam_id in cam_id_list:
--> 106                 cam_id_read = cid2cidread[cam_id]
    107 
    108                 if heatmap is not None:# and type(heatmap) is np.core.memmap:

TypeError: 'NoneType' object is not subscriptable

To note, I have the following tree from ...data/test/df3d:

.
├── calib__home_hank-x299_src_DeepFly3D_data_test.pkl
├── cam_order.npy
├── heatmap_-home-hank-x299-src-DeepFly3D-data-test.pkl
├── pose_corr_-home-hank-x299-src-DeepFly3D-data-test-df3d-.pkl
├── pose_result__home_hank-x299_src_DeepFly3D_data_test.pkl
└── preds_-home-hank-x299-src-DeepFly3D-data-test.pkl

How might I address the error?
Thanks

Exceptions when running training example in the docs.

When running
$ python deepfly/pose2d/drosophila.py -s 8 --resume ./weights/sh8_mpii.tar
I got the following exception

Traceback (most recent call last):
  File "deepfly/pose2d/drosophila.py", line 708, in <module> 
    "mv" if args.multiview "",
AttributeError: 'Namespace' object has no attribute 'multiview'

After fixing this, the same error occured because args.name didn't exist. (Also for args.carry).

The next error was

Traceback (most recent call last):
  File "deepfly/pose2d/drosophila.py", line 710, in <module>
    args.name,
  File "/usr/lib64/python3.6/posixpath.py", line 80, in join
    a = os.fspath(a)
TypeError: expected str, bytes or os.PathLike object, not bool

It seems args.checkpoint should default to a checkpoint directory "checkpoint", rather than False.

Error when using the -f flag of the cli to provide a list of folders

The following error is raised when using the the -f flag of the cli.

Looking for folders listed in beh_dirs.txt
Traceback (most recent call last):
  File "/home/aymanns/.conda/envs/df3d/bin/df3d-cli", line 30, in <module>
    sys.exit(load_entry_point('deepfly', 'console_scripts', 'df3d-cli')())                               
  File "/home/aymanns/DeepFly3D/deepfly/cli.py", line 37, in main
    return run_from_file(args)
  File "/home/aymanns/DeepFly3D/deepfly/cli.py", line 196, in run_from_file
    folders_str = "\n-".join(folders)
TypeError: sequence item 0: expected str instance, PosixPath found

Search for .jpg is too general

DeepFly3D searches for all .jpg files in a sub-folder, but this seems to be too general to me.
If this search finds any .jpg that does not fulfill the camera_X_frame_YYYY.jpg pattern exactly, it throws an error.
In my case, I had a file called "camera_3_mean_img.jpg" in the images folder, which made DeepFly3D fail because os.util.parse_img_name() throws an error.
Here, the file name is very close to the original format and a ValueError is raised because "img" cannot be converted to int, but os.util.parse_img_name() would also fail with any other .jpg in the same folder as well.

I temporarily fixed the problem by making
os_utils.parse_img_name() return (-1, -1) instead of throwing an error and handling this case whenever os_utils.parse_img_name() was called, for example in pose2d.DrosophilaDataset.read_unlabeled_folder()
But I'm sure there's a better way, for example checking whether a file corresponds to the expected formatting scheme whenever searching through all .jpg files in the folder

Possible bug applies BP only to the left cameras

def solve_bp(self, save_correction=False):

pts_bp = self.state.camNetLeft.solveBP(

for ip in self.image_pose_list:

for idx, image_pose in enumerate(self.image_pose_list):

I noticed that I was only getting BP automatic corrections for cameras 0,1,2 and not for cameras 4,5,6 and I think this might be why.
Unless I'm misunderstanding what this function does, it's only applying the belief propagation to images in self.image_pose_list using self.state.camNetLeft, excluding everything from cameras 4,5,6 and the images in self.image_pose_list_bot

-i is ignored when -f is used in the df3d-cli

When using a txt file with directories for batch processing with df3d-cli the camera order has no effect.

To reproduce this issue run
df3d-cli -f folder.txt -v -i 6 5 4 3 2 1 0
where folder.txt is a text file that holds one or more directories.

Checking the saved .npy file in the created df3d directories shows that the -i flag seems to have no effect.

'Namespace' object has no attribute 'max_img_id'

When I try to run the code following

python deepfly/pose2d/drosophila.py --resume ./weights/sh8_mpii.tar --unlabeled ./data/test

It comes out this error

Traceback (most recent call last):
  File "deepfly/pose2d/drosophila.py", line 542, in <module>
    main(args)
  File "deepfly/pose2d/drosophila.py", line 354, in main
    max_img_id=min(get_max_img_id(args.unlabeled), args.max_img_id),
AttributeError: 'Namespace' object has no attribute 'max_img_id'

Update scipy / opencv / matplotlib / numpy versions

In d8f4b88 we relaxed the scipy version requirement a bit, but scipy==1.4.1 still only has wheels for python3.8 and below (see available wheels at https://pypi.org/project/scipy/1.4.1/#files). The latest version of scipy currently is 1.13.0, which has wheels for python3.9 to python3.12. We should try just unpinning the scipy version to let pip install the latest version that's compatible with the version of python the user is trying to use. If unpinning breaks things, there might be some work to do to get everything to run with a more modern python version. Maybe aim for 3.10 or so.

This will also fix https://github.com/NeLy-EPFL/DeepFly3D/security/dependabot/2

I can get around to doing this sometime, though @azmaite if you're testing/using this code soon feel free to give the updated scipy a try.

`test_missing_camera` is failing

In tests.py, test_missing_camera() attempts to call df3d-cli on a folder that doesn't exist. I think some lines of code may be missing that prepare a folder with image data from only some cameras.

If anyone knows whether df3d is actually supposed to behave well will some missing cameras, or if this was a test that someone optimistically started writing without any actual implementation of the desired behavior in the package yet, let me know so I know whether to care about this test failing 😅

Wrong assumption about default for zero padding of image files

This issue concerns the front branch.

When opening the GUI with the df3d path/to/image/folder/ and error with the following traceback is raise if the folder contains images without zero padding.

Traceback (most recent call last):
File "/home/aymanns/.conda/envs/df3dfork/bin/df3d", line 11, in <module>
load_entry_point('deepfly', 'console_scripts', 'df3d')()
File "/home/aymanns/DeepFly3DFork/deepfly/gui.py", line 18, in main
window.setup(**cli_args)
File "/home/aymanns/DeepFly3DFork/deepfly/gui.py", line 63, in setup
self.core = Core(input_folder, output_subfolder, num_images_max)
File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 71, in __init__
self.check_cameras()
File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 523, in check_cameras
cam_missing = [cam.cam_id for cam in self.camNetAll.cam_list if cam.is_empty()]
File "/home/aymanns/DeepFly3DFork/deepfly/core.py", line 523, in <listcomp>
cam_missing = [cam.cam_id for cam in self.camNetAll.cam_list if cam.is_empty()]
File "/home/aymanns/DeepFly3DFork/deepfly/Camera.py", line 97, in is_empty
has_images = self.get_image(img_id=0) is not None
File "/home/aymanns/DeepFly3DFork/deepfly/Camera.py", line 203, in get_image
raise FileNotFoundError
FileNotFoundError

Camera Intrinsics

Hello,

looking through the code and having made some tests, I can see where the Rotation and Translation matrices are calculated and the written into each Camera object (calling the set_rvec() and set_tvec() methods), but I was unable to find any instance where the intrinsics of the cameras (the intr and distort matrices) are calculated.

And in fact, they just remain as default values. Except for the "fly" example, where the "default" camera intrinsics are read from a pickled file.

Am I to understand that the camera intrinsics are not calculated by the framework and need to be provided for each camera manually before the start of the calibration? Or am I missing something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.