Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
41e7bfe426
|
|
@ -1,6 +1,7 @@
|
|||
[hardware_config]
|
||||
; archive_synchronizer: present
|
||||
; galaxy_camera: present
|
||||
; uvc_camera: absent
|
||||
; label_printer: present
|
||||
; multicomp: present
|
||||
; neo_pixels: present
|
||||
|
|
@ -25,6 +26,12 @@ balance_red: 1.85
|
|||
balance_green: 1.0
|
||||
balance_blue: 1.5
|
||||
|
||||
[uvc_camera]
|
||||
horizontal_resolution: 2448
|
||||
vertical_resolution: 2048
|
||||
exposure_time: 10000
|
||||
focus: 100
|
||||
|
||||
[vision_saver]
|
||||
time_format: %Y-%m-%d_%H-%M-%S
|
||||
path: ./data/images
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[hostnames]
|
||||
DESKTOP-VOCOB38: vm
|
||||
mino: mino
|
||||
neodl-MS-7A62: stten3
|
||||
neodl-MS-7A62: stten1
|
||||
ST-TEN-1: stten1
|
||||
ST-TEN-2: stten2
|
||||
stten3: stten3
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
[hardware_config]
|
||||
archive_synchronizer: absent
|
||||
galaxy_camera: present
|
||||
#galaxy_camera: present
|
||||
uvc_camera: present
|
||||
label_printer: present
|
||||
neo_pixels: present
|
||||
remote_api: absent
|
||||
|
|
|
|||
|
|
@ -58,6 +58,11 @@ void setup() {
|
|||
set_color(-1, 0, 0, 0);
|
||||
delay(1000);
|
||||
set_color(-1, 255, 255, 255);
|
||||
delay(2000);
|
||||
for(int cnt=255;cnt>=0;cnt--){
|
||||
set_color(-1, cnt, cnt,cnt);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t parse_message(uint8_t *message, Address *address, Color color) {
|
||||
|
|
|
|||
213
src/components/uvc_camera.py
Normal file
213
src/components/uvc_camera.py
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
import pathlib
|
||||
import sys
|
||||
from itertools import cycle
|
||||
|
||||
import cv2
|
||||
import imutils
|
||||
import numpy as np
|
||||
from PyQt5.QtCore import QMutex, Qt, QThread, pyqtSignal
|
||||
from PyQt5.QtGui import QImage, QPixmap
|
||||
from PyQt5.QtWidgets import (QDialog, QFormLayout, QLabel, QMessageBox,
|
||||
QPushButton, QSizePolicy, QSlider)
|
||||
|
||||
|
||||
if "--sim-camera" in sys.argv:
|
||||
from components.dummies.gxpy import DummyCamera
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from .component import Component
|
||||
|
||||
|
||||
class UVCCamera(Component):
|
||||
_edits_new_frame = pyqtSignal(object)
|
||||
|
||||
def __init__(self, config=None, name=None, period=1, lazy=True, paused=False, threaded=True, registers=None):
|
||||
super().__init__(config=config, name=name, period=period, lazy=lazy, paused=paused, threaded=threaded)
|
||||
self.lock = QMutex()
|
||||
self.simulate = "--sim-camera" in sys.argv
|
||||
self._last_frame = None
|
||||
|
||||
def config_changed(self):
|
||||
if self.simulate:
|
||||
self.device_manager = None
|
||||
self.camera = DummyCamera()
|
||||
self.sim_imgs = cycle(sorted(pathlib.Path("data/simulation_images/").glob("*.png")))
|
||||
else:
|
||||
self.camera = cv2.VideoCapture(0)
|
||||
|
||||
self.resolution = {
|
||||
"w": int(self.round_4(self.config[self.name]["horizontal_resolution"])),
|
||||
"h": int(self.round_4(self.config[self.name]["vertical_resolution"])),
|
||||
}
|
||||
self._period = int(self.config[self.name].get("frame_time_ms", 300)) / 1000
|
||||
self.exposure_time = int(self.config[self.name]["exposure_time"])
|
||||
self.roi = {
|
||||
"x": int(self.round_4(self.config[self.name].get("horizontal_crop_offset", 0))),
|
||||
"w": int(self.round_4(self.config[self.name].get("horizontal_crop_resolution", self.resolution["w"]))),
|
||||
"y": int(self.round_4(self.config[self.name].get("vertical_crop_offset", 0))),
|
||||
"h": int(self.round_4(self.config[self.name].get("vertical_crop_resolution", self.resolution["h"]))),
|
||||
"r": int(self.config[self.name].get("rotate_90_clockwise_times", 0)),
|
||||
}
|
||||
self.auto_white_balance = self.config[self.name].get("auto_white_balance", "").lower() in {"on", "1", "y", "yes", "true", "enable", "enabled", }
|
||||
self.balance = {
|
||||
"r": float(self.config[self.name].get("balance_red", 1)),
|
||||
"g": float(self.config[self.name].get("balance_green", 1)),
|
||||
"b": float(self.config[self.name].get("balance_blue", 1)),
|
||||
}
|
||||
self.lock.lock()
|
||||
|
||||
self.edits = None
|
||||
self.lock.unlock()
|
||||
self.edits_enabled = "--camera-edits" in sys.argv
|
||||
if self.edits_enabled:
|
||||
self.init_edits()
|
||||
|
||||
@staticmethod
|
||||
def round_4(x):
|
||||
return 4 * round(int(x) / 4)
|
||||
|
||||
@Component.reconfig_on_error
|
||||
def _get(self):
|
||||
frame = None
|
||||
self.lock.lock()
|
||||
if self.simulate:
|
||||
img_path = next(self.sim_imgs)
|
||||
self.log.debug(f"loading image {img_path}")
|
||||
frame = cv2.cvtColor(cv2.imread(str(img_path)), cv2.COLOR_BGR2RGB)
|
||||
QThread.msleep(1000)
|
||||
else:
|
||||
self.camera.TriggerSoftware.send_command()
|
||||
frame = self.camera.read()
|
||||
if frame is not None:
|
||||
frame = np.rot90(frame, self.roi["r"])
|
||||
self.lock.unlock()
|
||||
if frame is None:
|
||||
self.log.error("failed to get frame")
|
||||
elif self.edits_enabled:
|
||||
frame = self.edit(frame, self.edits)
|
||||
self._edits_new_frame.emit([frame])
|
||||
super()._get([frame])
|
||||
|
||||
def __del__(self, event=None):
|
||||
if self.camera is not None:
|
||||
self.camera.stream_off()
|
||||
self.camera.close_device()
|
||||
|
||||
def init_edits(self):
|
||||
self.edits_enabled = True
|
||||
self.edits_dialog = EditsDialog(self.roi)
|
||||
self.edits_dialog.edits_changed.connect(self.set_edits)
|
||||
self._edits_new_frame.connect(self.edits_dialog.save_and_show_edits_new_frame)
|
||||
self.edits_dialog.edits_pause.connect(self.toggle_paused)
|
||||
|
||||
def toggle_paused(self):
|
||||
if self.running:
|
||||
self.pause()
|
||||
else:
|
||||
self.resume()
|
||||
|
||||
def set_edits(self, edits=None):
|
||||
self.edits = edits
|
||||
|
||||
def edit(self, img, edits=None):
|
||||
if edits is None:
|
||||
return img
|
||||
# BRIGHTNESS AND CONTRAST
|
||||
contrast = float(edits.get("contrast", 0))
|
||||
brightness = float(edits.get("brightness", 0))
|
||||
if not (contrast == 0 and brightness == 0):
|
||||
img = imutils.adjust_brightness_contrast(img, brightness=brightness, contrast=contrast / 255 * 500)
|
||||
# ROTATE AND SCALE
|
||||
rotation = -float(edits.get("rotation", 0))
|
||||
scale = float(edits.get("scale", 1))
|
||||
if not (rotation == 0 and scale == 1):
|
||||
img = imutils.rotate(img, rotation, scale=scale)
|
||||
# TRANSLATE
|
||||
translation_x = float(edits.get("translation_x", 0))
|
||||
translation_y = float(edits.get("translation_y", 0))
|
||||
if not (translation_x == 0 and translation_y == 0):
|
||||
img = imutils.translate(img, translation_x, translation_y)
|
||||
return img
|
||||
|
||||
|
||||
class EditsDialog(QDialog):
|
||||
edits_changed = pyqtSignal(object)
|
||||
edits_pause = pyqtSignal()
|
||||
|
||||
def __init__(self, roi):
|
||||
super().__init__()
|
||||
self.frame = None
|
||||
self.edits = {
|
||||
"brightness": 0,
|
||||
"contrast": 0,
|
||||
"rotation": 0,
|
||||
"scale": 1,
|
||||
"translation_x": 0,
|
||||
"translation_y": 0,
|
||||
}
|
||||
self.edits_specs = {
|
||||
"brightness": [[-255, 255], 1, QSlider(Qt.Horizontal), QLabel()],
|
||||
"contrast": [[-255, 255], 1, QSlider(Qt.Horizontal), QLabel()],
|
||||
"rotation": [[-180, 180], 1, QSlider(Qt.Horizontal), QLabel()],
|
||||
"scale": [[0, 5], 100, QSlider(Qt.Horizontal), QLabel()],
|
||||
"translation_x": [[-roi["w"], roi["w"]], 1, QSlider(Qt.Horizontal), QLabel()],
|
||||
"translation_y": [[-roi["h"], roi["h"]], 1, QSlider(Qt.Horizontal), QLabel()],
|
||||
}
|
||||
layout = QFormLayout()
|
||||
self.edits_frame_l = QLabel()
|
||||
self.edits_frame_l.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
layout.addRow(self.edits_frame_l)
|
||||
self.edits_pause_b = QPushButton("toggle paused")
|
||||
layout.addRow(self.edits_pause_b)
|
||||
self.edits_pause_b.clicked.connect(self.edits_pause)
|
||||
for edit, limits in self.edits_specs.items():
|
||||
limit, multiplier, slider, label = limits
|
||||
slider.setRange(limit[0] * multiplier, limit[1] * multiplier)
|
||||
slider.setSingleStep(1)
|
||||
slider.setValue(self.edits[edit] * multiplier)
|
||||
label.setText(f"{edit}: {self.edits[edit]}")
|
||||
layout.addRow(label, slider)
|
||||
slider.valueChanged.connect(self.update_edits)
|
||||
self.edits_save_frame_b = QPushButton("save frame")
|
||||
layout.addRow(self.edits_save_frame_b)
|
||||
self.edits_save_frame_b.clicked.connect(self.edits_save_frame)
|
||||
self.setLayout(layout)
|
||||
self.update_edits()
|
||||
self.show()
|
||||
|
||||
def update_edits(self):
|
||||
for edit, limits in self.edits_specs.items():
|
||||
limit, multiplier, slider, label = limits
|
||||
self.edits[edit] = slider.value() / multiplier
|
||||
label.setText(f"{edit}: {self.edits[edit]}")
|
||||
self.edits_changed.emit(self.edits)
|
||||
|
||||
def save_and_show_edits_new_frame(self, frame):
|
||||
self.frame = frame[0]
|
||||
if self.frame is not None:
|
||||
self.edits_frame_l.setPixmap(
|
||||
QPixmap.fromImage(
|
||||
QImage(
|
||||
self.frame.data,
|
||||
self.frame.shape[1], # width
|
||||
self.frame.shape[0], # height
|
||||
self.frame.shape[2] * self.frame.shape[1], # width * channels
|
||||
QImage.Format_RGB888
|
||||
)
|
||||
).scaled(
|
||||
max(self.edits_frame_l.width(), 640),
|
||||
max(self.edits_frame_l.height(), 480),
|
||||
Qt.KeepAspectRatio,
|
||||
Qt.SmoothTransformation
|
||||
)
|
||||
)
|
||||
|
||||
def edits_save_frame(self):
|
||||
if self.frame is None:
|
||||
return
|
||||
out_path = f"./{datetime.now().isoformat()}.png"
|
||||
self.log.info(f"saving frame: {out_path!r}")
|
||||
img = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR)
|
||||
cv2.imwrite(out_path, img)
|
||||
return out_path
|
||||
22
src/test/uvc_camera.py
Normal file
22
src/test/uvc_camera.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import time
|
||||
|
||||
import cv2
|
||||
from PIL import Image
|
||||
|
||||
|
||||
def main():
|
||||
print("Initializing......")
|
||||
|
||||
cap = cv2.VideoCapture(0)
|
||||
num = 10
|
||||
for i in range(num):
|
||||
# Capture frame-by-frame
|
||||
ret, numpy_image = cap.read()
|
||||
img = Image.fromarray(numpy_image, 'RGB')
|
||||
img.show()
|
||||
|
||||
|
||||
cap.release()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user