Added high speed mode to cv pubsubs. Added files for pip. Fixed code to match PEP8.
This commit is contained in:
@@ -1 +1 @@
|
||||
A simple pub-sub threaded cv webcam opener
|
||||
A threaded PubSub OpenCV interface. Webcam and video feeds to multiple windows is supported.
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
from .cv_webcam_pub import *
|
||||
from .sub_win import sub_win_loop, frameDict
|
||||
from .cv_window_sub import sub_win_loop, frame_dict
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from .listen_default import _listen_default
|
||||
from .listen_default import listen_default
|
||||
from .get_cam_ids import get_cam_ids
|
||||
from .pub_cam import pub_cam_thread
|
||||
from .frame_handler import frame_handler_thread
|
||||
from .cam_ctrl import cam_ctrl
|
||||
from .camctrl import CamCtrl
|
||||
|
||||
@@ -2,9 +2,10 @@ import pubsub
|
||||
if False:
|
||||
from typing import Union
|
||||
|
||||
class cam_ctrl:
|
||||
|
||||
class CamCtrl:
|
||||
|
||||
@staticmethod
|
||||
def stop_cam(cam_id # type: Union[int, str]
|
||||
):
|
||||
pubsub.publish("cvcamhandlers." + str(cam_id) + ".cmd", 'q')
|
||||
pubsub.publish("cvcamhandlers." + str(cam_id) + ".cmd", 'q')
|
||||
@@ -1,35 +1,39 @@
|
||||
import pubsub
|
||||
import numpy as np
|
||||
import threading
|
||||
from .listen_default import _listen_default
|
||||
from .listen_default import listen_default
|
||||
from .pub_cam import pub_cam_thread
|
||||
|
||||
if False:
|
||||
from typing import Union, Tuple, Any, Callable
|
||||
|
||||
|
||||
def frame_handler_loop(cam_id, # type: Union[int, str]
|
||||
frame_handler, # type: Callable[[int, np.ndarray], Any]
|
||||
frame_handler, # type: Callable[[np.ndarray, int], Any]
|
||||
request_size=(1280, 720), # type: Tuple[int, int]
|
||||
fps_limit = 60
|
||||
high_speed=False, # type: bool
|
||||
fps_limit=240 # type: float
|
||||
):
|
||||
t = pub_cam_thread(cam_id, request_size, fps_limit)
|
||||
t = pub_cam_thread(cam_id, request_size, high_speed, fps_limit)
|
||||
sub_cam = pubsub.subscribe("cvcams." + str(cam_id) + ".vid")
|
||||
sub_owner = pubsub.subscribe("cvcamhandlers." + str(cam_id) + ".cmd")
|
||||
msg_owner = ''
|
||||
while msg_owner != 'q':
|
||||
frame = _listen_default(sub_cam, timeout=.1) # type: np.ndarray
|
||||
frame = listen_default(sub_cam, timeout=.1) # type: np.ndarray
|
||||
if frame is not None:
|
||||
frame = frame[0]
|
||||
frame_handler(frame, cam_id)
|
||||
msg_owner = _listen_default(sub_owner, block=False, empty='')
|
||||
msg_owner = listen_default(sub_owner, block=False, empty='')
|
||||
pubsub.publish("cvcams." + str(cam_id) + ".cmd", 'q')
|
||||
t.join()
|
||||
|
||||
|
||||
def frame_handler_thread(cam_id, # type: Union[int, str]
|
||||
frame_handler, # type: Callable[[int, np.ndarray], Any]
|
||||
request_size=(1280, 720), # type: Tuple[int, int]
|
||||
fps_limit = 60
|
||||
): # type: (...) -> threading.Thread
|
||||
t = threading.Thread(target=frame_handler_loop, args=(cam_id, frame_handler, request_size, fps_limit))
|
||||
frame_handler, # type: Callable[[int, np.ndarray], Any]
|
||||
request_size=(1280, 720), # type: Tuple[int, int]
|
||||
high_speed=False, # type: bool
|
||||
fps_limit=240 # type: float
|
||||
): # type: (...) -> threading.Thread
|
||||
t = threading.Thread(target=frame_handler_loop, args=(cam_id, frame_handler, request_size, high_speed, fps_limit))
|
||||
t.start()
|
||||
return t
|
||||
return t
|
||||
|
||||
@@ -14,5 +14,3 @@ def get_cam_ids(): # type: () -> List[int]
|
||||
cam_list.append(len(cam_list))
|
||||
|
||||
return cam_list
|
||||
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
if False:
|
||||
from typing import Any, Optional, queue
|
||||
|
||||
def _listen_default(sub, # type: queue
|
||||
block=True, # type: bool
|
||||
timeout=None, # type: Optional[float]
|
||||
empty=None # type: Any
|
||||
): # type: (...)->Any
|
||||
|
||||
def listen_default(sub, # type: queue
|
||||
block=True, # type: bool
|
||||
timeout=None, # type: Optional[float]
|
||||
empty=None # type: Any
|
||||
): # type: (...)->Any
|
||||
try:
|
||||
msg = (sub.listen(block=block, timeout=timeout))
|
||||
try:
|
||||
@@ -14,4 +15,4 @@ def _listen_default(sub, # type: queue
|
||||
msg = empty
|
||||
except queue.Empty:
|
||||
msg = empty
|
||||
return msg
|
||||
return msg
|
||||
|
||||
+29
-21
@@ -3,57 +3,65 @@ import cv2
|
||||
import numpy as np
|
||||
import time
|
||||
import threading
|
||||
from .listen_default import _listen_default
|
||||
from .listen_default import listen_default
|
||||
|
||||
if False:
|
||||
from typing import Union, Tuple
|
||||
|
||||
|
||||
def pub_cam_loop(cam_id, # type: Union[int, str]
|
||||
request_size=(1280, 720), # type: Tuple[int, int]
|
||||
fps_limit = 60
|
||||
): # type: (...)->bool
|
||||
"""
|
||||
request_size=(1280, 720), # type: Tuple[int, int]
|
||||
high_speed=False, # type: bool
|
||||
fps_limit=240 # type: float
|
||||
): # type: (...)->bool
|
||||
"""Publishes whichever camera you select to cvcams.<cam_id>.vid
|
||||
You can send a quit command 'q' to cvcams.<cam_id>.cmd
|
||||
Status information, such as failure to open, will be posted to cvcams.<cam_id>.status
|
||||
|
||||
|
||||
:param cam_id:
|
||||
:param request_size:
|
||||
:return:
|
||||
:param high_speed: Selects mjpeg transferring, which most cameras seem to support, so speed isn't limited
|
||||
:param fps_limit: Limits the frames per second.
|
||||
:param cam_id: An integer representing which webcam to use, or a string representing a video file.
|
||||
:param request_size: A tuple with width, then height, to request the video size.
|
||||
:return: True if loop ended normally, False if it failed somehow.
|
||||
"""
|
||||
sub = pubsub.subscribe("cvcams." + str(cam_id) + ".cmd")
|
||||
msg = ''
|
||||
cam = cv2.VideoCapture(cam_id)
|
||||
#cam.set(cv2.CAP_PROP_CONVERT_RGB, 0)
|
||||
# cam.set(cv2.CAP_PROP_CONVERT_RGB, 0)
|
||||
|
||||
if high_speed:
|
||||
cam.set(cv2.CAP_PROP_FOURCC, cv2.CAP_OPENCV_MJPEG)
|
||||
|
||||
cam.set(cv2.CAP_PROP_FOURCC, cv2.CAP_OPENCV_MJPEG)
|
||||
cam.set(cv2.CAP_PROP_FRAME_WIDTH, request_size[0])
|
||||
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, request_size[1])
|
||||
|
||||
#cam.set(cv2.CAP_PROP_FPS, fps_limit) Breaks FPS with Windows. WTF guys...
|
||||
if not cam.isOpened():
|
||||
pubsub.publish("cvcams." + str(cam_id) + ".status", "failed")
|
||||
return False
|
||||
#now = time.time()
|
||||
now = time.time()
|
||||
while msg != 'q':
|
||||
#time.sleep(1. / (fps_limit - (time.time() - now)))
|
||||
#now = time.time()
|
||||
time.sleep(1. / (fps_limit - (time.time() - now)))
|
||||
now = time.time()
|
||||
(ret, frame) = cam.read() # type: Tuple[bool, np.ndarray ]
|
||||
if ret is False or not isinstance(frame, np.ndarray):
|
||||
cam.release()
|
||||
pubsub.publish("cvcams." + str(cam_id) + ".status", "failed")
|
||||
return False
|
||||
pubsub.publish("cvcams." + str(cam_id) + ".vid", (frame,))
|
||||
msg = _listen_default(sub, block=False, empty='')
|
||||
msg = listen_default(sub, block=False, empty='')
|
||||
|
||||
pass
|
||||
cam.release()
|
||||
return True
|
||||
|
||||
def pub_cam_thread(cam_id, # type: Union[int, str]
|
||||
request_ize=(1280, 720), # type: Tuple[int, int]
|
||||
fps_limit = 60
|
||||
):
|
||||
|
||||
def pub_cam_thread(cam_id, # type: Union[int, str]
|
||||
request_ize=(1280, 720), # type: Tuple[int, int]
|
||||
high_speed=False, # type: bool
|
||||
fps_limit=240 # type: float
|
||||
):
|
||||
# type: (...) -> threading.Thread
|
||||
t = threading.Thread(target=pub_cam_loop, args=(cam_id, request_ize, fps_limit))
|
||||
t = threading.Thread(target=pub_cam_loop, args=(cam_id, request_ize, high_speed, fps_limit))
|
||||
t.start()
|
||||
return t
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import cv2
|
||||
from .cv_webcam_pub.cam_ctrl import cam_ctrl
|
||||
from .cv_webcam_pub.camctrl import CamCtrl
|
||||
|
||||
if False:
|
||||
from typing import List
|
||||
|
||||
cvWindows = []
|
||||
frameDict = {}
|
||||
frame_dict = {}
|
||||
|
||||
|
||||
# todo: figure out how to get the red x button to work. Try: https://stackoverflow.com/a/37881722/782170
|
||||
@@ -16,20 +16,20 @@ def sub_win_loop(*,
|
||||
input_cams=(0,)
|
||||
):
|
||||
global cvWindows
|
||||
global frameDict
|
||||
global frame_dict
|
||||
|
||||
while True:
|
||||
for i in range(len(input_vid_global_names)):
|
||||
if input_vid_global_names[i] in frameDict and frameDict[input_vid_global_names[i]] is not None:
|
||||
if input_vid_global_names[i] in frame_dict and frame_dict[input_vid_global_names[i]] is not None:
|
||||
if callbacks[i % len(callbacks)] is not None:
|
||||
frames = callbacks[i % len(callbacks)](frameDict[input_vid_global_names[i]])
|
||||
frames = callbacks[i % len(callbacks)](frame_dict[input_vid_global_names[i]])
|
||||
else:
|
||||
frames = frameDict[input_vid_global_names[i]]
|
||||
frames = frame_dict[input_vid_global_names[i]]
|
||||
for f in range(len(frames)):
|
||||
cv2.imshow(names[f % len(names)], frames[f])
|
||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||
for name in names:
|
||||
cv2.destroyWindow(name)
|
||||
for c in input_cams:
|
||||
cam_ctrl.stop_cam(c)
|
||||
CamCtrl.stop_cam(c)
|
||||
return
|
||||
@@ -0,0 +1,13 @@
|
||||
from distutils.core import setup
|
||||
|
||||
setup(
|
||||
name= 'cv_pubsubs',
|
||||
packages = ['cv_webcam_pub', 'cv_window_sub'],
|
||||
version='0.1',
|
||||
description='Pubsub interface for Python OpenCV',
|
||||
author='Josh Miklos',
|
||||
author_email='Simulator.Leek@gmail.com',
|
||||
url='https://github.com/SimLeek/cv_pubsubs',
|
||||
download_url='*',
|
||||
keywords=['OpenCV', 'PubSub']
|
||||
)
|
||||
@@ -9,9 +9,12 @@ class TestFrameHandler(ut.TestCase):
|
||||
|
||||
def test_frame_handler(frame, cam_id):
|
||||
if self.i == 200:
|
||||
w.cam_ctrl.stop_cam(cam_id)
|
||||
w.CamCtrl.stop_cam(cam_id)
|
||||
if self.i % 100 == 0:
|
||||
print(frame.shape)
|
||||
self.i += 1
|
||||
|
||||
w.frame_handler_thread(0, test_frame_handler)
|
||||
w.frame_handler_thread(0, test_frame_handler,
|
||||
request_size=(1280, 720),
|
||||
high_speed=True,
|
||||
fps_limit=240)
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
import unittest as ut
|
||||
import cv_pubsubs.cv_webcam_pub as w
|
||||
from cv_pubsubs.sub_win import frameDict, sub_win_loop
|
||||
from cv_pubsubs.cv_window_sub import frame_dict, sub_win_loop
|
||||
|
||||
|
||||
class TestSubWin(ut.TestCase):
|
||||
|
||||
def test_sub(self):
|
||||
def camHandler(frame, camId):
|
||||
frameDict[str(camId) + "Frame"] = (frame,frame)
|
||||
def cam_handler(frame, cam_id):
|
||||
frame_dict[str(cam_id) + "Frame"] = (frame, frame)
|
||||
|
||||
t = w.frame_handler_thread(0, camHandler)
|
||||
t = w.frame_handler_thread(0, cam_handler,
|
||||
request_size=(1280, 720),
|
||||
high_speed=True,
|
||||
fps_limit=240
|
||||
)
|
||||
|
||||
sub_win_loop(names=['cammy', 'cammy2'], input_vid_global_names=[str(0)+"Frame"])
|
||||
sub_win_loop(names=['cammy', 'cammy2'],
|
||||
input_vid_global_names=[str(0) + "Frame"])
|
||||
|
||||
w.cam_ctrl.stop_cam(0)
|
||||
w.CamCtrl.stop_cam(0)
|
||||
|
||||
t.join()
|
||||
|
||||
Reference in New Issue
Block a user