Commit 0434cf0c authored by Jonas Tobias Ulbrich's avatar Jonas Tobias Ulbrich
Browse files

Implement logger... needs feature test

parent 490eb311
root {
html {
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100vh;
width: 100vw;
}
body {
background-color: #f0f0f0;
display:flex;
flex-direction:column;
......@@ -6,56 +15,63 @@ root {
font-size: calc(9pt + 0.5vw);
font-family: Arial;
/*font-weight: bold;/**/
color: #3a3a3a;
color: #787878;
width: 100vw;
overflow-x: hidden;
scrollbar-width:none;
}
info, warn, error {
body > * {
display: flex;
position: relative;
width: calc(85vw - calc(1.5em + 4px));
min-height: 3em;
border-radius: 1em;
margin: 0.5em auto 0 auto;
border-style:solid;
border-width: 2px;
/*border-style:solid;
border-width: 2px;/**/
padding: 0.5em 0.5em 0.5em 1em;
text-shadow: 2px 2px 2px #00000080;
background-color: #78787850;
box-shadow: 0.1vw 0.3vw 0.3vw #888888;
/*text-shadow: 2px 2px 2px #00000080;/**/
}
timestamp {
.timestamp {
position: absolute;
bottom:0.8em;
right: 0.8em;
height: 0.8em;
font-size: calc(calc(9pt + 0.5vw) * 0.7);
color:#cacaca;
text-shadow: 2px 2px 2px #00000060;
color:#787878;
/*text-shadow: 2px 2px 2px #00000060;/**/
}
message {
.message {
margin-bottom: 1.2em;
min-height: 1.2em;
width: 100%;
text-align: left;
}
info {
background-color: lightskyblue;
border-color: lightskyblue;
color: #fafafa;
.info {
background-color: #87cefa50;
box-shadow: 0.1vw 0.3vw 0.3vw #87defa;
/*border-color: lightskyblue;/**/
}
warn {
background-color: #ffb84d;
border-color: #ffb84d;
color: #fafafa;
.warn {
background-color: #ffb84d50;
box-shadow: 0.1vw 0.3vw 0.3vw #ffb85d;
/*border-color: #ffb84d;/**/
}
error {
background-color: lightcoral;
border-color: lightcoral;
color: #fafafa;
.error {
background-color: #f0808050;
box-shadow: 0.1vw 0.3vw 0.3vw #f09090;
/*border-color: lightcoral;/**/
}
......@@ -42,7 +42,6 @@ section {
box-shadow: 0.1vw 0.3vw 0.3vw #888888;
}
h2 {
margin: 0;
padding: 0;
......@@ -73,13 +72,25 @@ h2 {
/* --- CONSOLE VIEW ---*/
.console {
width: calc(49.5em + 28px);
height: 22em;
position: relative;
margin-bottom: 3em;
}
.console iframe {
border: none;
width: 100%;
height: 100%;
width: 49.5em;
height: 22em;
margin-top:0.5em;
}
.console_gradient {
display: block;
position: absolute;
bottom: 1em;
left:1em;
right: 1em;
height: 2em;
background-image: linear-gradient(#00000000, var(--section-bg-color));
}
/* --- ALERT BOX ---*/
......@@ -148,7 +159,7 @@ input, button {
justify-content: center;
flex-direction: column;
background: #000000b0;
/*display: none;/**/
display: none;/**/
}
#new_sample_form form {
......
......@@ -148,12 +148,16 @@
</div>
</section>
<section class="inspection tab">
<iframe src="sample.xml"></iframe>
</section>
<!--<section class="inspection tab">
<iframe src="sample_data.xml"></iframe>
</section>-->
<section class="console tab">
<iframe src="../data/log.xml"></iframe>
<h2>Experiment Log</h2>
<iframe name="console_frame" src="log.html"></iframe>
<div class="console_gradient">
</div>
</section>
<section id="new_sample_form">
......
......@@ -15,6 +15,12 @@ function require_GUI_update() {
});
}
eel.expose(require_GUI_update);
function log_update() {
//simply reload file
document.getElementsByName("console_frame")[0].src=document.getElementsByName("console_frame")[0].src;
}
function set_day_time_cb() {
var hh=parseInt(document.getElementsByName("day_h")[0].value);
var mm=parseInt(document.getElementsByName("day_m")[0].value);
......
<html lang="en" dir="ltr"><head><meta charset="utf-8"/><link rel="stylesheet" href="css/log.css"/></head><body><div class="warn"><div class="timestamp">2022-06-23 17:48:36.632130</div><div class="message">tua mamma</div></div><div class="warn"><div class="timestamp">2022-06-23 17:48:36.415099</div><div class="message">tua mamma</div></div><div class="warn"><div class="timestamp">2022-06-23 17:48:36.216926</div><div class="message">tua mamma</div></div><div class="warn"><div class="timestamp">2022-06-23 17:48:35.798924</div><div class="message">tua mamma</div></div><div class="warn"><div class="timestamp">2022-06-23 17:48:34.981212</div><div class="message">tua mamma</div></div><div class="info"><div class="timestamp">2022-06-23 17:48:30.426475</div><div class="message">skuuuu</div></div><div class="error"><div class="timestamp">2022-06-23 17:48:30.419492</div><div class="message">oramai hai fatto la cacca</div></div><div class="warn"><div class="timestamp">2022-06-23 17:48:30.408486</div><div class="message">tua mamma</div></div></body></html>
\ No newline at end of file
......@@ -29,17 +29,21 @@ r_timeout = 1
#Rack
rows=2
slots=6
#Logger
path_to_log="GUI/"
#Instantiate components
tracker = SampleTracker(rows*slots)
logger=HTMLLogger(path_to_log,eel)
tracker = SampleTracker(rows*slots,logger)
controller = CentralCtrl(
CameraCtrl(camera_idx),
CartesianRobot(r_com_port, r_baud, r_timeout),
Peripherals(g_com_port, g_baud, device_name=g_name),
tracker,
logger,
eel
)
scheduler = Scheduler(controller,tracker)
scheduler = Scheduler(controller,tracker,logger)
def delete_objects(scheduler=scheduler,controller=controller,tracker=tracker):
scheduler.stopThread()
......@@ -90,27 +94,27 @@ def setRotationIntervall(hh,mm):
@eel.expose
def imageSample(sample_id):
scheduler.addTask(Task(Task.RECORD_SAMPLE,sample_id=sample_id, priority=1))
scheduler.addTask(Task(Task.RECORD_SAMPLE,sample_id=sample_id, priority=Task.NORMAL_PRIORITY))
return
@eel.expose
def lightsOnCb():
scheduler.addTask(Task(Task.LIGHTS_ON, priority=0))
scheduler.addTask(Task(Task.LIGHTS_ON, priority=Task.HIGH_PRIORITY))
return
@eel.expose
def lightsOffCb():
scheduler.addTask(Task(Task.LIGHTS_OFF, priority=0))
scheduler.addTask(Task(Task.LIGHTS_OFF, priority=Task.HIGH_PRIORITY))
return
@eel.expose
def pickupSample(sample_id):
scheduler.addTask(Task(Task.PICKUP_SAMPLE,sample_id=sample_id,priority=1))
scheduler.addTask(Task(Task.PICKUP_SAMPLE,sample_id=sample_id,priority=Task.NORMAL_PRIORITY))
return
@eel.expose
def putSample(target_slot):
scheduler.addTask(Task(Task.PUT_SAMPLE,to_slot=target_slot,priority=1))
scheduler.addTask(Task(Task.PUT_SAMPLE,to_slot=target_slot,priority=Task.NORMAL_PRIORITY))
return
@eel.expose
......
......@@ -54,15 +54,15 @@ class CentralCtrl(object):
# Automatically launch the CV thread/process
AUTO_CV = False
def __init__(self,camera,robot,peripherals,sample_tracker,gui,analyzer=None):
def __init__(self,camera,robot,peripherals,sample_tracker,logger,gui):
super(CentralCtrl, self).__init__()
#instantiate components
self._camera = camera
self._robot = robot
self._peripherals = peripherals
self._tracker = sample_tracker
self._logger=logger
self._gui = gui
self._analyzer = analyzer
self.xy_speed = self.XY_SPEED
self.inDayCycle=False
......@@ -70,7 +70,9 @@ class CentralCtrl(object):
try:
self._tracker.loadData(os.path.join(self.PATH_TO_DATA,"rack_data.pickle"))
except Exception as e:
print("could not load the rack data, samples must be added/loaded manually")
str="could not load the rack data, samples must be added/loaded manually"
if logger is not None: logger.error(str)
print(str)
#setup lookup for slot coordinates
self._slot_coords = []
......@@ -140,7 +142,9 @@ class CentralCtrl(object):
if self._checkXYCoordinates(x,y):
self._robot.moveXY(x,y, self.xy_speed)
else:
print("something went wrong with the conversion indices to coordinates")
str="something went wrong with the conversion indices to coordinates"
if logger is not None: logger.error(str)
print(str)
def _pickupApproachSample(self,slot):
x,y=self._getCoordinates(slot)
......@@ -229,7 +233,9 @@ class CentralCtrl(object):
return True
elif self._tracker.getSlotFromId(sample_id) is not None:
#Only put down what it is holding if it can pickup something
print(f"Putting back sample {sample.id}")
str=f"Putting back sample {sample.id}"
if logger is not None: logger.info(str)
print(str)
ret = self.putSample(sample.home_slot)
#If put sample fails pickup will not be attempted
ret = ret and self.pickupSample(sample_id)
......@@ -303,11 +309,6 @@ class CentralCtrl(object):
ret = ret and self.imageSample(auto_recording=True)
#here one could queue the image processing and CV task
if self.AUTO_CV and self._analyzer is not None:
cv = threading.Thread(target=self._analyzer.run, args=(sample_id))
cv.start()
return ret and self.putSample(self._tracker.getSampleHome(sample_id))
def moveSample(self, sample_id, to):
......
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="../GUI/css/log.css"?>
<root>
<info>
<timestamp>
DD.MM.YYY, hh:mm:ss
</timestamp>
<message>
This is an info
</message>
</info>
<warn>
<timestamp>
DD.MM.YYY, hh:mm:ss
</timestamp>
<message>
This is a warning
</message>
</warn>
<error>
<timestamp>
DD.MM.YYY, hh:mm:ss
</timestamp>
<message>
This is an error
</message>
</error>
</root>
......@@ -3,6 +3,7 @@ import numpy as np
import glob
import matplotlib.pyplot as plt
from skimage import exposure, filters, morphology, measure
import os
try:
from scripts.preprocessing import *
......@@ -31,9 +32,27 @@ cv2.imshow('pre',out)
cv2.waitKey(0)
cv2.destroyAllWindows()
# %% Automatic preprocessing
#choose img
image_count="0003"
sample_id="brx1"
image_name=f"raw_{image_count}.jpg"
# do stuff
data_path=os.path.join("scripts/data/samples/",sample_id,"RAW/",image_name)
image=roi=cv2.imread(data_path)
p=Preprocrssor()
out,roi=p(image)
cv2.imshow('img',image)
cv2.imshow('ROI',roi)
cv2.imshow('pre',out)
cv2.waitKey(0)
cv2.destroyAllWindows()
# %% Blob coloring
low=0.5#0.45
high=0.7#0.7
low=0.75#0.45
high=0.9#0.7
pre=out
pre = exposure.adjust_gamma(pre,0.6)
#pre = exposure.adjust_log(pre,0.1)
......@@ -58,6 +77,21 @@ img_ov[idx,2]=0#img_ov[idx,1]/2
f=plt.figure(figsize=(6,6),dpi=300)
plt.imshow(img_ov)
cv2.imshow('overlay',img_ov)
cv2.imwrite("img/previous_roots.png",pre)
cv2.imwrite(f"img/pre_{image_count}.png",pre)
cv2.waitKey(0)
cv2.destroyAllWindows()
# %% Overlay 3 preprocessing images
r=cv2.imread("img/pre_0001.png")
g=cv2.imread("img/pre_0002.png")
b=cv2.imread("img/pre_0003.png")
overlay=r.copy()
overlay[:,:,0]=r[:,:,0]
overlay[:,:,1]=g[:,:,0]
overlay[:,:,2]=b[:,:,0]
cv2.imshow('overlay',overlay)
cv2.waitKey(0)
cv2.destroyAllWindows()
f=plt.figure(figsize=(6,6),dpi=300)
plt.imshow(overlay)
from lxml import etree as ET
import os
import datetime
class HTMLLogger(object):
"""docstring for HTMLLogger."""
def __init__(self, path_to_log, gui, log_name='log.html'):
super(HTMLLogger, self).__init__()
self.path_to_log=path_to_log
self.log_name=log_name
self._gui=gui
#check if log file is around
try:
data = open(os.path.join(self.path_to_log,'log.html'),'r').read()
doc = ET.HTML(data)
except:
doc=None
if doc is None:
html=ET.Element("html", {"lang":"en", "dir":"ltr"})
head=html.makeelement("head")
head.append(head.makeelement("meta", {"charset":"utf-8"}))
head.append(head.makeelement("link", {"rel":"stylesheet", "href":"css/log.css"}))
html.append(head)
body=html.makeelement("body")
body.text=""
html.append(body)
self._writeHtmlFile(os.path.join(self.path_to_log,'log.html'), html)
def _openHtmlFile(self, path_to_file):
try:
data = open(path_to_file,'r').read()
doc = ET.HTML(data)
except:
doc=None
return doc
def _writeHtmlFile(self, path_to_file, html):
with open(path_to_file, "w") as html_file:
html_file.write(ET.tostring(html).decode("utf-8"))
def _addLogElement(self,root,str,log_priority="info"):
#create info element
elem = root.makeelement("div", {"class" : log_priority})
#create timestamp
timestamp=elem.makeelement("div", {"class" : "timestamp"})
timestamp.text=f"{datetime.datetime.now()}"
#create message
message=elem.makeelement("div", {"class" : "message"})
message.text=str
#add stuff
elem.append(timestamp)
elem.append(message)
root.insert(0,elem)
def _requireGUIupdate(self):
self._gui.log_update()
def info(self,str):
#load HTML file
doc=self._openHtmlFile(os.path.join(self.path_to_log,self.log_name))
root=doc[1] #get body
#create info element
self._addLogElement(root,str)
#save file
self._writeHtmlFile(os.path.join(self.path_to_log,'log.html'), doc)
self._requireGUIupdate()
def warn(self,str):
#load HTML file
doc=self._openHtmlFile(os.path.join(self.path_to_log,self.log_name))
root=doc[1] #get body
#create warning element
self._addLogElement(root,str,log_priority="warn")
#save file
self._writeHtmlFile(os.path.join(self.path_to_log,'log.html'), doc)
self._requireGUIupdate()
def error(self,str):
#load HTML file
doc=self._openHtmlFile(os.path.join(self.path_to_log,self.log_name))
root=doc[1] #get body
#create info element
self._addLogElement(root,str,log_priority="error")
#save file
self._writeHtmlFile(os.path.join(self.path_to_log,'log.html'), doc)
self._requireGUIupdate()
......@@ -108,7 +108,7 @@ class Preprocrssor(object):
def _loadConvolutionKernels(self):
self.kernels=[]
# TODO: save kernel weights as pickle and load them properly
self.kernel_weights=[1.0,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.8,1.0,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.8]
self.kernel_weights=[1.0,1.0,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.8,1.0,1.0,1.0,0.8,0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.8,1.0]
for i in range(24):
img = cv2.imread(f"scripts/data/kernels/{i}.png")
......@@ -189,11 +189,11 @@ class Preprocrssor(object):
def extractROI(self,img):
markers = self.getArUcoMarkers(img)
#the true ROI starts 2mm below the top markers and ends 2mm above the
#lower markers. The marker side is 11mm, thus the 2/11. Here the vector
#the true ROI starts 2mm below the top markers and ends 3mm above the
#lower markers. The marker side is 11mm, thus the 3/11. Here the vector
#along the marker side is computed and then scaled to get to the true
#border
vector_scaling=(1+2/11)
vector_scaling=(1+3/11)
get_vector=lambda f,t: t-f
scale_vector=lambda v: vector_scaling*v
vector_addition=lambda v,w: int(v+w) #int cast since those will be array indices
......@@ -248,11 +248,11 @@ class Preprocrssor(object):
return self._minmax(out)
def __call__(self, img):
out = self.extractROI(img)
out = cv2.cvtColor(out,cv2.COLOR_BGR2GRAY)
roi = self.extractROI(img)
out = cv2.cvtColor(roi,cv2.COLOR_BGR2GRAY)
#out = filters.gaussian(out,0)
out = self.enhanceFeatures(out)
return out
return out, roi
################################################################################
### FUNC DEF ###################################################################
......
......@@ -8,4 +8,6 @@ scipy==1.8.1
scripts==2.0
scikit-image
tifffile==2022.5.4
opencv-contrib-python
\ No newline at end of file
opencv-contrib-python
elementpath
lxml==4.9.0
......@@ -538,7 +538,7 @@ class Root(Chain):
return roots, data_img
# %% Example of code to test
img=cv2.imread("img/ideal_samples_refined.png")#previous_roots.png")#ideal_samples_refined.png")#root distance/dist_1.png")#
img=cv2.imread("img/previous_roots.png")#ideal_samples_refined.png")#root distance/dist_1.png")#
last_detection=None;#cv2.imread("img/root distance/dist_2.png")
bin_img=img[:,:,0]==255 #convert to bool
......
......@@ -51,12 +51,13 @@ class Sample(object):
class SampleTracker(SampleTrackerBase):
"""docstring for SampleTracker."""
def __init__(self, number_of_slots):
def __init__(self, number_of_slots,logger=None):
super(SampleTracker, self).__init__()
self._rack = [None] * number_of_slots
self._gripper = None
self._number_of_slots = number_of_slots
self._logger=logger
def _validTarget(self, target_slot):
return target_slot is not None and 0 <= target_slot < self._number_of_slots
......@@ -64,7 +65,9 @@ class SampleTracker(SampleTrackerBase):
def getSlotFromId(self,sample_id):
slot=next((i for i, sample in enumerate(self._rack) if sample is not None and sample.id == sample_id), None)
if slot is None:
print(f"No object with required id={sample_id} found")
str=f"No object with required id={sample_id} found"
print(str)
if logger is not None: logger.error(str)
return slot
......@@ -121,7 +124,9 @@ class SampleTracker(SampleTrackerBase):
def addSample(self, sample, target_slot, sample_overwrite=False):
if self.slotIsLoaded(target_slot) and not sample_overwrite:
print(f"Slot {target_slot} is already occupied")
str=f"Slot {target_slot} is already occupied"
print(str)
if logger is not None: logger.warn(str)
return False
sample.home_slot = target_slot
......@@ -153,11 +158,17 @@ class SampleTracker(SampleTrackerBase):
if self.slotIsLoaded(slot) and not holding:
return True
if holding and warn:
print(f"Holding sample {self._gripper.id}, can't pickup at target slot {slot}")
str=f"Holding sample {self._gripper.id}, can't pickup at target slot {slot}"
if logger is not None: logger.warn(str)
print(str)
elif warn:
print(f"Target slot {slot} is empty, can't pick up anything")
str=f"Target slot {slot} is empty, can't pick up anything"
if logger is not None: logger.warn(str)
print(str)
elif warn:
print(f"target slot {slot} is invalid")
str=f"target slot {slot} is invalid"
if logger is not None: logger.warn(str)
print(str)