Easy testing with or without dark room setup
This commit is contained in:
parent
3a63449c83
commit
2e4238fc60
|
|
@ -1,3 +1,6 @@
|
||||||
|
# Config file
|
||||||
|
config.py
|
||||||
|
|
||||||
.device
|
.device
|
||||||
data
|
data
|
||||||
data-*
|
data-*
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ def inject():
|
||||||
conn = db.get()
|
conn = db.get()
|
||||||
return {
|
return {
|
||||||
'calibration': utils.get_calibration(conn),
|
'calibration': utils.get_calibration(conn),
|
||||||
'leds': config.LEDS_UUIDS,
|
'leds': config.GPIO_LEDS.leds,
|
||||||
'CalibrationState': db.CalibrationState,
|
'CalibrationState': db.CalibrationState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
import gphoto2 as gp
|
||||||
|
import shutil
|
||||||
|
from . import leds
|
||||||
|
|
||||||
|
|
||||||
|
class Camera:
|
||||||
|
def __init__(self):
|
||||||
|
self.inner = gp.Camera()
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.inner.init()
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
self.inner.exit()
|
||||||
|
|
||||||
|
def capture(self, output_path: str) -> bool:
|
||||||
|
try:
|
||||||
|
with self:
|
||||||
|
file_path = self.inner.capture(gp.GP_CAPTURE_IMAGE)
|
||||||
|
preview = self.inner.file_get(file_path.folder, file_path.name[:-3] + '.JPG', gp.GP_FILE_TYPE_NORMAL)
|
||||||
|
raw = self.inner.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_RAW)
|
||||||
|
|
||||||
|
preview.sve(output_path + '.jpg')
|
||||||
|
raw.save(output_path + '.cr2')
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print('An error occured when capturing photo', e)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class DummyCamera:
|
||||||
|
def __init__(self, leds: leds.DummyLeds):
|
||||||
|
self.leds = leds
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __exit__(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def capture(self, output_path: str) -> bool:
|
||||||
|
# Find which leds are turned on
|
||||||
|
found = None
|
||||||
|
all_on = False
|
||||||
|
for led in self.leds.leds:
|
||||||
|
if led.is_on:
|
||||||
|
if found is None:
|
||||||
|
found = led
|
||||||
|
else:
|
||||||
|
all_on = True
|
||||||
|
|
||||||
|
if found:
|
||||||
|
shutil.copyfile('data-keep/small/' + str(found) + '.jpg', output_path + '.jpg')
|
||||||
|
elif all_on:
|
||||||
|
shutil.copyfile('data-keep/small/LED17.jpg', output_path + '.jpg')
|
||||||
|
else:
|
||||||
|
shutil.copyfile('data-keep/small/LED17.jpg', output_path + '.jpg')
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
from os.path import join
|
||||||
|
from . import camera, leds
|
||||||
|
|
||||||
|
DATA_DIR = 'data'
|
||||||
|
BACKUPS_DIR = 'data-backups'
|
||||||
|
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
||||||
|
OBJECT_DIR = join(DATA_DIR, 'objects')
|
||||||
|
DATABASE_PATH = join(DATA_DIR, 'db.sqlite')
|
||||||
|
|
||||||
|
AUTO_USE_LAST_CALIBRATION = True
|
||||||
|
GPIO_CHIP = 'gpiochip0'
|
||||||
|
LEDS_UUIDS = [17, 18, 22, 23, 24, 27]
|
||||||
|
GPIO_LEDS = leds.GpioLeds(LEDS_UUIDS)
|
||||||
|
CAMERA = camera.Camera()
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
from os.path import join
|
||||||
|
from . import camera, leds
|
||||||
|
|
||||||
|
DATA_DIR = 'data'
|
||||||
|
BACKUPS_DIR = 'data-backups'
|
||||||
|
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
||||||
|
OBJECT_DIR = join(DATA_DIR, 'objects')
|
||||||
|
DATABASE_PATH = join(DATA_DIR, 'db.sqlite')
|
||||||
|
|
||||||
|
AUTO_USE_LAST_CALIBRATION = False
|
||||||
|
GPIO_CHIP = None
|
||||||
|
LEDS_UUIDS = [17, 18, 22, 23, 24, 27]
|
||||||
|
GPIO_LEDS = leds.DummyLeds(LEDS_UUIDS)
|
||||||
|
CAMERA = camera.DummyCamera(GPIO_LEDS)
|
||||||
28
config.py
28
config.py
|
|
@ -1,28 +0,0 @@
|
||||||
from os.path import join
|
|
||||||
|
|
||||||
DATA_DIR = 'data'
|
|
||||||
BACKUPS_DIR = 'data-backups'
|
|
||||||
CALIBRATION_DIR = join(DATA_DIR, 'calibrations')
|
|
||||||
OBJECT_DIR = join(DATA_DIR, 'objects')
|
|
||||||
DATABASE_PATH = join(DATA_DIR, 'db.sqlite')
|
|
||||||
|
|
||||||
AUTO_USE_LAST_CALIBRATION = False
|
|
||||||
|
|
||||||
GPIO_CHIP = 'gpiochip0'
|
|
||||||
|
|
||||||
# LEDS_UUIDS = [
|
|
||||||
# 'ac59350e-3787-46d2-88fa-743c1d34fe86',
|
|
||||||
# '83ab3133-d4de-4a42-99a7-8f8a3f3732ba',
|
|
||||||
# '577d6e72-f518-4d65-af28-f8faf1ca3f5d',
|
|
||||||
# 'ec49a20c-bddd-4614-b828-fa45e01bfb19',
|
|
||||||
# '5c249cce-d2b6-4b56-96c8-5caa43d8f040',
|
|
||||||
# '22d783fb-ae55-4581-a3c6-e010d9d5e9de',
|
|
||||||
# '12cb6a32-04a6-433b-8146-b753b8f1286d',
|
|
||||||
# '461255a3-259a-4291-adc3-2fb736231a04',
|
|
||||||
# '3896662f-9826-4445-ad70-86c2e6c143e7',
|
|
||||||
# 'f87698ec-3cba-42fe-9a61-5ac9f77d767a',
|
|
||||||
# '4c77a655-4b68-4557-a696-29345c6676a1',
|
|
||||||
# 'b1cfe287-aa3b-445e-bcdc-75ae375efe43',
|
|
||||||
# ]
|
|
||||||
|
|
||||||
LEDS_UUIDS = [17, 18, 22, 23, 24, 27]
|
|
||||||
60
leds.py
60
leds.py
|
|
@ -1,20 +1,17 @@
|
||||||
import gpiod
|
import gpiod
|
||||||
|
|
||||||
from . import config
|
|
||||||
|
|
||||||
class GpioLed:
|
class GpioLed:
|
||||||
chip = gpiod.Chip(config.GPIO_CHIP)
|
|
||||||
|
|
||||||
def __init__(self, gpio_pin: int):
|
def __init__(self, gpio_pin: int):
|
||||||
self.gpio_pin = gpio_pin
|
self.gpio_pin = gpio_pin
|
||||||
self.led = None
|
self.led = None
|
||||||
|
|
||||||
def __enter__(self):
|
def enter(self, chip: gpiod.Chip):
|
||||||
self.led = GpioLed.chip.get_line(self.gpio_pin)
|
self.led = chip.get_line(self.gpio_pin)
|
||||||
self.led.request(consumer=str(self), type=gpiod.LINE_REQ_DIR_OUT)
|
self.led.request(consumer=str(self), type=gpiod.LINE_REQ_DIR_OUT)
|
||||||
self.off()
|
self.off()
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def exit(self):
|
||||||
self.off()
|
self.off()
|
||||||
self.led.release()
|
self.led.release()
|
||||||
self.led = None
|
self.led = None
|
||||||
|
|
@ -30,18 +27,63 @@ class GpioLed:
|
||||||
|
|
||||||
|
|
||||||
class GpioLeds:
|
class GpioLeds:
|
||||||
def __init__(self, gpio_pins: list[int]):
|
def __init__(self, chip: str, gpio_pins: list[int]):
|
||||||
|
self.chip = gpiod.Chip(chip)
|
||||||
self.leds = []
|
self.leds = []
|
||||||
for pin in gpio_pins:
|
for pin in gpio_pins:
|
||||||
self.leds.append(GpioLed(pin))
|
self.leds.append(GpioLed(pin))
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
for led in self.leds:
|
for led in self.leds:
|
||||||
led.__enter__()
|
led.enter(self.chip)
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
for led in self.leds:
|
for led in self.leds:
|
||||||
led.__exit__(*args)
|
led.exit()
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
for led in self.leds:
|
||||||
|
led.off()
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
for led in self.leds:
|
||||||
|
led.on()
|
||||||
|
|
||||||
|
|
||||||
|
class DummyLed:
|
||||||
|
def __init__(self, gpio_pin: int):
|
||||||
|
self.gpio_pin = gpio_pin
|
||||||
|
self.is_on = False
|
||||||
|
|
||||||
|
def enter(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
self.is_on = True
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
self.is_on = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'LED{self.gpio_pin:02}'
|
||||||
|
|
||||||
|
|
||||||
|
class DummyLeds:
|
||||||
|
def __init__(self, gpio_pins: list[int]):
|
||||||
|
self.leds = []
|
||||||
|
for pin in gpio_pins:
|
||||||
|
self.leds.append(DummyLed(pin))
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
for led in self.leds:
|
||||||
|
led.enter()
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
for led in self.leds:
|
||||||
|
led.exit()
|
||||||
|
|
||||||
def off(self):
|
def off(self):
|
||||||
for led in self.leds:
|
for led in self.leds:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
Flask
|
Flask
|
||||||
pillow
|
pillow
|
||||||
opencv-python
|
|
||||||
gphoto2
|
gphoto2
|
||||||
scipy
|
scipy
|
||||||
lgpio
|
gpiod
|
||||||
|
|
|
||||||
63
scanner.py
63
scanner.py
|
|
@ -1,51 +1,17 @@
|
||||||
import cv2
|
|
||||||
import os
|
import os
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import subprocess
|
|
||||||
import shutil
|
|
||||||
import time
|
import time
|
||||||
import gphoto2 as gp
|
from . import config
|
||||||
import gpiod
|
|
||||||
from . import config, leds
|
|
||||||
|
|
||||||
# Delay between to captures
|
# Delay between to captures
|
||||||
DELAY = 0.5
|
DELAY = 0.5
|
||||||
|
|
||||||
def capture(camera, output_path: str) -> bool:
|
|
||||||
try:
|
|
||||||
print('Capturing image')
|
|
||||||
file_path = camera.capture(gp.GP_CAPTURE_IMAGE)
|
|
||||||
print('Camera file path: {0}/{1}'.format(file_path.folder, file_path.name))
|
|
||||||
target = output_path + '.cr2'
|
|
||||||
print('Copying image to', target)
|
|
||||||
print(file_path.folder, file_path.name[:-3] + 'JPG')
|
|
||||||
camera_file_jpg = camera.file_get(file_path.folder, file_path.name[:-3] + 'JPG', gp.GP_FILE_TYPE_NORMAL)
|
|
||||||
camera_file_jpg.save(output_path + '.jpg')
|
|
||||||
|
|
||||||
camera_file_raw = camera.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_RAW)
|
|
||||||
camera_file_raw.save(target)
|
|
||||||
|
|
||||||
camera.exit()
|
|
||||||
camera.init()
|
|
||||||
s = True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f'Somethings wrong on gphoto2')
|
|
||||||
print(e)
|
|
||||||
s = False
|
|
||||||
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def scan(output_dir: str):
|
def scan(output_dir: str):
|
||||||
camera = gp.Camera()
|
|
||||||
camera.init()
|
|
||||||
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
os.makedirs(output_dir, exist_ok=True)
|
||||||
gpio_leds = leds.GpioLeds(config.LEDS_UUIDS)
|
|
||||||
|
|
||||||
with gpio_leds:
|
with config.GPIO_LEDS:
|
||||||
for count, led in enumerate(gpio_leds.leds):
|
for count, led in enumerate(config.GPIO_LEDS.leds):
|
||||||
print(f'Turn on {led}')
|
print(f'Turn on {led}')
|
||||||
img = join(output_dir, f'{led}')
|
img = join(output_dir, f'{led}')
|
||||||
|
|
||||||
|
|
@ -53,12 +19,9 @@ def scan(output_dir: str):
|
||||||
start = time.time()
|
start = time.time()
|
||||||
|
|
||||||
led.on()
|
led.on()
|
||||||
capture(camera, img)
|
config.CAMERA.capture(img)
|
||||||
led.off()
|
led.off()
|
||||||
|
|
||||||
# For debug purposes
|
|
||||||
# shutil.copyfile(join('data-keep/small', led + '.jpg'), img)
|
|
||||||
|
|
||||||
delta = time.time() - start
|
delta = time.time() - start
|
||||||
|
|
||||||
# Wait for at least one second between each capture
|
# Wait for at least one second between each capture
|
||||||
|
|
@ -66,18 +29,14 @@ def scan(output_dir: str):
|
||||||
time.sleep(DELAY - delta)
|
time.sleep(DELAY - delta)
|
||||||
|
|
||||||
print(f'Turn off {led}')
|
print(f'Turn off {led}')
|
||||||
if count == len(config.LEDS_UUIDS) -1:
|
if count == len(config.LEDS_UUIDS) - 1:
|
||||||
|
|
||||||
# capture with all leds ON OFF
|
# capture with all leds ON OFF
|
||||||
gpio_leds.on()
|
config.GPIO_LEDS.on()
|
||||||
img = join(output_dir, f'all_on')
|
img = join(output_dir, 'all_on')
|
||||||
capture(camera, img)
|
config.CAMERA.capture(img)
|
||||||
|
|
||||||
gpio_leds.off()
|
config.GPIO_LEDS.off()
|
||||||
img = join(output_dir, f'all_off')
|
img = join(output_dir, 'all_off')
|
||||||
capture(camera, img)
|
config.CAMERA.capture(img)
|
||||||
|
|
||||||
camera.exit()
|
|
||||||
|
|
||||||
yield led
|
yield led
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@
|
||||||
<div class="has-text-centered mb-3">Voulez-vous vraiment supprimer l'objet ?</div>
|
<div class="has-text-centered mb-3">Voulez-vous vraiment supprimer l'objet ?</div>
|
||||||
<div class="field is-grouped is-grouped-centered">
|
<div class="field is-grouped is-grouped-centered">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button custom-modal-close">Annuler</a>
|
<button class="button custom-modal-close">Annuler</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a href="/object/delete/{{ object.id }}" class="button is-danger">Supprimer cet objet</a>
|
<a href="/object/delete/{{ object.id }}" class="button is-danger">Supprimer cet objet</a>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@
|
||||||
<div class="has-text-centered mb-3">Voulez-vous vraiment supprimer l'acquisition ?</div>
|
<div class="has-text-centered mb-3">Voulez-vous vraiment supprimer l'acquisition ?</div>
|
||||||
<div class="field is-grouped is-grouped-centered">
|
<div class="field is-grouped is-grouped-centered">
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<button class="button custom-modal-close">Annuler</a>
|
<button class="button custom-modal-close">Annuler</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
<a id="delete-link" {% if acquisition %} href="/acquisition/delete/{{ acquisition.id }}"{% endif %} class="button is-danger">Supprimer cette acquisition</a>
|
<a id="delete-link" {% if acquisition %} href="/acquisition/delete/{{ acquisition.id }}"{% endif %} class="button is-danger">Supprimer cette acquisition</a>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue