Realcat commited on
Commit
a96e8d6
1 Parent(s): 41de4df

add: poselib

Browse files
Files changed (3) hide show
  1. common/config.yaml +1 -1
  2. common/utils.py +189 -60
  3. requirements.txt +2 -1
common/config.yaml CHANGED
@@ -7,7 +7,7 @@ defaults:
7
  max_keypoints: 2000
8
  keypoint_threshold: 0.05
9
  enable_ransac: true
10
- ransac_method: USAC_MAGSAC
11
  ransac_reproj_threshold: 8
12
  ransac_confidence: 0.999
13
  ransac_max_iter: 10000
 
7
  max_keypoints: 2000
8
  keypoint_threshold: 0.05
9
  enable_ransac: true
10
+ ransac_method: CV2_USAC_MAGSAC
11
  ransac_reproj_threshold: 8
12
  ransac_confidence: 0.999
13
  ransac_max_iter: 10000
common/utils.py CHANGED
@@ -8,6 +8,7 @@ import shutil
8
  import numpy as np
9
  import gradio as gr
10
  from pathlib import Path
 
11
  from itertools import combinations
12
  from typing import Callable, Dict, Any, Optional, Tuple, List, Union
13
  from hloc import matchers, extractors, logger
@@ -33,7 +34,7 @@ DEFAULT_SETTING_THRESHOLD = 0.1
33
  DEFAULT_SETTING_MAX_FEATURES = 2000
34
  DEFAULT_DEFAULT_KEYPOINT_THRESHOLD = 0.01
35
  DEFAULT_ENABLE_RANSAC = True
36
- DEFAULT_RANSAC_METHOD = "USAC_MAGSAC"
37
  DEFAULT_RANSAC_REPROJ_THRESHOLD = 8
38
  DEFAULT_RANSAC_CONFIDENCE = 0.999
39
  DEFAULT_RANSAC_MAX_ITER = 10000
@@ -42,7 +43,6 @@ DEFAULT_MATCHING_THRESHOLD = 0.2
42
  DEFAULT_SETTING_GEOMETRY = "Homography"
43
  GRADIO_VERSION = gr.__version__.split(".")[0]
44
  MATCHER_ZOO = None
45
- models_already_loaded = {}
46
 
47
 
48
  class ModelCache:
@@ -314,13 +314,141 @@ def set_null_pred(feature_type: str, pred: dict):
314
  return pred
315
 
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  def filter_matches(
318
  pred: Dict[str, Any],
319
  ransac_method: str = DEFAULT_RANSAC_METHOD,
320
  ransac_reproj_threshold: float = DEFAULT_RANSAC_REPROJ_THRESHOLD,
321
  ransac_confidence: float = DEFAULT_RANSAC_CONFIDENCE,
322
  ransac_max_iter: int = DEFAULT_RANSAC_MAX_ITER,
323
- ) -> Dict[str, Any]:
 
