毕业设计-题目:基于机器视觉opencv的手势检测手势识别算法-深度学习卷积神经网络opencvpython(代码片段)

DanCheng-studio DanCheng-studio     2023-03-02     602

关键词:

1 简介

今天学长向大家介绍一个机器视觉项目

基于机器视觉opencv的手势检测 手势识别 算法

毕设帮助,开题指导,技术解答
🇶746876041

2 传统机器视觉的手势检测

普通机器视觉手势检测的基本流程如下:


其中轮廓的提取,多边形拟合曲线的求法,凸包集和凹陷集的求法都是采用opencv中自带的函数。手势数字的识别是利用凸包点以及凹陷点和手部中心点的几何关系,简单的做了下逻辑判别了(可以肯定的是这种方法很烂),具体的做法是先在手部定位出2个中心点坐标,这2个中心点坐标之间的距离阈值由程序设定,其中一个中心点就是利用OpenNI跟踪得到的手部位置。有了这2个中心点的坐标,在程序中就可以分别计算出在这2个中心点坐标上的凸凹点的个数。当然了,这样做的前提是用人在做手势表示数字的同时应该是将手指的方向朝上(因为没有像机器学习那样通过样本来训练,所以使用时条件要苛刻很多)。利用上面求出的4种点的个数(另外程序中还设置了2个辅助计算点的个数,具体见代码部分)和简单的逻辑判断就可以识别出数字0~5了。其它的数字可以依照具体的逻辑去设计(还可以设计出多位数字的识别),只是数字越多设计起来越复杂,因为要考虑到它们之间的干扰性,且这种不通用的设计方法也没有太多的实际意义。

2.1 轮廓检测法

使用 void convexityDefects(InputArray contour, InputArray convexhull, OutputArray convexityDefects) 方法

该函数的作用是对输入的轮廓contour,凸包集合来检测其轮廓的凸型缺陷,一个凸型缺陷结构体包括4个元素,缺陷起点坐标,缺陷终点坐标,缺陷中离凸包线距离最远的点的坐标,以及此时最远的距离。参数3即其输出的凸型缺陷结构体向量。

其凸型缺陷的示意图如下所示:


第1个参数虽然写的是contour,字面意思是轮廓,但是本人实验过很多次,发现如果该参数为目标通过轮廓检测得到的原始轮廓的话,则程序运行到onvexityDefects()函数时会报内存错误。因此本程序中采用的不是物体原始的轮廓,而是经过多项式曲线拟合后的轮廓,即多项式曲线,这样程序就会顺利地运行得很好。另外由于在手势识别过程中可能某一帧检测出来的轮廓非常小(由于某种原因),以致于少到只有1个点,这时候如果程序运行到onvexityDefects()函数时就会报如下的错误:

int Mat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) const



    return (depth() == _depth || _depth <= 0) &&

        (isContinuous() || !_requireContinuous) &&

        ((dims == 2 && (((rows == 1 || cols == 1) && channels() == _elemChannels) || (cols == _elemChannels))) ||

        (dims == 3 && channels() == 1 && size.p[2] == _elemChannels && (size.p[0] == 1 || size.p[1] == 1) &&

         (isContinuous() || step.p[1] == step.p[2]*size.p[2])))

    ? (int)(total()*channels()/_elemChannels) : -1;


该函数源码大概意思就是说对应的Mat矩阵如果其深度,连续性,通道数,行列式满足一定条件的话就返回Mat元素的个数和其通道数的乘积,否则返回-1;而本文是要求其返回值大于3,有得知此处输入多边形曲线(即参数1)的通道数为2,所以还需要求其元素的个数大于1.5,即大于2才满足ptnum > 3。简单的说就是用convexityDefects()函数来对多边形曲线进行凹陷检测时,必须要求参数1曲线本身至少有2个点(也不知道这样分析对不对)。因此本人在本次程序convexityDefects()函数前加入了if(Mat(approx_poly_curve).checkVector(2, CV_32S) > 3)来判断,只有满足该if条件,才会进行后面的凹陷检测。这样程序就不会再出现类似的bug了。

