image viewer in Python
This is a simple JPEG image viewer. It is intended for view bulk collections of images -- especially those single frame collections from a video. This tool allows you to play the images back as a video stream or to single step forward and backward through the images. You can also swap the direction of the video playback. This is very handy for browsing for individual frames. You can easily find a single frames and not worry about overshooting the mark. You can easily back up if you overshoot. Many standard video players have trouble backup up, so if you overshoot you have the jump backwards and then come against in the forward direction. There is no provision for single stepping frames backwards or playing the video backwards.
#!/usr/bin/env python ''' SYNOPSIS vview [-h,--help] [-v,--verbose] [--version] DESCRIPTION Start this program in the directory where you wish to browse JPEG images. The SPACE bar will start and stop video playback. The '.' key will single-step frome by frome. The 'r' key will reverse the direction of video playback (including single step. EXIT STATUS TODO This exits with status 0 on success and 1 otherwise. AUTHOR Noah Spurrier <email@example.com> LICENSE This license is approved by the OSI and FSF as GPL-compatible. http://opensource.org/licenses/isc-license.txt Copyright (c) 2019, Noah Spurrier PERMISSION TO USE, COPY, MODIFY, AND/OR DISTRIBUTE THIS SOFTWARE FOR ANY PURPOSE WITH OR WITHOUT FEE IS HEREBY GRANTED, PROVIDED THAT THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE APPEAR IN ALL COPIES. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. VERSION Version 1 ''' import cv2 import os, os.path # This is a bit of an abuse of the iterator semantics. # In this class the caller may choose to change direction midcourse through the iteration. # The user may also choose to allow infinite iteration by turning off the StopIteration # exception when the end of the array is reached. In this case there are two choices. # The next iteration could cause the index to be fixed at the ends so that the same value we # be returned foreve. The second choice is that the next iteration could loop around the the other # end of the arrary. This streching of the meaning of iteration is not without precedent. # The itertools module has a number of infinite iterators too choose from. class ReversableArray: def __init__(self,indexible): self.array = indexible self.step = 1 self.buf =  self.index = -1 * self.step self.last_index = len(self.array) # 0 for STOP, 1 for BOUNCE, 2 for LOOP. Any other value defaults to 0, STOP. self.deadend_disposition = 0 def reverse(self): self.step = self.step * -1 def __iter__(self): return self def next(self): return self.__next__() def __next__(self): self.index = self.index + self.step if self.index < 0 or self.index >= self.last_index: if self.deadend_disposition == 1: # BOUNCE self.index = self.index - self.step elif self.deadend_disposition == 2: # LOOP if self.index < 0: self.index = self.last_index + self.index elif self.index >= self.last_index: self.index = self.index - self.last_index else: # STOP raise StopIteration return self.array[self.index] WindowName="Main View" view_window = cv2.namedWindow(WindowName, flags=cv2.CV_WINDOW_AUTOSIZE) imageDir = "/Volumes/UNTITLED/" image_path_list = [x for x in os.listdir(imageDir) if os.path.splitext(x) == '.jpg'] print("Number Images: %d" % (len(image_path_list))) print("") print("Press . to step forward one frame.") print("Press , to step back one frame.") ra = ReversableArray(image_path_list) ra.deadend_disposition=2 wait_key_delay = 0 for filename in ra: print("Filename: %s" % (filename)) img = cv2.imread(os.path.join(imageDir, filename)) if img is None: continue cv2.imshow(WindowName,img) key = cv2.waitKey(wait_key_delay) if key == ord(' '): if wait_key_delay == 0: wait_key_delay = 50 else: wait_key_delay = 0 continue if key == ord('.'): wait_key_delay=0 continue if key == ord('r'): ra.reverse() if key == 27 or key == ord('q'): break cv2.destroyAllWindows()