324
  """
325
  Filter matches using RANSAC. If keypoints are available, filter by keypoints.
326
  If lines are available, filter by lines. If both keypoints and lines are
@@ -359,16 +487,17 @@ def filter_matches(
359
 
360
  if len(mkpts0) < DEFAULT_MIN_NUM_MATCHES:
361
  return set_null_pred(feature_type, pred)
362
- H, mask = cv2.findHomography(
363
- mkpts0,
364
- mkpts1,
365
- method=ransac_zoo[ransac_method],
366
- ransacReprojThreshold=ransac_reproj_threshold,
367
- confidence=ransac_confidence,
368
- maxIters=ransac_max_iter,
369
  )
370
- mask = np.array(mask.ravel().astype("bool"), dtype="bool")
371
- if H is not None:
 
372
  if feature_type == "KEYPOINT":
373
  pred["mmkeypoints0_orig"] = mkpts0[mask]
374
  pred["mmkeypoints1_orig"] = mkpts1[mask]
@@ -376,9 +505,13 @@ def filter_matches(
376
  elif feature_type == "LINE":
377
  pred["mline_keypoints0_orig"] = mkpts0[mask]
378
  pred["mline_keypoints1_orig"] = mkpts1[mask]
379
- pred["H"] = H
380
  else:
381
  set_null_pred(feature_type, pred)
 
 
 
 
382
  return pred
383
 
384
 
@@ -419,34 +552,41 @@ def compute_geometry(
419
  if mkpts0 is not None and mkpts1 is not None:
420
  if len(mkpts0) < 2 * DEFAULT_MIN_NUM_MATCHES:
421
  return {}
422
- h1, w1, _ = pred["image0_orig"].shape
423
  geo_info: Dict[str, List[float]] = {}
424
- F, inliers = cv2.findFundamentalMat(
 
425
  mkpts0,
426
  mkpts1,
427
- method=ransac_zoo[ransac_method],
428
- ransacReprojThreshold=ransac_reproj_threshold,
429
- confidence=ransac_confidence,
430
- maxIters=ransac_max_iter,
 
431
  )
 
432
  if F is not None:
433
  geo_info["Fundamental"] = F.tolist()
434
- H, _ = cv2.findHomography(
 
435
  mkpts1,
436
  mkpts0,
437
- method=ransac_zoo[ransac_method],
438
- ransacReprojThreshold=ransac_reproj_threshold,
439
- confidence=ransac_confidence,
440
- maxIters=ransac_max_iter,
 
441
  )
 
 
442
  if H is not None:
443
  geo_info["Homography"] = H.tolist()
 
444
  try:
445
  _, H1, H2 = cv2.stereoRectifyUncalibrated(
446
  mkpts0.reshape(-1, 2),
447
  mkpts1.reshape(-1, 2),
448
  F,
449
- imgSize=(w1, h1),
450
  )
451
  geo_info["H1"] = H1.tolist()
452
  geo_info["H2"] = H2.tolist()
@@ -475,19 +615,21 @@ def wrap_images(
475
  Returns:
476
  A tuple containing a base64 encoded image string and a dictionary with the transformation matrix.
477
  """
478
- h1, w1, _ = img0.shape
479
- h2, w2, _ = img1.shape
480
  result_matrix: Optional[np.ndarray] = None
481
  if geo_info is not None and len(geo_info) != 0:
482
  rectified_image0 = img0
483
  rectified_image1 = None
 
 
 
 
484
  H = np.array(geo_info["Homography"])
485
 
486
  title: List[str] = []
487
  if geom_type == "Homography":
488
- rectified_image1 = cv2.warpPerspective(
489
- img1, H, (img0.shape[1], img0.shape[0])
490
- )
491
  result_matrix = H
492
  title = ["Image 0", "Image 1 - warped"]
493
  elif geom_type == "Fundamental":
