发帖
3 0 0

【安信可小安派BW21-CBV-Kit】手势识别之握拳识别

sujingliang
论坛元老

15

主题

15

回帖

5381

积分

论坛元老

积分
5381
小安派·BW21-CBV-KIt 43 3 8 小时前
手势识别示例:示例->AmebaNN->HandGestureDetection

本示例可以识别手型并实时通过rtsp进行查看,如果想进一步监测到具体的手势比如握拳(握拳是最容易识别的)需要自己编写识别代码解决。

相关库文件位于
C:\Users\用户名\AppData\Local\Arduino15\packages\realtek\hardware\AmebaPro2\4.0.9-build20250205\libraries\NeuralNetwork\src

其中NNGestureDetection.cpp,NNGestureDetection.h负责手势监测。

在NNGestureDetection.cpp中有手势组织的定义说明:

/*
        #        8   12  16  20
        #        |   |   |   |
        #        7   11  15  19
        #    4   |   |   |   |
        #    |   6   10  14  18
        #    3   |   |   |   |
        #    |   5---9---13--17
        #    2    \         /
        #     \    \       /
        #      1    \     /
        #       \    \   /
        #        ------0-


        connections = [
            (0, 1), (1, 2), (2, 3), (3, 4),
            (5, 6), (6, 7), (7, 8),
            (9, 10), (10, 11), (11, 12),
            (13, 14), (14, 15), (15, 16),
            (17, 18), (18, 19), (19, 20),
            (0, 5), (5, 9), (9, 13), (13, 17), (0, 17), (2,5)
        */

用21个点表示手的坐标,其中0点是手心。
计算其他点到0点的距离取平均值,当平均值小于某个阈值时,可以判断为握拳。

在NNGestureDetection.h中为NNGestureDetection增加一个成员函数
isFist(const landmark3d_t hand)用来判断是否处于握拳状态
  1. class NNGestureDetection: public NNModelSelection {
  2. public:
  3.    static bool isFist(const landmark3d_t hand);
  4. }
复制代码

在NNGestureDetection.cpp增加其实现函数
小于阈值90的判断为握拳
  1. bool NNGestureDetection::isFist(const landmark3d_t hand) {
  2.     // 假设手掌中心是手腕点(索引0)
  3.     const int wristIndex = 0;
  4.     const float fistThreshold = 90; // 阈值,根据实际情况调整

  5.     // 计算所有指尖点到手腕点的距离
  6.     float totalDistance = 0;
  7.     for (int i = 4; i < HAND_LANDMARK_NUM; i += 4) { // 指尖点的索引为4, 8, 12, 16, 20
  8.         float dx = hand.pos[i].x - hand.pos[wristIndex].x;
  9.         float dy = hand.pos[i].y - hand.pos[wristIndex].y;
  10.         float dz = hand.pos[i].z - hand.pos[wristIndex].z;
  11.         totalDistance += sqrt(dx * dx + dy * dy + dz * dz);
  12.     }

  13.     // 如果平均距离小于阈值,则认为是握拳
  14.     float averageDistance = totalDistance / 5; // 5个指尖点
  15.         
  16.         char text_str[20];
  17.         snprintf(text_str, sizeof(text_str), "averageDistance:%f",averageDistance);
  18.         OSD.drawText(RTSP_CHANNEL, 0, 48, text_str, COLOR_BLUE);
  19.     return averageDistance < fistThreshold;
  20. }
