@raytao-degirum there is one thing I am struggling: the face_and_age compound is the only model where I have had the problems to get the result of the second model displayed, face_and_gender work as well as face_and_emotion, with my actually code.
there is the model_loader where I load the models and create the command:
import yaml
import degirum as dg
import degirum_tools
class ModelLoader:
def __init__(
self,
config_path="<path>degirum-zoo/models.yaml",
zoo_path="<path>degirum-zoo",
inference_host="@local",
token=""
):
self.zoo_path = zoo_path
self.inference_host = inference_host
self.token = token
with open(config_path, "r") as f:
self.config = yaml.safe_load(f)["models"]
def load_model(self, model_name):
if model_name not in self.config:
raise ValueError(f"model '{model_name}' not found in config.")
model_cfg = self.config[model_name]
model_type = model_cfg.get("type", "single")
if model_type == "single":
return self._load_single(model_cfg)
elif model_type == "compound":
return self._load_compound(model_cfg)
else:
raise ValueError(f"Unknown model type: {model_type}")
def configure_model_overlay(self, model, config):
for key, attr in [
("overlay_show_labels", "overlay_show_labels"),
("overlay_show_probabilities", "overlay_show_probabilities"),
("overlay_font_scale", "overlay_font_scale"),
("overlay_line_width", "overlay_line_width"),
("overlay_alpha", "overlay_alpha"),
("overlay_blur", "overlay_blur"),
]:
if key in config:
setattr(model, attr, config[key])
if "overlay_font_color" in config:
try:
raw_color = config["overlay_font_color"]
overlay_font_color = [tuple(raw_color)]
model.overlay_font_color = overlay_font_color
print("Overlay-font-color set successfully:", overlay_font_color)
except Exception as e:
print(f"Error setting overlay_font_color: {e}")
if "overlay_color" in config:
try:
raw_color = config["overlay_color"]
if isinstance(raw_color[0], list): # multible colors
overlay_color = [tuple(c) for c in raw_color]
else: # single color
overlay_color = [tuple(raw_color)]
model.overlay_color = overlay_color
print("Overlay-color set successfully:", overlay_color)
except Exception as e:
print(f"Error setting overlay_color: {e}")
# load single model
def _load_single(self, model_cfg):
model = dg.load_model(
model_name=model_cfg["path"],
inference_host_address=self.inference_host,
zoo_url=self.zoo_path,
token=self.token
)
self.configure_model_overlay(model, model_cfg)
result_key = model_cfg.get("result_key", "default")
return {result_key: model}
# load compound model
def _load_compound(self, model_cfg):
components = model_cfg.get("components", [])
if len(components) != 2:
raise ValueError("Compound models require exactly 2 components.")
strategy = model_cfg.get("strategy", "crop_classify")
crop_extent = model_cfg.get("crop_extent", 30.0)
# Load components
det_cfg = components[0]
cls_cfg = components[1]
det_model = dg.load_model(
model_name=det_cfg["path"],
inference_host_address=self.inference_host,
zoo_url=self.zoo_path,
token=self.token
)
self.configure_model_overlay(det_model, det_cfg)
cls_model = dg.load_model(
model_name=cls_cfg["path"],
inference_host_address=self.inference_host,
zoo_url=self.zoo_path,
token=self.token
)
self.configure_model_overlay(cls_model, cls_cfg)
# Strategy: cropping and classifying
if strategy == "crop_classify":
compound = degirum_tools.CroppingAndClassifyingCompoundModel(
det_model, cls_model, crop_extent
)
return {
det_cfg["result_key"]: det_model,
cls_cfg["result_key"]: cls_model,
"compound": compound
}
# Strategy: chaining (you take care of the interaction)
elif strategy == "chain":
return {
det_cfg["result_key"]: det_model,
cls_cfg["result_key"]: cls_model
}
# Strategy: parallel (both models run in parallel and you take care of the interaction)
elif strategy == "parallel":
return {
det_cfg["result_key"]: det_model,
cls_cfg["result_key"]: cls_model
}
else:
raise NotImplementedError(f"Strategy '{strategy}' is not supported.")
and then there is the routine in the main.py where the results are dislpayed (prepared for streaming to Homeassistant)
...
# initialize camera
picam2 = Picamera2()
picam2.start()
def fix_age_labels(results):
for r in results:
if r.get("label", "").lower() == "age":
r["label"] = f"Age: {r.get('score', 0):.0f}y"
return results
def run_inference(frame):
global current_model
if not current_model:
return frame #if no model is loaded, return the original frame
# single model
if callable(current_model):
result = current_model(frame)
return result.image_overlay
# compoundmodell (as dict)
elif isinstance(current_model, dict):
if "compound" in current_model:
result = current_model["compound"](frame)
if model_name == "face_and_age":
fix_age_labels(result.results)
return result.image_overlay
# parallel
else:
overlay = frame.copy()
for model in current_model.values():
result = model(frame)
overlay = result.image_overlay
return overlay
# Fallback
return frame
app = Flask(__name__)
def gen_frames():
while True:
frame = picam2.capture_array()
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
processed_frame = run_inference(frame_rgb)
ret, jpeg = cv2.imencode('.jpg', processed_frame)
if not ret:
continue
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + jpeg.tobytes() + b'\r\n')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, threaded=True)