#coding: utf-8
import os
import cv2
import numpy as np
from . import cvui
from ._cvpath import PYCHARMERS_OPENCV_VIDEO_DIR
from .editing import resize_aspect
from .video_image_handler import VideoCaptureCreate
from .windows import cv2key2chr
from ..utils.generic_utils import now_str
from ..utils.subprocess_utils import get_monitor_size
from ..utils._colorings import toBLUE
from ..__meta__ import __project_name__
[docs]class cv2Project():
"""OpenCV project wrapper with useful GUI tools.
Args:
args (Namespace) : Simple object for storing attributes.
Note:
* Image object ( ``np.ndarray`` ) has the shape ( ``height`` , ``width`` , ``channel`` )
* ``XXX_size`` attributes are formatted as ( ``width`` , ``height`` )
Attributes:
cap (VideoCapture) : VideoCapture (mimic) object. See :meth:`VideoCaptureCreate <pycharmers.opencv.video_image_handler.VideoCaptureCreate>`
monitor (np.ndarray) : Background image. shape= ( ``monitor_height`` , ``monitor_width``, 3)
monitor_height : The height of monitor.
monitor_width : The width of monitor.
original_height (int) : The height of original frame.
original_width (int) : The width of original frame.
frame_height (int) : The height of resized frame.
frame_width (int) : The width of resized frame.
frame_dsize (tuple) : ( ``frame_width`` , ``frame_height`` )
frame_halfsize (tuple) : ( ``frame_width//2`` , ``frame_height//2`` )
gui_x (int) : ``frame_width`` + ``gui_margin``
fps (int) : Frame per seconds.
video (cv2.VideoWriter) : Video Writer.
video_fn (str) : The file name of video.
OtherAttributes:
See :py:class:`cv2ArgumentParser <pycharmers.utils.argparse_utils.cv2ArgumentParser>` .
"""
def __init__(self, args, **kwargs):
self.__dict__.update(args.__dict__)
self.__dict__.update(kwargs)
self.init()
[docs] def init(self):
"""Initialize VideoCapture (mimic) object and GUI tools.
Note:
* To run this method, ``self`` must have these attributes.
* winname (str) : Window name.
* path (str) : Path to video or image.
* cam (int) : The ID of the web camera.
* ext (str) : The extension for saved image.
* gui_width (int) : The width of the GUI tools.
* gui_margin (int) : The margin of GUI control tools.
* monitor_size (ListParamProcessor) : Monitor size. ( ``width`` , ``height`` )
* autofit (bool) : Whether to fit display size to window size.
* twitter (bool) : Whether you want to run for tweet. ( ``display_size`` will be () )
* capture (bool) : Whether you want to save as video.
* After run this method, ``self`` will have these attributes.
* cap (VideoCapture) : VideoCapture (mimic) object. See :meth:`VideoCaptureCreate <pycharmers.opencv.video_image_handler.VideoCaptureCreate>`
* monitor (np.ndarray) : Background image. shape= ( ``monitor_height`` , ``monitor_width``, 3)
* monitor_height : The height of monitor.
* monitor_width : The width of monitor.
* original_height (int) : The height of original frame.
* original_width (int) : The width of original frame.
* frame_height (int) : The height of resized frame.
* frame_width (int) : The width of resized frame.
* frame_dsize (tuple) : ( ``frame_width`` , ``frame_height`` )
* frame_halfsize (tuple) : ( ``frame_width//2`` , ``frame_height//2`` )
* gui_x (int) : ``frame_width`` + ``gui_margin``
* fps (int) : Frame per seconds.
* video (cv2.VideoWriter) : Video Writer.
* video_fn (str) : The file name of video.
* fn_prefix (str) : The prefix of filename ( ``"" if self.path is None else self.path+"."`` )
"""
cap = VideoCaptureCreate(path=self.path, cam=self.cam)
if self.autofit:
monitor_width, monitor_height = get_monitor_size()
elif self.twitter:
monitor_width, monitor_height = (1300, 733)
else:
monitor_width, monitor_height = self.monitor_size
fn_prefix = "" if self.path is None else self.path+"."
monitor = np.zeros(shape=(monitor_height, monitor_width, 3), dtype=np.uint8)
original_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
original_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height, frame_width = resize_aspect(src=np.zeros(shape=(original_height, original_width, 1), dtype=np.uint8), dsize=(monitor_width-self.gui_width, monitor_height)).shape[:2]
frame_dsize = (frame_width, frame_height)
frame_halfsize = (frame_width//2, frame_height//2)
gui_x = frame_width + self.gui_margin
fps = cap.get(cv2.CAP_PROP_FPS)
video_path = f'{fn_prefix}.{now_str()}.mp4'
video = cv2.VideoWriter(video_path, cv2.VideoWriter_fourcc('m','p','4','v'), fps, (monitor_width, monitor_height))
print(f"Created {toBLUE(video_path)}")
cvui.init(windowNames=self.winname, numWindows=1, delayWaitKey=1, createNamedWindows=True)
cv2.moveWindow(winname=self.winname, x=0, y=0)
# NOTE: Register the variables defined here as attributes.
defined_args = locals()
defined_args.pop("self")
self.__dict__.update(defined_args)
[docs] def wrap(self, func):
"""Wrap the function.
Args:
func (function) : A function that receives and returns ``frame``.
"""
params = self.__dict__
char = ""
while (True):
self.monitor[:] = self.gui_color
ret, frame = self.cap.read()
if not ret: break
# Wrap the function.
frame = func(frame=frame, **params)
# Recieve the key.
key = cvui.lastKeyPressed()
if key != -1:
char = cv2key2chr(key)
# y = self.frame_height-120
cvui.text(where=self.monitor, x=self.gui_x, y=self.frame_height-120, text=f" Your input: {char}")
# y = self.frame_height-95
if cvui.button(where=self.monitor, x=self.gui_x, y=self.frame_height-95, width=70, height=30, label="&Save", color=(137, 225, 241)):
filename = f'{self.fn_prefix}.{now_str()}{self.ext}'
cv2.imwrite(filename=filename, img=frame)
cv2.imshow(winname=filename, mat=resize_aspect(cv2.imread(filename), dsize=self.frame_halfsize))
print(f"Saved {toBLUE(filename)}")
if cvui.button(where=self.monitor, x=self.gui_x+80, y=self.frame_height-95, width=80, height=30, label="&Stop" if self.capture else "&Capture", color=(110, 93, 211) if self.capture else (177, 163, 121)):
self.capture = not self.capture
# y = self.frame_height-60
if key == cvui.ESCAPE or cvui.button(where=self.monitor, x=self.gui_x+105, y=self.frame_height-60, width=55, height=30, label="&Quit", color=(128, 95, 159)):
break
if cvui.button(where=self.monitor, x=self.gui_x, y=self.frame_height-60, width=95, height=30, label="&FullScreen", color=(116, 206, 173)):
cv2.setWindowProperty(
winname=self.winname,
prop_id=cv2.WND_PROP_FULLSCREEN,
prop_value=1-cv2.getWindowProperty(
winname=self.winname,
prop_id=cv2.WND_PROP_FULLSCREEN,
)
)
# y = self.frame_height-20
cvui.text(where=self.monitor, x=self.gui_x, y=self.frame_height-20, text=__project_name__)
cvui.beginRow(where=self.monitor, x=0, y=0)
cvui.image(image=cv2.resize(src=frame, dsize=self.frame_dsize))
cvui.endRow()
cvui.update()
cv2.imshow(self.winname, self.monitor)
if self.capture:
self.video.write(self.monitor)
self.release()
[docs] def release(self):
"""Do the necessary processing at the end"""
cv2.destroyAllWindows()
self.cap.release()
if os.path.getsize(self.video_path) <= 1000:
os.remove(self.video_path)
print(f"Deleted {toBLUE(self.video_path)} (because you didn't capture the window)")