From 8579c8469299f713318f1e553fd2636b9e1dafec Mon Sep 17 00:00:00 2001 From: Josh Sumner <51797700+joshqsumner@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:27:24 -0500 Subject: [PATCH 1/5] extend timelapse video to take a list of numpy arrays as source --- docs/visualize_time_lapse_video.md | 2 +- plantcv/plantcv/visualize/time_lapse_video.py | 25 ++++++++++++------- .../visualize/test_time_lapse_video.py | 16 +++++++++++- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/docs/visualize_time_lapse_video.md b/docs/visualize_time_lapse_video.md index b4857440e..78a7bde42 100644 --- a/docs/visualize_time_lapse_video.md +++ b/docs/visualize_time_lapse_video.md @@ -7,7 +7,7 @@ This function generates and saves the time-lapse video based on a list of paths **returns** frame_size - **Parameters:** - - source - List of paths to the images to create the video or file path to a directory of images to use. + - source - File path to a directory of images to use, list of paths to the images, or list of `numpy.ndarray` objects to create the video - out_filename - Name of file to save the generated video to. - fps - Frame rate (frames per second) By default fps=29.97. Commonly used values: 23.98, 24, 25, 29.97, 30, 50, 59.94, 60 diff --git a/plantcv/plantcv/visualize/time_lapse_video.py b/plantcv/plantcv/visualize/time_lapse_video.py index 5a390cb91..1fdf4b518 100644 --- a/plantcv/plantcv/visualize/time_lapse_video.py +++ b/plantcv/plantcv/visualize/time_lapse_video.py @@ -15,7 +15,8 @@ def time_lapse_video(source, out_filename='./time_lapse_video.mp4', fps=29.97): Parameters: ----------- source = string or list, - Path to a folder of images to use or list of paths to the images to create the video + Path to a folder of images to use, list of paths to the images, + or list of numpy.ndarray objects to create the video out_filename = string, name of file to save the generated video to fps = float, @@ -30,15 +31,21 @@ def time_lapse_video(source, out_filename='./time_lapse_video.mp4', fps=29.97): img_list = source if isinstance(source, str): img_list = read_dataset(source, sort=True) + # for file paths read the images + if isinstance(img_list[0], str): + imgs = [] + list_r = [] + list_c = [] + for file in img_list: + img = iio.imread(file) + list_r.append(img.shape[0]) + list_c.append(img.shape[1]) + imgs.append(img) + else: + list_c = [img.shape[0] for img in img_list] + list_r = [img.shape[1] for img in img_list] + imgs = img_list - imgs = [] - list_r = [] - list_c = [] - for file in img_list: - img = iio.imread(file) - list_r.append(img.shape[0]) - list_c.append(img.shape[1]) - imgs.append(img) max_c, max_r = np.max(list_c), np.max(list_r) # use the largest size of the images as the frame size diff --git a/tests/plantcv/visualize/test_time_lapse_video.py b/tests/plantcv/visualize/test_time_lapse_video.py index 3d39357e7..367648a51 100644 --- a/tests/plantcv/visualize/test_time_lapse_video.py +++ b/tests/plantcv/visualize/test_time_lapse_video.py @@ -4,7 +4,7 @@ from plantcv.plantcv.visualize.time_lapse_video import time_lapse_video -def test_plantcv_visualize_time_lapse_video_list_input(tmpdir): +def test_plantcv_visualize_time_lapse_video_path_list_input(tmpdir): """Test for PlantCV.""" # Generate 3 test images and saved in tmpdir list_im = [] @@ -21,6 +21,20 @@ def test_plantcv_visualize_time_lapse_video_list_input(tmpdir): assert os.path.exists(vid_name) and os.path.getsize(vid_name) > 100 +def test_plantcv_visualize_time_lapse_video_array_list_input(tmpdir): + """Test for PlantCV.""" + # Generate 3 test images and saved in tmpdir + list_im = [] + for i in range(3): + temp_img = np.random.rand(3, 3) + min_, max_ = np.nanmin(temp_img), np.nanmax(temp_img) + temp_img = np.interp(temp_img, (min_, max_), (0, 255)).astype('uint8') + list_im.append(temp_img) + vid_name = os.path.join(tmpdir, 'test_time_lapse_video.mp4') + _ = time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) + assert os.path.exists(vid_name) and os.path.getsize(vid_name) > 100 + + def test_plantcv_visualize_time_lapse_video_str_input(tmpdir): """Test for PlantCV.""" # Generate 3 test images and saved in tmpdir From 133ae685b30ff7760324e18ae61da7aa348874b2 Mon Sep 17 00:00:00 2001 From: Josh Sumner <51797700+joshqsumner@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:36:00 -0500 Subject: [PATCH 2/5] deepsource being funny --- tests/plantcv/visualize/test_time_lapse_video.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/plantcv/visualize/test_time_lapse_video.py b/tests/plantcv/visualize/test_time_lapse_video.py index 367648a51..9e704d061 100644 --- a/tests/plantcv/visualize/test_time_lapse_video.py +++ b/tests/plantcv/visualize/test_time_lapse_video.py @@ -25,7 +25,7 @@ def test_plantcv_visualize_time_lapse_video_array_list_input(tmpdir): """Test for PlantCV.""" # Generate 3 test images and saved in tmpdir list_im = [] - for i in range(3): + for _ in range(3): temp_img = np.random.rand(3, 3) min_, max_ = np.nanmin(temp_img), np.nanmax(temp_img) temp_img = np.interp(temp_img, (min_, max_), (0, 255)).astype('uint8') From dc34dbb2e6aa7a64114c92bb54594d8fba7900d0 Mon Sep 17 00:00:00 2001 From: Josh Sumner <51797700+joshqsumner@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:44:31 -0500 Subject: [PATCH 3/5] no return --- docs/visualize_time_lapse_video.md | 6 +++--- plantcv/plantcv/visualize/time_lapse_video.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/visualize_time_lapse_video.md b/docs/visualize_time_lapse_video.md index 78a7bde42..ba3a050ea 100644 --- a/docs/visualize_time_lapse_video.md +++ b/docs/visualize_time_lapse_video.md @@ -4,7 +4,7 @@ This function generates and saves the time-lapse video based on a list of paths **plantcv.visualize.time_lapse_video**(*source, out_filename='./time_lapse_video.mp4', fps=29.97*) -**returns** frame_size +**returns** None - **Parameters:** - source - File path to a directory of images to use, list of paths to the images, or list of `numpy.ndarray` objects to create the video @@ -23,8 +23,8 @@ from plantcv import plantcv as pcv # Note you will have to change this part on your own path img_directory = './path_to_images_directory/' -frame_size = pcv.visualize.time_lapse_video(source=img_directory, - out_filename='./eg_time_lapse.mp4') +_ = pcv.visualize.time_lapse_video(source=img_directory, + out_filename='./eg_time_lapse.mp4') ``` **Video generated** diff --git a/plantcv/plantcv/visualize/time_lapse_video.py b/plantcv/plantcv/visualize/time_lapse_video.py index 1fdf4b518..b2f481cc7 100644 --- a/plantcv/plantcv/visualize/time_lapse_video.py +++ b/plantcv/plantcv/visualize/time_lapse_video.py @@ -61,5 +61,3 @@ def time_lapse_video(source, out_filename='./time_lapse_video.mp4', fps=29.97): frames = [resize(img, frame_size, interpolation=None) for img in imgs] iio.imwrite(out_filename, frames, plugin="FFMPEG", fps=fps, codec="libx264") - - return frame_size From 865794a044aa1878c2a9e8be95a43d4bd09909d9 Mon Sep 17 00:00:00 2001 From: Josh Sumner <51797700+joshqsumner@users.noreply.github.com> Date: Mon, 29 Jun 2026 15:10:00 -0500 Subject: [PATCH 4/5] deepsource don't assign None returns --- docs/visualize_time_lapse_video.md | 4 ++-- tests/plantcv/visualize/test_time_lapse_video.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/visualize_time_lapse_video.md b/docs/visualize_time_lapse_video.md index ba3a050ea..211e53dcd 100644 --- a/docs/visualize_time_lapse_video.md +++ b/docs/visualize_time_lapse_video.md @@ -23,8 +23,8 @@ from plantcv import plantcv as pcv # Note you will have to change this part on your own path img_directory = './path_to_images_directory/' -_ = pcv.visualize.time_lapse_video(source=img_directory, - out_filename='./eg_time_lapse.mp4') +pcv.visualize.time_lapse_video(source=img_directory, + out_filename='./eg_time_lapse.mp4') ``` **Video generated** diff --git a/tests/plantcv/visualize/test_time_lapse_video.py b/tests/plantcv/visualize/test_time_lapse_video.py index 9e704d061..72d3eb0f1 100644 --- a/tests/plantcv/visualize/test_time_lapse_video.py +++ b/tests/plantcv/visualize/test_time_lapse_video.py @@ -17,7 +17,7 @@ def test_plantcv_visualize_time_lapse_video_path_list_input(tmpdir): list_im.append(img_i_path) vid_name = os.path.join(tmpdir, 'test_time_lapse_video.mp4') - _ = time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) + time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) assert os.path.exists(vid_name) and os.path.getsize(vid_name) > 100 @@ -31,7 +31,7 @@ def test_plantcv_visualize_time_lapse_video_array_list_input(tmpdir): temp_img = np.interp(temp_img, (min_, max_), (0, 255)).astype('uint8') list_im.append(temp_img) vid_name = os.path.join(tmpdir, 'test_time_lapse_video.mp4') - _ = time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) + time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) assert os.path.exists(vid_name) and os.path.getsize(vid_name) > 100 @@ -46,7 +46,7 @@ def test_plantcv_visualize_time_lapse_video_str_input(tmpdir): cv2.imwrite(img_i_path, temp_img) vid_name = os.path.join(tmpdir, 'test_time_lapse_video.mp4') - _ = time_lapse_video(source=str(tmpdir), out_filename=vid_name, fps=29.97) + time_lapse_video(source=str(tmpdir), out_filename=vid_name, fps=29.97) assert os.path.exists(vid_name) and os.path.getsize(vid_name) > 100 @@ -64,7 +64,7 @@ def test_plantcv_visualize_time_lapse_video_different_img_sizes_warns(tmpdir, ca list_im.append(img_i_path) vid_name = os.path.join(tmpdir, 'test_time_lapse_video.mp4') - _ = time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) + time_lapse_video(source=list_im, out_filename=vid_name, fps=29.97) _, err = capsys.readouterr() assert "Warning" in err and os.path.exists(vid_name) From 478a2a301db099c0474661755cd2059c523b60f0 Mon Sep 17 00:00:00 2001 From: Noah Fahlgren Date: Fri, 10 Jul 2026 17:36:49 -0500 Subject: [PATCH 5/5] Remove output from time_lapse_video --- docs/updating.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/updating.md b/docs/updating.md index cb6b34c8b..2ced08361 100644 --- a/docs/updating.md +++ b/docs/updating.md @@ -1625,7 +1625,7 @@ pages for more details on the input and output variable types. * pre v4.0: NA * post v4.0: frame_size = **pcv.visualize.time_lapse_video**(*img_list, out_filename='./time_lapse_video.mp4', fps=29.97, display=True*) -* post v5.0: frame_size = **pcv.visualize.time_lapse_video**(*source, out_filename='./time_lapse_video.mp4', fps=29.97*) +* post v5.0: **pcv.visualize.time_lapse_video**(*source, out_filename='./time_lapse_video.mp4', fps=29.97*) #### plantcv.watershed_segmentation