@@ -496,8 +638,8 @@ def wrap_images(
496
  return None, None
497
  else:
498
  H1, H2 = np.array(geo_info["H1"]), np.array(geo_info["H2"])
499
- rectified_image0 = cv2.warpPerspective(img0, H1, (w1, h1))
500
- rectified_image1 = cv2.warpPerspective(img1, H2, (w2, h2))
501
  result_matrix = np.array(geo_info["Fundamental"])
502
  title = ["Image 0 - warped", "Image 1 - warped"]
503
  else:
@@ -537,8 +679,8 @@ def generate_warp_images(
537
  or "geom_info" not in matches_info.keys()
538
  ):
539
  return None, None
540
- geom_info: Dict[str, Any] = matches_info["geom_info"]
541
- wrapped_images: Optional[np.ndarray] = None
542
  if choice != "No":
543
  wrapped_images, _ = wrap_images(
544
  input_image0, input_image1, geom_info, choice
@@ -603,17 +745,10 @@ def run_ransac(
603
  t1 = time.time()
604
 
605
  # compute warp images
606
- geom_info = compute_geometry(
607
- state_cache,
608
- ransac_method=ransac_method,
609
- ransac_reproj_threshold=ransac_reproj_threshold,
610
- ransac_confidence=ransac_confidence,
611
- ransac_max_iter=ransac_max_iter,
612
- )
613
  output_wrapped, _ = generate_warp_images(
614
  state_cache["image0_orig"],
615
  state_cache["image1_orig"],
616
- {"geom_info": geom_info},
617
  choice_geometry_type,
618
  )
619
  plt.close("all")
@@ -774,6 +909,7 @@ def run_matching(
774
  ransac_confidence=ransac_confidence,
775
  ransac_max_iter=ransac_max_iter,
776
  )
 
777
  # gr.Info(f"RANSAC matches done using: {time.time()-t1:.3f}s")
778
  logger.info(f"RANSAC matches done using: {time.time()-t1:.3f}s")
779
  t1 = time.time()
@@ -791,21 +927,13 @@ def run_matching(
791
 
792
  t1 = time.time()
793
  # plot wrapped images
794
- geom_info = compute_geometry(
795
- pred,
796
- ransac_method=ransac_method,
797
- ransac_reproj_threshold=ransac_reproj_threshold,
798
- ransac_confidence=ransac_confidence,
799
- ransac_max_iter=ransac_max_iter,
800
- )
801
  output_wrapped, _ = generate_warp_images(
802
  pred["image0_orig"],
803
  pred["image1_orig"],
804
- {"geom_info": geom_info},
805
  choice_geometry_type,
806
  )
807
  plt.close("all")
808
- # del pred
809
  # gr.Info(f"In summary, total time: {time.time()-t0:.3f}s")
810
  logger.info(f"TOTAL time: {time.time()-t0:.3f}s")
811
 
@@ -825,7 +953,7 @@ def run_matching(
825
  "extractor_conf": extract_conf,
826
  },
827
  {
828
- "geom_info": geom_info,
829
  },
830
  output_wrapped,
831
  state_cache,
@@ -835,14 +963,15 @@ def run_matching(
835
  # @ref: https://docs.opencv.org/4.x/d0/d74/md__build_4_x-contrib_docs-lin64_opencv_doc_tutorials_calib3d_usac.html
836
  # AND: https://opencv.org/blog/2021/06/09/evaluating-opencvs-new-ransacs
837
  ransac_zoo = {
838
- "RANSAC": cv2.RANSAC,
839
- "USAC_MAGSAC": cv2.USAC_MAGSAC,
840
- "USAC_DEFAULT": cv2.USAC_DEFAULT,
841
- "USAC_FM_8PTS": cv2.USAC_FM_8PTS,
842
- "USAC_PROSAC": cv2.USAC_PROSAC,
843
- "USAC_FAST": cv2.USAC_FAST,
844
- "USAC_ACCURATE": cv2.USAC_ACCURATE,
845
- "USAC_PARALLEL": cv2.USAC_PARALLEL,
 
846
  }
847
 
848
 
 
8
  import numpy as np
9
  import gradio as gr
10
  from pathlib import Path
11
+ import poselib
12
  from itertools import combinations
13
  from typing import Callable, Dict, Any, Optional, Tuple, List, Union
14
  from hloc import matchers, extractors, logger
 
34
  DEFAULT_SETTING_MAX_FEATURES = 2000
35
  DEFAULT_DEFAULT_KEYPOINT_THRESHOLD = 0.01
36
  DEFAULT_ENABLE_RANSAC = True
37
+ DEFAULT_RANSAC_METHOD = "CV2_USAC_MAGSAC"
38
  DEFAULT_RANSAC_REPROJ_THRESHOLD = 8
39
  DEFAULT_RANSAC_CONFIDENCE = 0.999
40
  DEFAULT_RANSAC_MAX_ITER = 10000
 
43
  DEFAULT_SETTING_GEOMETRY = "Homography"
44
  GRADIO_VERSION = gr.__version__.split(".")[0]
45
  MATCHER_ZOO = None
 
46
 
47
 
48
  class ModelCache:
 
314
  return pred
315
 
316
 
317
+ def _filter_matches_opencv(
318
+ kp0: np.ndarray,
319
+ kp1: np.ndarray,
320
+ method: int = cv2.RANSAC,
321
+ reproj_threshold: float = 3.0,
322
+ confidence: float = 0.99,
323
+ max_iter: int = 2000,
324
+ geometry_type: str = "Homography",
325
+ ) -> Tuple[np.ndarray, np.ndarray]:
326
+ """
327
+ Filters matches between two sets of keypoints using OpenCV's findHomography.
328
+
329
+ Args:
330
+ kp0 (np.ndarray): Array of keypoints from the first image.
331
+ kp1 (np.ndarray): Array of keypoints from the second image.
332
+ method (int, optional): RANSAC method. Defaults to "cv2.RANSAC".
333
+ reproj_threshold (float, optional): RANSAC reprojection threshold. Defaults to 3.0.
334
+ confidence (float, optional): RANSAC confidence. Defaults to 0.99.
335
+ max_iter (int, optional): RANSAC maximum iterations. Defaults to 2000.
336
+ geometry_type (str, optional): Type of geometry. Defaults to "Homography".
337
+
338
+ Returns:
339
+ Tuple[np.ndarray, np.ndarray]: Homography matrix and mask.
340
+ """
341
+ if geometry_type == "Homography":
342
+ M, mask = cv2.findHomography(
343
+ kp0,
344
+ kp1,
345
+ method=method,
346
+ ransacReprojThreshold=reproj_threshold,
347
+ confidence=confidence,
348
+ maxIters=max_iter,
349
+ )
350
+ elif geometry_type == "Fundamental":
351
+ M, mask = cv2.findFundamentalMat(
352
+ kp0,
353
+ kp1,
354
+ method=method,
355
+ ransacReprojThreshold=reproj_threshold,
356
+ confidence=confidence,
357
+ maxIters=max_iter,
358
+ )
359
+ mask = np.array(mask.ravel().astype("bool"), dtype="bool")
360
+ return M, mask
361
+
362
+
363
+ def _filter_matches_poselib(
364
+ kp0: np.ndarray,
365
+ kp1: np.ndarray,
366
+ method: int = None, # not used
367
+ reproj_threshold: float = 3,
368
+ confidence: float = 0.99,
369
+ max_iter: int = 2000,
370
+ geometry_type: str = "Homography",
371
+ ) -> dict:
372
+ """
373
+ Filters matches between two sets of keypoints using the poselib library.
374
+
375
+ Args:
376
+ kp0 (np.ndarray): Array of keypoints from the first image.
377
+ kp1 (np.ndarray): Array of keypoints from the second image.
378
+ method (str, optional): RANSAC method. Defaults to "RANSAC".
379
+ reproj_threshold (float, optional): RANSAC reprojection threshold. Defaults to 3.
380
+ confidence (float, optional): RANSAC confidence. Defaults to 0.99.
381
+ max_iter (int, optional): RANSAC maximum iterations. Defaults to 2000.
382
+ geometry_type (str, optional): Type of geometry. Defaults to "Homography".
383
+
384
+ Returns:
385
+ dict: Information about the homography estimation.
386
+ """
387
+ ransac_options = {
388
+ "max_iterations": max_iter,
389
+ # "min_iterations": min_iter,
390
+ "success_prob": confidence,
391
+ "max_reproj_error": reproj_threshold,
392
+ # "progressive_sampling": args.sampler.lower() == 'prosac'
393
+ }
394
+
395
+ if geometry_type == "Homography":
396
+ M, info = poselib.estimate_homography(kp0, kp1, ransac_options)
397
+ elif geometry_type == "Fundamental":
398
+ M, info = poselib.estimate_fundamental(kp0, kp1, ransac_options)
399
+ else:
400
+ raise notImplementedError("Not Implemented")
401
+
402
+ return M, np.array(info["inliers"])
403
+
404
+
405
+ def proc_ransac_matches(
406
+ mkpts0: np.ndarray,
407
+ mkpts1: np.ndarray,
408
+ ransac_method: str = DEFAULT_RANSAC_METHOD,
409
+ ransac_reproj_threshold: float = 3.0,
410
+ ransac_confidence: float = 0.99,
411
+ ransac_max_iter: int = 2000,
412
+ geometry_type: str = "Homography",
413
+ ):
414
+ if ransac_method.startswith("CV2"):
415
+ logger.info(
416
+ f"ransac_method: {ransac_method}, geometry_type: {geometry_type}"
417
+ )
418
+ return _filter_matches_opencv(
419
+ mkpts0,
420
+ mkpts1,
421
+ ransac_zoo[ransac_method],
422
+ ransac_reproj_threshold,
423
+ ransac_confidence,
424
+ ransac_max_iter,
425
+ geometry_type,
426
+ )
427
+ elif ransac_method.startswith("POSELIB"):
428
+ logger.info(
429
+ f"ransac_method: {ransac_method}, geometry_type: {geometry_type}"
430
+ )
431
+ return _filter_matches_poselib(
432
+ mkpts0,
433
+ mkpts1,
434
+ None,
435
+ ransac_reproj_threshold,
436
+ ransac_confidence,
437
+ ransac_max_iter,
438
+ geometry_type,
439
+ )
440
+ else:
441
+ raise notImplementedError("Not Implemented")
442
+
443
+
444
  def filter_matches(
445
  pred: Dict[str, Any],
446
  ransac_method: str = DEFAULT_RANSAC_METHOD,
447
  ransac_reproj_threshold: float = DEFAULT_RANSAC_REPROJ_THRESHOLD,
448
  ransac_confidence: float = DEFAULT_RANSAC_CONFIDENCE,
449
  ransac_max_iter: int = DEFAULT_RANSAC_MAX_ITER,
450
+ ransac_estimator: str = None,
451
+ ):
452
  """
453
  Filter matches using RANSAC. If keypoints are available, filter by keypoints.
454
  If lines are available, filter by lines. If both keypoints and lines are
 
487
 
488
  if len(mkpts0) < DEFAULT_MIN_NUM_MATCHES:
489
  return set_null_pred(feature_type, pred)
490
+
491
+ geom_info = compute_geometry(
492
+ pred,
493
+ ransac_method=ransac_method,
494
+ ransac_reproj_threshold=ransac_reproj_threshold,
495
+ ransac_confidence=ransac_confidence,
496
+ ransac_max_iter=ransac_max_iter,
497
  )
498
+
499
+ if "Homography" in geom_info.keys():
500
+ mask = geom_info["mask_h"]
501
  if feature_type == "KEYPOINT":
502
  pred["mmkeypoints0_orig"] = mkpts0[mask]
503
  pred["mmkeypoints1_orig"] = mkpts1[mask]
 
505
  elif feature_type == "LINE":
506
  pred["mline_keypoints0_orig"] = mkpts0[mask]
507
  pred["mline_keypoints1_orig"] = mkpts1[mask]
508
+ pred["H"] = np.array(geom_info["Homography"])
509
  else:
510
  set_null_pred(feature_type, pred)
511
+ # do not show mask
512
+ geom_info.pop("mask_h", None)
513
+ geom_info.pop("mask_f", None)
514
+ pred["geom_info"] = geom_info
515
  return pred
516
 
517
 
 
552
  if mkpts0 is not None and mkpts1 is not None:
553
  if len(mkpts0) < 2 * DEFAULT_MIN_NUM_MATCHES:
554
  return {}
 
555
  geo_info: Dict[str, List[float]] = {}
556
+
557
+ F, mask_f = proc_ransac_matches(
558
  mkpts0,
559
  mkpts1,
560
+ ransac_method,
561
+ ransac_reproj_threshold,
562
+ ransac_confidence,
563
+ ransac_max_iter,
564
+ geometry_type="Fundamental",
565
  )
566
+
567
  if F is not None:
568
  geo_info["Fundamental"] = F.tolist()
569
+ geo_info["mask_f"] = mask_f
570
+ H, mask_h = proc_ransac_matches(
571
  mkpts1,
572
  mkpts0,
573
+ ransac_method,
574
+ ransac_reproj_threshold,
575
+ ransac_confidence,
576
+ ransac_max_iter,
577
+ geometry_type="Homography",
578
  )
579
+
580
+ h0, w0, _ = pred["image0_orig"].shape
581
  if H is not None:
582
  geo_info["Homography"] = H.tolist()
583
+ geo_info["mask_h"] = mask_h
584
  try:
585
  _, H1, H2 = cv2.stereoRectifyUncalibrated(
586
  mkpts0.reshape(-1, 2),
587
  mkpts1.reshape(-1, 2),
588
  F,
589
+ imgSize=(w0, h0),
590
  )
591
  geo_info["H1"] = H1.tolist()
592
  geo_info["H2"] = H2.tolist()
 
615
  Returns:
616
  A tuple containing a base64 encoded image string and a dictionary with the transformation matrix.
617
  """
618
+ h0, w0, _ = img0.shape
619
+ h1, w1, _ = img1.shape
620
  result_matrix: Optional[np.ndarray] = None
621
  if geo_info is not None and len(geo_info) != 0:
622
  rectified_image0 = img0
623
  rectified_image1 = None
624
+ if "Homography" not in geo_info:
625
+ logger.warning(f"{geom_type} not exist, maybe too less matches")
626
+ return None, None
627
+
628
  H = np.array(geo_info["Homography"])
629
 
630
  title: List[str] = []
631
  if geom_type == "Homography":
632
+ rectified_image1 = cv2.warpPerspective(img1, H, (w0, h0))
 
 
633
  result_matrix = H
634
  title = ["Image 0", "Image 1 - warped"]
635
  elif geom_type == "Fundamental":
 
638
  return None, None
639
  else:
640
  H1, H2 = np.array(geo_info["H1"]), np.array(geo_info["H2"])
641
+ rectified_image0 = cv2.warpPerspective(img0, H1, (w0, h0))
642
+ rectified_image1 = cv2.warpPerspective(img1, H2, (w1, h1))
643
  result_matrix = np.array(geo_info["Fundamental"])
644
  title = ["Image 0 - warped", "Image 1 - warped"]
645
  else:
 
679
  or "geom_info" not in matches_info.keys()
680
  ):
681
  return None, None
682
+ geom_info = matches_info["geom_info"]
683
+ wrapped_images = None
684
  if choice != "No":
685
  wrapped_images, _ = wrap_images(
686
  input_image0, input_image1, geom_info, choice
 
745
  t1 = time.time()
746
 
747
  # compute warp images
 
 
 
 
 
 
 
748
  output_wrapped, _ = generate_warp_images(
749
  state_cache["image0_orig"],
750
  state_cache["image1_orig"],
751
+ state_cache,
752
  choice_geometry_type,
753
  )
754
  plt.close("all")
 
909
  ransac_confidence=ransac_confidence,
910
  ransac_max_iter=ransac_max_iter,
911
  )
912
+
913
  # gr.Info(f"RANSAC matches done using: {time.time()-t1:.3f}s")
914
  logger.info(f"RANSAC matches done using: {time.time()-t1:.3f}s")
915
  t1 = time.time()
 
927
 
928
  t1 = time.time()
929
  # plot wrapped images
 
 
 
 
 
 
 
930
  output_wrapped, _ = generate_warp_images(
931
  pred["image0_orig"],
932
  pred["image1_orig"],
933
+ pred,
934
  choice_geometry_type,
935
  )
936
  plt.close("all")
 
937
  # gr.Info(f"In summary, total time: {time.time()-t0:.3f}s")
938
  logger.info(f"TOTAL time: {time.time()-t0:.3f}s")
939
 
 
953
  "extractor_conf": extract_conf,
954
  },
955
  {
956
+ "geom_info": pred["geom_info"],
957
  },
958
  output_wrapped,
959
  state_cache,
 
963
  # @ref: https://docs.opencv.org/4.x/d0/d74/md__build_4_x-contrib_docs-lin64_opencv_doc_tutorials_calib3d_usac.html
964
  # AND: https://opencv.org/blog/2021/06/09/evaluating-opencvs-new-ransacs
965
  ransac_zoo = {
966
+ "POSELIB": "LO-RANSAC",
967
+ "CV2_RANSAC": cv2.RANSAC,
968
+ "CV2_USAC_MAGSAC": cv2.USAC_MAGSAC,
969
+ "CV2_USAC_DEFAULT": cv2.USAC_DEFAULT,
970
+ "CV2_USAC_FM_8PTS": cv2.USAC_FM_8PTS,
971
+ "CV2_USAC_PROSAC": cv2.USAC_PROSAC,
972
+ "CV2_USAC_FAST": cv2.USAC_FAST,
973
+ "CV2_USAC_ACCURATE": cv2.USAC_ACCURATE,
974
+ "CV2_USAC_PARALLEL": cv2.USAC_PARALLEL,
975
  }
976
 
977
 
requirements.txt CHANGED
@@ -31,4 +31,5 @@ torchmetrics==0.6.0
31
  torchvision==0.17.1
32
  tqdm==4.65.0
33
  yacs==0.1.8
34
- onnxruntime
 
 
31
  torchvision==0.17.1
32
  tqdm==4.65.0
33
  yacs==0.1.8
34
+ onnxruntime
35
+ poselib