planktoscope/scripts/mqtt_pump_focus_image.py

440 lines
15 KiB
Python
Raw Normal View History

2020-01-31 04:42:39 +01:00
import paho.mqtt.client as mqtt
from picamera import PiCamera
from datetime import datetime, timedelta
from adafruit_motor import stepper
from adafruit_motorkit import MotorKit
from time import sleep
2020-01-31 08:49:32 +01:00
import json
import os
2020-02-02 04:20:55 +01:00
import subprocess
2020-01-31 08:49:32 +01:00
from skimage.util import img_as_ubyte
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,
)
2020-02-02 04:20:55 +01:00
2020-01-31 08:49:32 +01:00
from morphocut.stat import RunningMedian
from morphocut.str import Format
2020-02-02 04:20:55 +01:00
from morphocut.stream import TQDM, Enumerate, FilterVariables
2020-01-31 08:49:32 +01:00
from skimage.feature import canny
from skimage.color import rgb2gray, label2rgb
from skimage.morphology import disk
from skimage.morphology import erosion, dilation, closing
from skimage.measure import label, regionprops
2020-02-02 04:20:55 +01:00
import cv2, shutil
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
import smbus
#fan
bus = smbus.SMBus(1)
2020-01-31 04:42:39 +01:00
################################################################################
kit = MotorKit()
pump_stepper = kit.stepper1
pump_stepper.release()
focus_stepper = kit.stepper2
focus_stepper.release()
################################################################################
camera = PiCamera()
camera.resolution = (3280, 2464)
camera.iso = 60
2020-02-01 21:25:49 +01:00
camera.shutter_speed = 500
2020-02-02 04:20:55 +01:00
camera.exposure_mode = 'fixedfps'
2020-01-31 04:42:39 +01:00
################################################################################
message = ''
topic = ''
count=''
################################################################################
def on_connect(client, userdata, flags, rc):
2020-02-02 04:20:55 +01:00
print("Connected! - " + str(rc))
client.subscribe("actuator/#")
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
def on_subscribe(client, obj, mid, granted_qos):
print("Subscribed! - "+str(mid)+" "+str(granted_qos))
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))
global message
global topic
global count
message=str(msg.payload.decode())
2020-01-31 08:49:32 +01:00
topic=msg.topic.split("/")[1]
2020-01-31 04:42:39 +01:00
count=0
def on_log(client, obj, level, string):
print(string)
2020-02-02 04:20:55 +01:00
def rgb(R,G,B):
bus.write_byte_data(0x0d, 0x00, 0)
bus.write_byte_data(0x0d, 0x01, R)
bus.write_byte_data(0x0d, 0x02, G)
bus.write_byte_data(0x0d, 0x03, B)
bus.write_byte_data(0x0d, 0x00, 1)
bus.write_byte_data(0x0d, 0x01, R)
bus.write_byte_data(0x0d, 0x02, G)
bus.write_byte_data(0x0d, 0x03, B)
bus.write_byte_data(0x0d, 0x00, 2)
bus.write_byte_data(0x0d, 0x01, R)
bus.write_byte_data(0x0d, 0x02, G)
bus.write_byte_data(0x0d, 0x03, B)
cmd="i2cdetect -y 1"
subprocess.Popen(cmd.split(),stdout=subprocess.PIPE)
2020-01-31 04:42:39 +01:00
################################################################################
client = mqtt.Client()
client.connect("127.0.0.1",1883,60)
client.on_connect = on_connect
client.on_subscribe = on_subscribe
client.on_message = on_message
client.on_log = on_log
client.loop_start()
2020-01-31 08:49:32 +01:00
2020-01-31 04:42:39 +01:00
################################################################################
while True:
################################################################################
2020-02-02 04:20:55 +01:00
if (topic=="pump"):
rgb(0,0,255)
2020-01-31 04:42:39 +01:00
direction=message.split(" ")[0]
2020-01-31 08:49:32 +01:00
delay=float(message.split(" ")[1])
nb_step=int(message.split(" ")[2])
2020-01-31 04:42:39 +01:00
client.publish("receiver/pump", "Start");
2020-01-31 08:49:32 +01:00
2020-01-31 04:42:39 +01:00
while True:
2020-02-02 04:20:55 +01:00
if direction == "BACKWARD":
direction=stepper.BACKWARD
if direction == "FORWARD":
direction=stepper.FORWARD
2020-01-31 04:42:39 +01:00
count+=1
2020-02-02 04:20:55 +01:00
# print(count,nb_step)
2020-01-31 08:49:32 +01:00
pump_stepper.onestep(direction=direction, style=stepper.DOUBLE)
2020-01-31 04:42:39 +01:00
sleep(delay)
if topic!="pump":
pump_stepper.release()
print("The pump has been interrompted.")
client.publish("receiver/pump", "Interrompted");
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
break
if count>nb_step:
pump_stepper.release()
print("The pumping is done.")
topic="wait"
client.publish("receiver/pump", "Done");
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
break
################################################################################
elif (topic=="focus"):
2020-02-02 04:20:55 +01:00
rgb(255,255,0)
2020-01-31 04:42:39 +01:00
direction=message.split(" ")[0]
nb_step=int(message.split(" ")[1])
client.publish("receiver/focus", "Start");
2020-01-31 08:49:32 +01:00
2020-01-31 04:42:39 +01:00
while True:
2020-02-02 04:20:55 +01:00
if direction == "FORWARD":
direction=stepper.FORWARD
if direction == "BACKWARD":
direction=stepper.BACKWARD
2020-01-31 04:42:39 +01:00
count+=1
2020-02-02 04:20:55 +01:00
# print(count,nb_step)
2020-01-31 08:49:32 +01:00
focus_stepper.onestep(direction=direction, style=stepper.MICROSTEP)
2020-01-31 04:42:39 +01:00
if topic!="focus":
2020-01-31 08:49:32 +01:00
focus_stepper.release()
2020-01-31 04:42:39 +01:00
print("The stage has been interrompted.")
client.publish("receiver/focus", "Interrompted");
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
break
if count>nb_step:
2020-01-31 08:49:32 +01:00
focus_stepper.release()
2020-01-31 04:42:39 +01:00
print("The focusing is done.")
topic="wait"
client.publish("receiver/focus", "Done");
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
break
################################################################################
elif (topic=="image"):
2020-02-02 04:20:55 +01:00
camera.start_preview(fullscreen=False, window = (160, 0, 640, 480))
2020-01-31 08:49:32 +01:00
sleep_before=int(message.split(" ")[0])
nb_step=int(message.split(" ")[1])
path=str(message.split(" ")[2])
nb_frame=int(message.split(" ")[3])
sleep_during=int(message.split(" ")[4])
2020-01-31 04:42:39 +01:00
#sleep a duration before to start
2020-01-31 08:49:32 +01:00
sleep(sleep_before)
2020-01-31 04:42:39 +01:00
client.publish("receiver/image", "Start");
#flushing before to begin
2020-02-01 21:25:49 +01:00
2020-02-02 04:20:55 +01:00
rgb(0,0,255)
2020-01-31 04:42:39 +01:00
for i in range(nb_step):
2020-01-31 08:49:32 +01:00
pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
2020-02-02 04:20:55 +01:00
sleep(0.01)
rgb(0,255,0)
2020-01-31 04:42:39 +01:00
directory = os.path.join(path, "PlanktonScope")
os.makedirs(directory, exist_ok=True)
2020-02-02 04:20:55 +01:00
export = os.path.join(directory, "export")
os.makedirs(export, exist_ok=True)
2020-01-31 08:49:32 +01:00
date=datetime.now().strftime("%m_%d_%Y")
time=datetime.now().strftime("%H_%M")
path_date = os.path.join(directory, date)
2020-01-31 04:42:39 +01:00
os.makedirs(path_date, exist_ok=True)
2020-01-31 08:49:32 +01:00
path_time = os.path.join(path_date,time)
os.makedirs(path_time, exist_ok=True)
2020-01-31 04:42:39 +01:00
while True:
2020-02-01 21:25:49 +01:00
2020-01-31 04:42:39 +01:00
count+=1
2020-02-02 04:20:55 +01:00
# print(count,nb_frame)
2020-01-31 04:42:39 +01:00
2020-01-31 08:49:32 +01:00
filename = os.path.join(path_time,datetime.now().strftime("%M_%S_%f")+".jpg")
2020-02-02 04:20:55 +01:00
rgb(0,255,255)
2020-01-31 04:42:39 +01:00
camera.capture(filename)
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
client.publish("receiver/image", datetime.now().strftime("%M_%S_%f")+".jpg has been imaged.");
rgb(0,0,255)
2020-01-31 08:49:32 +01:00
for i in range(10):
pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
sleep(0.01)
sleep(0.5)
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
2020-01-31 08:49:32 +01:00
if(count>nb_frame):
2020-02-02 04:20:55 +01:00
camera.stop_preview()
client.publish("receiver/image", "Completed");
2020-01-31 08:49:32 +01:00
# Meta data that is added to every object
local_metadata = {
"process_datetime": datetime.now(),
"acq_camera_resolution" : camera.resolution,
"acq_camera_iso" : camera.iso,
"acq_camera_shutter_speed" : camera.shutter_speed
}
2020-02-02 04:20:55 +01:00
global_metadata = None
config_txt = None
RAW = None
CLEAN = None
ANNOTATED = None
OBJECTS = None
archive_fn = None
2020-01-31 08:49:32 +01:00
config_txt = open('/home/pi/PlanktonScope/config.txt','r')
node_red_metadata = json.loads(config_txt.read())
2020-01-31 04:42:39 +01:00
2020-01-31 08:49:32 +01:00
global_metadata = {**local_metadata, **node_red_metadata}
2020-02-02 04:20:55 +01:00
RAW = os.path.join(path_time, "RAW")
os.makedirs(RAW, exist_ok=True)
os.system("mv "+str(path_time)+"/*.jpg "+str(RAW))
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
CLEAN = os.path.join(path_time, "CLEAN")
os.makedirs(CLEAN, exist_ok=True)
ANNOTATED = os.path.join(path_time, "ANNOTATED")
os.makedirs(ANNOTATED, exist_ok=True)
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
OBJECTS = os.path.join(path_time, "OBJECTS")
os.makedirs(OBJECTS, exist_ok=True)
archive_fn = os.path.join(directory,"export", str(date)+"_"+str(time)+"_ecotaxa_export.zip")
client.publish("receiver/segmentation", "Start");
2020-01-31 08:49:32 +01:00
# Define processing pipeline
2020-02-02 04:20:55 +01:00
# Define processing pipeline
2020-01-31 08:49:32 +01:00
with Pipeline() as p:
# Recursively find .jpg files in import_path.
# Sort to get consective frames.
2020-02-02 04:20:55 +01:00
abs_path = Find(RAW, [".jpg"], sort=True, verbose=True)
FilterVariables(abs_path)
2020-01-31 08:49:32 +01:00
# Extract name from abs_path
name = Call(lambda p: os.path.splitext(os.path.basename(p))[0], abs_path)
2020-02-02 04:20:55 +01:00
Call(rgb, 0,255,0)
2020-01-31 08:49:32 +01:00
# Read image
img = ImageReader(abs_path)
2020-02-02 04:20:55 +01:00
# Show progress bar for frames
#TQDM(Format("Frame {name}", name=name))
2020-01-31 08:49:32 +01:00
# Apply running median to approximate the background image
flat_field = RunningMedian(img, 5)
2020-02-02 04:20:55 +01:00
2020-01-31 08:49:32 +01:00
# Correct image
img = img / flat_field
2020-02-02 04:20:55 +01:00
FilterVariables(name,img)
2020-01-31 08:49:32 +01:00
# Rescale intensities and convert to uint8 to speed up calculations
img = RescaleIntensity(img, in_range=(0, 1.1), dtype="uint8")
2020-02-02 04:20:55 +01:00
frame_fn = Format(os.path.join(CLEAN, "{name}.jpg"), name=name)
ImageWriter(frame_fn, img)
FilterVariables(name,img)
2020-01-31 08:49:32 +01:00
# Convert image to uint8 gray
img_gray = RGB2Gray(img)
2020-02-02 04:20:55 +01:00
# ?
2020-01-31 08:49:32 +01:00
img_gray = Call(img_as_ubyte, img_gray)
2020-02-02 04:20:55 +01:00
#Canny edge detection
img_canny = Call(cv2.Canny, img_gray, 50,100)
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
#Dilate
kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))
img_dilate = Call(cv2.dilate, img_canny, kernel, iterations=2)
#Close
kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (5, 5))
img_close = Call(cv2.morphologyEx, img_dilate, cv2.MORPH_CLOSE, kernel, iterations=1)
#Erode
kernel = Call(cv2.getStructuringElement, cv2.MORPH_ELLIPSE, (15, 15))
mask = Call(cv2.erode, img_close, kernel, iterations=2)
FilterVariables(name,img,img_gray,mask)
2020-01-31 08:49:32 +01:00
# Find objects
regionprops = FindRegions(
mask, img_gray, min_area=1000, padding=10, warn_empty=name
)
2020-02-02 04:20:55 +01:00
Call(rgb, 255,0,255)
2020-01-31 08:49:32 +01:00
# For an object, extract a vignette/ROI from the image
roi_orig = ExtractROI(img, regionprops, bg_color=255)
# Generate an object identifier
i = Enumerate()
#Call(print,i)
object_id = Format("{name}_{i:d}", name=name, i=i)
#Call(print,object_id)
2020-02-02 04:20:55 +01:00
object_fn = Format(os.path.join(OBJECTS, "{name}.jpg"), name=object_id)
ImageWriter(object_fn, roi_orig)
2020-01-31 08:49:32 +01:00
# 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
)
2020-02-02 04:20:55 +01:00
json_meta = Call(json.dumps,meta, sort_keys=True, default=str)
Call(client.publish, "receiver/segmentation/metric", json_meta)
2020-01-31 08:49:32 +01:00
# Add object_id to the metadata dictionary
meta["object_id"] = object_id
# Generate object filenames
orig_fn = Format("{object_id}.jpg", object_id=object_id)
2020-02-02 04:20:55 +01:00
FilterVariables(orig_fn,roi_orig,meta,object_id)
2020-01-31 08:49:32 +01:00
# 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))
2020-02-02 04:20:55 +01:00
Call(client.publish, "receiver/segmentation/object_id", object_id)
meta=None
FilterVariables(meta)
2020-01-31 08:49:32 +01:00
2020-02-01 21:25:49 +01:00
p.run()
2020-01-31 08:49:32 +01:00
2020-02-02 04:20:55 +01:00
#remove directory
#shutil.rmtree(import_path)
client.publish("receiver/segmentation", "Completed");
rgb(255,255,255)
sleep(sleep_during)
rgb(0,255,0)
2020-02-01 21:25:49 +01:00
date=datetime.now().strftime("%m_%d_%Y")
time=datetime.now().strftime("%H_%M")
path_date = os.path.join(directory, date)
os.makedirs(path_date, exist_ok=True)
path_time = os.path.join(path_date,time)
2020-02-02 04:20:55 +01:00
os.makedirs(path_time, exist_ok=True)
rgb(0,0,255)
for i in range(nb_step):
pump_stepper.onestep(direction=stepper.FORWARD, style=stepper.DOUBLE)
sleep(0.01)
rgb(0,255,0)
2020-01-31 08:49:32 +01:00
2020-02-01 21:25:49 +01:00
os.makedirs(path_time, exist_ok=True)
2020-02-02 04:20:55 +01:00
count=0
2020-01-31 04:42:39 +01:00
if topic!="image":
2020-02-02 04:20:55 +01:00
pump_stepper.release()
2020-01-31 04:42:39 +01:00
print("The imaging has been interrompted.")
client.publish("receiver/image", "Interrompted");
2020-02-02 04:20:55 +01:00
rgb(0,255,0)
count=0
2020-01-31 04:42:39 +01:00
break
else:
2020-02-02 04:20:55 +01:00
# print("Waiting")
2020-01-31 04:42:39 +01:00
sleep(1)
2020-01-31 08:49:32 +01:00