4141from lib .core import LIMITED_FUNCTIONS
4242from lib .core .enums import ImageQuality
4343from lib .core .exceptions import AppException
44+ from lib .core .plugin import VideoPlugin
4445from lib .core .types import AttributeGroup
4546from lib .core .types import ClassesJson
4647from lib .core .types import MLModel
@@ -1632,13 +1633,13 @@ def upload_videos_from_folder_to_project(
16321633 extensions : Optional [
16331634 Union [Tuple [NotEmptyStr ], List [NotEmptyStr ]]
16341635 ] = constances .DEFAULT_VIDEO_EXTENSIONS ,
1635- exclude_file_patterns : Optional [Iterable [NotEmptyStr ]] = () ,
1636+ exclude_file_patterns : Optional [List [NotEmptyStr ]] = [] ,
16361637 recursive_subfolders : Optional [StrictBool ] = False ,
16371638 target_fps : Optional [int ] = None ,
16381639 start_time : Optional [float ] = 0.0 ,
16391640 end_time : Optional [float ] = None ,
16401641 annotation_status : Optional [AnnotationStatuses ] = "NotStarted" ,
1641- image_quality_in_editor : Optional [str ] = None ,
1642+ image_quality_in_editor : Optional [ImageQualityChoices ] = None ,
16421643):
16431644 """Uploads image frames from all videos with given extensions from folder_path to the project.
16441645 Sets status of all the uploaded images to set_status if it is not None.
@@ -1694,19 +1695,33 @@ def upload_videos_from_folder_to_project(
16941695 filtered_paths = []
16951696 video_paths = [str (path ) for path in video_paths ]
16961697 for path in video_paths :
1698+
16971699 not_in_exclude_list = [x not in Path (path ).name for x in exclude_file_patterns ]
16981700 if all (not_in_exclude_list ):
16991701 filtered_paths .append (path )
17001702
17011703 project_folder_name = project_name + (f"/{ folder_name } " if folder_name else "" )
1702-
17031704 logger .info (
1704- f"Uploading all videos with extensions { extensions } from { str (folder_path )} to project { project_name } . Excluded file patterns are: { [ * exclude_file_patterns ] } ." ,
1705+ f"Uploading all videos with extensions { extensions } from { str (folder_path )} to project { project_name } . Excluded file patterns are: { exclude_file_patterns } ."
17051706 )
17061707 uploaded_paths = []
1707- for path in video_paths :
1708+ for path in filtered_paths :
1709+ progress_bar = None
17081710 with tempfile .TemporaryDirectory () as temp_path :
1709- res = controller .extract_video_frames (
1711+ frame_names = VideoPlugin .get_extractable_frames (
1712+ path , start_time , end_time , target_fps
1713+ )
1714+ duplicate_images = (
1715+ controller .get_duplicate_images (
1716+ project_name = project_name ,
1717+ folder_name = folder_name ,
1718+ images = frame_names ,
1719+ )
1720+ .execute ()
1721+ .data
1722+ )
1723+ duplicate_images = [image .name for image in duplicate_images ]
1724+ frames_generator = controller .extract_video_frames (
17101725 project_name = project_name ,
17111726 folder_name = folder_name ,
17121727 video_path = path ,
@@ -1717,48 +1732,51 @@ def upload_videos_from_folder_to_project(
17171732 annotation_status = annotation_status ,
17181733 image_quality_in_editor = image_quality_in_editor ,
17191734 )
1720- if res .errors :
1721- raise AppException (res .errors )
1722- use_case = controller .upload_images_from_folder_to_project (
1723- project_name = project_name ,
1724- folder_name = folder_name ,
1725- folder_path = temp_path ,
1726- annotation_status = annotation_status ,
1727- image_quality_in_editor = image_quality_in_editor ,
1728- )
1729- images_to_upload , duplicates = use_case .images_to_upload
1735+ total_frames_count = len (frame_names )
1736+ logger .info (f"Video frame count is { total_frames_count } ." )
17301737 logger .info (
1731- f"Extracted { len ( res . data ) } frames from video. Now uploading to platform." ,
1738+ f"Extracted { total_frames_count } frames from video. Now uploading to platform." ,
17321739 )
17331740 logger .info (
1734- f"Uploading { len ( images_to_upload ) } images to project { str (project_folder_name )} ."
1741+ f"Uploading { total_frames_count } images to project { str (project_folder_name )} ."
17351742 )
1736-
1737- if len (duplicates ):
1743+ if len (duplicate_images ):
17381744 logger .warning (
1739- f"{ len (duplicates )} already existing images found that won't be uploaded."
1740- )
1741- if not images_to_upload :
1742- logger .warning (
1743- f"{ len (duplicates )} already existing images found that won't be uploaded."
1745+ f"{ len (duplicate_images )} already existing images found that won't be uploaded."
17441746 )
1747+ if set (duplicate_images ) == set (frame_names ):
17451748 continue
1746- if use_case .is_valid ():
1747- with tqdm (
1748- total = len (images_to_upload ), desc = "Uploading images"
1749- ) as progress_bar :
1749+
1750+ for _ in frames_generator :
1751+ use_case = controller .upload_images_from_folder_to_project (
1752+ project_name = project_name ,
1753+ folder_name = folder_name ,
1754+ folder_path = temp_path ,
1755+ annotation_status = annotation_status ,
1756+ image_quality_in_editor = image_quality_in_editor ,
1757+ )
1758+
1759+ images_to_upload , duplicates = use_case .images_to_upload
1760+ if not len (images_to_upload ):
1761+ continue
1762+ if not progress_bar :
1763+ progress_bar = tqdm (
1764+ total = total_frames_count , desc = "Uploading images"
1765+ )
1766+ if use_case .is_valid ():
17501767 for _ in use_case .execute ():
17511768 progress_bar .update ()
1752- uploaded , failed_images , duplicated = use_case .response .data
1753- uploaded_paths .extend (uploaded )
1754- if failed_images :
1755- logger .warning (f"Failed { len (uploaded )} ." )
1756- if duplicated :
1757- logger .warning (
1758- f"{ len (duplicated )} already existing images found that won't be uploaded."
1759- )
1760- else :
1761- raise AppException (use_case .response .errors )
1769+ uploaded , failed_images , _ = use_case .response .data
1770+ uploaded_paths .extend (uploaded )
1771+ if failed_images :
1772+ logger .warning (f"Failed { len (failed_images )} ." )
1773+ files = os .listdir (temp_path )
1774+ image_paths = [f"{ temp_path } /{ f } " for f in files ]
1775+ for path in image_paths :
1776+ os .remove (path )
1777+ else :
1778+ raise AppException (use_case .response .errors )
1779+
17621780 return uploaded_paths
17631781
17641782
@@ -1771,7 +1789,7 @@ def upload_video_to_project(
17711789 start_time : Optional [float ] = 0.0 ,
17721790 end_time : Optional [float ] = None ,
17731791 annotation_status : Optional [AnnotationStatuses ] = "NotStarted" ,
1774- image_quality_in_editor : Optional [NotEmptyStr ] = None ,
1792+ image_quality_in_editor : Optional [ImageQualityChoices ] = None ,
17751793):
17761794 """Uploads image frames from video to platform. Uploaded images will have
17771795 names "<video_name>_<frame_no>.jpg".
@@ -1799,36 +1817,77 @@ def upload_video_to_project(
17991817 """
18001818
18011819 project_name , folder_name = extract_project_folder (project )
1820+ project_folder_name = project_name + (f"/{ folder_name } " if folder_name else "" )
1821+
1822+ uploaded_paths = []
1823+ path = video_path
1824+ progress_bar = None
18021825 with tempfile .TemporaryDirectory () as temp_path :
1803- res = controller .extract_video_frames (
1826+ frame_names = VideoPlugin .get_extractable_frames (
1827+ video_path , start_time , end_time , target_fps
1828+ )
1829+ duplicate_images = (
1830+ controller .get_duplicate_images (
1831+ project_name = project_name , folder_name = folder_name , images = frame_names ,
1832+ )
1833+ .execute ()
1834+ .data
1835+ )
1836+ duplicate_images = [image .name for image in duplicate_images ]
1837+ frames_generator = controller .extract_video_frames (
18041838 project_name = project_name ,
18051839 folder_name = folder_name ,
1806- video_path = video_path ,
1840+ video_path = path ,
18071841 extract_path = temp_path ,
18081842 target_fps = target_fps ,
18091843 start_time = start_time ,
18101844 end_time = end_time ,
18111845 annotation_status = annotation_status ,
18121846 image_quality_in_editor = image_quality_in_editor ,
18131847 )
1814- if res .errors :
1815- raise AppException (res .errors )
1816- use_case = controller .upload_images_from_folder_to_project (
1817- project_name = project_name ,
1818- folder_name = folder_name ,
1819- folder_path = temp_path ,
1820- annotation_status = annotation_status ,
1821- image_quality_in_editor = image_quality_in_editor ,
1848+ total_frames_count = len (frame_names )
1849+ logger .info (
1850+ f"Extracted { total_frames_count } frames from video. Now uploading to platform." ,
18221851 )
1823- images_to_upload , _ = use_case .images_to_upload
1824- if use_case .is_valid ():
1825- with tqdm (
1826- total = len (images_to_upload ), desc = "Uploading frames."
1827- ) as progress_bar :
1852+ logger .info (
1853+ f"Uploading { total_frames_count } images to project { str (project_folder_name )} ."
1854+ )
1855+ if len (duplicate_images ):
1856+ logger .warning (
1857+ f"{ len (duplicate_images )} already existing images found that won't be uploaded."
1858+ )
1859+ if set (duplicate_images ) == set (frame_names ):
1860+ return []
1861+
1862+ for _ in frames_generator :
1863+ use_case = controller .upload_images_from_folder_to_project (
1864+ project_name = project_name ,
1865+ folder_name = folder_name ,
1866+ folder_path = temp_path ,
1867+ annotation_status = annotation_status ,
1868+ image_quality_in_editor = image_quality_in_editor ,
1869+ )
1870+
1871+ images_to_upload , duplicates = use_case .images_to_upload
1872+ if not len (images_to_upload ):
1873+ continue
1874+ if not progress_bar :
1875+ progress_bar = tqdm (total = total_frames_count , desc = "Uploading images" )
1876+ if use_case .is_valid ():
18281877 for _ in use_case .execute ():
1829- progress_bar .update (1 )
1830- return use_case .data [0 ]
1831- raise AppException (use_case .response .errors )
1878+ progress_bar .update ()
1879+ uploaded , failed_images , _ = use_case .response .data
1880+ uploaded_paths .extend (uploaded )
1881+ if failed_images :
1882+ logger .warning (f"Failed { len (failed_images )} ." )
1883+ files = os .listdir (temp_path )
1884+ image_paths = [f"{ temp_path } /{ f } " for f in files ]
1885+ for path in image_paths :
1886+ os .remove (path )
1887+ else :
1888+ raise AppException (use_case .response .errors )
1889+
1890+ return uploaded_paths
18321891
18331892
18341893@Trackable
0 commit comments