Merge remote-tracking branch 'thibault/master'

Update to the README merged accordingly
This commit is contained in:
Romain Bazile 2020-07-19 17:42:43 +02:00
commit d289f28aa3
12 changed files with 3244 additions and 15478 deletions

View file

@ -1,13 +1,15 @@
# PlanktoScop Main Repository # PlanktoScop Main Repository
The PlanktoScop is an open and affordable modular imaging platform for citizen oceanography. The PlanktoScop is an open and affordable modular imaging platform for citizen oceanography.
It's a high-throughtput microscope platform, designed with an open-hardware and open-software mentality. This GitHub is part of a community that you can find on [its website](https://www.planktonscope.org/).
You can learn more about the PlantoScop [on its website](https://www.planktonscope.org/discover). # Fast Setup
Before going further, notice that you can download the image disk already setup without having to deal with all these command lines.
Jump here : http://planktonscope.su.domains/Images_raspberry/Raspbian_Buster_Morphocut_WiFi.img
# PlanktoScop Raspberry Pi Setup # Expert Setup
After getting your kit and finding the necessary components, but before assembling your kit, you should take the time to do a mockup build and setup your Raspberry! After getting your kit and finding the necessary components, but before assembling your kit, you should take the time to do a mockup build and setup your Raspberry.
## Install and setup Raspbian on your Raspberry Pi ## Install and setup Raspbian on your Raspberry Pi
@ -197,13 +199,13 @@ https://www.pyimagesearch.com/2019/09/16/install-opencv-4-on-raspberry-pi-4-and-
### Install MorphoCut ### Install MorphoCut
[Installing MorphoCut](https://morphocut.readthedocs.io/en/stable/installation.html)
_Installing MorphoCut <https://morphocut.readthedocs.io/en/stable/installation.html>`_
MorphoCut is packaged on PyPI and can be installed with pip: MorphoCut is packaged on PyPI and can be installed with pip:
```
```sh
sudo apt-get install python3-scipy sudo apt-get install python3-scipy
pip3 install -U git+https://github.com/morphocut/morphocut.git@pyrocystis pip3 install -U git+https://github.com/morphocut/morphocut.git
``` ```
## Finishing the install ## Finishing the install

View file

@ -1 +0,0 @@
theme: jekyll-theme-minimal

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,612 +0,0 @@
[
{
"id": "7f885510.6173fc",
"type": "tab",
"label": "Home",
"disabled": false,
"info": ""
},
{
"id": "55a31f5b.d4ec5",
"type": "tab",
"label": "Static Observation",
"disabled": false,
"info": ""
},
{
"id": "c04dcc2a.47862",
"type": "tab",
"label": "Fluidic Acquisition",
"disabled": false,
"info": ""
},
{
"id": "300f077.33624f8",
"type": "tab",
"label": "Segmentation",
"disabled": false,
"info": ""
},
{
"id": "121f01ae.4c4abe",
"type": "tab",
"label": "Dashboard Control",
"disabled": false,
"info": ""
},
{
"id": "56d9742b.9ed99c",
"type": "ui_base",
"theme": {
"name": "theme-dark",
"lightTheme": {
"default": "#0094CE",
"baseColor": "#0094CE",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": false,
"reset": false
},
"darkTheme": {
"default": "#097479",
"baseColor": "#097479",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif",
"edited": true,
"reset": false
},
"customTheme": {
"name": "Untitled Theme 1",
"default": "#4B7930",
"baseColor": "#4B7930",
"baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
},
"themeState": {
"base-color": {
"default": "#097479",
"value": "#097479",
"edited": false
},
"page-titlebar-backgroundColor": {
"value": "#097479",
"edited": false
},
"page-backgroundColor": {
"value": "#111111",
"edited": false
},
"page-sidebar-backgroundColor": {
"value": "#000000",
"edited": false
},
"group-textColor": {
"value": "#0eb8c0",
"edited": false
},
"group-borderColor": {
"value": "#555555",
"edited": false
},
"group-backgroundColor": {
"value": "#333333",
"edited": false
},
"widget-textColor": {
"value": "#eeeeee",
"edited": false
},
"widget-backgroundColor": {
"value": "#097479",
"edited": false
},
"widget-borderColor": {
"value": "#333333",
"edited": false
},
"base-font": {
"value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"
}
},
"angularTheme": {
"primary": "indigo",
"accents": "blue",
"warn": "red",
"background": "grey"
}
},
"site": {
"name": "Node-RED Dashboard",
"hideToolbar": "false",
"allowSwipe": "false",
"lockMenu": "false",
"allowTempTheme": "true",
"dateFormat": "DD/MM/YYYY",
"sizes": {
"sx": 48,
"sy": 48,
"gx": 6,
"gy": 6,
"cx": 6,
"cy": 6,
"px": 0,
"py": 0
}
}
},
{
"id": "c18fae15.516ce",
"type": "ui_tab",
"z": "",
"name": "Home",
"icon": "dashboard",
"order": 1,
"disabled": false,
"hidden": false
},
{
"id": "29a78fc9.b034c",
"type": "ui_group",
"z": "",
"name": "Static Observation",
"tab": "c18fae15.516ce",
"order": 1,
"disp": false,
"width": "12",
"collapse": false
},
{
"id": "10d36e29.c78b42",
"type": "ui_group",
"z": "",
"name": "Fluidic Acquisition",
"tab": "c18fae15.516ce",
"order": 2,
"disp": false,
"width": "12",
"collapse": false
},
{
"id": "8c1b4542.a177a8",
"type": "ui_group",
"z": "",
"name": "Segmentation",
"tab": "c18fae15.516ce",
"order": 3,
"disp": false,
"width": "12",
"collapse": false
},
{
"id": "edb89598.853498",
"type": "ui_group",
"z": "",
"name": "Gallery",
"tab": "c18fae15.516ce",
"order": 4,
"disp": false,
"width": "12",
"collapse": false
},
{
"id": "98e9fd1a.1bbe5",
"type": "ui_tab",
"z": "",
"name": "Static Observation",
"icon": "dashboard",
"order": 2,
"disabled": false,
"hidden": false
},
{
"id": "2e62c9a8.c191f6",
"type": "ui_tab",
"z": "",
"name": "Fluidic Acquisition",
"icon": "",
"order": 3,
"disabled": false,
"hidden": false
},
{
"id": "609b39b5.d91f28",
"type": "ui_tab",
"z": "",
"name": "Segmentation",
"icon": "dashboard",
"order": 4,
"disabled": false,
"hidden": false
},
{
"id": "b253b89c.1c4458",
"type": "ui_tab",
"z": "",
"name": "Dashboard Control",
"icon": "dashboard",
"order": 5,
"disabled": false,
"hidden": false
},
{
"id": "498d73e3.d1c94c",
"type": "ui_group",
"name": "Group 1",
"tab": "98e9fd1a.1bbe5",
"order": 1,
"disp": true,
"width": 6
},
{
"id": "72fe0cc7.df9fd4",
"type": "ui_group",
"name": "Group 1",
"tab": "2e62c9a8.c191f6",
"order": 1,
"disp": true,
"width": 6
},
{
"id": "54c8e6e0.223fc8",
"type": "ui_group",
"name": "Group 1",
"tab": "609b39b5.d91f28",
"order": 1,
"disp": true,
"width": 6
},
{
"id": "5841eafd.95e5e4",
"type": "ui_group",
"name": "Group 1",
"tab": "b253b89c.1c4458",
"order": 1,
"disp": true,
"width": 6
},
{
"id": "df3ac001.1d82a",
"type": "ui_button",
"z": "7f885510.6173fc",
"name": "",
"group": "29a78fc9.b034c",
"order": 1,
"width": 12,
"height": 6,
"passthru": false,
"label": "Static Observation",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Static Observation",
"x": 210,
"y": 260,
"wires": [
[
"82696634.821678"
]
]
},
{
"id": "113ae8d3.b52867",
"type": "ui_button",
"z": "7f885510.6173fc",
"name": "",
"group": "8c1b4542.a177a8",
"order": 1,
"width": 12,
"height": 6,
"passthru": false,
"label": "Segmentation",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Segmentation",
"x": 220,
"y": 300,
"wires": [
[
"82696634.821678"
]
]
},
{
"id": "ec028844.198c98",
"type": "ui_button",
"z": "7f885510.6173fc",
"name": "",
"group": "10d36e29.c78b42",
"order": 1,
"width": 12,
"height": 6,
"passthru": false,
"label": "Fluidic Acquisition",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Fluidic Acquisition",
"x": 210,
"y": 340,
"wires": [
[
"82696634.821678"
]
]
},
{
"id": "47a9f575.dc2c8c",
"type": "ui_button",
"z": "7f885510.6173fc",
"name": "",
"group": "edb89598.853498",
"order": 1,
"width": 12,
"height": 6,
"passthru": false,
"label": "Dashboard Control",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Dashboard Control",
"x": 270,
"y": 380,
"wires": [
[
"82696634.821678"
]
]
},
{
"id": "c0f2a501.1677c8",
"type": "ui_ui_control",
"z": "7f885510.6173fc",
"name": "",
"events": "change",
"x": 540,
"y": 260,
"wires": [
[]
]
},
{
"id": "c52be0d9.e6412",
"type": "ui_button",
"z": "55a31f5b.d4ec5",
"name": "",
"group": "498d73e3.d1c94c",
"order": 0,
"width": 0,
"height": 0,
"passthru": false,
"label": "Home",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Home",
"x": 70,
"y": 40,
"wires": [
[
"66e609a2.2d57d8"
]
]
},
{
"id": "82696634.821678",
"type": "function",
"z": "7f885510.6173fc",
"name": "swtich tab",
"func": "\nmsg.payload={\"tab\":msg.topic};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 400,
"y": 260,
"wires": [
[
"c0f2a501.1677c8"
]
]
},
{
"id": "8059df68.0963c",
"type": "ui_ui_control",
"z": "55a31f5b.d4ec5",
"name": "",
"events": "change",
"x": 380,
"y": 40,
"wires": [
[]
]
},
{
"id": "66e609a2.2d57d8",
"type": "function",
"z": "55a31f5b.d4ec5",
"name": "change tab",
"func": "\nmsg.payload={\"tab\":msg.topic};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 220,
"y": 40,
"wires": [
[
"8059df68.0963c"
]
]
},
{
"id": "f8c2a4c7.928f88",
"type": "ui_button",
"z": "c04dcc2a.47862",
"name": "",
"group": "72fe0cc7.df9fd4",
"order": 0,
"width": 0,
"height": 0,
"passthru": false,
"label": "Home",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Home",
"x": 70,
"y": 40,
"wires": [
[
"6715b713.0ea1e8"
]
]
},
{
"id": "16edbf14.c67bb1",
"type": "ui_ui_control",
"z": "c04dcc2a.47862",
"name": "",
"events": "change",
"x": 380,
"y": 40,
"wires": [
[]
]
},
{
"id": "6715b713.0ea1e8",
"type": "function",
"z": "c04dcc2a.47862",
"name": "change tab",
"func": "\nmsg.payload={\"tab\":msg.topic};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 220,
"y": 40,
"wires": [
[
"16edbf14.c67bb1"
]
]
},
{
"id": "e46b58fd.671568",
"type": "ui_button",
"z": "300f077.33624f8",
"name": "",
"group": "54c8e6e0.223fc8",
"order": 0,
"width": 0,
"height": 0,
"passthru": false,
"label": "Home",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Home",
"x": 70,
"y": 40,
"wires": [
[
"5c885d69.f82f74"
]
]
},
{
"id": "c492a6c.3ff6558",
"type": "ui_ui_control",
"z": "300f077.33624f8",
"name": "",
"events": "change",
"x": 380,
"y": 40,
"wires": [
[]
]
},
{
"id": "5c885d69.f82f74",
"type": "function",
"z": "300f077.33624f8",
"name": "change tab",
"func": "\nmsg.payload={\"tab\":msg.topic};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 220,
"y": 40,
"wires": [
[
"c492a6c.3ff6558"
]
]
},
{
"id": "cb7440f4.3efff",
"type": "ui_button",
"z": "121f01ae.4c4abe",
"name": "",
"group": "5841eafd.95e5e4",
"order": 0,
"width": 0,
"height": 0,
"passthru": false,
"label": "Home",
"tooltip": "",
"color": "",
"bgcolor": "",
"icon": "",
"payload": "",
"payloadType": "str",
"topic": "Home",
"x": 70,
"y": 40,
"wires": [
[
"b0b1ec9.5371e1"
]
]
},
{
"id": "a4505700.60eb18",
"type": "ui_ui_control",
"z": "121f01ae.4c4abe",
"name": "",
"events": "change",
"x": 380,
"y": 40,
"wires": [
[]
]
},
{
"id": "b0b1ec9.5371e1",
"type": "function",
"z": "121f01ae.4c4abe",
"name": "change tab",
"func": "\nmsg.payload={\"tab\":msg.topic};\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 220,
"y": 40,
"wires": [
[
"a4505700.60eb18"
]
]
}
]

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -1,140 +0,0 @@
import datetime
import os
from skimage.util import img_as_ubyte
from skimage.filters import threshold_otsu
from morphocut import Call
from morphocut.contrib.ecotaxa import EcotaxaWriter
from morphocut.contrib.zooprocess import CalculateZooProcessFeatures
from morphocut.core import Pipeline
from morphocut.file import Find
from morphocut.image import (
ExtractROI,
FindRegions,
ImageReader,
ImageWriter,
RescaleIntensity,
RGB2Gray,
)
from morphocut.stat import RunningMedian
from morphocut.str import Format
from morphocut.stream import TQDM, Enumerate
import_path = "/home/pi/Desktop/PlanktonScope_acquisition/01_17_2020/16_2"
export_path = "/home/pi/Desktop/PlanktonScope_acquisition/01_17_2020/16"
archive_fn = os.path.join(export_path, "17_morphocut_processed.zip")
# Meta data that is added to every object
global_metadata = {
"process_datetime": datetime.datetime.now(),
"sample_project": "PlanktonScope Villefranche",
"sample_ship": "Kayak de Fabien",
"sample_operator": "Thibaut Pollina",
"sample_id": "Flowcam_PlanktonScope_comparison",
"sample_sampling_gear": "net",
"object_date": 20200117,
"object_time": 150000,
"object_lat": 43.696146,
"object_lon": 7.308359,
"object_depth_min": 0,
"object_depth_max": 1,
"acq_fnumber_objective": 16,
"acq_celltype": 400,
"acq_camera": "Pi Camera V2.1",
"acq_instrument": "PlanktonScope V2.1",
"acq_software": "Node-RED Dashboard and raw python",
"acq_instrument_ID": "copepode",
"acq_camera_resolution" : "(3280, 2464)",
"acq_camera_iso" : 60,
"acq_camera_shutter_speed" : 100,
"acq_camera_exposure_mode" : "off",
"acq_camera_awb_mode" : "off",
"process_pixel": 1.19
}
if __name__ == "__main__":
print("Processing images under {}...".format(import_path))
# Create export_path in case it doesn't exist
os.makedirs(export_path, exist_ok=True)
# Define processing pipeline
with Pipeline() as p:
# Recursively find .jpg files in import_path.
# Sort to get consective frames.
abs_path = Find(import_path, [".jpg"], sort=True, verbose=True)
# Extract name from abs_path
name = Call(lambda p: os.path.splitext(os.path.basename(p))[0], abs_path)
# Show progress bar for frames
TQDM(Format("Frame {name}", name=name))
# Read image
img = ImageReader(abs_path)
# Convert image to uint8 gray
img_gray = RGB2Gray(img)
#img_gray = Call(img_as_ubyte, img_gray)
# Apply threshold find objects
#threshold = 200 #
#threshold = Call(threshold_otsu, img_gray)
threshold = 180 #
mask = img_gray < threshold
# Write corrected frames
ImageWriter(frame_fn, mask)
# Find objects
regionprops = FindRegions(
mask, img_gray, min_area=300, padding=10, warn_empty=name
)
# For an object, extract a vignette/ROI from the image
roi_orig = ExtractROI(img, regionprops, bg_color=255)
#roi_gray = ExtractROI(img_gray, regionprops, bg_color=255)
# Generate an object identifier
i = Enumerate()
object_id = Format("{name}_{i:d}", name=name, i=i)
# Calculate features. The calculated features are added to the global_metadata.
# Returns a Variable representing a dict for every object in the stream.
#meta = CalculateZooProcessFeatures(
# regionprops, prefix="object_", meta=global_metadata
#)
# If CalculateZooProcessFeatures is not used, we need to copy global_metadata into the stream:
# meta = Call(lambda: global_metadata.copy())
# https://github.com/morphocut/morphocut/issues/51
# Add object_id to the metadata dictionary
#meta["object_id"] = object_id
# Generate object filenames
orig_fn = Format(os.path.join(export_path, "{object_id}.jpg"), object_id=object_id)
#gray_fn = Format("{object_id}-gray.jpg", object_id=object_id)
ImageWriter(orig_fn, roi_orig)
# Write objects to an EcoTaxa archive:
# roi image in original color, roi image in grayscale, metadata associated with each object
#EcotaxaWriter(archive_fn, [(orig_fn, roi_orig)], meta)
# Progress bar for objects
TQDM(Format("Object {object_id}", object_id=object_id))
# Execute pipeline
p.run()

View file

@ -1,116 +0,0 @@
#!/usr/bin/env python
# coding: utf-8
################################################################################
# A) Import the librairies needed to execute the script
################################################################################
#Activate pinout to control the LEDs and the RELAY
from gpiozero import LED
#Allow to access the I2C BUS from the Raspberry Pi
import smbus
#Time librairy in order to sleep when need
from time import sleep
#Picamera library to take images
from picamera import PiCamera
#Enable calculation of remaining duration and datetime
from datetime import datetime, timedelta
#Enable creation of new folders
import os
from adafruit_motor import stepper
from adafruit_motorkit import MotorKit
from time import sleep
kit = MotorKit()
pump_stepper = kit.stepper1
pump_stepper.release()
################################################################################
# C) Configuration file
################################################################################
camera = PiCamera()
camera.resolution = (3280, 2464)
camera.iso = 60
sleep(3)
camera.shutter_speed = 300
camera.exposure_mode = 'off'
g = camera.awb_gains
camera.awb_mode = 'off'
camera.awb_gains = g
nb_frame=2000
pump_stepper.release()
################################################################################
# E) Define simple functions making the whole sequence
###
################################################################################
print("###############")
print("IMAGING")
print("###############")
#Inform on the statut of the operation
print("Imaging : engaged")
#start the preview only during the acquisition
camera.start_preview(fullscreen=False, window = (160, 0, 640, 480))
#get the actual date
date_now = datetime.now().strftime("%m_%d_%Y")
day_now="/home/pi/Desktop/PlanktonScope_acquisition/"+str(date_now)
#create a directory if the directory doesn't exist yet
if not os.path.exists(day_now):
os.makedirs(day_now)
#get the actual date
hour_now = datetime.now().strftime("%H")
hour="/home/pi/Desktop/PlanktonScope_acquisition/"+str(date_now)+"/"+str(hour_now)
#create a directory if the directory doesn't exist yet
if not os.path.exists(hour):
os.makedirs(hour)
#allow the camera to warm up
for i in range(200):
pump_stepper.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
sleep(0.01)
for frame in range(nb_frame):
#get the time now
time = datetime.now().strftime("%M_%S_%f")
#create a filename from the date and the time
filename="/home/pi/Desktop/PlanktonScope_acquisition/"+str(date_now)+"/"+str(hour_now)+"/"+str(time)+".jpg"
#capture an image with the specified filename
camera.capture(filename)
#wait to complete the imaging process and print info on the terminal
print("Imaging : "+str(frame)+"/"+str(nb_frame))
for i in range(10):
pump_stepper.onestep(direction=stepper.BACKWARD, style=stepper.SINGLE)
sleep(0.01)
sleep(0.5)
#stop the preview during the rest of the sequence
camera.stop_preview()
pump_stepper.release()
#Inform on the statut of the operation
print("Imaging : done")
################################################################################
#################################################
# F) Execute the sequence
################################################################################