复制代码
修改void NNGestureDetection::drawHandObject(void *p, void *img_param)函数:
  1. void NNGestureDetection::drawHandObject(void *p, void *img_param)
  2. {
  3.     if (!p || !img_param) {
  4.         return;
  5.     }

  6.     vipnn_out_buf_t *out = (vipnn_out_buf_t *)p;
  7.     handland_res_t *res = (handland_res_t *)&out->res[0];
  8.     nn_data_param_t *im = (nn_data_param_t *)img_param;
  9.         landmark3d_t lm3d=res->landmark3d;
  10.         
  11.     int im_h = RTSP_HEIGHT;
  12.     int im_w = RTSP_WIDTH;

  13.     // printf("im->width = %d, im->height = %d\r\n", im->img.width, im->img.height);
  14.     im->img.width = im->img.height = handlandmark_nn_roi.img.width;

  15.     float ratio_w = (float)im_w / (float)im->img.width;
  16.     float ratio_h = (float)im_h / (float)im->img.height;
  17.     float ratio = ratio_h < ratio_w ? ratio_h : ratio_w;

  18.     roi_delta_qp_set_param(RTSP_CHANNEL, 0, 0, RTSP_WIDTH, RTSP_HEIGHT, ROI_DELTA_QP_MAX);
  19.     OSD.createBitmap(RTSP_CHANNEL, HAND_JOINT_LAYER);
  20.     OSD.createBitmap(RTSP_CHANNEL, HAND_LINK_LAYER);

  21.     if (res->handedness != HANDEDNESS_NOTFOUND) {
  22.         // printf("theta:%f w:%d h:%d\r\n", res->theta, res->w, res->h);
  23.         if (fixLandmark(res) < 0) {
  24.             return;
  25.         }
  26.                
  27.                
  28.                 char text_str[20];
  29.         
  30.                 if(res->handedness==HANDEDNESS_LEFT)
  31.                 {
  32.                         snprintf(text_str, sizeof(text_str), "LEFT");
  33.                         OSD.drawText(RTSP_CHANNEL, 0, 0, text_str, COLOR_RED);
  34.                         
  35.                 }
  36.                 else if(res->handedness==HANDEDNESS_RIGHT)
  37.                 {
  38.                         snprintf(text_str, sizeof(text_str), "RIGHT");
  39.                         OSD.drawText(RTSP_CHANNEL, 0, 0, text_str, COLOR_RED);
  40.                 }
  41.                
  42.                 if(isFist(lm3d)){
  43.                         printf("detect fist");
  44.                         snprintf(text_str, sizeof(text_str), "FIST");
  45.                         OSD.drawText(RTSP_CHANNEL, 0, 24, text_str, COLOR_BLUE);
  46.                 }
  47.                
  48.         // First, draw the points for the joints.
  49.         for (int i = 0; i < HAND_LANDMARK_NUM; i++) {
  50.             // printf("res->landmark3d.pos[i].x = %f, res->landmark3d.pos[i].y = %f, res->landmark3d.pos[i].z = %f\r\n", res->landmark3d.pos[i].x, res->landmark3d.pos[i].y, res->landmark3d.pos[i].z);
  51.             int xr = res->landmark3d.pos[i].x * ratio + (RTSP_WIDTH - RTSP_HEIGHT) / 2;
  52.             int yr = res->landmark3d.pos[i].y * ratio;
  53.             OSD.drawPoint(RTSP_CHANNEL, xr, yr, 12, COLOR_RED, HAND_JOINT_LAYER);
  54.             // res->landmark3d.pos[i].z = roundf(q2f(&llm[(i*3+2)*datasize], llm_fmt.format));//Not needed to draw OSD
  55.             // printf("llm %d(%f,%f,%f)\r\n", i, hand_landmark_res->landmark3d.pos[i].x, hand_landmark_res->landmark3d.pos[i].y, hand_landmark_res->landmark3d.pos[i].z);
  56.         }

  57.         /*
  58.         #        8   12  16  20
  59.         #        |   |   |   |
  60.         #        7   11  15  19
  61.         #    4   |   |   |   |
  62.         #    |   6   10  14  18
  63.         #    3   |   |   |   |
  64.         #    |   5---9---13--17
  65.         #    2    \         /
  66.         #     \    \       /
  67.         #      1    \     /
  68.         #       \    \   /
  69.         #        ------0-
  70.         connections = [
  71.             (0, 1), (1, 2), (2, 3), (3, 4),
  72.             (5, 6), (6, 7), (7, 8),
  73.             (9, 10), (10, 11), (11, 12),
  74.             (13, 14), (14, 15), (15, 16),
  75.             (17, 18), (18, 19), (19, 20),
  76.             (0, 5), (5, 9), (9, 13), (13, 17), (0, 17), (2,5)
  77.         */
  78.         int connections[22][2] = {
  79.             {0,  1 },
  80.             {1,  2 },
  81.             {2,  3 },
  82.             {3,  4 },
  83.             {5,  6 },
  84.             {6,  7 },
  85.             {7,  8 },
  86.             {9,  10},
  87.             {10, 11},
  88.             {11, 12},
  89.             {13, 14},
  90.             {14, 15},
  91.             {15, 16},
  92.             {17, 18},
  93.             {18, 19},
  94.             {19, 20},
  95.             {0,  5 },
  96.             {5,  9 },
  97.             {9,  13},
  98.             {13, 17},
  99.             {0,  17},
  100.             {2,  5 }
  101.         };

  102.         // Draw the connections of the joints
  103.         for (int i = 0; i < 22; i++) {
  104.             int idx_start = connections[i][0];
  105.             int idx_end = connections[i][1];
  106.             int start_x = res->landmark3d.pos[idx_start].x * ratio + (RTSP_WIDTH - RTSP_HEIGHT) / 2;
  107.             int start_y = res->landmark3d.pos[idx_start].y * ratio;
  108.             int end_x = res->landmark3d.pos[idx_end].x * ratio + (RTSP_WIDTH - RTSP_HEIGHT) / 2;
  109.             int end_y = res->landmark3d.pos[idx_end].y * ratio;
  110.             // printf("start_x = %d, start_y = %d, end_x = %d, end_y = %d\r\n", start_x, start_y, end_x, end_y);
  111.             OSD.drawLine(RTSP_CHANNEL, start_x, start_y, end_x, end_y, 8, COLOR_GREEN, HAND_LINK_LAYER);
  112.         }
  113.         if (osd_cleanup_timer) {
  114.             xTimerReset(osd_cleanup_timer, 10);
  115.         }
  116.     }

  117.     OSD.update(RTSP_CHANNEL, HAND_JOINT_LAYER, 0);
  118.     OSD.update(RTSP_CHANNEL, HAND_LINK_LAYER, 1);
  119. }
