Skip to content

Commit

Permalink
Accepts fixed image as input
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric-Canas committed Jul 27, 2023
1 parent ed2a83f commit 4ca6d72
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 2 deletions.
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='webcam',
version='1.16',
version='1.17',
author='Eric-Canas',
author_email='[email protected]',
url='https://github.com/Eric-Canas/webcam',
Expand Down
71 changes: 71 additions & 0 deletions webcam/_image_webcam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""
_image_webcam.py: Contains the _ImageWebcam class, which is a convenient class that shares interface with
cv2.VideoCapture.
This class is used by the Webcam class in webcam.py to simulate a webcam stream from a single image.
It is a webcam that will always retrieve the same image, and will always return True when read() is called,
except when the image is closed (when release() is called).
Author: Eric Canas
Github: https://github.com/Eric-Canas
Email: [email protected]
Date: 27-07-2023
"""

from __future__ import annotations

import numpy as np
import cv2
import os
import time


class _ImageWebcam:
def __init__(self, image_source: str|np.ndarray, _dummy_fps: int = 30):
"""
Initialize the _ImageWebcam.
:param image_source: str or np.ndarray. Path to the image file or a numpy array of image
"""
if isinstance(image_source, str):
assert os.path.isfile(image_source), f'Image file not found at {image_source}'
self.img = cv2.imread(image_source)
elif isinstance(image_source, np.ndarray):
self.img = image_source
else:
raise ValueError('image_source must be a file path or a numpy array')

self.image_width = self.img.shape[1]
self.image_height = self.img.shape[0]

self.fps = _dummy_fps

self.start_timestamp = time.time()

def read(self):
if self.isOpened():
assert isinstance(self.img, np.ndarray), 'Non image available, but isOpened() is True'
return True, self.img.copy()
else:
return False, None

def stop(self):
self.release()

def get(self, propId):
if propId == cv2.CAP_PROP_FRAME_WIDTH:
return self.image_width
elif propId == cv2.CAP_PROP_FRAME_HEIGHT:
return self.image_height
elif propId == cv2.CAP_PROP_FPS:
return self.fps
else:
return None

def set(self, propId, value):
pass

def release(self):
self.img = None

def isOpened(self):
return self.img is not None
30 changes: 29 additions & 1 deletion webcam/webcam.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import os

from webcam._image_webcam import _ImageWebcam
from webcam._video_webcam import _VideoWebcam
from webcam._webcam_background import _WebcamBackground
from webcam._perspective_manager import _PerspectiveManager
Expand Down Expand Up @@ -67,8 +68,12 @@ def __init__(
f" Valid values are: {CROP}, {RESIZE}"
self._background = run_in_background
self.on_aspect_ratio_lost = on_aspect_ratio_lost

is_file = isinstance(src, str) and os.path.isfile(src)
# Initialize it for videos if the source is a string and a file exists at the path
if isinstance(src, str) and os.path.isfile(src):
if (is_file and _is_image_file(file_path=src)) or isinstance(src, np.ndarray):
self.cap = _ImageWebcam(image_source=src)
elif is_file and _is_video_file(file_path=src):
self.cap = _VideoWebcam(video_path=src, simulate_webcam=simulate_webcam)
# Otherwise assume it is a webcam (both webcam or RTSP stream)
else:
Expand Down Expand Up @@ -540,3 +545,26 @@ def get_rtsp_url(ip: str, username: str, password: str, port: int = 554, channel
:return: str. The generated RTSP URL.
"""
return f"rtsp://{username}:{password}@{ip}:{port}/cam/realmonitor?channel={channel}&subtype={stream}"


def _is_image_file(file_path: str) -> bool:
"""
Check if a file is an image by its extension.
:param file_path: str. Path to the file.
:return: bool. True if the file is an image, False otherwise.
"""
image_extensions = {".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".gif"}
_, extension = os.path.splitext(file_path)
return extension.lower() in image_extensions

def _is_video_file(file_path: str) -> bool:
"""
Check if a file is a video by its extension.
:param file_path: str. Path to the file.
:return: bool. True if the file is a video, False otherwise.
"""
video_extensions = {".mp4", ".avi", ".mov", ".mkv", ".wmv", ".flv", ".webm", ".mpeg", ".mpg", ".m4v", ".3gp"}
_, extension = os.path.splitext(file_path)
return extension.lower() in video_extensions

0 comments on commit 4ca6d72

Please sign in to comment.