fix playback timing, apply cam settings, rest wb/exp key binding
This commit is contained in:
parent
5aec1e0dac
commit
c4e9c00b67
157
frame_opencv.py
157
frame_opencv.py
|
@ -9,14 +9,10 @@ import signal
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
from timeit import default_timer as timer
|
||||||
import tomllib
|
import tomllib
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import serialutils
|
||||||
# TODO : find camera module version from image size
|
|
||||||
# https://www.raspberrypi.com/documentation/accessories/camera.html#hardware-specification
|
|
||||||
# v4l2-ctl --list-framesizes=YU12
|
|
||||||
# 2592 x 1944 == v1
|
|
||||||
# 3280 × 2464 == v2
|
|
||||||
|
|
||||||
running_from_folder = os.path.realpath(__file__)
|
running_from_folder = os.path.realpath(__file__)
|
||||||
alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
|
||||||
|
@ -65,6 +61,15 @@ for location in config_locations:
|
||||||
config_found_msg = _("Found configuration file in {}").format(os.path.expanduser(location))
|
config_found_msg = _("Found configuration file in {}").format(os.path.expanduser(location))
|
||||||
print(config_found_msg)
|
print(config_found_msg)
|
||||||
|
|
||||||
|
def reset_wb_exp():
|
||||||
|
# Flip auto-exposure, white-balance on to adapt to light environment
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c auto_exposure=0 -c white_balance_auto_preset=1')
|
||||||
|
# Give some time to the captor to adapt
|
||||||
|
time.sleep(1)
|
||||||
|
# Flip back, wb 3 = fluorescent
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c auto_exposure=1 -c white_balance_auto_preset=2')
|
||||||
|
|
||||||
|
|
||||||
def generate_text_image(text:str, screen_w, screen_h, bullets=False):
|
def generate_text_image(text:str, screen_w, screen_h, bullets=False):
|
||||||
text_image = Image.new('RGB',
|
text_image = Image.new('RGB',
|
||||||
(screen_w, screen_h),
|
(screen_w, screen_h),
|
||||||
|
@ -352,26 +357,26 @@ def remove_frame(img_list, img_index):
|
||||||
else:
|
else:
|
||||||
return img_list, 0, blank_image
|
return img_list, 0, blank_image
|
||||||
|
|
||||||
def playback_animation(img_list, img_index):
|
# ~ def playback_animation(img_list, img_index):
|
||||||
# save onionskin state
|
# ~ # save onionskin state
|
||||||
if onionskin:
|
# ~ if onionskin:
|
||||||
onionskin = False
|
# ~ onionskin = False
|
||||||
onionskin_was_on = True
|
# ~ onionskin_was_on = True
|
||||||
|
|
||||||
for file in img_list:
|
# ~ for file in img_list:
|
||||||
img = update_image(img_list, img_list.index(file))
|
# ~ img = update_image(img_list, img_list.index(file))
|
||||||
print(str(img_list.index(file)) + " : " + file )
|
# ~ print(str(img_list.index(file)) + " : " + file )
|
||||||
cv2.imshow("StopiCV", img)
|
# ~ cv2.imshow("StopiCV", img)
|
||||||
time.sleep(.5)
|
# ~ time.sleep(.5)
|
||||||
# Restore previous frame
|
# ~ # Restore previous frame
|
||||||
print(img_index)
|
# ~ print(img_index)
|
||||||
frame_before_playback = update_image(img_list, img_index)
|
# ~ frame_before_playback = update_image(img_list, img_index)
|
||||||
# ~ cv2.imshow("StopiCV", img)
|
# ~ cv2.imshow("StopiCV", img)
|
||||||
# Restore onionskin
|
# ~ # Restore onionskin
|
||||||
if 'onionskin_was_on' in locals():
|
# ~ if 'onionskin_was_on' in locals():
|
||||||
onionskin = True
|
# ~ onionskin = True
|
||||||
# Restore index
|
# ~ # Restore index
|
||||||
return img_index, frame_before_playback
|
# ~ return img_index, frame_before_playback
|
||||||
|
|
||||||
def testDevice(source):
|
def testDevice(source):
|
||||||
cap = cv2.VideoCapture(source)
|
cap = cv2.VideoCapture(source)
|
||||||
|
@ -424,7 +429,83 @@ def main(args):
|
||||||
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 900)
|
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 900)
|
||||||
|
|
||||||
frame = get_onionskin_frame(savepath, index)
|
frame = get_onionskin_frame(savepath, index)
|
||||||
|
|
||||||
|
# TODO : (re)set camera settings on startup
|
||||||
|
# Using serial to send v4l2-ctl cmd to the camera
|
||||||
|
# Use v4l-ctl to flip frame
|
||||||
|
# v4l2-ctl -d /dev/video0 -c vertical_flip=1 -c control=value
|
||||||
|
# DEPRECATED : Using config file and loading with camera-ctl
|
||||||
|
# Write config file to /tmp/blah
|
||||||
|
# ~ write_config_file = '''rm /tmp/blah && echo "power_line_frequency=2
|
||||||
|
# ~ sharpness=50
|
||||||
|
# ~ video_bitrate=25000000
|
||||||
|
# ~ auto_exposure=1
|
||||||
|
# ~ auto_exposure_bias=2
|
||||||
|
# ~ white_balance_auto_preset=3
|
||||||
|
# ~ exposure_metering_mode=1
|
||||||
|
# ~ " > /tmp/blah'''
|
||||||
|
# Apply config
|
||||||
|
# ~ apply_config = '/opt/camera-control/camera-ctl -c /tmp/blah -v /dev/video0 -i repeat_sequence_header -i h264_i_frame_period -i h264_level -i h264_profile -i compression_quality\rl\rq\r'
|
||||||
|
# ~ serialutils.send_serial_cmd(serialutils.find_cam_port(), write_config_file)
|
||||||
|
# ~ serialutils.send_serial_cmd(serialutils.find_cam_port(), apply_config)
|
||||||
|
|
||||||
|
# ~ User Controls
|
||||||
|
|
||||||
|
# ~ brightness 0x00980900 (int) : min=0 max=100 step=1 default=50 value=50 flags=slider
|
||||||
|
# ~ contrast 0x00980901 (int) : min=-100 max=100 step=1 default=0 value=-2 flags=slider
|
||||||
|
# ~ saturation 0x00980902 (int) : min=-100 max=100 step=1 default=0 value=5 flags=slider
|
||||||
|
# ~ red_balance 0x0098090e (int) : min=1 max=7999 step=1 default=1000 value=1000 flags=slider
|
||||||
|
# ~ blue_balance 0x0098090f (int) : min=1 max=7999 step=1 default=1000 value=1000 flags=slider
|
||||||
|
# ~ horizontal_flip 0x00980914 (bool) : default=0 value=0
|
||||||
|
# ~ vertical_flip 0x00980915 (bool) : default=0 value=0
|
||||||
|
# ~ power_line_frequency 0x00980918 (menu) : min=0 max=3 default=1 value=1
|
||||||
|
# ~ sharpness 0x0098091b (int) : min=-100 max=100 step=1 default=0 value=10 flags=slider
|
||||||
|
# ~ color_effects 0x0098091f (menu) : min=0 max=15 default=0 value=0
|
||||||
|
# ~ rotate 0x00980922 (int) : min=0 max=360 step=90 default=0 value=0 flags=modify-layout
|
||||||
|
# ~ color_effects_cbcr 0x0098092a (int) : min=0 max=65535 step=1 default=32896 value=32896
|
||||||
|
|
||||||
|
# ~ Codec Controls
|
||||||
|
|
||||||
|
# ~ video_bitrate_mode 0x009909ce (menu) : min=0 max=1 default=0 value=0 flags=update
|
||||||
|
# ~ video_bitrate 0x009909cf (int) : min=25000 max=25000000 step=25000 default=10000000 value=25000000
|
||||||
|
# ~ repeat_sequence_header 0x009909e2 (bool) : default=0 value=0
|
||||||
|
# ~ h264_i_frame_period 0x00990a66 (int) : min=0 max=2147483647 step=1 default=60 value=60
|
||||||
|
# ~ h264_level 0x00990a67 (menu) : min=0 max=11 default=11 value=11
|
||||||
|
# ~ h264_profile 0x00990a6b (menu) : min=0 max=4 default=4 value=4
|
||||||
|
|
||||||
|
# ~ Camera Controls
|
||||||
|
|
||||||
|
# ~ auto_exposure 0x009a0901 (menu) : min=0 max=3 default=0 value=0
|
||||||
|
# ~ exposure_time_absolute 0x009a0902 (int) : min=1 max=10000 step=1 default=1000 value=1000
|
||||||
|
# ~ exposure_dynamic_framerate 0x009a0903 (bool) : default=0 value=0
|
||||||
|
# ~ auto_exposure_bias 0x009a0913 (intmenu): min=0 max=24 default=12 value=2
|
||||||
|
# ~ white_balance_auto_preset 0x009a0914 (menu) : min=0 max=9 default=1 value=1
|
||||||
|
# ~ image_stabilization 0x009a0916 (bool) : default=0 value=0
|
||||||
|
# ~ iso_sensitivity 0x009a0917 (intmenu): min=0 max=4 default=0 value=0
|
||||||
|
# ~ iso_sensitivity_auto 0x009a0918 (menu) : min=0 max=1 default=1 value=1
|
||||||
|
# ~ exposure_metering_mode 0x009a0919 (menu) : min=0 max=3 default=0 value=0
|
||||||
|
# ~ scene_mode 0x009a091a (menu) : min=0 max=13 default=0 value=0
|
||||||
|
|
||||||
|
# ~ JPEG Compression Controls
|
||||||
|
# ~ compression_quality 0x009d0903 (int) : min=1 max=100 step=1 default=30 value=30
|
||||||
|
|
||||||
|
# Make sure we're using max bitrate
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c video_bitrate=25000000')
|
||||||
|
# Flip auto-exposure, white-balance on and off to adapt to light environment
|
||||||
|
reset_wb_exp()
|
||||||
|
# Flip preview (0 = vert; 1 = hor)
|
||||||
|
if project_settings['vflip']:
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c vertical_flip=1')
|
||||||
|
else:
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c vertical_flip=0')
|
||||||
|
if project_settings['hflip']:
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c horizontal_flip=1')
|
||||||
|
else:
|
||||||
|
serialutils.send_serial_cmd(serialutils.find_cam_port(), 'v4l2-ctl -d /dev/video0 -c horizontal_flip=0')
|
||||||
|
time.sleep(.5)
|
||||||
|
loop_delta = 0
|
||||||
while True:
|
while True:
|
||||||
|
start = timer()
|
||||||
if playback:
|
if playback:
|
||||||
if onionskin:
|
if onionskin:
|
||||||
onionskin = False
|
onionskin = False
|
||||||
|
@ -433,7 +514,11 @@ def main(args):
|
||||||
if playhead < len(img_list)-1:
|
if playhead < len(img_list)-1:
|
||||||
playhead, img = next_frame(playhead, loop_playback)
|
playhead, img = next_frame(playhead, loop_playback)
|
||||||
cv2.imshow("StopiCV", img)
|
cv2.imshow("StopiCV", img)
|
||||||
time.sleep(1.0/project_settings['framerate'])
|
# Calculate framerate according to loop execution time
|
||||||
|
frame_interval = 1.0/project_settings['framerate']-loop_delta
|
||||||
|
if frame_interval < 0:
|
||||||
|
frame_interval = 0
|
||||||
|
time.sleep(frame_interval)
|
||||||
else:
|
else:
|
||||||
playhead = index
|
playhead = index
|
||||||
img = update_image(img_list, index)
|
img = update_image(img_list, index)
|
||||||
|
@ -445,24 +530,14 @@ def main(args):
|
||||||
|
|
||||||
if onionskin:
|
if onionskin:
|
||||||
ret, overlay = cam.read()
|
ret, overlay = cam.read()
|
||||||
og_frame = overlay
|
og_frame = overlay.copy()
|
||||||
# Resize preview
|
# Resize preview
|
||||||
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
overlay = cv2.resize(overlay, (project_settings['screen_w'], project_settings['screen_h']))
|
||||||
# Apply onionskin
|
# Apply onionskin
|
||||||
alpha = project_settings['onionskin_alpha_default']
|
alpha = project_settings['onionskin_alpha_default']
|
||||||
beta = (1.0 - alpha)
|
beta = (1.0 - alpha)
|
||||||
overlay = cv2.addWeighted(frame, alpha, overlay, beta, 0)
|
overlay = cv2.addWeighted(frame, alpha, overlay, beta, 0)
|
||||||
# TODO : use v4l-ctl to flip frame
|
|
||||||
# v4l2-ctl -d /dev/video0 -c vertical_flip=1
|
|
||||||
# Flip preview (0 = vert; 1 = hor)
|
|
||||||
if project_settings['vflip'] or project_settings['hflip']:
|
|
||||||
if project_settings['vflip'] and project_settings['hflip']:
|
|
||||||
flip_dir = -1
|
|
||||||
elif project_settings['vflip']:
|
|
||||||
flip_dir = 0
|
|
||||||
elif project_settings['hflip']:
|
|
||||||
flip_dir = 1
|
|
||||||
overlay = cv2.flip(overlay, flip_dir)
|
|
||||||
if not ret:
|
if not ret:
|
||||||
print(_("Failed to grab frame."))
|
print(_("Failed to grab frame."))
|
||||||
break
|
break
|
||||||
|
@ -502,6 +577,9 @@ def main(args):
|
||||||
if playback:
|
if playback:
|
||||||
playback = False
|
playback = False
|
||||||
index, frame = next_frame(index)
|
index, frame = next_frame(index)
|
||||||
|
# Key r / keypad 9 - reset wb,exp
|
||||||
|
elif (k%256 == 114) or (k%256 == 57):
|
||||||
|
reset_wb_exp()
|
||||||
# Key e / keypad *
|
# Key e / keypad *
|
||||||
elif (k%256 == 101) or (k%256 == 42):
|
elif (k%256 == 101) or (k%256 == 42):
|
||||||
print(_("Export"))
|
print(_("Export"))
|
||||||
|
@ -509,7 +587,6 @@ def main(args):
|
||||||
# Key Return
|
# Key Return
|
||||||
elif (k%256 == 13):
|
elif (k%256 == 13):
|
||||||
print(_("Playback"))
|
print(_("Playback"))
|
||||||
print(img_list)
|
|
||||||
playhead = index
|
playhead = index
|
||||||
loop_playback = True
|
loop_playback = True
|
||||||
playback = not playback
|
playback = not playback
|
||||||
|
@ -546,6 +623,10 @@ def main(args):
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
print(k) # else print its value
|
print(k) # else print its value
|
||||||
|
end = timer()
|
||||||
|
loop_delta = end - start
|
||||||
|
print(loop_playback)
|
||||||
|
|
||||||
if 'ffmpeg_process' in locals():
|
if 'ffmpeg_process' in locals():
|
||||||
if ffmpeg_process.poll() is None:
|
if ffmpeg_process.poll() is None:
|
||||||
print(_("Ffmpeg is still running.\n Waiting for task to complete."))
|
print(_("Ffmpeg is still running.\n Waiting for task to complete."))
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import serial
|
||||||
|
import serial.tools.list_ports
|
||||||
|
|
||||||
|
def find_cam_port():
|
||||||
|
serial_devices = serial.tools.list_ports.comports()
|
||||||
|
for dev in serial_devices:
|
||||||
|
if str(dev).find('Piwebcam') != -1:
|
||||||
|
return str(dev).split(' ')[0]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def send_serial_cmd(cam_port, cmd:str, clear=True):
|
||||||
|
con = serial.Serial(cam_port, baudrate=115200)
|
||||||
|
if clear:
|
||||||
|
append = b'\rclear\r'
|
||||||
|
else:
|
||||||
|
append = b'\r'
|
||||||
|
con.write(str.encode(cmd) + append)
|
||||||
|
con.close()
|
Loading…
Reference in New Issue