第2个参数一般是由opencv中的函数convexHull()获得的,一般情况下该参数里面存的是凸包集合中的点在多项式曲线点中的位置索引,且该参数以vector的形式存在,因此参数convexhull中其元素的类型为unsigned int。在本次凹陷点检测函数convexityDefects()里面根据文档,要求该参数为Mat型。因此在使用convexityDefects()的参数2时,一般将vector直接转换Mat型。

参数3是一个含有4个元素的结构体的集合,如果在c++的版本中,该参数可以直接用vector来代替,Vec4i中的4个元素分别表示凹陷曲线段的起始坐标索引,终点坐标索引,离凸包集曲线最远点的坐标索引以及此时的最远距离值,这4个值都是整数。在c版本的opencv中一般不是保存的索引,而是坐标值。

2.2 算法结果

数字“0”的识别结果:

数字“1”的识别结果

数字“2”的识别结果

数字“3”的识别结果:

数字“4”的识别结果:

数字“5”的识别结果:

2.3 整体代码实现

2.3.1 算法流程

学长实现过程和上面的系统流程图类似,大概过程如下:

  • 1. 求出手部的掩膜

  • 2. 求出掩膜的轮廓

  • 3. 求出轮廓的多变形拟合曲线

  • 4. 求出多边形拟合曲线的凸包集,找出凸点

  • 5. 求出多变形拟合曲线的凹陷集,找出凹点

  • 6. 利用上面的凸凹点和手部中心点的几何关系来做简单的数字手势识别

(这里用的是C语言写的,这个代码是学长早期写的,同学们需要的话,学长出一个python版本的)

#include <iostream>

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include "copenni.cpp"

#include <iostream>

#define DEPTH_SCALE_FACTOR 255./4096.
#define ROI_HAND_WIDTH 140
#define ROI_HAND_HEIGHT 140
#define MEDIAN_BLUR_K 5
#define XRES  640
#define YRES  480
#define DEPTH_SEGMENT_THRESH 5
#define MAX_HANDS_COLOR 10
#define MAX_HANDS_NUMBER  10
#define HAND_LIKELY_AREA 2000
#define DELTA_POINT_DISTENCE 25     //手部中心点1和中心点2距离的阈值
#define SEGMENT_POINT1_DISTANCE 27  //凸点与手部中心点1远近距离的阈值
#define SEGMENT_POINT2_DISTANCE 30  //凸点与手部中心点2远近距离的阈值

using namespace cv;
using namespace xn;
using namespace std;


