proof of concept
This commit is contained in:
51
550d_config.py
Normal file
51
550d_config.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
import gphoto2 as gp
|
||||||
|
|
||||||
|
# def list_config(widget, indent=0):
|
||||||
|
# name = widget.get_name()
|
||||||
|
# label = widget.get_label()
|
||||||
|
# type_name = widget.get_type()
|
||||||
|
# choices = widget.get_choices()
|
||||||
|
# if choices:
|
||||||
|
# choices_str = ", ".join(choices)
|
||||||
|
# print(" " * indent + f"{name} ({label}) type={type_name} choices=[{choices_str}]")
|
||||||
|
# else:
|
||||||
|
|
||||||
|
# print(" " * indent + f"{name} ({label}) type={type_name}")
|
||||||
|
|
||||||
|
# for i in range(widget.count_children()):
|
||||||
|
# child = widget.get_child(i)
|
||||||
|
# list_config(child, indent + 1)
|
||||||
|
|
||||||
|
|
||||||
|
def list_config(widget, indent=0):
|
||||||
|
name = widget.get_name()
|
||||||
|
label = widget.get_label()
|
||||||
|
type_name = widget.get_type()
|
||||||
|
|
||||||
|
line = " " * indent + f"{name} ({label}) type={type_name}"
|
||||||
|
|
||||||
|
# tylko jeśli widget obsługuje choices
|
||||||
|
try:
|
||||||
|
choices = widget.get_choices()
|
||||||
|
if choices:
|
||||||
|
choices_str = ", ".join(str(c) for c in choices)
|
||||||
|
line += f" choices=[{choices_str}]"
|
||||||
|
except gp.GPhoto2Error:
|
||||||
|
# brak choices -> ignorujemy
|
||||||
|
pass
|
||||||
|
|
||||||
|
print(line)
|
||||||
|
|
||||||
|
# rekurencja dla dzieci
|
||||||
|
for i in range(widget.count_children()):
|
||||||
|
child = widget.get_child(i)
|
||||||
|
list_config(child, indent + 1)
|
||||||
|
|
||||||
|
|
||||||
|
camera = gp.Camera()
|
||||||
|
camera.init()
|
||||||
|
|
||||||
|
config = camera.get_config()
|
||||||
|
list_config(config)
|
||||||
|
|
||||||
|
camera.exit()
|
||||||
82
config.txt
Normal file
82
config.txt
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
(.venv) bartool@BARTOOL-PC:~/local_projects/canon_550d$ python 550d_config.py
|
||||||
|
main (Camera and Driver Configuration) type=0
|
||||||
|
actions (Camera Actions) type=1
|
||||||
|
syncdatetime (Synchronize camera date and time with PC) type=4
|
||||||
|
uilock (UI Lock) type=4
|
||||||
|
popupflash (Popup Flash) type=4
|
||||||
|
autofocusdrive (Drive Canon DSLR Autofocus) type=4
|
||||||
|
manualfocusdrive (Drive Canon DSLR Manual focus) type=5 choices=[Near 1, Near 2, Near 3, None, Far 1, Far 2, Far 3]
|
||||||
|
cancelautofocus (Cancel Canon DSLR Autofocus) type=4
|
||||||
|
eoszoom (Canon EOS Zoom) type=2
|
||||||
|
eoszoomposition (Canon EOS Zoom Position) type=2
|
||||||
|
viewfinder (Canon EOS Viewfinder) type=4
|
||||||
|
eosremoterelease (Canon EOS Remote Release) type=5 choices=[None, Press Half, Press Full, Release Half, Release Full, Immediate, Press 1, Press 2, Press 3, Release 1, Release 2, Release 3]
|
||||||
|
eosmoviemode (Movie Mode) type=4
|
||||||
|
opcode (PTP Opcode) type=2
|
||||||
|
settings (Camera Settings) type=1
|
||||||
|
datetime (Camera Date and Time) type=8
|
||||||
|
reviewtime (Quick Review Time) type=5 choices=[None, 2 seconds, 4 seconds, 8 seconds, Hold]
|
||||||
|
output (Camera Output) type=5 choices=[TFT, PC, MOBILE, Off]
|
||||||
|
movierecordtarget (Recording Destination) type=5 choices=[None]
|
||||||
|
evfmode (EVF Mode) type=5 choices=[0, 1]
|
||||||
|
ownername (Owner Name) type=2
|
||||||
|
artist (Artist) type=2
|
||||||
|
copyright (Copyright) type=2
|
||||||
|
customfuncex (Custom Functions Ex) type=2
|
||||||
|
focusinfo (Focus Info) type=2
|
||||||
|
strobofiring (Strobo Firing) type=5 choices=[0, 1, 2]
|
||||||
|
flashcharged (Flash Charging State) type=2
|
||||||
|
autopoweroff (Auto Power Off) type=2
|
||||||
|
depthoffield (Depth of Field) type=2
|
||||||
|
capturetarget (Capture Target) type=5 choices=[Internal RAM, Memory card]
|
||||||
|
capture (Capture) type=4
|
||||||
|
remotemode (Remote Mode) type=2
|
||||||
|
eventmode (Event Mode) type=2
|
||||||
|
status (Camera Status Information) type=1
|
||||||
|
serialnumber (Serial Number) type=2
|
||||||
|
manufacturer (Camera Manufacturer) type=2
|
||||||
|
cameramodel (Camera Model) type=2
|
||||||
|
deviceversion (Device Version) type=2
|
||||||
|
vendorextension (Vendor Extension) type=2
|
||||||
|
model (Camera Model) type=2
|
||||||
|
ptpversion (PTP Version) type=2
|
||||||
|
batterylevel (Battery Level) type=2
|
||||||
|
batterylevel (Battery Level) type=2
|
||||||
|
mirrorlockstatus (Mirror Lock Status) type=2
|
||||||
|
mirrordownstatus (Mirror Down Status) type=2
|
||||||
|
lensname (Lens Name) type=2
|
||||||
|
eosserialnumber (Serial Number) type=2
|
||||||
|
shuttercounter (Shutter Counter) type=2
|
||||||
|
availableshots (Available Shots) type=2
|
||||||
|
eosmovieswitch (Movie Switch) type=2
|
||||||
|
imgsettings (Image Settings) type=1
|
||||||
|
imageformat (Image Format) type=5 choices=[L, cL, M, cM, S, cS, RAW + L, RAW]
|
||||||
|
imageformatsd (Image Format SD) type=5 choices=[L, cL, M, cM, S, cS, RAW + L, RAW]
|
||||||
|
iso (ISO Speed) type=5 choices=[Auto, 100, 200, 400, 800, 1600, 3200, 6400]
|
||||||
|
whitebalance (WhiteBalance) type=5 choices=[Auto, Daylight, Shadow, Cloudy, Tungsten, Fluorescent, Flash, Manual]
|
||||||
|
whitebalanceadjusta (WhiteBalance Adjust A) type=5 choices=[-9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
whitebalanceadjustb (WhiteBalance Adjust B) type=5 choices=[-9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
|
whitebalancexa (WhiteBalance X A) type=5 choices=[0, 1, 2, 3]
|
||||||
|
whitebalancexb (WhiteBalance X B) type=5 choices=[0, 1, 2, 3]
|
||||||
|
colorspace (Color Space) type=5 choices=[sRGB, AdobeRGB]
|
||||||
|
capturesettings (Capture Settings) type=1
|
||||||
|
exposurecompensation (Exposure Compensation) type=5 choices=[-5, -4.6, -4.3, -4, -3.6, -3.3, -3, -2.6, -2.3, -2, -1.6, -1.3, -1, -0.6, -0.3, 0, 0.3, 0.6, 1, 1.3, 1.6, 2, 2.3, 2.6, 3, 3.3, 3.6, 4, 4.3, 4.6, 5]
|
||||||
|
focusmode (Focus Mode) type=5 choices=[One Shot, AI Focus, AI Servo, Manual]
|
||||||
|
afmethod (AF Method) type=5 choices=[Live, LiveFace, Quick]
|
||||||
|
storageid (Storage Device) type=2
|
||||||
|
autoexposuremode (Canon Auto Exposure Mode) type=5 choices=[P, TV, AV, Manual, Bulb, A_DEP, DEP, Custom, Lock, Green, Night Portrait, Sports, Portrait, Landscape, Closeup, Flash Off, C2, C3, Creative Auto, Movie, Auto, Handheld Night Scene, HDR Backlight Control, SCN, Food, Grainy B/W, Soft focus, Toy camera effect, Fish-eye effect, Water painting effect, Miniature effect, HDR art standard, HDR art vivid, HDR art bold, HDR art embossed, Panning, HDR, Self Portrait, Hybrid Auto, Smooth skin, Fv]
|
||||||
|
drivemode (Drive Mode) type=5 choices=[Single, Continuous, Timer 10 sec, Timer 2 sec, Continuous timer]
|
||||||
|
picturestyle (Picture Style) type=5 choices=[Standard, Portrait, Landscape, Neutral, Faithful, Monochrome, User defined 1, User defined 2, User defined 3]
|
||||||
|
aperture (Aperture) type=5 choices=[implicit auto]
|
||||||
|
shutterspeed (Shutter Speed) type=5 choices=[30, 25, 20, 15, 13, 10.3, 8, 6.3, 5, 4, 3.2, 2.5, 2, 1.6, 1.3, 1, 0.8, 0.6, 0.5, 0.4, 0.3, 1/4, 1/5, 1/6, 1/8, 1/10, 1/13, 1/15, 1/20, 1/25, 1/30, 1/40, 1/50, 1/60, 1/80, 1/100, 1/125, 1/160, 1/200, 1/250, 1/320, 1/400, 1/500, 1/640, 1/800, 1/1000, 1/1250, 1/1600, 1/2000, 1/2500, 1/3200, 1/4000]
|
||||||
|
meteringmode (Metering Mode) type=5 choices=[Evaluative, Partial, Spot, Center-weighted average]
|
||||||
|
liveviewsize (Live View Size) type=5 choices=[Large, Medium]
|
||||||
|
bracketmode (Bracket Mode) type=5 choices=[Unknown value 0000]
|
||||||
|
aeb (Auto Exposure Bracketing) type=5 choices=[off, +/- 1/3, +/- 2/3, +/- 1, +/- 1 1/3, +/- 1 2/3, +/- 2]
|
||||||
|
alomode (Auto Lighting Optimization) type=5 choices=[Standard (disabled in manual exposure), x1, x2, x3]
|
||||||
|
other (Other PTP Device Properties) type=1
|
||||||
|
d402 (Friendly Device Name) type=2
|
||||||
|
d407 (Perceived Device Type) type=2
|
||||||
|
d406 (Session Initiator Info) type=2
|
||||||
|
d303 (PTP Property 0xd303) type=2
|
||||||
|
5001 (Battery Level) type=6 choices=[100, 0, 75, 50]
|
||||||
29
live_flask.py
Normal file
29
live_flask.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import gphoto2 as gp
|
||||||
|
from flask import Flask, Response
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
camera = gp.Camera()
|
||||||
|
camera.init()
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
while True:
|
||||||
|
file = camera.capture_preview()
|
||||||
|
data = file.get_data_and_size()
|
||||||
|
frame = np.frombuffer(data, dtype=np.uint8)
|
||||||
|
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
|
||||||
|
|
||||||
|
if frame is not None:
|
||||||
|
_, buffer = cv2.imencode('.jpg', frame)
|
||||||
|
yield (b'--frame\r\n'
|
||||||
|
b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
|
||||||
|
|
||||||
|
@app.route('/liveview')
|
||||||
|
def liveview():
|
||||||
|
return Response(generate(),
|
||||||
|
mimetype='multipart/x-mixed-replace; boundary=frame')
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host="0.0.0.0", port=5000)
|
||||||
125
live_pyside.py
Normal file
125
live_pyside.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import sys
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QHBoxLayout
|
||||||
|
from PySide6.QtGui import QImage, QPixmap
|
||||||
|
from PySide6.QtCore import QTimer
|
||||||
|
import gphoto2 as gp
|
||||||
|
|
||||||
|
class LiveViewApp(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("Canon LiveView")
|
||||||
|
|
||||||
|
# Widget do obrazu
|
||||||
|
self.image_label = QLabel("Brak obrazu")
|
||||||
|
self.image_label.setFixedSize(640, 480)
|
||||||
|
|
||||||
|
# Przyciski start/stop
|
||||||
|
self.start_button = QPushButton("Start LiveView")
|
||||||
|
self.stop_button = QPushButton("Stop LiveView")
|
||||||
|
self.stop_button.setEnabled(False)
|
||||||
|
|
||||||
|
self.start_button.clicked.connect(self.start_liveview)
|
||||||
|
self.stop_button.clicked.connect(self.stop_liveview)
|
||||||
|
|
||||||
|
# Layout
|
||||||
|
button_layout = QHBoxLayout()
|
||||||
|
button_layout.addWidget(self.start_button)
|
||||||
|
button_layout.addWidget(self.stop_button)
|
||||||
|
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(self.image_label)
|
||||||
|
layout.addLayout(button_layout)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
# Timer do odświeżania obrazu
|
||||||
|
self.timer = QTimer()
|
||||||
|
self.timer.timeout.connect(self.update_frame)
|
||||||
|
|
||||||
|
# kamera (na razie None – podepniesz gphoto2)
|
||||||
|
self.camera = None
|
||||||
|
self.set_dummy_frame()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def set_dummy_frame(self):
|
||||||
|
self.dummy_frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
||||||
|
cv2.putText(self.dummy_frame, "LiveView OFF", (200, 240),
|
||||||
|
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
||||||
|
|
||||||
|
rgb_image = cv2.cvtColor(self.dummy_frame, cv2.COLOR_BGR2RGB)
|
||||||
|
h, w, ch = rgb_image.shape
|
||||||
|
qimg = QImage(rgb_image.data, w, h, ch * w, QImage.Format_RGB888)
|
||||||
|
pixmap = QPixmap.fromImage(qimg)
|
||||||
|
|
||||||
|
self.image_label.setPixmap(pixmap)
|
||||||
|
|
||||||
|
def start_liveview(self):
|
||||||
|
print("Start LiveView")
|
||||||
|
self.start_button.setEnabled(False)
|
||||||
|
self.stop_button.setEnabled(True)
|
||||||
|
# TODO: tu zainicjalizujesz kamerę gphoto2
|
||||||
|
# Przykład inicjalizacji kamery przez gphoto2 (wymaga zainstalowanego python-gphoto2)
|
||||||
|
try:
|
||||||
|
self.camera = gp.Camera()
|
||||||
|
self.camera.init()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Błąd inicjalizacji kamery: {e}")
|
||||||
|
self.camera = None
|
||||||
|
self.timer.start(100) # odświeżanie co 100ms
|
||||||
|
|
||||||
|
def stop_liveview(self):
|
||||||
|
print("Stop LiveView")
|
||||||
|
self.timer.stop()
|
||||||
|
self.start_button.setEnabled(True)
|
||||||
|
self.stop_button.setEnabled(False)
|
||||||
|
self.image_label.setText("Brak obrazu")
|
||||||
|
self.image_label.setPixmap(QPixmap()) # czyści obraz
|
||||||
|
|
||||||
|
self.set_dummy_frame()
|
||||||
|
# TODO: tu zamkniesz kamerę gphoto2
|
||||||
|
if self.camera:
|
||||||
|
self.camera.exit()
|
||||||
|
self.camera = None
|
||||||
|
self.start_button.setEnabled(True)
|
||||||
|
self.stop_button.setEnabled(False)
|
||||||
|
|
||||||
|
def update_frame(self):
|
||||||
|
# Na razie sztuczna klatka testowa z OpenCV (czarne tło + napis)
|
||||||
|
# frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
||||||
|
# cv2.putText(frame, "Canon LiveView", (50, 240),
|
||||||
|
# cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
||||||
|
|
||||||
|
if self.camera:
|
||||||
|
try:
|
||||||
|
file = self.camera.capture_preview()
|
||||||
|
data = file.get_data_and_size()
|
||||||
|
frame = np.frombuffer(data, dtype=np.uint8)
|
||||||
|
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
|
||||||
|
|
||||||
|
if frame is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
except gp.GPhoto2Error as e:
|
||||||
|
print(f"Błąd odczytu LiveView: {e}")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Nieoczekiwany błąd: {e}")
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
# Konwersja OpenCV -> QImage
|
||||||
|
rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||||
|
h, w, ch = rgb_image.shape
|
||||||
|
qimg = QImage(rgb_image.data, w, h, ch * w, QImage.Format_RGB888)
|
||||||
|
pixmap = QPixmap.fromImage(qimg)
|
||||||
|
|
||||||
|
self.image_label.setPixmap(pixmap)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = LiveViewApp()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
26
live_view.py
Normal file
26
live_view.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import gphoto2 as gp
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
camera = gp.Camera()
|
||||||
|
camera.init()
|
||||||
|
|
||||||
|
def liveview():
|
||||||
|
while True:
|
||||||
|
# Pobierz klatkę z LiveView
|
||||||
|
file = camera.capture_preview()
|
||||||
|
data = file.get_data_and_size()
|
||||||
|
frame = np.frombuffer(data, dtype=np.uint8)
|
||||||
|
frame = cv2.imdecode(frame, cv2.IMREAD_COLOR)
|
||||||
|
|
||||||
|
if frame is not None:
|
||||||
|
cv2.imshow("LiveView", frame)
|
||||||
|
|
||||||
|
if cv2.waitKey(1) == 27: # ESC
|
||||||
|
break
|
||||||
|
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
camera.exit()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
liveview()
|
||||||
27
test_pyside.py
Normal file
27
test_pyside.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import sys
|
||||||
|
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout
|
||||||
|
|
||||||
|
class TestWindow(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.setWindowTitle("PySide6 Test")
|
||||||
|
|
||||||
|
# Tworzymy label
|
||||||
|
self.label = QLabel("Hello from PySide6!", self)
|
||||||
|
|
||||||
|
# Tworzymy przycisk do zamykania
|
||||||
|
self.close_button = QPushButton("Zamknij")
|
||||||
|
self.close_button.clicked.connect(self.close)
|
||||||
|
|
||||||
|
# Układ pionowy
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
layout.addWidget(self.label)
|
||||||
|
layout.addWidget(self.close_button)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
window = TestWindow()
|
||||||
|
window.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
Reference in New Issue
Block a user