Merge pull request #1 from oceantrotter/master
Major documentation update and latest changes from tpollina
This commit is contained in:
commit
6921587bac
413
README.md
413
README.md
|
@ -1,4 +1,411 @@
|
||||||
# PlanktonScope
|
# PlanktoScop Main Repository
|
||||||
|
The PlanktoScop is an open and affordable modular imaging platform for citizen oceanography.
|
||||||
|
|
||||||
Please find the documentation here :
|
This GitHub is part of a community that you can find on [its website](https://www.planktonscope.org/).
|
||||||
https://planktonscope.readthedocs.io/en/latest/index.html
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
## Install and setup Raspbian on your Raspberry Pi
|
||||||
|
|
||||||
|
### Computer setup
|
||||||
|
In order to make it easy to connect to the PlanktoScop, you may want to install [avahi](https://en.wikipedia.org/wiki/Avahi_%28software%29) or the [Bonjour](https://en.wikipedia.org/wiki/Bonjour_%28software%29) service on any computer you will use to access the PlanktoScop interface. This will allow you to connect to the PlantoScop using an address similar such as http://planktoscope.local instead of an IP address.
|
||||||
|
|
||||||
|
### Download the image
|
||||||
|
|
||||||
|
The latest Raspbian version can always be downloaded from [the Raspberry Pi Downloads page](https://www.raspberrypi.org/downloads/raspbian/).
|
||||||
|
For a first build, it's recommende to download an image of Raspbian Buster with desktop.
|
||||||
|
|
||||||
|
#### Writing an image to the SD card
|
||||||
|
|
||||||
|
Download the latest version of [balenaEtcher](https://www.balena.io/etcher/) and install it.
|
||||||
|
|
||||||
|
Connect an SD card reader with the micro SD card inside.
|
||||||
|
|
||||||
|
Open balenaEtcher and select from your hard drive the image zip file you just downloaded.
|
||||||
|
|
||||||
|
Select the SD card you want to write your image to.
|
||||||
|
|
||||||
|
Review your selections and click `Flash!` to begin writing data to the SD card.
|
||||||
|
|
||||||
|
#### Prepare your Raspberry Pi
|
||||||
|
[Getting Started with your Raspberry Pi](https://projects.raspberrypi.org/en/projects/raspberry-pi-getting-started/)
|
||||||
|
|
||||||
|
Plug the SD Card in your Raspberry Pi and connect your Pi to a screen, mouse and a keyboard. Check the connection twice before plugging the power.
|
||||||
|
|
||||||
|
The first boot to the desktop may take up to 120 seconds. This is normal and is caused by the image expanding the filesystem to the whole SD card. DO NOT REBOOT before you reach the desktop.
|
||||||
|
|
||||||
|
#### Finish the setup
|
||||||
|
|
||||||
|
Make sure you have access to internet and update/upgrade your fresh Raspbian install.
|
||||||
|
|
||||||
|
Update your Pi first. Open up a terminal, and do the following:
|
||||||
|
```sh
|
||||||
|
sudo apt update -y
|
||||||
|
sudo apt upgrade -y
|
||||||
|
sudo apt install git
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now reboot your Pi safely.
|
||||||
|
```sh
|
||||||
|
sudo reboot now
|
||||||
|
```
|
||||||
|
|
||||||
|
## Raspberry Pi configuration
|
||||||
|
|
||||||
|
### Clone this repository!
|
||||||
|
|
||||||
|
First of all, and to ensure you have the latest documentation available locally, you should clone this repository using git.
|
||||||
|
|
||||||
|
Simply run the following in a terminal:
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/PlanktonPlanet/PlanktonScope/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Enable Camera/SSH/I2C in raspi-config
|
||||||
|
|
||||||
|
You can now launch the configuration tool:
|
||||||
|
```sh
|
||||||
|
sudo raspi-config
|
||||||
|
```
|
||||||
|
|
||||||
|
While you're here, a wise thing to do would be to change the default password for the `pi` user. This is very warmly recommended if your PlanktoScop is connected to a shared network you do not control. Just select the first option `1 Change User Password`.
|
||||||
|
|
||||||
|
You may also want to change the default hostname of your Raspberry. To do so, choose option `2 Network Options` then `N1 Hostname`. Choose a new hostname. We recommend using `planktoscope`.
|
||||||
|
|
||||||
|
We need to activate a few things for the PlanktoScop to work properly.
|
||||||
|
|
||||||
|
First, we need to activate the camera interface. Choose `5 Interfacing Options`, then `P1 Camera` and `Yes`.
|
||||||
|
|
||||||
|
Now, you can go to `5 Interfacing Options`, then `P2 SSH`. Choose `Yes` to activate the SSH access.
|
||||||
|
|
||||||
|
Again, select `5 Interfacing Options`, then `P4 SPI`. Choose `Yes` to enable the SPI interface.
|
||||||
|
|
||||||
|
One more, select `5 Interfacing Options`, then `P5 I2C`. Choose `Yes` to enable the ARM I2C interface of the Raspberry.
|
||||||
|
|
||||||
|
Finally, select `5 Interfacing Options`, then `P6 Serial`.
|
||||||
|
|
||||||
|
This time, choose `No` to deactivate the login shell on the serial connection, but then choose `Yes` to keep the Serial port hardware enabled.
|
||||||
|
|
||||||
|
These steps can also be done from the Raspberry Pi Configuration GUI tool that you can find in `Main Menu > Preferences`. Go to the `Interfaces` tab. Pay attention, here the Serial Port must be enabled, but the Serial Port Console must be disabled.
|
||||||
|
|
||||||
|
Reboot your Pi safely.
|
||||||
|
```sh
|
||||||
|
sudo reboot now
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install the needed libraries for the PlanktoScop
|
||||||
|
|
||||||
|
Most of the following happens in a command line environment. If you are using the desktop, please start a terminal emulator.
|
||||||
|
|
||||||
|
You can also connect to your PlanktoScop by using ssh using `ssh pi@planktoscope.local`.
|
||||||
|
|
||||||
|
You can then run the following to make sure your Raspberry has the necessary components to install and build everything it needs and to create the necessary folders:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install build-essential python3 python3-pip
|
||||||
|
mkdir test libraries
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install CircuitPython
|
||||||
|
Start by following [Adafruit's guide](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi). You can start at the chapter `Install Python Libraries`.
|
||||||
|
|
||||||
|
For the record, the command are as following, however, Adafruit's page might have been updated, so please make sure this is still needed:
|
||||||
|
```sh
|
||||||
|
sudo pip3 install RPI.GPIO
|
||||||
|
sudo pip3 install adafruit-blinka
|
||||||
|
sudo pip3 install adafruit-circuitpython-motorkit
|
||||||
|
```
|
||||||
|
|
||||||
|
It is recommended to test this setup by creating this small script under the name `test/blinkatest.py` and running it (you can use the editor nano if you are using the terminal).
|
||||||
|
```python
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import board
|
||||||
|
import digitalio
|
||||||
|
import busio
|
||||||
|
|
||||||
|
|
||||||
|
print("Hello blinka!")
|
||||||
|
|
||||||
|
# Try to great a Digital input
|
||||||
|
pin = digitalio.DigitalInOut(board.D4)
|
||||||
|
print("Digital IO ok!")
|
||||||
|
|
||||||
|
# Try to create an I2C device
|
||||||
|
i2c = busio.I2C(board.SCL, board.SDA)
|
||||||
|
print("I2C ok!")
|
||||||
|
|
||||||
|
# Try to create an SPI device
|
||||||
|
spi = busio.SPI(board.SCLK, board.MOSI, board.MISO)
|
||||||
|
print("SPI ok!")
|
||||||
|
|
||||||
|
print("done!")
|
||||||
|
```
|
||||||
|
|
||||||
|
To run the script, just run the following:
|
||||||
|
```sh
|
||||||
|
chmod +x test/blinkatest.py
|
||||||
|
./test/blinkatest.py
|
||||||
|
```
|
||||||
|
|
||||||
|
The output should be similar to this:
|
||||||
|
```
|
||||||
|
pi@planktoscope:~ $ ./test/blinkatest.py
|
||||||
|
Hello blinka!
|
||||||
|
Digital IO ok!
|
||||||
|
I2C ok!
|
||||||
|
SPI ok!
|
||||||
|
done!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install RPi Cam Web Interface
|
||||||
|
|
||||||
|
You can find more information about the RPi Cam Web Interface on [eLinux' website](https://elinux.org/RPi-Cam-Web-Interface).
|
||||||
|
|
||||||
|
To set it up, clone the code from Github and enable and run the install script with the following commands
|
||||||
|
```sh
|
||||||
|
cd ~/libraries
|
||||||
|
git clone https://github.com/silvanmelchior/RPi_Cam_Web_Interface.git
|
||||||
|
cd RPi_Cam_Web_Interface
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Press Enter to allow default setting of the installation. Once everything is installed, press Enter to start the RPi Cam Web Interface now.
|
||||||
|
|
||||||
|
To test the interface locally, try accessing this url from the browser in the Raspberry: http://localhost/html
|
||||||
|
|
||||||
|
You can also try to access this page from another computer connected to the same network.
|
||||||
|
|
||||||
|
If your computer has `avahi` or the `Bonjour` service installed and running, you can directly use this url: http://raspberrypi.local/html/ .
|
||||||
|
|
||||||
|
If this is not the case, you first need to find the IP address of your Raspberry Pi by running the following:
|
||||||
|
```sh
|
||||||
|
sudo ip addr show | grep 'inet 1'
|
||||||
|
```
|
||||||
|
|
||||||
|
The web page can then be accessed at `http://[IP_ADDRESS]/html/`.
|
||||||
|
|
||||||
|
If the interface is loading and a picture is displayed, you can stop this interface for now by simply running `./stop.sh`.
|
||||||
|
|
||||||
|
|
||||||
|
### Install Ultimate GPS HAT
|
||||||
|
|
||||||
|
You can start by testing that the GPS module is working. Either install your PlanktoScop with a view of the sky, or connect the external antenna.
|
||||||
|
|
||||||
|
Now you need to run the following:
|
||||||
|
```sh
|
||||||
|
sudo apt install gpsd gpsd-clients
|
||||||
|
stty -F /dev/serial0 raw 9600 cs8 clocal -cstopb
|
||||||
|
cat /dev/serial0
|
||||||
|
```
|
||||||
|
|
||||||
|
If the GPS works, you should now see NMEA sentences scrolling:
|
||||||
|
```
|
||||||
|
$GPGGA,000908.799,,,,,0,00,,,M,,M,,*7E
|
||||||
|
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
|
||||||
|
$GPGSV,1,1,00*79
|
||||||
|
$GPRMC,000908.799,V,,,,,0.00,0.00,060180,,,N*44
|
||||||
|
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
|
||||||
|
$GPGGA,000909.799,,,,,0,00,,,M,,M,,*7F
|
||||||
|
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
|
||||||
|
$GPRMC,000909.799,V,,,,,0.00,0.00,060180,,,N*45
|
||||||
|
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
|
||||||
|
$GPGGA,000910.799,,,,,0,00,,,M,,M,,*77
|
||||||
|
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
|
||||||
|
$GPRMC,000910.799,V,,,,,0.00,0.00,060180,,,N*4D
|
||||||
|
$GPVTG,0.00,T,,M,0.00,N,0.00,K,N*32
|
||||||
|
```
|
||||||
|
|
||||||
|
Until you get a GPS fix, most of the sentences are empty (see the lines starting with GPGSA and with lot of commas).
|
||||||
|
|
||||||
|
|
||||||
|
You can find more information in this hardware module in Adafruit documentation at [Installing Adafruit GPS HAT](https://learn.adafruit.com/adafruit-ultimate-gps-hat-for-raspberry-pi/overview) or on this page to [use Python Thread with GPS HAT](http://www.danmandle.com/blog/getting-gpsd-to-work-with-python/)
|
||||||
|
|
||||||
|
|
||||||
|
### Install RGB Cooling HAT
|
||||||
|
To setup the RGB Cooling HAT, you just need to clone and build the WiringPi library:
|
||||||
|
```sh
|
||||||
|
cd ~/libraries
|
||||||
|
git clone https://github.com/WiringPi/WiringPi.git
|
||||||
|
cd WiringPi
|
||||||
|
sudo ./build
|
||||||
|
gpio -v
|
||||||
|
```
|
||||||
|
|
||||||
|
The last command should output something similar to the following:
|
||||||
|
```
|
||||||
|
gpio version: 2.60
|
||||||
|
Copyright (c) 2012-2018 Gordon Henderson
|
||||||
|
This is free software with ABSOLUTELY NO WARRANTY.
|
||||||
|
For details type: gpio -warranty
|
||||||
|
|
||||||
|
Raspberry Pi Details:
|
||||||
|
Type: Pi 4B, Revision: 01, Memory: 4096MB, Maker: Sony
|
||||||
|
* Device tree is enabled.
|
||||||
|
*--> Raspberry Pi 4 Model B Rev 1.1
|
||||||
|
* This Raspberry Pi supports user-level GPIO access.
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
You will also need to install some python modules:
|
||||||
|
```sh
|
||||||
|
sudo apt install python3-smbus i2c-tools
|
||||||
|
sudo pip3 install Adafruit-SSD1306
|
||||||
|
```
|
||||||
|
|
||||||
|
More information can be found on Yahboom website, on the page [Installing RGB Cooling HAT](https://www.yahboom.net/study/RGB_Cooling_HAT).
|
||||||
|
|
||||||
|
|
||||||
|
### Install Node-RED
|
||||||
|
|
||||||
|
#### Download and installation
|
||||||
|
To install Node.js, npm and Node-RED onto a Raspberry Pi, you just need to run the following command. You can review the content of this script [here](https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered).
|
||||||
|
```sh
|
||||||
|
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
|
||||||
|
```
|
||||||
|
Type `y` at both prompts to accept the installation and its settings.
|
||||||
|
|
||||||
|
#### Enable start on boot and launch Node-RED
|
||||||
|
To run Node-RED when the Pi is turned on or restarted, you need to enable the systemd service by running this command:
|
||||||
|
```sh
|
||||||
|
sudo systemctl enable nodered.service
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now start Node-RED by running the following:
|
||||||
|
```sh
|
||||||
|
sudo systemctl start nodered.service
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Check the installation
|
||||||
|
Make sure Node-RED is correctly installed by reaching the following page from the browser of your pi http://localhost:1880 or http://planktoscope.local:1880 from another computer on the same network.
|
||||||
|
|
||||||
|
#### Install the necessary nodes
|
||||||
|
These nodes will be used by the PlanktoScop software and needs to be installed:
|
||||||
|
```sh
|
||||||
|
cd ~/.node-red/
|
||||||
|
npm install node-red-dashboard node-red-contrib-python3-function node-red-contrib-camerapi node-red-contrib-gpsd node-red-contrib-web-worldmap node-red-contrib-interval
|
||||||
|
sudo systemctl restart nodered.service
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Import the last GUI
|
||||||
|
|
||||||
|
From Node-RED gui in your browser, choose the Hamburger menu top right, and then Import. You can paste the code directly from the lastest version of the GUI available [here](https://raw.githubusercontent.com/PlanktonPlanet/PlanktonScope/blob/master/flows/main.json).
|
||||||
|
|
||||||
|
You can also download it directly:
|
||||||
|
```sh
|
||||||
|
wget -N -O ~/.node-red/flows_planktoscope.json https://raw.githubusercontent.com/PlanktonPlanet/PlanktonScope/master/flows/main.json
|
||||||
|
sudo systemctl restart nodered.service
|
||||||
|
```
|
||||||
|
|
||||||
|
#### More information
|
||||||
|
[Installing Node-RED on Raspberry Pi](https://nodered.org/docs/getting-started/raspberrypi)
|
||||||
|
|
||||||
|
|
||||||
|
### Install Mosquitto MQTT
|
||||||
|
|
||||||
|
In order to send and receive data from Node-RED, you need to install this. Run the following:
|
||||||
|
```
|
||||||
|
sudo apt install mosquitto mosquitto-clients
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Install mqtt-paho
|
||||||
|
|
||||||
|
In order to send and receive data from python, you need this library. Run the following:
|
||||||
|
```
|
||||||
|
sudo pip3 install paho-mqtt
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Install OpenCV
|
||||||
|
|
||||||
|
We need to install the latest OpenCV version. Unfortunately, it is not available in the repositories. We are going to install it directly by using pip.
|
||||||
|
|
||||||
|
First, we need to install the needed dependencies, then we will directly install opencv:
|
||||||
|
```sh
|
||||||
|
sudo apt install libgtk-3-0 libavformat58 libtiff5 libcairo2 libqt4-test libpango-1.0-0 libopenexr23 libavcodec58 libilmbase23 libatk1.0-0 libpangocairo-1.0-0 libwebp6 libqtgui4 libavutil56 libjasper1 libqtcore4 libcairo-gobject2 libswscale5 libgdk-pixbuf2.0-0 libhdf5-dev libilmbase-dev libopenexr-dev libgstreamer1.0-dev libavcodec-dev libavformat-dev libswscale-dev libwebp-dev libatlas-base-dev
|
||||||
|
sudo pip3 install "picamera[array]"
|
||||||
|
sudo pip3 install opencv-contrib-python==4.1.0.25
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now check that opencv is properly installed by running a python interpreter and importing the cv2 module.
|
||||||
|
```sh
|
||||||
|
pi@planktoscope:~ $ python3
|
||||||
|
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
|
||||||
|
[GCC 8.3.0] on linux
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> import cv2
|
||||||
|
>>> cv2.__version__
|
||||||
|
'4.1.0'
|
||||||
|
>>> quit()
|
||||||
|
```
|
||||||
|
|
||||||
|
If all goes well, the displayed version number should be `4.1.0`.
|
||||||
|
|
||||||
|
More detailed information can be found on this [website](https://www.pyimagesearch.com/2019/09/16/install-opencv-4-on-raspberry-pi-4-and-raspbian-buster/).
|
||||||
|
|
||||||
|
|
||||||
|
### Install MorphoCut
|
||||||
|
|
||||||
|
MorphoCut is packaged on PyPI and can be installed with pip:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt install python3-scipy
|
||||||
|
sudo pip3 install -U git+https://github.com/morphocut/morphocut.git
|
||||||
|
```
|
||||||
|
|
||||||
|
To test the installation, open up once again a python interpreter and import the morphocut module:
|
||||||
|
```sh
|
||||||
|
pi@planktoscope:~ $ python3
|
||||||
|
Python 3.7.3 (default, Dec 20 2019, 18:57:59)
|
||||||
|
[GCC 8.3.0] on linux
|
||||||
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
|
>>> import morphocut
|
||||||
|
>>> morphocut.__version__
|
||||||
|
'0.1.1+42.g01a051e'
|
||||||
|
>>> quit()
|
||||||
|
```
|
||||||
|
|
||||||
|
The MorphoCut documentation can be found [on this page](https://morphocut.readthedocs.io/en/stable/index.html).
|
||||||
|
|
||||||
|
|
||||||
|
## Finishing the install
|
||||||
|
|
||||||
|
Make sure to update your Pi
|
||||||
|
```
|
||||||
|
sudo apt update -y
|
||||||
|
sudo apt full-upgrade -y
|
||||||
|
```
|
||||||
|
|
||||||
|
Reboot your Pi safely
|
||||||
|
```
|
||||||
|
sudo reboot now
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Useful later maybe
|
||||||
|
|
||||||
|
### Update the cloned repository
|
||||||
|
|
||||||
|
Updates are published on Github regurlarly. Make sure to update once in a while by running this command:
|
||||||
|
```sh
|
||||||
|
cd PlanktonScope
|
||||||
|
git pull
|
||||||
|
```
|
||||||
|
|
||||||
|
This will pull and merge all the changes made since your last update.
|
||||||
|
|
||||||
|
### Update node-RED interface
|
||||||
|
To update the interface and make sure you run the latest version, you need to copy the json config file from the cloned repository to the Node-RED library:
|
||||||
|
```sh
|
||||||
|
cp ~/PlanktonScope/flows/main.json ~/.node-red/flows_planktoscope.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### Share WiFi via Ethernet
|
||||||
|
|
||||||
|
At this link : https://www.instructables.com/id/Share-WiFi-With-Ethernet-Port-on-a-Raspberry-Pi/
|
||||||
|
|
3502
flows/flow_mqtt.json
3502
flows/flow_mqtt.json
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
612
flows/flows.json
612
flows/flows.json
|
@ -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
|
@ -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()
|
|
|
@ -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
|
|
||||||
################################################################################
|
|
Loading…
Reference in a new issue