int main (int argc, char **argv)

    unsigned int convex_number_above_point1 = 0;
    unsigned int concave_number_above_point1 = 0;
    unsigned int convex_number_above_point2 = 0;
    unsigned int concave_number_above_point2 = 0;
    unsigned int convex_assist_above_point1 = 0;
    unsigned int convex_assist_above_point2 = 0;
    unsigned int point_y1 = 0;
    unsigned int point_y2 = 0;
    int number_result = -1;
    bool recognition_flag = false;  //开始手部数字识别的标志

    vector<Scalar> color_array;//采用默认的10种颜色
    
        color_array.push_back(Scalar(255, 0, 0));
        color_array.push_back(Scalar(0, 255, 0));
        color_array.push_back(Scalar(0, 0, 255));
        color_array.push_back(Scalar(255, 0, 255));
        color_array.push_back(Scalar(255, 255, 0));
        color_array.push_back(Scalar(0, 255, 255));
        color_array.push_back(Scalar(128, 255, 0));
        color_array.push_back(Scalar(0, 128, 255));
        color_array.push_back(Scalar(255, 0, 128));
        color_array.push_back(Scalar(255, 128, 255));
    
    vector<unsigned int> hand_depth(MAX_HANDS_NUMBER, 0);
    vector<Rect> hands_roi(MAX_HANDS_NUMBER, Rect(XRES/2, YRES/2, ROI_HAND_WIDTH, ROI_HAND_HEIGHT));

    namedWindow("color image", CV_WINDOW_AUTOSIZE);
    namedWindow("depth image", CV_WINDOW_AUTOSIZE);
    namedWindow("hand_segment", CV_WINDOW_AUTOSIZE);    //显示分割出来的手的区域
    namedWindow("handrecognition", CV_WINDOW_AUTOSIZE); //显示0~5数字识别的图像

    COpenNI openni;
    if(!openni.Initial())
        return 1;

    if(!openni.Start())
        return 1;
    while(1) 
        if(!openni.UpdateData()) 
            return 1;
        
        /*获取并显示色彩图像*/
        Mat color_image_src(openni.image_metadata_.YRes(), openni.image_metadata_.XRes(),
                            CV_8UC3, (char *)openni.image_metadata_.Data());
        Mat color_image;
        cvtColor(color_image_src, color_image, CV_RGB2BGR);
        Mat hand_segment_mask(color_image.size(), CV_8UC1, Scalar::all(0));

        for(auto itUser = openni.hand_points_.cbegin(); itUser != openni.hand_points_.cend(); ++itUser) 

            point_y1 = itUser->second.Y;
            point_y2 = itUser->second.Y + DELTA_POINT_DISTENCE;
            circle(color_image, Point(itUser->second.X, itUser->second.Y),
                   5, color_array.at(itUser->first % color_array.size()), 3, 8);

            /*设置不同手部的深度*/
            hand_depth.at(itUser->first % MAX_HANDS_COLOR) = (unsigned int)(itUser->second.Z* DEPTH_SCALE_FACTOR);//itUser->first会导致程序出现bug

            /*设置不同手部的不同感兴趣区域*/
            hands_roi.at(itUser->first % MAX_HANDS_NUMBER) = Rect(itUser->second.X - ROI_HAND_WIDTH/2, itUser->second.Y - ROI_HAND_HEIGHT/2,
                                               ROI_HAND_WIDTH, ROI_HAND_HEIGHT);
            hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x =  itUser->second.X - ROI_HAND_WIDTH/2;
            hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y =  itUser->second.Y - ROI_HAND_HEIGHT/2;
            hands_roi.at(itUser->first % MAX_HANDS_NUMBER).width = ROI_HAND_WIDTH;
            hands_roi.at(itUser->first % MAX_HANDS_NUMBER).height = ROI_HAND_HEIGHT;
            if(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x <= 0)
                hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x  = 0;
            if(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x > XRES)
                hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x =  XRES;
            if(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y <= 0)
                hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y = 0;
            if(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y > YRES)
                hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y =  YRES;
        
        imshow("color image", color_image);

        /*获取并显示深度图像*/
        Mat depth_image_src(openni.depth_metadata_.YRes(), openni.depth_metadata_.XRes(),
                            CV_16UC1, (char *)openni.depth_metadata_.Data());//因为kinect获取到的深度图像实际上是无符号的16位数据
        Mat depth_image;
        depth_image_src.convertTo(depth_image, CV_8U, DEPTH_SCALE_FACTOR);
        imshow("depth image", depth_image);

        //取出手的mask部分
        //不管原图像时多少通道的,mask矩阵声明为单通道就ok
        for(auto itUser = openni.hand_points_.cbegin(); itUser != openni.hand_points_.cend(); ++itUser) 
            for(int i = hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x; i < std::min(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).x+hands_roi.at(itUser->first % MAX_HANDS_NUMBER).width, XRES); i++)
                for(int j = hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y; j < std::min(hands_roi.at(itUser->first % MAX_HANDS_NUMBER).y+hands_roi.at(itUser->first % MAX_HANDS_NUMBER).height, YRES); j++) 
                    hand_segment_mask.at<unsigned char>(j, i) = ((hand_depth.at(itUser->first % MAX_HANDS_NUMBER)-DEPTH_SEGMENT_THRESH) < depth_image.at<unsigned char>(j, i))
                                                                & ((hand_depth.at(itUser->first % MAX_HANDS_NUMBER)+DEPTH_SEGMENT_THRESH) > depth_image.at<unsigned char>(j,i));
                
         
        medianBlur(hand_segment_mask, hand_segment_mask, MEDIAN_BLUR_K);
        Mat hand_segment(color_image.size(), CV_8UC3);
        color_image.copyTo(hand_segment, hand_segment_mask);

        /*对mask图像进行轮廓提取,并在手势识别图像中画出来*/
        std::vector< std::vector<Point> > contours;
        findContours(hand_segment_mask, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);//找出mask图像的轮廓
        Mat hand_recognition_image = Mat::zeros(color_image.rows, color_image.cols, CV_8UC3);

        for(int i = 0; i < contours.size(); i++)   //只有在检测到轮廓时才会去求它的多边形,凸包集,凹陷集
            recognition_flag = true;
            /*找出轮廓图像多边形拟合曲线*/
            Mat contour_mat = Mat(contours[i]);
            if(contourArea(contour_mat) > HAND_LIKELY_AREA)    //比较有可能像手的区域
                std::vector<Point> approx_poly_curve;
                approxPolyDP(contour_mat, approx_poly_curve, 10, true);//找出轮廓的多边形拟合曲线
                std::vector< std::vector<Point> > approx_poly_curve_debug;
                approx_poly_curve_debug.push_back(approx_poly_curve);

                 drawContours(hand_recognition_image, contours, i, Scalar(255, 0, 0), 1, 8); //画出轮廓
    //            drawContours(hand_recognition_image, approx_poly_curve_debug, 0, Scalar(256, 128, 128), 1, 8); //画出多边形拟合曲线

                /*对求出的多边形拟合曲线求出其凸包集*/
                vector<int> hull;
                convexHull(Mat(approx_poly_curve), hull, true);
                for(int i = 0; i < hull.size(); i++) 
                    circle(hand_recognition_image, approx_poly_curve[hull[i]], 2, Scalar(0, 255, 0), 2, 8);

                    /*统计在中心点1以上凸点的个数*/
                    if(approx_poly_curve[hull[i]].y <= point_y1) 
                        /*统计凸点与中心点1的y轴距离*/
                        long dis_point1 = abs(long(point_y1 - approx_poly_curve[hull[i]].y));
                        int dis1 = point_y1 - approx_poly_curve[hull[i]].y;
                        if(dis_point1 > SEGMENT_POINT1_DISTANCE && dis1 >= 0查看详情  

计算机视觉基于python—opencv的手势识别详解(代码片段)

文章目录前言前期准备识别手部模型识别视频输入方法手势识别方法完整代码结语前言人工智能的浪潮正在席卷全球。一个已经被谈论了几十年的概念,如今这几年,相关技术的发展速度越来越快。机器学习、深度学习... 查看详情

毕业设计疲劳驾驶检测系统-机器学习机器视觉opencvpython

...;各个学校对毕设的要求越来越高,难度也越来越大…毕业设计耗费时间&#x 查看详情

毕业设计python机器视觉车牌识别-opencv深度学习机器学习(代码片段)

1前言🚩基于python机器视觉的车牌识别系统🥇学长这里给一个题目综合评分(每项满分5分)难度系数:3分工作量:3分创新点:2分🧿选题指导,项目分享:https://gitee.com/dancheng-senior/project-sharing-1/blob/master/%... 查看详情

计算机视觉基于python—opencv的手势识别详解(代码片段)

文章目录更新日记前言前期准备识别手部模型识别视频输入方法手势识别方法完整代码结语更新日记更新日记:2022.04.18:应各位网友需求,已mp库更新后的手部识别模型代码。目前可以正常的RUN啦!!前言人... 查看详情

机器视觉python+opencv+mediapipe手势识别系统(代码片段)

...iapipeMediaPipeMediaPipe为直播和流媒体提供跨平台、可定制的机器学习解决方案。端到端加速引擎:内置的快速ML推理和处理即使在常见硬件上也能加速一次构建,任意部署:统一解决方案适用于Android、iOS、桌面/云、Web... 查看详情

毕业设计题目:基于深度学习的动物识别-卷积神经网络机器视觉图像识别(代码片段)

文章目录0前言1背景2算法原理2.1动物识别方法概况2.2常用的网络模型2.2.1B-CNN2.2.2SSD3SSD动物目标检测流程4实现效果5部分相关代码5.1数据预处理5.2构建卷积神经网络5.3tensorflow计算图可视化5.4网络模型训练5.5对猫狗图像进行2分类6最... 查看详情

“opencv”是啥?

参考技术AOpenCV是一个用于图像处理、分析、机器视觉方面的开源函数库.无论你是做科学研究,还是商业应用,opencv都可以作为你理想的工具库,因为,对于这两者,它完全是免费的。该库采用C及C++语言编写,可以在windows,linux,m... 查看详情

python+opencv机器视觉-基于霍夫圈变换算法检测图像中的圆形实例演示(代码片段)

Python+opencv机器视觉-基于霍夫圈变换算法检测图像中的圆形实例演示第一章:霍夫变换检测圆①实例演示1②实例演示2③霍夫变换函数解析第二章:Python+opencv完整检测代码①源代码②运行效果图第一章:霍夫变... 查看详情

python+opencv机器视觉-基于霍夫圈变换算法检测图像中的圆形实例演示(代码片段)

Python+opencv机器视觉-基于霍夫圈变换算法检测图像中的圆形实例演示第一章:霍夫变换检测圆①实例演示1②实例演示2③霍夫变换函数解析第二章:Python+opencv完整检测代码①源代码②运行效果图第一章:霍夫变... 查看详情

手势识别基于matlabpca+lda手语检测识别含matlab源码1551期(代码片段)

一、手势识别简介手势识别可以分为基于可穿戴设备的识别、基于触摸技术的识别和基于计算机视觉的识别。其中,基于计算机视觉的识别,手势图像信息由一个或多个摄像头采集,采集的数据进行预处理,包括... 查看详情

如何开展一个机器视觉检测项目?

当接触一个全新的机器视觉检测项目时,如何开展一个机器视觉检测项目?机器视觉检测项目基本流程有哪些?简单流程如下:确定客户需求、方案设计、软件开发、现场调试、文档交接。在实际项目中,各个流程可能互相耦合... 查看详情

毕业设计深度学习手势识别实现-pythonopencv机器视觉(代码片段)

...;各个学校对毕设的要求越来越高,难度也越来越大…毕业设计耗费时间,耗 查看详情

机器视觉的应用领域

...确定位  机器视觉系统的分类•智能相机•基于嵌入式•基于PC 机器视觉系统的组成•图像获取:光源、镜头、相机、采集卡、机械平台•图像处理与分析:工控主机、图像处理分析软件、图形交互界... 查看详情

毕业设计深度学习机器视觉人脸识别系统-opencvpython(代码片段)

...人脸检测人脸识别MetricLarning3最后0前言🔥这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统... 查看详情

机器视觉案例ai视觉,手势调节物体尺寸,附python完整代码(代码片段)

各位同学好,今天和大家分享一下如何使用opencv+mediapipe完成远程手势调节图片尺寸的案例。先放张图看效果。当拇指和食指竖起时,根据食指间的连线的长度自由缩放图片尺寸。图片的中点始终位于指尖连线的中点。... 查看详情

opencv调用手机摄像头与人脸检测(代码片段)

...、参考文献一、OpenCV机器视觉环境搭建1.OpenCV下载本文是基于Windows上Anaconda的OpenCV,在下载OpenCV前需要通过Anconda安装pyth 查看详情

机器视觉编程作业02(01)

背景:机器视觉课堂编程作业之二功能:实现边界检测、直线检测、圆检测使用平台:python36  opencv34注意事项:python36下的opencv34出现了一些函数的用法变动总体效果还是很好的。   显示效果:源代码:1#-*-coding:utf-... 查看详情