|
@@ -506,18 +506,36 @@ int main(int argc, char* argv[]) {
|
|
|
bool pose_crouch = cfg.value("pose_crouch", true);
|
|
bool pose_crouch = cfg.value("pose_crouch", true);
|
|
|
bool pose_recline = cfg.value("pose_recline", true);
|
|
bool pose_recline = cfg.value("pose_recline", true);
|
|
|
bool pose_hand_to_mouth = cfg.value("pose_hand_to_mouth", true);
|
|
bool pose_hand_to_mouth = cfg.value("pose_hand_to_mouth", true);
|
|
|
- float pose_min_body_h = cfg.value("pose_min_body_h", 60.0f);
|
|
|
|
|
|
|
+ float pose_min_area = cfg.value("pose_min_area", 3000.0f);
|
|
|
|
|
+ // 姿态检测屏蔽区域: {"通道id": [[x1,y1,x2,y2], ...]} 相对原始分辨率
|
|
|
|
|
+ map<int, vector<cv::Rect>> pose_exclude_zones;
|
|
|
|
|
+ if (cfg.contains("pose_exclude_zones") && cfg["pose_exclude_zones"].is_object()) {
|
|
|
|
|
+ for (auto& [k, v] : cfg["pose_exclude_zones"].items()) {
|
|
|
|
|
+ int cid = atoi(k.c_str());
|
|
|
|
|
+ if (!v.is_array()) continue;
|
|
|
|
|
+ vector<cv::Rect> zones;
|
|
|
|
|
+ for (auto& z : v) {
|
|
|
|
|
+ if (z.is_array() && z.size() >= 4) {
|
|
|
|
|
+ zones.push_back(cv::Rect(z[0].get<int>(), z[1].get<int>(),
|
|
|
|
|
+ z[2].get<int>() - z[0].get<int>(),
|
|
|
|
|
+ z[3].get<int>() - z[1].get<int>()));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!zones.empty()) pose_exclude_zones[cid] = zones;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
fallAnalyzer.setHandRaiseEnabled(pose_hand_raise);
|
|
fallAnalyzer.setHandRaiseEnabled(pose_hand_raise);
|
|
|
fallAnalyzer.setCrouchEnabled(pose_crouch);
|
|
fallAnalyzer.setCrouchEnabled(pose_crouch);
|
|
|
fallAnalyzer.setReclineEnabled(pose_recline);
|
|
fallAnalyzer.setReclineEnabled(pose_recline);
|
|
|
fallAnalyzer.setHandToMouthEnabled(pose_hand_to_mouth);
|
|
fallAnalyzer.setHandToMouthEnabled(pose_hand_to_mouth);
|
|
|
- fallAnalyzer.setMinBodyHeight(pose_min_body_h);
|
|
|
|
|
|
|
+ fallAnalyzer.setMinBodyArea(pose_min_area);
|
|
|
cout << "[Pose] 动作类型: 跌倒/倒地(固定)"
|
|
cout << "[Pose] 动作类型: 跌倒/倒地(固定)"
|
|
|
<< " 举手呼救=" << (pose_hand_raise ? "开" : "关")
|
|
<< " 举手呼救=" << (pose_hand_raise ? "开" : "关")
|
|
|
<< " 异常蹲坐=" << (pose_crouch ? "开" : "关")
|
|
<< " 异常蹲坐=" << (pose_crouch ? "开" : "关")
|
|
|
<< " 半躺=" << (pose_recline ? "开" : "关")
|
|
<< " 半躺=" << (pose_recline ? "开" : "关")
|
|
|
<< " 手近嘴部=" << (pose_hand_to_mouth ? "开" : "关")
|
|
<< " 手近嘴部=" << (pose_hand_to_mouth ? "开" : "关")
|
|
|
- << " 距离阈值=" << pose_min_body_h << "px" << endl;
|
|
|
|
|
|
|
+ << " 最小面积=" << pose_min_area << "px"
|
|
|
|
|
+ << " 屏蔽区=" << pose_exclude_zones.size() << "路" << endl;
|
|
|
bool pose_ok = false;
|
|
bool pose_ok = false;
|
|
|
if (pose_enabled) {
|
|
if (pose_enabled) {
|
|
|
if (poseDetector.load(pose_model_path, pose_input_size,
|
|
if (poseDetector.load(pose_model_path, pose_input_size,
|
|
@@ -1629,7 +1647,17 @@ int main(int argc, char* argv[]) {
|
|
|
r["pose_crouch"] = pose_crouch;
|
|
r["pose_crouch"] = pose_crouch;
|
|
|
r["pose_recline"] = pose_recline;
|
|
r["pose_recline"] = pose_recline;
|
|
|
r["pose_hand_to_mouth"] = pose_hand_to_mouth;
|
|
r["pose_hand_to_mouth"] = pose_hand_to_mouth;
|
|
|
- r["pose_min_body_h"] = pose_min_body_h;
|
|
|
|
|
|
|
+ r["pose_min_area"] = pose_min_area;
|
|
|
|
|
+ {
|
|
|
|
|
+ json zj = json::object();
|
|
|
|
|
+ for (auto& [cid, zones] : pose_exclude_zones) {
|
|
|
|
|
+ json arr = json::array();
|
|
|
|
|
+ for (auto& z : zones)
|
|
|
|
|
+ arr.push_back({z.x, z.y, z.x + z.width, z.y + z.height});
|
|
|
|
|
+ zj[to_string(cid)] = arr;
|
|
|
|
|
+ }
|
|
|
|
|
+ r["pose_exclude_zones"] = zj;
|
|
|
|
|
+ }
|
|
|
json chs = json::array();
|
|
json chs = json::array();
|
|
|
{
|
|
{
|
|
|
lock_guard<mutex> lk(channels_mtx);
|
|
lock_guard<mutex> lk(channels_mtx);
|
|
@@ -1695,12 +1723,12 @@ int main(int argc, char* argv[]) {
|
|
|
fallAnalyzer.setHandToMouthEnabled(v);
|
|
fallAnalyzer.setHandToMouthEnabled(v);
|
|
|
full["pose_hand_to_mouth"] = v;
|
|
full["pose_hand_to_mouth"] = v;
|
|
|
}
|
|
}
|
|
|
- if (j.contains("pose_min_body_h")) {
|
|
|
|
|
- float v = j["pose_min_body_h"].get<float>();
|
|
|
|
|
- if (v >= 20.0f && v <= 500.0f) {
|
|
|
|
|
- pose_min_body_h = v;
|
|
|
|
|
- fallAnalyzer.setMinBodyHeight(v);
|
|
|
|
|
- full["pose_min_body_h"] = v;
|
|
|
|
|
|
|
+ if (j.contains("pose_min_area")) {
|
|
|
|
|
+ float v = j["pose_min_area"].get<float>();
|
|
|
|
|
+ if (v >= 500.0f && v <= 500000.0f) {
|
|
|
|
|
+ pose_min_area = v;
|
|
|
|
|
+ fallAnalyzer.setMinBodyArea(v);
|
|
|
|
|
+ full["pose_min_area"] = v;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
if (j.contains("pose_enabled")) {
|
|
if (j.contains("pose_enabled")) {
|
|
@@ -1721,6 +1749,24 @@ int main(int argc, char* argv[]) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ if (j.contains("pose_exclude_zones") && j["pose_exclude_zones"].is_object()) {
|
|
|
|
|
+ pose_exclude_zones.clear();
|
|
|
|
|
+ for (auto& [k, v] : j["pose_exclude_zones"].items()) {
|
|
|
|
|
+ int cid = atoi(k.c_str());
|
|
|
|
|
+ if (!v.is_array()) continue;
|
|
|
|
|
+ vector<cv::Rect> zones;
|
|
|
|
|
+ for (auto& z : v) {
|
|
|
|
|
+ if (z.is_array() && z.size() >= 4) {
|
|
|
|
|
+ int x1 = z[0].get<int>(), y1 = z[1].get<int>();
|
|
|
|
|
+ int x2 = z[2].get<int>(), y2 = z[3].get<int>();
|
|
|
|
|
+ if (x2 > x1 && y2 > y1)
|
|
|
|
|
+ zones.push_back(cv::Rect(x1, y1, x2 - x1, y2 - y1));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!zones.empty()) pose_exclude_zones[cid] = zones;
|
|
|
|
|
+ }
|
|
|
|
|
+ full["pose_exclude_zones"] = j["pose_exclude_zones"];
|
|
|
|
|
+ }
|
|
|
saveJson(config_path, full);
|
|
saveJson(config_path, full);
|
|
|
cout << "[Pose] 配置已更新: 阈值=" << fall_thresh
|
|
cout << "[Pose] 配置已更新: 阈值=" << fall_thresh
|
|
|
<< " 连续" << fall_frames << "帧" << endl;
|
|
<< " 连续" << fall_frames << "帧" << endl;
|
|
@@ -2004,9 +2050,22 @@ int main(int argc, char* argv[]) {
|
|
|
if (pose_ok && ch->pose_running) {
|
|
if (pose_ok && ch->pose_running) {
|
|
|
vector<PersonPose> falls;
|
|
vector<PersonPose> falls;
|
|
|
// 对每个人做多动作分析, 取最高分动作
|
|
// 对每个人做多动作分析, 取最高分动作
|
|
|
|
|
+ // 先过滤屏蔽区域内的人体(地图等误识别)
|
|
|
|
|
+ auto zit = pose_exclude_zones.find(ch->id);
|
|
|
|
|
+ vector<PersonPose> valid_poses;
|
|
|
|
|
+ for (auto& p : poses) {
|
|
|
|
|
+ bool excluded = false;
|
|
|
|
|
+ if (zit != pose_exclude_zones.end()) {
|
|
|
|
|
+ cv::Point center(p.bbox.x + p.bbox.width / 2,
|
|
|
|
|
+ p.bbox.y + p.bbox.height / 2);
|
|
|
|
|
+ for (auto& z : zit->second)
|
|
|
|
|
+ if (z.contains(center)) { excluded = true; break; }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!excluded) valid_poses.push_back(p);
|
|
|
|
|
+ }
|
|
|
PoseAction bestAction = PoseAction::NONE;
|
|
PoseAction bestAction = PoseAction::NONE;
|
|
|
float bestScore = 0.0f;
|
|
float bestScore = 0.0f;
|
|
|
- for (auto& p : poses) {
|
|
|
|
|
|
|
+ for (auto& p : valid_poses) {
|
|
|
if (pose_alarm_classes.empty() ||
|
|
if (pose_alarm_classes.empty() ||
|
|
|
find(pose_alarm_classes.begin(),
|
|
find(pose_alarm_classes.begin(),
|
|
|
pose_alarm_classes.end(),
|
|
pose_alarm_classes.end(),
|
|
@@ -2025,10 +2084,34 @@ int main(int argc, char* argv[]) {
|
|
|
if (hit) ch->pose_fall_count++;
|
|
if (hit) ch->pose_fall_count++;
|
|
|
else ch->pose_fall_count = 0;
|
|
else ch->pose_fall_count = 0;
|
|
|
bool pose_rising = (ch->pose_fall_count == fall_frames);
|
|
bool pose_rising = (ch->pose_fall_count == fall_frames);
|
|
|
|
|
+ if (pose_rising && !poses.empty()) {
|
|
|
|
|
+ // 诊断: 打印命中人体面积
|
|
|
|
|
+ cout << "[Pose] CH" << ch->id << " 命中" << poseActionName(bestAction)
|
|
|
|
|
+ << " 面积=" << (poses[0].bbox.width * poses[0].bbox.height)
|
|
|
|
|
+ << " bbox=" << poses[0].bbox << endl;
|
|
|
|
|
+ }
|
|
|
{
|
|
{
|
|
|
lock_guard<mutex> lk(ch->mtx);
|
|
lock_guard<mutex> lk(ch->mtx);
|
|
|
- ch->poses = poses;
|
|
|
|
|
- ch->fall_poses = hit ? poses : vector<PersonPose>{};
|
|
|
|
|
|
|
+ // 面积过小(太远)的人体不显示; 屏蔽区域内的人体也不显示
|
|
|
|
|
+ vector<PersonPose> vis_poses;
|
|
|
|
|
+ auto zit = pose_exclude_zones.find(ch->id);
|
|
|
|
|
+ for (auto& p : poses) {
|
|
|
|
|
+ float area = (float)p.bbox.width * p.bbox.height;
|
|
|
|
|
+ if (area < pose_min_area) continue;
|
|
|
|
|
+ // 屏蔽区判定: bbox中心落入任一排除矩形则忽略
|
|
|
|
|
+ bool excluded = false;
|
|
|
|
|
+ if (zit != pose_exclude_zones.end()) {
|
|
|
|
|
+ cv::Point center(p.bbox.x + p.bbox.width / 2,
|
|
|
|
|
+ p.bbox.y + p.bbox.height / 2);
|
|
|
|
|
+ for (auto& z : zit->second) {
|
|
|
|
|
+ if (z.contains(center)) { excluded = true; break; }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (excluded) continue;
|
|
|
|
|
+ vis_poses.push_back(p);
|
|
|
|
|
+ }
|
|
|
|
|
+ ch->poses = vis_poses;
|
|
|
|
|
+ ch->fall_poses = hit ? vis_poses : vector<PersonPose>{};
|
|
|
ch->pose_action = hit ? poseActionName(bestAction) : "";
|
|
ch->pose_action = hit ? poseActionName(bestAction) : "";
|
|
|
ch->pose_score = bestScore;
|
|
ch->pose_score = bestScore;
|
|
|
}
|
|
}
|