YOLOv8 人体姿态估计 跌倒检测

这段代码展示了如何利用OpenCV处理图像,结合Yolov7-pose模型的结果来检测跌倒事件。关键在于计算两个关键点(PT5和PT6,PT11和PT12)的中点连线与另一直角边的夹角,通过比较夹角和高度差来判断是否发生跌倒。当夹角超过60度、中心点位置异常或检测框宽高比大于5/3时,系统认为是跌倒情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:

  1. pt5与pt6取中间点,记为center_up; pt11 与 pt12取中间点记为center_down,作直角三角形,直角为right_angle_point。
  2. center_up与center_down连线,right_angle_point与center_down连线,计算这线夹角的tan值,然后用tan的反函数求出夹角值。
  3. 当夹角>60度,或center_up_y <= center_down_y , 或检测框宽高比大于5/3,则为跌倒

思路来自b站视频:

Yolov7-pose跌倒检测

关键代码:

void DrawPred(cv::Mat& img, std::vector<OutputPose>& results,
              const std::vector<std::vector<unsigned int>> &SKELLTON,
              const std::vector<std::vector<unsigned int>> &KPS_COLORS,
              const std::vector<std::vector<unsigned int>> &LIMB_COLORS)
{
    const int num_point =17;
    for (auto &result:results){
        int  left,top,width, height;
        left = result.box.x;
        top = result.box.y;
        width = result.box.width;
        height = result.box.height;


//        printf("x: %d  y:%d  w:%d  h%d\n",(int)left, (int)top, (int)result.box.width, (int)result.box.height);

        // 框出目标
        rectangle(img, result.box,Scalar(0,0,255), 2, 8);

        // 在目标框左上角标识目标类别以及概率
        string label = "person:" + to_string(result.confidence) ;
        int baseLine;
        Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
        top = max(top, labelSize.height);
        putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255), 2);

        // 连线
        auto &kps = result.kps;
//        cout << "该目标关键点:" << kps.size() << endl;
        for (int k=0; k<num_point+2; k++){// 不要设置为>0.5f ,>0.0f显示效果比较好
            // 关键点绘制
            if (k<num_point){
                int kps_x = std::round(kps[k*3]);
                int kps_y = std::round(kps[k*3 + 1]);
                float kps_s = kps[k*3 + 2];

//                printf("x:%d y:%d s:%f\n", kps_x, kps_y, kps_s);

                if (kps_s > 0.0f){
                    cv::Scalar kps_color = Scalar(KPS_COLORS[k][0],KPS_COLORS[k][1],KPS_COLORS[k][2]);
                    cv::circle(img, {kps_x, kps_y}, 5, kps_color, -1);
                }
            }

            auto &ske = SKELLTON[k];
            int pos1_x = std::round(kps[(ske[0] -1) * 3]);
            int pos1_y = std::round(kps[(ske[0] -1) * 3 + 1]);

            int pos2_x = std::round(kps[(ske[1] -1) * 3]);
            int pos2_y = std::round(kps[(ske[1] -1) * 3 + 1]);

            float pos1_s = kps[(ske[0] -1) * 3 + 2];
            float pos2_s = kps[(ske[1] -1) * 3 + 2];

            if (pos1_s > 0.0f && pos2_s >0.0f){// 不要设置为>0.5f ,>0.0f显示效果比较好
                cv::Scalar limb_color = cv::Scalar(LIMB_COLORS[k][0], LIMB_COLORS[k][1], LIMB_COLORS[k][3]);
                cv::line(img, {pos1_x, pos1_y}, {pos2_x, pos2_y}, limb_color);
            }

        // 跌倒检测
            float pt5_x = kps[5*3];
            float pt5_y = kps[5*3 + 1];
            float pt6_x = kps[6*3];
            float pt6_y = kps[6*3+1];
            float center_up_x = (pt5_x + pt6_x) /2.0f ;
            float center_up_y = (pt5_y + pt6_y) / 2.0f;
            Point center_up = Point((int)center_up_x, (int)center_up_y);

            float pt11_x = kps[11*3];
            float pt11_y = kps[11*3 + 1];
            float pt12_x = kps[12*3];
            float pt12_y = kps[12*3 + 1];
            float center_down_x = (pt11_x + pt12_x) / 2.0f;
            float center_down_y = (pt11_y + pt12_y) / 2.0f;
            Point center_down = Point((int)center_down_x, (int)center_down_y);


            float right_angle_point_x = center_down_x;
            float righ_angle_point_y = center_up_y;
            Point right_angl_point = Point((int)right_angle_point_x, (int)righ_angle_point_y);


            float a = abs(right_angle_point_x - center_up_x);
            float b = abs(center_down_y - righ_angle_point_y);

            float tan_value = a / b;
            float Pi = acos(-1);
            float angle = atan(tan_value) * 180.0f/ Pi;
            string angel_label = "angle: " + to_string(angle);
            putText(img, angel_label, Point(left, top-40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255), 2);

            if (angle > 60.0f || center_down_y <= center_up_y || (double)width/ height > 5.0f/3.0f) // 宽高比小于0.6为站立,大于5/3为跌倒
            {
                string fall_down_label = "person fall down!!!!";
                putText(img, fall_down_label , Point(left, top-20), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0,0,255), 2);

                printf("angel:%f width/height:%f\n",angle, (double)width/ height );
            }






            cv::line(img, center_up, center_down,
                     Scalar(0,0,255), 2, 8);
            cv::line(img, center_up, right_angl_point,
                     Scalar(0,0,255), 2, 8);
            cv::line(img, right_angl_point, center_down,
                     Scalar(0,0,255), 2, 8);



        }
    }
}

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值