复制代码
其中增加:


                if(res->handedness==HANDEDNESS_LEFT)//判断是左手
                {
                        snprintf(text_str, sizeof(text_str), "LEFT");
                        OSD.drawText(RTSP_CHANNEL, 0, 0, text_str, COLOR_RED);
                        
                }
                else if(res->handedness==HANDEDNESS_RIGHT)//判断是右手
                {
                        snprintf(text_str, sizeof(text_str), "RIGHT");
                        OSD.drawText(RTSP_CHANNEL, 0, 0, text_str, COLOR_RED);
                }
               
                if(isFist(lm3d)){//是否为握拳
                        printf("detect fist");
                        snprintf(text_str, sizeof(text_str), "FIST");
                        OSD.drawText(RTSP_CHANNEL, 0, 24, text_str, COLOR_BLUE);
                }


运行效果
1、左手非握拳
屏幕显示:LEFT,平均值大于90
12.png
2、左手握拳
屏幕显示:LEFT,FIST,平均值小于90

13.png
3、右手非握拳
屏幕显示:RIGHT,平均值大于90

14.png

4、右手握拳
屏幕显示:RIGHT,FIST,平均值小于90
11.png
──── 0人觉得很赞 ────

举报

7 小时前
棒~
6 小时前
棒棒哒
5 小时前
厉害
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28071 个
  • 话题数: 39642 篇