percept_simulator_2023/processing_chain/WebCam.py

326 lines
9.1 KiB
Python
Raw Normal View History

2023-07-31 15:23:13 +02:00
#%%
#
# WebCam.py
# ========================================================
# interface to cv2 for using a webcam or for reading from
# a video file
#
# Version 1.0, before 30.03.2023:
# written by David...
#
# Version 1.1, 30.03.2023:
# thrown out test image
# added test code
# added code to "capture" from video file
#
# Version 1.2, 20.06.2023:
# added code to capture wirelessly from "GoPro" camera
# added test code for "GoPro"
#
# Version 1.3, 23.06.2023
# test display in pyplot or cv2
#
# Version 1.4, 28.06.2023
# solved Windows DirectShow problem
#
from PIL import Image
import os
import cv2
import torch
import torchvision as tv
# for GoPro
import time
import socket
try:
print("Trying to import GoPro modules...")
from goprocam import GoProCamera, constants
gopro_exists = True
except:
print("...not found, continuing!")
gopro_exists = False
import platform
class WebCam:
# test_pattern: torch.Tensor
# test_pattern_gray: torch.Tensor
source: int
framesize: tuple[int, int]
fps: float
cap_frame_width: int
cap_frame_height: int
cap_fps: float
webcam_is_ready: bool
cap_frames_available: int
default_dtype = torch.float32
def __init__(
self,
source: str | int = 1,
framesize: tuple[int, int] = (720, 1280), # (1920, 1080), # (640, 480),
fps: float = 30.0,
):
super().__init__()
assert fps > 0
self.source = source
self.framesize = framesize
self.cap = None
self.fps = fps
self.webcam_is_ready = False
def open_cam(self) -> bool:
if self.cap is not None:
self.cap.release()
self.cap = None
self.webcam_is_ready = False
# handle GoPro...
if self.source == "GoProWireless":
if not gopro_exists:
print("No GoPro driver/support!")
self.webcam_is_ready = False
return False
print("GoPro: Starting access")
gpCam = GoProCamera.GoPro()
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
print("GoPro: Socket created!!!")
self.t = time.time()
gpCam.livestream("start")
gpCam.video_settings(res="1080p", fps="30")
gpCam.gpControlSet(
constants.Stream.WINDOW_SIZE, constants.Stream.WindowSize.R720
)
self.cap = cv2.VideoCapture("udp://10.5.5.9:8554", cv2.CAP_FFMPEG)
print("GoPro: Video capture started!!!")
else:
self.sock = None
self.t = -1
if platform.system().lower() == "windows":
self.cap = cv2.VideoCapture(self.source, cv2.CAP_DSHOW)
else:
self.cap = cv2.VideoCapture(self.source)
print("Normal capture started!!!")
assert self.cap is not None
if self.cap.isOpened() is not True:
self.webcam_is_ready = False
return False
if type(self.source) != str:
self.cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
self.cap.set(cv2.CAP_PROP_FPS, self.fps)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.framesize[0])
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.framesize[1])
self.cap_frames_available = None
else:
# ...for files and GoPro...
self.cap_frames_available = self.cap.get(cv2.CAP_PROP_FRAME_COUNT)
self.cap_frame_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.cap_frame_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.cap_fps = float(self.cap.get(cv2.CAP_PROP_FPS))
print(
(
f"Capturing or reading with: {self.cap_frame_width:.0f} x "
f"{self.cap_frame_height:.0f} @ "
f"{self.cap_fps:.1f}."
)
)
self.webcam_is_ready = True
return True
def close_cam(self) -> None:
if self.cap is not None:
self.cap.release()
def get_frame(self) -> torch.Tensor | None:
if self.cap is None:
return None
else:
if self.sock:
dt_min = 0.015
success, frame = self.cap.read()
t_next = time.time()
t_prev = t_next
while t_next - t_prev < dt_min:
t_prev = t_next
success, frame = self.cap.read()
t_next = time.time()
if self.t >= 0:
if time.time() - self.t > 2.5:
print("GoPro-Stream must be kept awake!...")
self.sock.sendto(
"_GPHD_:0:0:2:0.000000\n".encode(), ("10.5.5.9", 8554)
)
self.t = time.time()
else:
success, frame = self.cap.read()
if success is False:
self.webcam_is_ready = False
return None
output = (
torch.tensor(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
.movedim(-1, 0)
.type(dtype=self.default_dtype)
/ 255.0
)
return output
# for testing the code if module is executed from command line
if __name__ == "__main__":
import matplotlib.pyplot as plt
import cv2
TEST_FILEREAD = False
TEST_WEBCAM = True
TEST_GOPRO = False
display = "cv2"
n_capture = 200
delay_capture = 0.001
print("Testing the WebCam interface")
if TEST_FILEREAD:
file_name = "level1.mp4"
# open
print("Opening video file")
w = WebCam(file_name)
if not w.open_cam():
raise OSError(f"Opening file with name {file_name} failed!")
# print information
print(
f"Frame size {w.cap_frame_width} x {w.cap_frame_height} at {w.cap_fps} fps."
)
# capture three frames and show them
for i in range(min([n_capture, w.cap_frames_available])): # TODO: available?
frame = w.get_frame()
if frame == None:
raise OSError(f"Can not get frame from file with name {file_name}!")
print(f"frame {i} has shape {frame.shape}")
frame_numpy = (frame.movedim(0, -1) * 255).type(dtype=torch.uint8).numpy()
if display == "pyplot":
plt.imshow(frame_numpy)
plt.show()
if display == "cv2":
cv2.imshow("File", frame_numpy[:, :, (2, 1, 0)])
cv2.waitKey(1)
time.sleep(delay_capture)
# close
print("Closing file")
w.close_cam()
if TEST_WEBCAM:
camera_index = 0
# open
print("Opening camera")
w = WebCam(camera_index)
if not w.open_cam():
raise OSError(f"Opening web cam with index {camera_index} failed!")
# print information
print(
f"Frame size {w.cap_frame_width} x {w.cap_frame_height} at {w.cap_fps} fps."
)
# capture three frames and show them
for i in range(n_capture):
frame = w.get_frame()
if frame == None:
raise OSError(
f"Can not get frame from camera with index {camera_index}!"
)
print(f"frame {i} has shape {frame.shape}")
frame_numpy = (frame.movedim(0, -1) * 255).type(dtype=torch.uint8).numpy()
if display == "pyplot":
plt.imshow(frame_numpy)
plt.show()
if display == "cv2":
cv2.imshow("WebCam", frame_numpy[:, :, (2, 1, 0)])
cv2.waitKey(1)
time.sleep(delay_capture)
# close
print("Closing camera")
w.close_cam()
if TEST_GOPRO:
camera_name = "GoProWireless"
# open
print("Opening GoPro")
w = WebCam(camera_name)
if not w.open_cam():
raise OSError(f"Opening GoPro with index {camera_index} failed!")
# print information
print(
f"Frame size {w.cap_frame_width} x {w.cap_frame_height} at {w.cap_fps} fps."
)
w.cap.set(cv2.CAP_PROP_BUFFERSIZE, 0)
# capture three frames and show them
# print("Empty Buffer...")
# for i in range(500):
# print(i)
# frame = w.get_frame()
# print("Buffer Emptied...")
for i in range(n_capture):
frame = w.get_frame()
if frame == None:
raise OSError(
f"Can not get frame from camera with index {camera_index}!"
)
print(f"frame {i} has shape {frame.shape}")
frame_numpy = (frame.movedim(0, -1) * 255).type(dtype=torch.uint8).numpy()
if display == "pyplot":
plt.imshow(frame_numpy)
plt.show()
if display == "cv2":
cv2.imshow("GoPro", frame_numpy[:, :, (2, 1, 0)])
cv2.waitKey(1)
time.sleep(delay_capture)
# close
print("Closing Cam/File/GoPro")
w.close_cam()
if display == "cv2":
cv2.destroyAllWindows()
# %%