#include "visualizer.hpp" #include "camera_pipeline.hpp" #include #include #include #include #include #include #include #include namespace cms { namespace { constexpr char windowName[]="CMS Camera Risk"; cv::Point point(PosePoint const& p){return {int(std::nearbyint(p.x)),int(std::nearbyint(p.y))};} cv::Scalar color(std::string const& level) { if(level=="danger")return {40,40,255}; if(level=="warning")return {0,160,255}; if(level=="watch")return {0,240,240}; if(level=="clear")return {80,220,90}; return {190,190,190}; } void segment(cv::Mat& image,cv::Point a,cv::Point b,cv::Scalar c,int thickness,bool dashed) { if(!dashed){cv::line(image,a,b,c,thickness,cv::LINE_AA);return;} cv::Point2d d=b-a;double length=cv::norm(d);if(length<1)return;d*=1.0/length; for(double x=0;x(image.pixels.data()),image.stride); auto canvas=view.clone(); if(r.door_mask_pixels) { auto const& m=*r.door_mask_pixels; if(m.width!=image.width||m.height!=image.height||m.stride(m.pixels.data()),m.stride); auto tint=canvas.clone();tint.setTo(cv::Scalar(255,180,0),mask); cv::addWeighted(canvas,0.75,tint,0.25,0,canvas); std::vector> contours;cv::findContours(mask.clone(),contours,cv::RETR_EXTERNAL,cv::CHAIN_APPROX_SIMPLE); cv::drawContours(canvas,contours,-1,{255,180,0},2); } for(auto const& person:r.persons) { auto const& b=person.box; cv::rectangle(canvas,{int(b[0]),int(b[1])},{int(b[2]),int(b[3])},{0,220,255},2); std::ostringstream text;text<<"ID "<>{{5+s,7+s},{7+s,9+s}}) { segment(canvas,point(k[e.first]),point(k[e.second]),state.limb_consensus?arm:cv::Scalar(0,140,255),3,!state.limb_consensus); cv::circle(canvas,point(k[e.second]),4,arm,-1,cv::LINE_AA); } if(state.state=="rejected")continue; int start=s==0?91:112; auto hand=state.distance_eligible?(s==0?cv::Scalar(255,80,220):cv::Scalar(255,190,40)):cv::Scalar(0,140,255); for(int f=0;f<5;++f)for(int j=0;j<4;++j){int a=j==0?start:start+f*4+j;int b=start+1+f*4+j;segment(canvas,point(k[a]),point(k[b]),hand,2,!state.distance_eligible);} for(int j=0;j<21;++j)cv::circle(canvas,point(k[start+j]),3,hand,-1,cv::LINE_AA); } } for(auto const& h:r.hand_regions) { std::vector points,hull;for(auto const& p:h.keypoints)points.push_back(point(p));cv::convexHull(points,hull); auto risk=std::find_if(r.risk.regions.begin(),r.risk.regions.end(),[&](auto const& item){return item.track_id==h.track_id&&item.side==h.side;}); auto c=color(risk==r.risk.regions.end()?"unavailable":risk->risk_level); cv::polylines(canvas,std::vector>{hull},true,c,2,cv::LINE_AA); } for(auto const& region:r.risk.regions)if(region.source=="YOLO_BODY_BOX_FALLBACK") { auto it=std::find(r.track_ids.begin(),r.track_ids.end(),region.track_id); if(it!=r.track_ids.end()){auto const& b=r.boxes.at(it-r.track_ids.begin());cv::putText(canvas,"BODY FALLBACK",{int(b[0])+4,int(b[1])+50},cv::FONT_HERSHEY_SIMPLEX,.65,{0,160,255},2,cv::LINE_AA);} } cv::rectangle(canvas,{0,0},{canvas.cols,148},{20,24,30},-1); std::ostringstream headline;headline<<"RISK ";if(r.risk.risk_score)headline<