wip
This commit is contained in:
parent
df3be4c784
commit
304fd9d664
|
|
@ -44,7 +44,4 @@ port: COM1
|
|||
baudrate: 9600
|
||||
|
||||
[vision]
|
||||
detection_threshold: 0.5
|
||||
neural_network: hs5-20000
|
||||
|
||||
; recipes_path: ./config/vision_test_recipes
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ instruction: CONTROLLARE PRESENZA TERMORESTRINGENTE
|
|||
[markers]
|
||||
|
||||
[zones]
|
||||
p1: 1000,500 800,800 hs-ok # HEATSINK PRESENT
|
||||
p1: 1200,600 1800,1200 hs-ok # HEATSINK PRESENT
|
||||
|
||||
[labels]
|
||||
p1: 660,1200 120 0xffffffff 0xff000000 4 TERMORESTRINGENTE
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ $* 2> >(sed $'s/.*/\e[31m&\e[m/' >&2) # &
|
|||
# --auto-login-user \
|
||||
# --autotests-archive \
|
||||
# --camera-edits \
|
||||
# --fail-vision \
|
||||
# --full-screen \
|
||||
# --interact \
|
||||
# --maximized \
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ registers = {
|
|||
180: "END SEQUENCE PROGRAM",
|
||||
190: "END PLUG",
|
||||
200: "END CAGE",
|
||||
210: "FINE TEST", # WAITING THE START OF A NEW TEST",
|
||||
210: "FINE TEST", # "WAITING THE START OF A NEW TEST",
|
||||
}, }],
|
||||
"Running test: phase backwards time": [33 - 1, {"dt": "16bit_uint", "f": 26, }],
|
||||
"Running test: filling pressure": [34 - 1, {"dt": "32bit_int", "f": 21, }],
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ else:
|
|||
def Interpreter(*args, **kwargs):
|
||||
raise ValueError("\"--no-tflite\" in sys.argv")
|
||||
|
||||
if "--fail-vision" not in sys.argv:
|
||||
vision_override = None
|
||||
else:
|
||||
vision_override = False
|
||||
|
||||
# # Patch the location of gfile
|
||||
# tf.gfile = tf.io.gfile
|
||||
|
||||
|
|
@ -95,7 +100,7 @@ class Vision(Component):
|
|||
|
||||
def config_changed(self):
|
||||
# OBJECT DETECTION
|
||||
self.detection_threshold = float(self.config[self.name]["detection_threshold"])
|
||||
self.detection_threshold = float(self.config[self.name].get("detection_threshold", 0.5))
|
||||
# recipe
|
||||
self.zones = None
|
||||
self.labels = None
|
||||
|
|
@ -122,20 +127,26 @@ class Vision(Component):
|
|||
self.num_classes = len(label_map.item)
|
||||
categories = label_map_util.convert_label_map_to_categories(label_map, max_num_classes=self.num_classes, use_display_name=True)
|
||||
self.category_index = label_map_util.create_category_index(categories)
|
||||
for k in self.category_index:
|
||||
self.category_index[k]["color"] = self.category_index[k]["color"].replace("0x", "#")
|
||||
self.classes_map = {c["name"]: k for k, c in self.category_index.items()}
|
||||
self.zone_detection_filter_mode = self.config[self.name].get("zone_detection_filter_mode", "box_touches")
|
||||
self.zone_detection_preference_mode = self.config[self.name].get("zone_detection_preference_mode", "distance")
|
||||
self.zone_detection_filter_mode = self.config[self.name].get("zone_detection_filter_mode", "box_inside")
|
||||
self.zone_detection_preference_mode = self.config[self.name].get("zone_detection_preference_mode", "score")
|
||||
|
||||
def get_center(self, rect):
|
||||
@staticmethod
|
||||
def get_center(rect):
|
||||
return [(rect[0] + rect[2]) / 2, (rect[1] + rect[3]) / 2]
|
||||
|
||||
def get_size(self, rect):
|
||||
@staticmethod
|
||||
def get_size(rect):
|
||||
return [rect[2] - rect[0], rect[3] - rect[1]]
|
||||
|
||||
def get_box(self, center, size):
|
||||
@staticmethod
|
||||
def get_box(center, size):
|
||||
return [center[0] - size[0] / 2, center[1] - size[1] / 2, center[0] + size[0] / 2, center[1] + size[1] / 2]
|
||||
|
||||
def get_distance(self, p1, p2):
|
||||
@staticmethod
|
||||
def get_distance(p1, p2):
|
||||
return pow((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2, 1 / 2)
|
||||
|
||||
def clear_recipe(self):
|
||||
|
|
@ -180,6 +191,7 @@ class Vision(Component):
|
|||
if recipe is None:
|
||||
self.clear_recipe()
|
||||
else:
|
||||
self.recipe = recipe
|
||||
self._set_recipe(self.recipes_dir / str(recipe))
|
||||
|
||||
def parse_markers(self, config=None):
|
||||
|
|
@ -229,9 +241,10 @@ class Vision(Component):
|
|||
shape = "ellipse"
|
||||
d_class = self.category_index[self.classes_map[d_class]]
|
||||
zones[zone_name] = {
|
||||
"border_color": QColor(d_class["color"].replace("0x", "#")),
|
||||
"border_color": QColor(d_class["color"]),
|
||||
"border_thickness": 25,
|
||||
"box": self.get_box(center, size),
|
||||
"convert_negative_placement": False,
|
||||
"center": center,
|
||||
"class": d_class,
|
||||
"fill_color": QColor("#00000000"),
|
||||
|
|
@ -426,22 +439,23 @@ class Vision(Component):
|
|||
style = {
|
||||
"border_thickness": 25,
|
||||
"fill_color": QColor("#00000000"),
|
||||
"shape": "ellipse",
|
||||
"shape": "rect",
|
||||
"convert_negative_placement": False,
|
||||
}
|
||||
items = {}
|
||||
for item_name, item in enumerate(detections):
|
||||
items[str(item_name)] = {
|
||||
"box": item["box"],
|
||||
**item,
|
||||
**style,
|
||||
"border_color": QColor(item["class"]["color"].replace("0x", "#")),
|
||||
"border_color": QColor(item["class"]["color"]),
|
||||
}
|
||||
return items
|
||||
else:
|
||||
return {}
|
||||
|
||||
def process_detections(self, detections):
|
||||
if self.zones is None or not len(self.zones) or detections is None or not len(detections):
|
||||
return {}
|
||||
if self.zones is None or not len(self.zones):
|
||||
return None
|
||||
# MATCH DETECTIONS WITH RECIPE
|
||||
results = dict.fromkeys(self.zones)
|
||||
for detection in detections:
|
||||
|
|
@ -533,8 +547,13 @@ class Vision(Component):
|
|||
"expected": expected_class,
|
||||
"detection": detection,
|
||||
}
|
||||
global vision_override
|
||||
if vision_override is None:
|
||||
ok = all(map(lambda detection: detection["ok"] is True, checked.values()))
|
||||
else:
|
||||
ok = vision_override
|
||||
return {
|
||||
"ok": all(map(lambda detection: detection["ok"] is True, checked.values())),
|
||||
"ok": ok,
|
||||
"results": checked,
|
||||
}
|
||||
|
||||
|
|
@ -542,6 +561,7 @@ class Vision(Component):
|
|||
# DRAW ZONES RESULTS
|
||||
if self.zones is not None and len(self.zones) and results is not None and len(results):
|
||||
style = {
|
||||
"pen_line": "SolidLine",
|
||||
"border_thickness": 50,
|
||||
"fill_color": QColor("#00000000"),
|
||||
}
|
||||
|
|
@ -561,9 +581,7 @@ class Vision(Component):
|
|||
for item_name, item in results["results"].items():
|
||||
zone = self.zones[item_name]
|
||||
items[str(item_name)] = {
|
||||
"center": zone["center"],
|
||||
"size": zone["size"],
|
||||
"shape": zone["shape"],
|
||||
**zone,
|
||||
**style,
|
||||
"border_color": Qt.green if item["ok"] else Qt.red,
|
||||
}
|
||||
|
|
@ -571,9 +589,30 @@ class Vision(Component):
|
|||
else:
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
def convert_negative_placement(p, painter):
|
||||
for k in p:
|
||||
if p[k] < 0:
|
||||
if k.startswith("x") or k.startswith("w"):
|
||||
p[k] += painter.device().width()
|
||||
elif k.startswith("y") or k.startswith("h"):
|
||||
p[k] += painter.device().height()
|
||||
else:
|
||||
raise AssertionError("could not detect variable direction")
|
||||
|
||||
@staticmethod
|
||||
def apply_placement_offset(p, offset):
|
||||
for k in p:
|
||||
if k.startswith("x"):
|
||||
p[k] += offset["x"]
|
||||
elif k.startswith("y"):
|
||||
p[k] += offset["y"]
|
||||
else:
|
||||
raise AssertionError("could not detect variable direction")
|
||||
|
||||
def render_items(self, items, offset=None, qimage=None, painter=None):
|
||||
if offset is None:
|
||||
offset = [0, 0]
|
||||
offset = {"x": 0, "y": 0}
|
||||
if painter is None:
|
||||
if qimage is None:
|
||||
raise AssertionError("one of 'qimage' or 'painter' parameter must not be None")
|
||||
|
|
@ -581,35 +620,36 @@ class Vision(Component):
|
|||
painter.begin(qimage)
|
||||
for item_name, item in items.items():
|
||||
try:
|
||||
v = {}
|
||||
convert_negative_placement = item.get("convert_negative_placement", True)
|
||||
if "box" in item:
|
||||
v["x1"], v["y1"], v["x2"], v["y2"] = item["box"][1] + offset[1], item["box"][0] + offset[0], item["box"][3] + offset[1], item["box"][2] + offset[0]
|
||||
v["w"], v["h"] = v["x2"] - v["x1"], v["y2"] - v["y1"]
|
||||
v["xc"], v["yc"] = self.get_center([v["x1"], v["y1"], v["x2"], v["y2"]])
|
||||
p = {"x1": item["box"][1], "y1": item["box"][0], "x2": item["box"][3], "y2": item["box"][2], }
|
||||
if convert_negative_placement:
|
||||
Vision.convert_negative_placement(p, painter)
|
||||
Vision.apply_placement_offset(p, offset)
|
||||
p["w"], p["h"] = p["x2"] - p["x1"], p["y2"] - p["y1"]
|
||||
p["xc"], p["yc"] = Vision.get_center([p["x1"], p["y1"], p["x2"], p["y2"]])
|
||||
elif "location" in item:
|
||||
v["x1"], v["y1"] = item["location"][1] + offset[1], item["location"][0] + offset[0]
|
||||
p = {"x1": item["location"][1], "y1": item["location"][0], }
|
||||
if convert_negative_placement:
|
||||
Vision.convert_negative_placement(p, painter)
|
||||
Vision.apply_placement_offset(p, offset)
|
||||
if "size" in item:
|
||||
v["w"], v["h"] = item["size"][1], item["size"][0]
|
||||
v["x2"], v["y2"] = v["x1"] + v["w"], v["y1"] + v["h"]
|
||||
v["xc"], v["yc"] = self.get_center([v["x1"], v["y1"], v["x2"], v["y2"]])
|
||||
p["w"], p["h"] = item["size"][1], item["size"][0]
|
||||
p["x2"], p["y2"] = p["x1"] + p["w"], p["y1"] + p["h"]
|
||||
p["xc"], p["yc"] = Vision.get_center([p["x1"], p["y1"], p["x2"], p["y2"]])
|
||||
else:
|
||||
v["w"], v["h"] = 0, 0
|
||||
v["x2"], v["y2"] = v["x1"], v["y1"]
|
||||
v["xc"], v["yc"] = v["x1"], v["y1"]
|
||||
p["w"], p["h"] = 0, 0
|
||||
p["x2"], p["y2"] = p["x1"], p["y1"]
|
||||
p["xc"], p["yc"] = p["x1"], p["y1"]
|
||||
elif "center" in item and "size" in item:
|
||||
v["xc"], v["yc"] = item["center"][1] + offset[1], item["center"][0] + offset[0]
|
||||
v["w"], v["h"] = item["size"][1], item["size"][0]
|
||||
v["x1"], v["y1"], v["x2"], v["y2"] = self.get_box([v["xc"], v["yc"]], [v["w"], v["h"]])
|
||||
p = {"xc": item["center"][1], "yc": item["center"][0], }
|
||||
if convert_negative_placement:
|
||||
Vision.convert_negative_placement(p, painter)
|
||||
Vision.apply_placement_offset(p, offset)
|
||||
p["w"], p["h"] = item["size"][1], item["size"][0]
|
||||
p["x1"], p["y1"], p["x2"], p["y2"] = Vision.get_box([p["xc"], p["yc"]], [p["w"], p["h"]])
|
||||
else:
|
||||
raise AssertionError("item has no valid positioning information")
|
||||
for k in list(v):
|
||||
if v[k] < 0:
|
||||
if k.startswith("x") or k.startswith("w"):
|
||||
v[k] = painter.device().width() + v[k]
|
||||
elif k.startswith("y") or k.startswith("h"):
|
||||
v[k] = painter.device().height() + v[k]
|
||||
else:
|
||||
raise AssertionError("could not detect variable direction")
|
||||
painter.setOpacity(item.get("opacity", 0.5))
|
||||
painter.setBrush(QBrush(item.get("fill_color", QColor("#ffffff")), getattr(Qt, item.get("brush_pattern", "SolidPattern"))))
|
||||
painter.setPen(QPen(
|
||||
|
|
@ -620,14 +660,14 @@ class Vision(Component):
|
|||
getattr(Qt, item.get("pen_join", "MiterJoin")),
|
||||
))
|
||||
if item["shape"] == "ellipse":
|
||||
painter.drawEllipse(QPointF(v["xc"], v["yc"]), v["w"] / 2, v["h"] / 2)
|
||||
painter.drawEllipse(QPointF(p["xc"], p["yc"]), p["w"] / 2, p["h"] / 2)
|
||||
elif item["shape"] == "cross":
|
||||
painter.drawLine(QLineF(v["xc"], v["y1"], v["xc"], v["y2"]))
|
||||
painter.drawLine(QLineF(v["x1"], v["yc"], v["x2"], v["yc"]))
|
||||
painter.drawLine(QLineF(p["xc"], p["y1"], p["xc"], p["y2"]))
|
||||
painter.drawLine(QLineF(p["x1"], p["yc"], p["x2"], p["yc"]))
|
||||
elif item["shape"] == "line":
|
||||
painter.drawLine(QLineF(v["xc"], v["yc"], v["x2"], v["y2"]))
|
||||
painter.drawLine(QLineF(p["xc"], p["yc"], p["x2"], p["y2"]))
|
||||
elif item["shape"] == "rect":
|
||||
painter.drawRect(QRectF(v["x1"], v["y1"], v["x2"], v["y2"]))
|
||||
painter.drawRect(QRectF(QPointF(p["x1"], p["y1"]), QPointF(p["x2"], p["y2"])))
|
||||
elif item["shape"] == "text":
|
||||
old_render_hints = painter.renderHints()
|
||||
painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing, True)
|
||||
|
|
@ -640,7 +680,7 @@ class Vision(Component):
|
|||
font.setWordSpacing(item.get("font_word_spacing", 0))
|
||||
font.setPixelSize(round(item.get("font_size", 25)))
|
||||
path = QPainterPath()
|
||||
path.addText(v["x1"], v["y1"], font, item["text"])
|
||||
path.addText(p["x1"], p["y1"], font, item["text"])
|
||||
painter.drawPath(path)
|
||||
painter.setRenderHints(old_render_hints, True)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import glob
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
|
|
@ -26,34 +27,60 @@ class VisionSaver(Component):
|
|||
self.minimum_disk_free_space_gb = float(self.minimum_disk_free_space_gb)
|
||||
self.time_format = self.config[self.name]["time_format"]
|
||||
|
||||
def save(self, save_time, img, mask=True, resize=True):
|
||||
if type(save_time) is float:
|
||||
save_time = int(save_time)
|
||||
if type(save_time) is int:
|
||||
save_time = datetime.fromtimestamp(save_time)
|
||||
def save(self, save_time=None, suffix=None, frame=None, vision=None, resize=None, mask=None):
|
||||
self.remove_older_images_if_needed()
|
||||
if type(save_time) is None:
|
||||
save_time = datetime.now()
|
||||
else:
|
||||
if type(save_time) is float:
|
||||
save_time = int(save_time)
|
||||
if type(save_time) is int:
|
||||
save_time = datetime.fromtimestamp(save_time)
|
||||
if type(save_time) is not datetime:
|
||||
raise ValueError(f"save_time must be float int or datetime, not {type(save_time)}")
|
||||
timestamp = save_time.strftime(self.time_format)
|
||||
save_dir = self.location / save_time.strftime("%Y") / save_time.strftime("%m")
|
||||
os.makedirs(save_dir, exist_ok=True)
|
||||
out_path = save_dir / f"{timestamp}.png"
|
||||
self.log.info(f"saving {out_path}")
|
||||
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
||||
if resize and self.resize_resolution is not None:
|
||||
img = cv2.resize(img, self.resize_resolution, interpolation=cv2.INTER_LINEAR)
|
||||
if mask and self.mask_zones is not None:
|
||||
height, width, channels = img.shape
|
||||
out = np.full(
|
||||
[height, width, channels],
|
||||
[0] * channels
|
||||
)
|
||||
for zone_name in self.mask_zones:
|
||||
zone = self.bench.zones[zone_name]["box"]
|
||||
out[zone[1]:zone[3], zone[0]:zone[2]] = img[zone[1]:zone[3], zone[0]:zone[2]]
|
||||
else:
|
||||
out = img
|
||||
cv2.imwrite(str(out_path), out)
|
||||
return out_path
|
||||
out_paths = []
|
||||
if frame is not None:
|
||||
if suffix is not None:
|
||||
out_paths.append(save_dir / f"{timestamp}.{suffix}.png")
|
||||
else:
|
||||
out_paths.append(save_dir / f"{timestamp}.png")
|
||||
self.log.info(f"saving {out_paths[-1]}")
|
||||
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
|
||||
# resize
|
||||
if resize is None or resize is True:
|
||||
resize = self.resize_resolution
|
||||
elif resize is False:
|
||||
resize = None
|
||||
if resize is not None:
|
||||
frame = cv2.resize(frame, resize, interpolation=cv2.INTER_LINEAR)
|
||||
# mask
|
||||
if mask is None or mask is True:
|
||||
mask = self.mask_zones
|
||||
elif mask is False:
|
||||
mask = None
|
||||
if mask is not None:
|
||||
height, width, channels = frame.shape
|
||||
out = np.full([height, width, channels], [0] * channels)
|
||||
for zone_name in mask:
|
||||
zone = self.bench.zones[zone_name]["box"]
|
||||
out[zone[1]:zone[3], zone[0]:zone[2]] = frame[zone[1]:zone[3], zone[0]:zone[2]]
|
||||
else:
|
||||
out = frame
|
||||
# save frame
|
||||
cv2.imwrite(str(out_paths[-1]), out)
|
||||
if vision is not None:
|
||||
if suffix is not None:
|
||||
out_paths.append(save_dir / f"{timestamp}.{suffix}.json")
|
||||
else:
|
||||
out_paths.append(save_dir / f"{timestamp}.json")
|
||||
self.log.info(f"saving {out_paths[-1]}")
|
||||
# save vision
|
||||
with open(out_paths[-1], "w") as f:
|
||||
json.dump(vision, f)
|
||||
return out_paths
|
||||
|
||||
def remove_older_images_if_needed(self):
|
||||
if self.minimum_disk_free_space_gb is None:
|
||||
|
|
|
|||
|
|
@ -46,19 +46,19 @@ class Archive(Widget):
|
|||
replace_widget(self, "crud_w", self.crud)
|
||||
self.selected = None
|
||||
self.print_b.setEnabled(False)
|
||||
self.crud().db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.crud().db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.crud().db_tw.itemSelectionChanged.connect(self.check)
|
||||
self.crud.db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.crud.db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.crud.db_tw.itemSelectionChanged.connect(self.check)
|
||||
self.print_b.clicked.connect(self.print_label)
|
||||
|
||||
def check(self):
|
||||
if not self.crud().modified:
|
||||
selected = self.crud().get_selected_rows()
|
||||
if not self.crud.modified:
|
||||
selected = self.crud.get_selected_rows()
|
||||
if len(selected) == 1:
|
||||
selected = selected[0] - 1 # - 1 because rn starts from 1 (filters line)
|
||||
if selected >= 0 and selected < len(self.crud().data_index):
|
||||
selected = self.crud().data_index[selected]
|
||||
self.selected = self.crud().db.table_model.get_by_id(selected)
|
||||
if selected >= 0 and selected < len(self.crud.data_index):
|
||||
selected = self.crud.data_index[selected]
|
||||
self.selected = self.crud.db.table_model.get_by_id(selected)
|
||||
self.print_b.setEnabled(True)
|
||||
return
|
||||
self.selected = None
|
||||
|
|
|
|||
|
|
@ -46,19 +46,19 @@ class Autotests_Archive(Widget):
|
|||
replace_widget(self, "crud_w", self.crud)
|
||||
self.selected = None
|
||||
self.print_b.setEnabled(False)
|
||||
self.crud().db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.crud().db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.crud().db_tw.itemSelectionChanged.connect(self.check)
|
||||
self.crud.db_tw.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||
self.crud.db_tw.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||
self.crud.db_tw.itemSelectionChanged.connect(self.check)
|
||||
self.print_b.clicked.connect(self.print_label)
|
||||
|
||||
def check(self):
|
||||
if not self.crud().modified:
|
||||
selected = self.crud().get_selected_rows()
|
||||
if not self.crud.modified:
|
||||
selected = self.crud.get_selected_rows()
|
||||
if len(selected) == 1:
|
||||
selected = selected[0] - 1 # - 1 because rn starts from 1 (filters line)
|
||||
if selected >= 0 and selected < len(self.crud().data_index):
|
||||
selected = self.crud().data_index[selected]
|
||||
self.selected = self.crud().db.table_model.get_by_id(selected)
|
||||
if selected >= 0 and selected < len(self.crud.data_index):
|
||||
selected = self.crud.data_index[selected]
|
||||
self.selected = self.crud.db.table_model.get_by_id(selected)
|
||||
self.print_b.setEnabled(True)
|
||||
return
|
||||
self.selected = None
|
||||
|
|
|
|||
|
|
@ -26,6 +26,18 @@
|
|||
<string>Crud</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="db_gb">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>28</width>
|
||||
<height>28</height>
|
||||
<width>94</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -20,6 +20,18 @@
|
|||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QWidget" name="centralWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
from PyQt5.QtGui import QColor
|
||||
|
||||
|
||||
def calc_foreground_color(background_color):
|
||||
if type(background_color) is QColor:
|
||||
background_color = [background_color.red(), background_color.green(), background_color.blue(), ]
|
||||
to_qcolor = True
|
||||
colors = []
|
||||
for c in background_color[:3]:
|
||||
c /= 255 # 8bit to sRGB
|
||||
|
|
@ -8,6 +14,8 @@ def calc_foreground_color(background_color):
|
|||
c = ((c + 0.055) / 1.055) ** 2.4
|
||||
colors.append(c)
|
||||
# Luminance
|
||||
L = 0.2126 * colors[0] + 0.7152 * colors[1] + 0.0722 * colors[1]
|
||||
L = 0.2126 * colors[0] + 0.7152 * colors[1] + 0.0722 * colors[2]
|
||||
foreground_color = [(1 - round(L)) * 255] * 3
|
||||
if to_qcolor:
|
||||
foreground_color = QColor(*foreground_color)
|
||||
return foreground_color
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>987</width>
|
||||
<height>210</height>
|
||||
<width>955</width>
|
||||
<height>161</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Leak Step Editor</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="font">
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
<width>347</width>
|
||||
<height>50</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Recipe Selection</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="select_b">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
|||
|
|
@ -38,18 +38,18 @@ class Test(Widget):
|
|||
self.step = None
|
||||
# INIT CYCLE STATES
|
||||
self.cycle_available_steps = {
|
||||
# "assembly_1": Test_Assembly(self.select_step_img("assembly_1"), u"INSERIRE SENSORE"),
|
||||
"autotest": Test_Assembly(None, u"ESEGUIRE PROCEDURA DI AUTOTEST", Test_Autotest()),
|
||||
"barcodes": Test_Assembly(self.select_step_img("scan"), u"LEGGERE IL BARCODE DEL PEZZO DA COLLAUDARE", Test_Barcodes()),
|
||||
"done": Test_Assembly(self.select_step_img("success"), u"COLLAUDO COMPLETATO"),
|
||||
"emergency": Test_Assembly(self.select_step_img("reset_emergency"), u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\""),
|
||||
"fail": Test_Assembly(self.select_step_img("fail"), u"CICLO INTERROTTO"),
|
||||
"leak": Test_Assembly(None, u"PREMERE START PER INIZIARE LA PROVA TENUTA", Test_Leak(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"print": Test_Assembly(self.select_step_img("print"), u"STAMPA ETICHETTA IN CORSO"),
|
||||
"select_recipe": Test_Assembly(None, u"SELEZIONARE IL CODICE DA COLLAUDARE", Recipe_Selection()),
|
||||
"vision": Test_Assembly(None, u"VERIFICARE CONTROLLO CON TELECAMERA", Test_Vision(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"wait": Test_Assembly(self.select_step_img("wait"), u"ATTENDERE - PAUSA INTER CICLO"),
|
||||
None: Test_Assembly(self.select_step_img("warning"), u"ATTENZIONE - LA RICETTA SELEZIONATA NON CONTIENE FASI DI TEST"),
|
||||
# "assembly_1": Test_Assembly(img_path=self.select_step_img("assembly_1"), text=u"INSERIRE SENSORE", widget=None),
|
||||
"autotest": Test_Assembly(img_path=None, text=u"ESEGUIRE PROCEDURA DI AUTOTEST", widget=Test_Autotest()),
|
||||
"barcodes": Test_Assembly(img_path=self.select_step_img("scan"), text=u"LEGGERE IL BARCODE DEL PEZZO DA COLLAUDARE", widget=Test_Barcodes()),
|
||||
"done": Test_Assembly(img_path=self.select_step_img("success"), text=u"COLLAUDO COMPLETATO", widget=None),
|
||||
"emergency": Test_Assembly(img_path=self.select_step_img("reset_emergency"), text=u"EMERGENZA INTERVENUTA - RIPRISTINARE PULSANTE E SELEZIONARE \"RESET EMERGENZA\" DAL MEN\u00d9 \"STRUMENTI\"", widget=None),
|
||||
"fail": Test_Assembly(img_path=self.select_step_img("fail"), text=u"CICLO INTERROTTO", widget=None),
|
||||
"leak": Test_Assembly(img_path=None, text=None, widget=Test_Leak(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"print": Test_Assembly(img_path=self.select_step_img("print"), text=u"STAMPA ETICHETTA IN CORSO", widget=None),
|
||||
"select_recipe": Test_Assembly(img_path=None, text=u"SELEZIONARE IL CODICE DA COLLAUDARE", widget=Recipe_Selection()),
|
||||
"vision": Test_Assembly(img_path=None, text=u"VERIFICARE CONTROLLO CON TELECAMERA", widget=Test_Vision(components=self.components, recipe=self.recipe, step=self.step)),
|
||||
"wait": Test_Assembly(img_path=self.select_step_img("wait"), text=u"ATTENDERE - PAUSA INTER CICLO", widget=None),
|
||||
None: Test_Assembly(img_path=self.select_step_img("warning"), text=u"ATTENZIONE - LA RICETTA SELEZIONATA NON CONTIENE FASI DI TEST", widget=None),
|
||||
}
|
||||
self.cycle_steps = None
|
||||
self.cycle_index = -1
|
||||
|
|
@ -155,16 +155,19 @@ class Test(Widget):
|
|||
# RESET TEST DATA
|
||||
self.data = {"ok": True, "overridden": False}
|
||||
self.archived = None
|
||||
# COUNT RESET
|
||||
self.pieces[0] = 0
|
||||
self.pieces[1] = 0
|
||||
elif action == "fail":
|
||||
self.log.info(f"cycle next: action: {action!r}")
|
||||
# COUNT FAIL
|
||||
self.pieces[1] += 1
|
||||
# FAIL AND RESTART TEST
|
||||
self.step = Steps(type="fail")
|
||||
self.cycle_index = -1
|
||||
# RESET TEST DATA
|
||||
self.data = {"ok": True, "overridden": False}
|
||||
self.archived = None
|
||||
# COUNT FAIL
|
||||
self.pieces[1] += 1
|
||||
elif action is not None:
|
||||
raise NotImplementedError(f"cycle next: action {action!r} is not a valid action")
|
||||
# if action did not set the next cycle step
|
||||
|
|
@ -270,11 +273,13 @@ class Test(Widget):
|
|||
|
||||
def done(self, ok=True):
|
||||
self.log.info("cycle done")
|
||||
t = self.data.get("vision", {}).get(0, {}).get("time", None)
|
||||
f = self.data.get("vision", {}).get(0, {}).get("frame", None)
|
||||
if t is not None and f is not None:
|
||||
file_path = self.components["vision_saver"].save(t, f)
|
||||
self.log.info(f"cycle vision image saved locally: {file_path!r}")
|
||||
vision_test_1 = self.data.get("vision", {}).get(0, {})
|
||||
out_paths = self.components["vision_saver"].save(
|
||||
save_time=vision_test_1.get("time", None),
|
||||
frame=vision_test_1.get("frame", None),
|
||||
# vision=vision_test_1.get("detections", None),
|
||||
)
|
||||
self.log.info(f"cycle vision saved locally: {out_paths!r}")
|
||||
for vision in self.data["vision"].values():
|
||||
vision.pop("frame", None)
|
||||
vision.pop("render", None)
|
||||
|
|
@ -287,10 +292,14 @@ class Test(Widget):
|
|||
def print(self, archived=None):
|
||||
self.log.info("cycle print")
|
||||
# LABEL PRINT
|
||||
leak_test_1 = self.data.get("leak", {}).get(0, {})
|
||||
leak_test_1_step_spec = leak_test_1.get("step", {}).get("spec", {})
|
||||
leak_test_1_results = leak_test_1.get("results", {})
|
||||
leak_test_1_results_data = leak_test_1_results.get("data", {})
|
||||
datamatrix = str(archived.recipe.part_number) + archived.time.strftime("%m%y") + f"{archived.id:0>5}"
|
||||
pmax = self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure", "-")
|
||||
pmin = self.data.get("leak", {}).get(0, {}).get("results", {}).get("data", {}).get("Running test: pressure at the end of settling", "-")
|
||||
leak = self.data.get("leak", {}).get(0, {}).get("results", {}).get("data", {}).get("Running test: measured leak", "-")
|
||||
pmax = leak_test_1_step_spec.get("test_pressure", "-")
|
||||
pmin = leak_test_1_results_data.get("Running test: pressure at the end of settling", "-")
|
||||
leak = leak_test_1_results_data.get("Running test: measured leak", "-")
|
||||
context = {
|
||||
"DATAMATRIX": datamatrix,
|
||||
"DATAMATRIX_TEXT": datamatrix,
|
||||
|
|
@ -302,13 +311,13 @@ class Test(Widget):
|
|||
"PMAX": f"{pmax:.3f}" if type(pmax) is not str else pmax,
|
||||
"PMIN": f"{pmin:.3f}" if type(pmin) is not str else pmin,
|
||||
"LEAK": f"{leak:.3f}" if type(leak) is not str else leak,
|
||||
"TFILL": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("filling_time", "-")),
|
||||
"TSTAB": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("settling_time", "-")),
|
||||
"TTEST": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_time", "-")),
|
||||
"MAXLEAK": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure_max_delta", "-")),
|
||||
"PTESTMIN": str(self.data.get("leak", {}).get(0, {}).get("step", {}).get("spec", {}).get("test_pressure_min_delta", "-")),
|
||||
"TFILL": str(leak_test_1_step_spec.get("filling_time", "-")),
|
||||
"TSTAB": str(leak_test_1_step_spec.get("settling_time", "-")),
|
||||
"TTEST": str(leak_test_1_step_spec.get("test_time", "-")),
|
||||
"MAXLEAK": str(leak_test_1_step_spec.get("test_pressure_max_delta", "-")),
|
||||
"PTESTMIN": str(leak_test_1_step_spec.get("test_pressure_min_delta", "-")),
|
||||
"RESULT_L1": "ESITO" + str(" FORZATO" if self.data.get("overridden", False) else ""),
|
||||
"RESULT_L2": str("CONFORME" if self.data.get("leak", {}).get(0, {}).get("results", {}).get("ok", False) else "SCARTO"),
|
||||
"RESULT_L2": str("CONFORME" if leak_test_1_results.get("ok", False) else "SCARTO"),
|
||||
}
|
||||
self.components["label_printer"].print_label("EtichettaR5", context=context)
|
||||
self.log.info(f"cycle printed: {context!r}")
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1003</width>
|
||||
<height>255</height>
|
||||
<width>804</width>
|
||||
<height>86</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>422</width>
|
||||
<height>139</height>
|
||||
<width>184</width>
|
||||
<height>103</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import weakref
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from ui.helpers import replace_widget
|
||||
|
|
@ -39,6 +41,8 @@ class Test_Assembly(Widget):
|
|||
else:
|
||||
if hasattr(self, attr):
|
||||
delattr(self, attr)
|
||||
if hasattr(widget, "set_parent_assembly_widget"):
|
||||
widget.set_parent_assembly_widget(weakref.ref(self))
|
||||
self.widget.setVisible(True)
|
||||
else:
|
||||
self.widget.setVisible(False)
|
||||
|
|
|
|||
|
|
@ -7,13 +7,25 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>94</width>
|
||||
<height>108</height>
|
||||
<height>89</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test Assembly</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="img_l">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
|||
|
|
@ -6,14 +6,27 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>18</width>
|
||||
<height>18</height>
|
||||
<width>94</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test Autotest</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout"/>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>187</width>
|
||||
<height>162</height>
|
||||
<width>169</width>
|
||||
<height>144</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test Barcodes</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="13" column="0">
|
||||
<widget class="QLineEdit" name="barcodes_le"/>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ class Test_Leak(Test_Test):
|
|||
self.components["tecna_t3"].write_recipe(self.recipe, self.step)
|
||||
self.get_connection = self.components["tecna_t3"].out.connect(self.get)
|
||||
self.components["tecna_t3"].resume()
|
||||
if self.parent_assembly_widget is not None:
|
||||
self.parent_assembly_widget().set_text(text=None)
|
||||
self.start_b.setEnabled(False)
|
||||
self.stop_b.setEnabled(False)
|
||||
|
||||
def stop(self):
|
||||
# disable tes loop
|
||||
|
|
@ -22,6 +26,10 @@ class Test_Leak(Test_Test):
|
|||
self.components["tecna_t3"].pause()
|
||||
self.disconnect(self.get_connection)
|
||||
super().stop()
|
||||
if self.parent_assembly_widget is not None:
|
||||
self.parent_assembly_widget().set_text(text=None)
|
||||
self.start_b.setEnabled(False)
|
||||
self.stop_b.setEnabled(False)
|
||||
|
||||
def get(self, data=None, override=False):
|
||||
if self.done: # avoid proccessing if completed
|
||||
|
|
@ -62,6 +70,21 @@ class Test_Leak(Test_Test):
|
|||
if type(v) is float:
|
||||
v = round(v, 2)
|
||||
l.setText(str(v))
|
||||
if d.get("Running test: active phase", None) in {
|
||||
"WAITING START",
|
||||
"ATTESA START",
|
||||
"WAITING THE START OF A NEW TEST"
|
||||
"FINE TEST",
|
||||
}:
|
||||
if self.parent_assembly_widget is not None:
|
||||
self.parent_assembly_widget().set_text(text=u"PREMERE START PER INIZIARE LA PROVA TENUTA")
|
||||
self.start_b.setEnabled(True)
|
||||
self.stop_b.setEnabled(False)
|
||||
else:
|
||||
if self.parent_assembly_widget is not None:
|
||||
self.parent_assembly_widget().set_text(text=u"PROVA TENUTA IN CORSO")
|
||||
self.start_b.setEnabled(False)
|
||||
self.stop_b.setEnabled(True)
|
||||
super().visualize(data)
|
||||
|
||||
def save_last(self):
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>980</width>
|
||||
<height>704</height>
|
||||
<width>370</width>
|
||||
<height>491</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test Leak</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="font">
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import sys
|
||||
import weakref
|
||||
|
||||
from lib.helpers import timing
|
||||
from PyQt5.QtCore import Qt, QTimer, pyqtSignal
|
||||
|
|
@ -40,6 +41,7 @@ class Test_Test(Widget):
|
|||
self.override_b.clicked.connect(self.override)
|
||||
self.override_b.setEnabled(True)
|
||||
# setup vision staus gui
|
||||
self.parent_assembly_widget = None
|
||||
self.status_imgs_full = {
|
||||
True: QPixmap("src/ui/imgs/success.png"),
|
||||
"": QPixmap("src/ui/imgs/neo.ico"),
|
||||
|
|
@ -61,6 +63,14 @@ class Test_Test(Widget):
|
|||
self.status_palettes[""].setColor(QPalette.Base, QColor(255, 255, 0))
|
||||
self.visualize()
|
||||
|
||||
def set_parent_assembly_widget(self, parent_assembly_widget=None):
|
||||
if parent_assembly_widget is None:
|
||||
self.parent_assembly_widget = None
|
||||
elif type(parent_assembly_widget) is weakref.ReferenceType:
|
||||
self.parent_assembly_widget = parent_assembly_widget
|
||||
else:
|
||||
self.parent_assembly_widget = weakref.ref(parent_assembly_widget)
|
||||
|
||||
def start(self, recipe=None, step=None):
|
||||
self.admin_challenged = False
|
||||
self.recipe = recipe
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<property name="title">
|
||||
<string>Risultato</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QProgressBar" name="ok_counter_pb">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -99,7 +99,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SALVA IMMAGINE</string>
|
||||
<string>SALVA</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import sys
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtGui import QImage, QPixmap
|
||||
from PyQt5.QtGui import QColor, QImage, QPalette, QPixmap
|
||||
from PyQt5.QtWidgets import QHeaderView, QProgressBar, QTableWidgetItem
|
||||
from ui.helpers import calc_foreground_color
|
||||
from ui.test_test import Test_Test
|
||||
|
||||
|
||||
|
|
@ -13,7 +15,17 @@ class Test_Vision(Test_Test):
|
|||
self.ok_counter_limit = 2
|
||||
else:
|
||||
self.ok_counter_limit = 1
|
||||
# DETECTIONS TABLE
|
||||
self.results_table_headers = {
|
||||
"class": "RILEVATO",
|
||||
"expected": "ATTESO",
|
||||
"score": "PUNTEGGIO",
|
||||
}
|
||||
super().__init__(components=components, recipe=recipe, step=step)
|
||||
self.results_tw.setColumnCount(len(self.results_table_headers))
|
||||
self.results_tw.setHorizontalHeaderLabels(self.results_table_headers.values())
|
||||
self.results_tw.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
self.results_tw.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||||
|
||||
def start(self, recipe=None, step=None):
|
||||
super().start(recipe=recipe, step=step)
|
||||
|
|
@ -27,6 +39,9 @@ class Test_Vision(Test_Test):
|
|||
self.components["vision"].resume()
|
||||
self.components["galaxy_camera"].resume()
|
||||
self.request_frame.emit() # request first frame
|
||||
# DETECTIONS TABLE
|
||||
# hide previous results
|
||||
self.results_tw.setRowCount(0)
|
||||
|
||||
def stop(self):
|
||||
# disable camera-vision loop
|
||||
|
|
@ -52,12 +67,36 @@ class Test_Vision(Test_Test):
|
|||
"render": data["vision"].get("render", None),
|
||||
}], override=override)
|
||||
|
||||
@staticmethod
|
||||
def tr(text):
|
||||
translations = {
|
||||
"no_detection": "non_rilevato",
|
||||
"_": " ",
|
||||
"big": "grande",
|
||||
"black": "nero",
|
||||
"blue": "blu",
|
||||
"brown": "marrone",
|
||||
"empty": "vuoto",
|
||||
"green": "verde",
|
||||
"ko": "ko",
|
||||
"ok": "ok",
|
||||
"orange": "arancione",
|
||||
"red": "rosso",
|
||||
"small": "piccolo",
|
||||
"white": "bianco",
|
||||
"yellow": "giallo",
|
||||
}
|
||||
for s, t in translations.items():
|
||||
text = text.replace(s, t)
|
||||
return text
|
||||
|
||||
def visualize(self, data=None):
|
||||
if data is None:
|
||||
data = {}
|
||||
overridden = data.get("overridden", False)
|
||||
frame = data.get("frame", None)
|
||||
render = data.get("render", None)
|
||||
results = data.get("results", {}).get("results", None)
|
||||
if overridden:
|
||||
img = self.status_imgs_full["warning"]
|
||||
elif render is not None:
|
||||
|
|
@ -81,12 +120,84 @@ class Test_Vision(Test_Test):
|
|||
self.components["neo_pixels"].set_all_pixel_color("#ff0000")
|
||||
else:
|
||||
self.components["neo_pixels"].set_all_pixel_color("#ffffff")
|
||||
# DETECTIONS TABLE
|
||||
if results is not None:
|
||||
self.results_tw.setRowCount(len(results))
|
||||
self.results_tw.setVerticalHeaderLabels(list(results))
|
||||
for r, [zone_name, result] in enumerate(results.items()):
|
||||
for c, header in enumerate(self.results_table_headers):
|
||||
if header == "class":
|
||||
i = self.results_tw.item(r, c)
|
||||
if i is None:
|
||||
i = QTableWidgetItem()
|
||||
self.results_tw.setItem(r, c, i)
|
||||
detection = result.get("detection", None)
|
||||
if detection is not None:
|
||||
text = self.tr(detection["class"]["name"])
|
||||
color = QColor(detection["class"]["color"])
|
||||
else:
|
||||
text = ""
|
||||
color = QColor("#ffffff")
|
||||
i.setText(text)
|
||||
i.setBackground(color)
|
||||
i.setForeground(calc_foreground_color(color))
|
||||
elif header == "expected":
|
||||
i = self.results_tw.item(r, c)
|
||||
if i is None:
|
||||
i = QTableWidgetItem()
|
||||
self.results_tw.setItem(r, c, i)
|
||||
expected = result.get("expected", None)
|
||||
if expected is not None:
|
||||
text = self.tr(expected["name"])
|
||||
color = QColor(expected["color"])
|
||||
else:
|
||||
text = ""
|
||||
color = QColor("#ffffff")
|
||||
i.setText(text)
|
||||
i.setBackground(color)
|
||||
i.setForeground(calc_foreground_color(color))
|
||||
elif header == "score":
|
||||
w = self.results_tw.cellWidget(r, c)
|
||||
if w is None:
|
||||
w = QProgressBar()
|
||||
w.setRange(0, 100)
|
||||
self.results_tw.setCellWidget(r, c, w)
|
||||
score = result.get("detection", {}).get("score", None)
|
||||
ok = result.get("ok", None)
|
||||
if score is not None:
|
||||
value = int(score * 100)
|
||||
else:
|
||||
value = 0
|
||||
w.setValue(value)
|
||||
if ok is not None:
|
||||
if ok:
|
||||
if score is not None:
|
||||
color = QColor(int(255 - max(score - 0.5, 0) / 0.5 * 255), 255, 0)
|
||||
else:
|
||||
color = QColor("#00ff00")
|
||||
else:
|
||||
color = QColor("#ff0000")
|
||||
else:
|
||||
color = QColor("#0000ff")
|
||||
p = QPalette()
|
||||
p.setColor(QPalette.Highlight, color)
|
||||
w.setPalette(p)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
self.results_tw.setRowCount(0)
|
||||
super().visualize(data, img=img)
|
||||
|
||||
def save_last(self):
|
||||
if self.last is None:
|
||||
return
|
||||
self.components["vision_saver"].save(self.last["time"], self.last["frame"])
|
||||
self.components["vision_saver"].save(
|
||||
save_time=self.last.get("time", None),
|
||||
frame=self.last.get("frame", None),
|
||||
vision=self.last.get("detections", None),
|
||||
suffix="manual_save",
|
||||
resize=[256, 256],
|
||||
)
|
||||
|
||||
def emit_ok(self):
|
||||
super().emit_ok()
|
||||
|
|
|
|||
|
|
@ -6,15 +6,27 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>618</width>
|
||||
<height>835</height>
|
||||
<width>880</width>
|
||||
<height>629</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Test Vision</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="2" column="0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="3" column="0">
|
||||
<widget class="QPushButton" name="override_b">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
|
|
@ -27,13 +39,32 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="save_b">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SALVA IMMAGINE</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Risultato</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QProgressBar" name="ok_counter_pb">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
|
|
@ -49,7 +80,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="state_l">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
|
|
@ -72,35 +103,77 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="img_l">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>600</width>
|
||||
<height>700</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QPushButton" name="save_b">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>SALVA IMMAGINE</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="2">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Visione</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QTableWidget" name="results_tw">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="img_l">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>612</width>
|
||||
<height>512</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>-</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
|
|
|||
|
|
@ -6,14 +6,26 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>174</width>
|
||||
<height>91</height>
|
||||
<width>143</width>
|
||||
<height>67</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Vision Step Edito</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="font">
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
<property name="windowTitle">
|
||||
<string>Window</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget"/>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user