精华内容
下载资源
问答
  • 人体姿态估计(Human Posture Estimation),是通过将图片中已检测到的人体关键点正确的联系起来,从而估计人体姿态。 人体关键点通常对应人体上有一定自由度的关节,比如颈、肩、肘、腕、腰、膝、踝等,如下图。 ...

    目录

    1、人体姿态估计简介

    2、人体姿态估计数据集

    3、OpenPose库

    4、实现原理

    5、实现神经网络

    6、实现代码


    1、人体姿态估计简介

    人体姿态估计(Human Posture Estimation),是通过将图片中已检测到的人体关键点正确的联系起来,从而估计人体姿态。

    人体关键点通常对应人体上有一定自由度的关节,比如颈、肩、肘、腕、腰、膝、踝等,如下图。

     

    通过对人体关键点在三维空间相对位置的计算,来估计人体当前的姿态。

    进一步,增加时间序列,看一段时间范围内人体关键点的位置变化,可以更加准确的检测姿态,估计目标未来时刻姿态,以及做更抽象的人体行为分析,例如判断一个人是否在打电话等。

    人体姿态检测的挑战:

    1. 每张图片中包含的人的数量是未知的。
    2. 人与人之间的相互作用是非常复杂的,比如接触、遮挡等,这使得联合各个肢体,即确定一个人有哪些部分变得困难。
    3. 图像中人越多,计算复杂度越大(计算量与人的数量正相关),这使得实时检测变得困难。

    2、人体姿态估计数据集

    由于缺乏高质量的数据集,在人体姿势估计方面进展缓慢。在近几年中,一些具有挑战性的数据集已经发布,这使得研究人员进行研发工作。人体姿态估计常用数据集:

    3、OpenPose库

     OpenPose人体姿态识别项目是美国卡耐基梅隆大学(CMU)基于卷积神经网络和监督学习并以Caffe为框架开发的开源库。可以实现人体动作、面部表情、手指运动等姿态估计。适用于单人和多人,具有极好的鲁棒性。是世界上首个基于深度学习的实时多人二维姿态估计应用,基于它的实例如雨后春笋般涌现。

    其理论基础来自Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields ,是CVPR 2017的一篇论文,作者是来自CMU感知计算实验室的曹哲(http://people.eecs.berkeley.edu/~zhecao/#top),Tomas Simon,Shih-En Wei,Yaser Sheikh 。

    人体姿态估计技术在体育健身、动作采集、3D试衣、舆情监测等领域具有广阔的应用前景,人们更加熟悉的应用就是抖音尬舞机。

    OpenPose项目Github链接:https://github.com/CMU-Perceptual-Computing-Lab/openpose

    4、实现原理

    1. 输入一幅图像,经过卷积网络提取特征,得到一组特征图,然后分成两个岔路,分别使用 CNN网络提取Part Confidence Maps 和 Part Affinity Fields;
    2. 得到这两个信息后,我们使用图论中的 Bipartite Matching(偶匹配) 求出Part Association,将同一个人的关节点连接起来,由于PAF自身的矢量性,使得生成的偶匹配很正确,最终合并为一个人的整体骨架;
    3. 最后基于PAFs求Multi-Person Parsing—>把Multi-person parsing问题转换成graphs问题—>Hungarian Algorithm(匈牙利算法)

    (匈牙利算法是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。)

    5、实现神经网络

    阶段一:VGGNet的前10层用于为输入图像创建特征映射。

    阶段二:使用2分支多阶段CNN,其中第一分支预测身体部位位置(例如肘部,膝部等)的一组2D置信度图(S)。 如下图所示,给出关键点的置信度图和亲和力图 - 左肩。

    第二分支预测一组部分亲和度的2D矢量场(L),其编码部分之间的关联度。 如下图所示,显示颈部和左肩之间的部分亲和力。

    阶段三: 通过贪心推理解析置信度和亲和力图,对图像中的所有人生成2D关键点。

    6、实现代码

    import cv2 as cv
    import numpy as np
    import argparse
    
    parser = argparse.ArgumentParser()
    parser.add_argument('--input', help='Path to image or video. Skip to capture frames from camera')
    parser.add_argument('--thr', default=0.2, type=float, help='Threshold value for pose parts heat map')
    parser.add_argument('--width', default=368, type=int, help='Resize input to specific width.')
    parser.add_argument('--height', default=368, type=int, help='Resize input to specific height.')
    
    args = parser.parse_args()
    
    BODY_PARTS = { "Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
                   "LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
                   "RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
                   "LEye": 15, "REar": 16, "LEar": 17, "Background": 18 }
    
    POSE_PAIRS = [ ["Neck", "RShoulder"], ["Neck", "LShoulder"], ["RShoulder", "RElbow"],
                   ["RElbow", "RWrist"], ["LShoulder", "LElbow"], ["LElbow", "LWrist"],
                   ["Neck", "RHip"], ["RHip", "RKnee"], ["RKnee", "RAnkle"], ["Neck", "LHip"],
                   ["LHip", "LKnee"], ["LKnee", "LAnkle"], ["Neck", "Nose"], ["Nose", "REye"],
                   ["REye", "REar"], ["Nose", "LEye"], ["LEye", "LEar"] ]
    
    inWidth = args.width
    inHeight = args.height
    
    net = cv.dnn.readNetFromTensorflow("graph_opt.pb")
    
    cap = cv.VideoCapture(args.input if args.input else 0)
    
    while cv.waitKey(1) < 0:
        hasFrame, frame = cap.read()
        if not hasFrame:
            cv.waitKey()
            break
    
        frameWidth = frame.shape[1]
        frameHeight = frame.shape[0]
        
        net.setInput(cv.dnn.blobFromImage(frame, 1.0, (inWidth, inHeight), (127.5, 127.5, 127.5), swapRB=True, crop=False))
        out = net.forward()
        out = out[:, :19, :, :]  # MobileNet output [1, 57, -1, -1], we only need the first 19 elements
    
        assert(len(BODY_PARTS) == out.shape[1])
    
        points = []
        for i in range(len(BODY_PARTS)):
            # Slice heatmap of corresponging body's part.
            heatMap = out[0, i, :, :]
    
            # Originally, we try to find all the local maximums. To simplify a sample
            # we just find a global one. However only a single pose at the same time
            # could be detected this way.
            _, conf, _, point = cv.minMaxLoc(heatMap)
            x = (frameWidth * point[0]) / out.shape[3]
            y = (frameHeight * point[1]) / out.shape[2]
            # Add a point if it's confidence is higher than threshold.
            points.append((int(x), int(y)) if conf > args.thr else None)
    
        for pair in POSE_PAIRS:
            partFrom = pair[0]
            partTo = pair[1]
            assert(partFrom in BODY_PARTS)
            assert(partTo in BODY_PARTS)
    
            idFrom = BODY_PARTS[partFrom]
            idTo = BODY_PARTS[partTo]
    
            if points[idFrom] and points[idTo]:
                cv.line(frame, points[idFrom], points[idTo], (0, 255, 0), 3)
                cv.ellipse(frame, points[idFrom], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
                cv.ellipse(frame, points[idTo], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
    
        t, _ = net.getPerfProfile()
        freq = cv.getTickFrequency() / 1000
        cv.putText(frame, '%.2fms' % (t / freq), (10, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
    
        cv.imshow('OpenPose using OpenCV', frame)

    本项目实现代码及模型参见网址:https://download.csdn.net/download/m0_38106923/11265524

     关注公众号,发送关键字:关键点检测,获取资源。

    展开全文
  • 3D-SIFT关键点检测(基于曲率不变特征约束)

    一、算法原理

    见:PCL 3D-SIFT关键点检测(Z方向梯度约束)
    这个例子展示了如何估计SIFT点基于法向梯度,即使用曲率代替强度梯度。

    二、代码实现

    #include <iostream>
    #include <pcl/io/pcd_io.h>
    #include <pcl/keypoints/sift_keypoint.h>
    #
    展开全文
  • 一、NARF关键点提取 1、背景 关键点也称为兴趣点,是通过定义检测标准来获取的具有稳定性、区别性的点集。从技术上来说,关键点的数量要比原始点云的数目少很多,与局部特征描述子结合在一起,组成关键点描述子常...

    一、NARF关键点提取 

    1、背景

    关键点也称为兴趣点,是通过定义检测标准来获取的具有稳定性、区别性的点集。从技术上来说,关键点的数量要比原始点云的数目少很多,与局部特征描述子结合在一起,组成关键点描述子常用来形成原始数据的紧凑表示,而且不失代表性与描述性,从而加快识别、追踪有等对数据的处理速度。故而,关键点提取就成了2D和3D信息处理中不可或缺的关键技术。

    本例程将点云数据生成深度图数据,然后对深度图数据进行关键点提取,最后将关键点在点云视图中进行可视化

    2、关键点提取代码

    //提取NARF关键点
    pcl::RangeImageBorderExtractor range_image_border_extractor;//创建深度图像边界提取对象
    pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);//创建Narf关键点提取器,输入为深度图像边缘提取器
    narf_keypoint_detector.setRangeImage(&range_image);//关键点提取设置输入深度图像
    narf_keypoint_detector.getParameters().support_size=support_size;//关键点提取的参数:搜索空间球体的半径
    narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;//对竖直边是否感兴趣
    //narf_keypoint_detector.getParameters ().distance_for_additional_points = 10;//与support_size一起作用
    
    pcl::PointCloud<int> keypoint_indices;//关键点索引
    narf_keypoint_detector.compute(keypoint_indices);//关键点计算,结果放置到keypoint_indices
    std::cerr<<"Found "<<keypoint_indices.points.size()<<" key points.\n";//输出得到的NARF关键点数目

    3、全部代码

    /* \author Bastian Steder */
    
    #include <iostream>
    #include <boost/thread/thread.hpp>
    #include <pcl/range_image/range_image.h>
    #include <pcl/io/pcd_io.h>
    #include <pcl/visualization/range_image_visualizer.h>
    #include <pcl/visualization/pcl_visualizer.h>
    #include <pcl/features/range_image_border_extractor.h>
    #include <pcl/keypoints/narf_keypoint.h>//特征点提取头文件
    #include <pcl/console/parse.h>//命令行解析
    
    #include <pcl/visualization/common/float_image_utils.h>//保存深度图像相关头文件
    #include <pcl/io/png_io.h>//保存深度图像相关头文件
    
    typedef pcl::PointXYZ PointType;
    //参数
    float angular_resolution=0.5f;
    float support_size=0.2f;//默认关键点提取的参数(关键点提取器所支持的范围:搜索空间球体的半径,指定了计算感兴趣值的测度时所使用的邻域范围)
    pcl::RangeImage::CoordinateFrame coordinate_frame=pcl::RangeImage::CAMERA_FRAME;
    bool setUnseenToMaxRange=false;
    //打印帮助
    void
    printUsage(const char* progName)
    {
    std::cout<<"\n\nUsage: "<<progName<<" [options] <scene.pcd>\n\n"
    <<"Options:\n"
    <<"-------------------------------------------\n"
    <<"-r <float>   angular resolution in degrees (default "<<angular_resolution<<")\n"
    <<"-c <int>     coordinate frame (default "<<(int)coordinate_frame<<")\n"
    <<"-m           Treat all unseen points as maximum range readings\n"
    <<"-s <float>   support size for the interest points (diameter of the used sphere - "
    <<"default "<<support_size<<")\n"
    <<"-h           this help\n"
    <<"\n\n";
    }
    
    void
    setViewerPose(pcl::visualization::PCLVisualizer& viewer, const Eigen::Affine3f& viewer_pose)
    {
    Eigen::Vector3f pos_vector = viewer_pose*Eigen::Vector3f(0,0,0);
    Eigen::Vector3f look_at_vector=viewer_pose.rotation()*Eigen::Vector3f(0,0,1)+pos_vector;
    Eigen::Vector3f up_vector=viewer_pose.rotation()*Eigen::Vector3f(0,-1,0);
    viewer.setCameraPosition(pos_vector[0],pos_vector[1],pos_vector[2],
                             look_at_vector[0],look_at_vector[1],look_at_vector[2],
                             up_vector[0],up_vector[1],up_vector[2]);
    /*
    viewer.camera_.pos[0]=pos_vector[0];
    viewer.camera_.pos[1]=pos_vector[1];
    viewer.camera_.pos[2]=pos_vector[2];
    viewer.camera_.focal[0]=look_at_vector[0];
    viewer.camera_.focal[1]=look_at_vector[1];
    viewer.camera_.focal[2]=look_at_vector[2];
    viewer.camera_.view[0]=up_vector[0];
    viewer.camera_.view[1]=up_vector[1];
    viewer.camera_.view[2]=up_vector[2];
    viewer.updateCamera();
     */
    }
    
    // -----Main-----
    int
    main(int argc,char** argv)
    {
    //解析命令行参数
    if(pcl::console::find_argument(argc,argv,"-h")>=0)
    {
    printUsage(argv[0]);
    return 0;
    }
    if(pcl::console::find_argument(argc,argv,"-m")>=0)
    {
    setUnseenToMaxRange=true;
    cout<<"Setting unseen values in range image to maximum range readings.\n";
    }
    int tmp_coordinate_frame;
    if(pcl::console::parse(argc,argv,"-c",tmp_coordinate_frame)>=0)
    {
    coordinate_frame=pcl::RangeImage::CoordinateFrame(tmp_coordinate_frame);
    cout<<"Using coordinate frame "<<(int)coordinate_frame<<".\n";
    }
    if(pcl::console::parse(argc,argv,"-s",support_size)>=0)
    cout<<"Setting support size to "<<support_size<<".\n";
    if(pcl::console::parse(argc,argv,"-r",angular_resolution)>=0)
    cout<<"Setting angular resolution to "<<angular_resolution<<"deg.\n";
    angular_resolution=pcl::deg2rad(angular_resolution);
    //读取给定的pcd文件或者自行创建随机点云
    pcl::PointCloud<PointType>::Ptr point_cloud_ptr(new pcl::PointCloud<PointType>);
    pcl::PointCloud<PointType>&point_cloud=*point_cloud_ptr;
    pcl::PointCloud<pcl::PointWithViewpoint> far_ranges;
    Eigen::Affine3f scene_sensor_pose(Eigen::Affine3f::Identity());
    std::vector<int> pcd_filename_indices = pcl::console::parse_file_extension_argument(argc,argv,"pcd");
    if(!pcd_filename_indices.empty())
    {
    std::string filename=argv[pcd_filename_indices[0]];
    if(pcl::io::loadPCDFile(filename,point_cloud)==-1)//打开失败
    {
    cerr<<"Was not able to open file \""<<filename<<"\".\n";
    printUsage(argv[0]);
    return 0;
    }
    //打开pcd文件成功
    scene_sensor_pose=Eigen::Affine3f(Eigen::Translation3f(point_cloud.sensor_origin_[0],
    point_cloud.sensor_origin_[1],
    point_cloud.sensor_origin_[2]))*
    Eigen::Affine3f(point_cloud.sensor_orientation_);
    std::string far_ranges_filename = pcl::getFilenameWithoutExtension(filename)+"_far_ranges.pcd";
    if(pcl::io::loadPCDFile(far_ranges_filename.c_str(),far_ranges)==-1)//如果打开far_ranges文件失败
    std::cout<<"Far ranges file \""<<far_ranges_filename<<"\" does not exists.\n";
    }
    
    //没有给的输入点云,则生成一个点云
    else
    {
    setUnseenToMaxRange=true;
    cout<<"\nNo *.pcd file given =>Genarating example point cloud.\n\n";
    for(float x = -0.5f;x<=0.5f;x+=0.01f)
    {
    for(float y = -0.5f;y<=0.5f;y+=0.01f)
    {
    PointType point;point.x=x;point.y=y;point.z=2.0f-y;
    point_cloud.points.push_back(point);
    }
    }
    point_cloud.width=(int)point_cloud.points.size();point_cloud.height=1;//height = 1为无序点云
    }
    //从点云创建距离图像
    float noise_level=0.0;
    float min_range=0.0f;
    int border_size=1;//深度图边界大小
    boost::shared_ptr<pcl::RangeImage> range_image_ptr(new pcl::RangeImage);
    pcl::RangeImage&range_image=*range_image_ptr;
    //生成深度图像range_image
    range_image.createFromPointCloud(point_cloud,angular_resolution,pcl::deg2rad(360.0f),pcl::deg2rad(180.0f),scene_sensor_pose,coordinate_frame,noise_level,min_range,border_size);
    range_image.integrateFarRanges(far_ranges);//不是太懂
    if(setUnseenToMaxRange)
    range_image.setUnseenToMaxRange();
    // 创建3D点云可视化窗口,并显示点云
    pcl::visualization::PCLVisualizer viewer("3D Viewer");//3D窗口
    //第一个窗口,点云和关键点都显示
    int v1(0);
    viewer.createViewPort(0,0,0.5,1,v1);
    viewer.setBackgroundColor(255,1,1,v1);//背景颜色
    pcl::visualization::PointCloudColorHandlerCustom<PointType> color1(point_cloud_ptr,200,10,10);//输入点云的颜色
    //pcl::visualization::PointCloudColorHandlerCustom<pcl::PointWithRange>range_image_color_handler(range_image_ptr,0,0,0);//输入点云的颜色,赋值兼容规则
    viewer.addPointCloud(point_cloud_ptr,color1,"point_cloud",v1);//添加点云
    //viewer.addPointCloud(range_image_ptr,range_image_color_handler,"range image",v1);//添加点云
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,1,"range image",v1);//设置点的大小
    
    //第二个窗口,只显示关键点
    int v2(0);
    viewer.createViewPort(0.5,0,1,1,v2);
    viewer.setBackgroundColor(128,0,190,v2);
    
    //viewer.addCoordinateSystem (1.0f);
    //PointCloudColorHandlerCustom<PointType>point_cloud_color_handler (point_cloud_ptr, 150, 150, 150);
    //viewer.addPointCloud (point_cloud_ptr, point_cloud_color_handler, "original point cloud");
    viewer.initCameraParameters();
    setViewerPose(viewer,range_image.getTransformationToWorldSystem());
    // 显示距离图像
    pcl::visualization::RangeImageVisualizer range_image_widget("Range image");
    range_image_widget.showRangeImage(range_image);
    //保存深度图像
    float* ranges = range_image.getRangesArray();
    unsigned char* rgb_image = pcl::visualization::FloatImageUtils::getVisualImage(ranges,range_image.width,range_image.height);
    pcl::io::saveRgbPNGFile("range_image.png",rgb_image,range_image.width,range_image.height);//保存深度图像至range_image.png
    std::cerr << "range_image has been saved!" << std::endl;
    
    
    //提取NARF关键点
    pcl::RangeImageBorderExtractor range_image_border_extractor;//创建深度图像边界提取对象
    pcl::NarfKeypoint narf_keypoint_detector(&range_image_border_extractor);//创建Narf关键点提取器,输入为深度图像边缘提取器
    narf_keypoint_detector.setRangeImage(&range_image);//关键点提取设置输入深度图像
    narf_keypoint_detector.getParameters().support_size=support_size;//关键点提取的参数:搜索空间球体的半径
    narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;//对竖直边是否感兴趣
    //narf_keypoint_detector.getParameters ().distance_for_additional_points = 10;//与support_size一起作用
    
    pcl::PointCloud<int> keypoint_indices;//关键点索引
    narf_keypoint_detector.compute(keypoint_indices);//关键点计算,结果放置到keypoint_indices
    std::cerr<<"Found "<<keypoint_indices.points.size()<<" key points.\n";//输出得到的NARF关键点数目
    //保存关键点
    //转换关键点类型
    pcl::PointCloud<PointType>::Ptr narf_points_ptr(new pcl::PointCloud<PointType>);
    narf_points_ptr->width = keypoint_indices.points.size();
    narf_points_ptr->height = 1;
    narf_points_ptr->resize(keypoint_indices.points.size());
    narf_points_ptr->is_dense = false;
    for (size_t i = 0;i<keypoint_indices.points.size();i++)
    {
        narf_points_ptr->points[i].getVector3fMap() = range_image.points[keypoint_indices.points[i]].getVector3fMap();
    }
    //输出narf转换后的关键点
    std::cerr<<"narf_points: "<<narf_points_ptr->points.size()<<std::endl;
    //for (size_t i = 0;i<narf_points_ptr->points.size();i++)
    //   std::cerr<<"   ["<<i<<"]   "<<narf_points_ptr->points[i].x<<", "<<narf_points_ptr->points[i].y<<", "<<narf_points_ptr->points[i].z<<std::endl;
    //保存narf关键点
    pcl::io::savePCDFileASCII("narf_points.pcd",*narf_points_ptr);
    std::cerr<<"narf_points save succeed!"<<std::endl;
    //在距离图像显示组件内显示关键点
    //for (size_ti=0; i<keypoint_indices.points.size (); ++i)
    //range_image_widget.markPoint (keypoint_indices.points[i]%range_image.width,
    //keypoint_indices.points[i]/range_image.width);
    //在3D窗口中显示关键点
    pcl::PointCloud<pcl::PointXYZ>::Ptr keypoints_ptr(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>&keypoints=*keypoints_ptr;
    keypoints.points.resize(keypoint_indices.points.size());
    for(size_t i=0;i<keypoint_indices.points.size();++i)
    keypoints.points[i].getVector3fMap()=range_image.points[keypoint_indices.points[i]].getVector3fMap();//将得到的关键点转换给keypoints(pcl::PointCloud<pcl::PointXYZ>类型)
    //设置关键点在3D Viewer中的颜色大小属性
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>keypoints_color_handler(keypoints_ptr,0,255,0);//颜色
    viewer.addPointCloud<pcl::PointXYZ>(keypoints_ptr,keypoints_color_handler,"keypoints");//显示
    viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,7,"keypoints");//关键点的大小
    // 主循环
    while(!viewer.wasStopped())
    {
    range_image_widget.spinOnce();// process GUI events
    viewer.spinOnce();
    pcl_sleep(0.01);
    }
    }
    

    4、可视化 

    1)、

    将” narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;//对竖直边是否感兴趣”设置为不感兴趣(false<默认>),此时关键点少

    2)、

    将” narf_keypoint_detector.getParameters ().add_points_on_straight_edges = true;//对竖直边是否感兴趣”设置为感兴趣(true),此时关键点多 

    二、SIFT关键点提取

    1、背景

    本例程将演示如何检测点云的SIFT关键点。SIFT,即尺度不变特征变换(Scale-invariant feature transform, SIFT),最初是图像处理领域的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征描述子,后来被引入3D点云领域用于关键点检测。

    2、SIFT检测代码

      const float min_scale = atof(argv[2]);//尺度空间中最小尺度的标准偏差
      const int n_octaves = atoi(argv[3]);//高斯金字塔中组的数目
      const int n_scales_per_octave = atoi(argv[4]);//每组计算的尺度数目
      const float min_contrast = atof(argv[5]);//设置关键点检测的阈值
    
      //SIFT关键点检测
      pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;//创建sift关键点检测对象
      pcl::PointCloud<pcl::PointWithScale> result;//SIFT关键点提取结果
      sift.setInputCloud(cloud_xyz);//设置输入点云
      pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ> ());
      sift.setSearchMethod(tree);//创建一个空的kd树对象tree,并把它传递给sift检测对象
      sift.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
      sift.setMinimumContrast(min_contrast);//设置限制关键点检测的阈值
      sift.compute(result);//执行sift关键点检测,保存结果在result

    3、全部代码

    #include <iostream>
    #include <pcl/io/pcd_io.h>
    #include <pcl/point_types.h>
    #include <pcl/common/io.h>
    #include <pcl/keypoints/sift_keypoint.h>
    #include <pcl/features/normal_3d.h>
    #include <pcl/visualization/pcl_visualizer.h>
    #include <pcl/console/time.h>
    using namespace std;
    
    namespace pcl
    {
      template<>
        struct SIFTKeypointFieldSelector<PointXYZ>
        {
          inline float
          operator () (const PointXYZ &p) const
          {
        return p.z;
          }
        };
    }
    
    int
    main(int argc, char *argv[])
    {
    
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointXYZ>);
      pcl::io::loadPCDFile (argv[1], *cloud_xyz);//将第二个命令行参数所代表的文件作为输入文件读入
    
      const float min_scale = atof(argv[2]);//尺度空间中最小尺度的标准偏差
      const int n_octaves = atoi(argv[3]);//高斯金字塔中组的数目
      const int n_scales_per_octave = atoi(argv[4]);//每组计算的尺度数目
      const float min_contrast = atof(argv[5]);//设置关键点检测的阈值
    
      //SIFT关键点检测
      pcl::SIFTKeypoint<pcl::PointXYZ, pcl::PointWithScale> sift;//创建sift关键点检测对象
      pcl::PointCloud<pcl::PointWithScale> result;//SIFT关键点提取结果
      sift.setInputCloud(cloud_xyz);//设置输入点云
      pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ> ());
      sift.setSearchMethod(tree);//创建一个空的kd树对象tree,并把它传递给sift检测对象
      sift.setScales(min_scale, n_octaves, n_scales_per_octave);//指定搜索关键点的尺度范围
      sift.setMinimumContrast(min_contrast);//设置限制关键点检测的阈值
      sift.compute(result);//执行sift关键点检测,保存结果在result
    
      //类型转换
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_temp (new pcl::PointCloud<pcl::PointXYZ>);
      copyPointCloud(result, *cloud_temp);//将点类型pcl::PointWithScale的数据转换为点类型pcl::PointXYZ的数据
     
      //可视化输入点云和关键点
      pcl::visualization::PCLVisualizer viewer("Sift keypoint");
      viewer.setBackgroundColor( 255, 255, 255 );
      viewer.addPointCloud(cloud_xyz, "cloud");//在视窗中添加原始点云数据
      viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,0,"cloud");
      viewer.addPointCloud(cloud_temp, "keypoints");//将SIFT关键点添加至视窗
      viewer.setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 9, "keypoints");
      viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,255,"keypoints");
    
      while(!viewer.wasStopped ())
      {
        viewer.spinOnce ();
      }
      return 0;
      
    }

    4、可视化

    三、Harris关键点提取

    1、背景

     本小结将演示如何检测点云的3D Harris角点。Harris算子是常见的特征检测算子,既可以提取角点又可以提取边缘点。与2D Harris角点检测原理不同,3D Harris角点检测利用的就是点云的法向量信息。

    2、Harris关键点提取代码

    	pcl::PointCloud<pcl::PointXYZI>::Ptr Harris_keypoints (new pcl::PointCloud<pcl::PointXYZI> ());//存放最后的特征点提取结果
    	//实例化一个Harris特征检测对象harris_detector
    	pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal>* harris_detector = new pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal> ;
    
    	//harris_detector->setNonMaxSupression(true);
    	harris_detector->setRadius(r_normal);//设置法向量估计的半径
    	harris_detector->setRadiusSearch(r_keypoint);//设置关键点估计的近邻搜索半径
    	harris_detector->setInputCloud (input_cloud);//设置输入点云
    	//harris_detector->setNormals(normal_source);
    	//harris_detector->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::LOWE);
    	harris_detector->compute (*Harris_keypoints);//结果存放在Harris_keypoints
    	cout<<"Harris_keypoints number: "<<Harris_keypoints->size()<<endl;
    	//writer.write<pcl::PointXYZI> ("Harris_keypoints.pcd",*Harris_keypoints,false);//结果保存

    3、全部代码

    #include <iostream>
    #include <pcl/io/pcd_io.h>
    #include <pcl/point_cloud.h>
    #include <pcl/visualization/pcl_visualizer.h>
    #include <pcl/io/io.h>
    #include <pcl/keypoints/harris_3d.h>//harris特征点估计类头文件声明
    #include <cstdlib>
    #include <vector>
    #include <pcl/console/parse.h>
    using namespace std;
    
    
    
    int main(int argc,char *argv[]) 
    {
    	pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud (new pcl::PointCloud<pcl::PointXYZ>);//输入点云的指针
    	pcl::io::loadPCDFile (argv[1], *input_cloud);//将命令行参数文件读至input_cloud指针
    	pcl::PCDWriter writer;
    	float r_normal;//法向量估计的半径
    	float r_keypoint;//关键点估计的近邻搜索半径
    
    	r_normal=atof(argv[2]);//将命令行的第三个参数解析为法向量估计的半径
    	r_keypoint=atof(argv[3]);//将命令行的第四个参数解析为关键点估计的近邻搜索半径
    
    	typedef pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZI> ColorHandlerT3;
    
    	pcl::PointCloud<pcl::PointXYZI>::Ptr Harris_keypoints (new pcl::PointCloud<pcl::PointXYZI> ());//存放最后的特征点提取结果
    	//实例化一个Harris特征检测对象harris_detector
    	pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal>* harris_detector = new pcl::HarrisKeypoint3D<pcl::PointXYZ,pcl::PointXYZI,pcl::Normal> ;
    
    	//harris_detector->setNonMaxSupression(true);
    	harris_detector->setRadius(r_normal);//设置法向量估计的半径
    	harris_detector->setRadiusSearch(r_keypoint);//设置关键点估计的近邻搜索半径
    	harris_detector->setInputCloud (input_cloud);//设置输入点云
    	//harris_detector->setNormals(normal_source);
    	//harris_detector->setMethod(pcl::HarrisKeypoint3D<pcl::PointXYZRGB,pcl::PointXYZI>::LOWE);
    	harris_detector->compute (*Harris_keypoints);//结果存放在Harris_keypoints
    	cout<<"Harris_keypoints number: "<<Harris_keypoints->size()<<endl;
    	//writer.write<pcl::PointXYZI> ("Harris_keypoints.pcd",*Harris_keypoints,false);//结果保存
    	pcl::io::savePCDFileASCII("Harris keypoints.pcd" , *Harris_keypoints);
    	cout<<"Points: "<<Harris_keypoints->points.size()<<endl;
    
    	//可视化点云
    	pcl::visualization::PCLVisualizer visu3("clouds");
    	visu3.setBackgroundColor(255,255,255);
    	//Harris_keypoints关键点可视化
    	visu3.addPointCloud (Harris_keypoints, ColorHandlerT3 (Harris_keypoints, 0.0, 0.0, 255.0), "Harris_keypoints");
    	visu3.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE,8,"Harris_keypoints");
    	//原始点云可视化
    	visu3.addPointCloud(input_cloud,"input_cloud");
    	visu3.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR,0,0,0,"input_cloud");
    	visu3.spin ();
    }

    4、可视化

    深度图: 

    展开全文
  • OpenCV实现人体姿态估计(人体关键点检测)OpenPose

    万次阅读 多人点赞 2019-08-04 11:53:03
    OpenCV实现人体姿态估计(人体关键点检测)OpenPose OpenPose人体姿态识别项目是美国卡耐基梅隆大学(CMU)基于卷积神经网络和监督学习并以Caffe为框架开发的开源库。可以实现人体动作、面部表情、手指运动等姿态...

    OpenCV实现人体姿态估计(人体关键点检测)OpenPose


    OpenPose人体姿态识别项目是美国卡耐基梅隆大学(CMU)基于卷积神经网络和监督学习并以Caffe为框架开发的开源库。可以实现人体动作、面部表情、手指运动等姿态估计。适用于单人和多人,具有极好的鲁棒性。是世界上首个基于深度学习的实时多人二维姿态估计应用,基于它的实例如雨后春笋般涌现。

    其理论基础来自Realtime Multi-Person 2D Pose Estimation using Part Affinity Fields ,是CVPR 2017的一篇论文,作者是来自CMU感知计算实验室的曹哲(http://people.eecs.berkeley.edu/~zhecao/#top),Tomas Simon,Shih-En Wei,Yaser Sheikh 。

    人体姿态估计技术在体育健身、动作采集、3D试衣、舆情监测等领域具有广阔的应用前景,人们更加熟悉的应用就是抖音尬舞机。

    OpenPose的效果并不怎么好,强烈推荐《2D Pose人体关键点检测(Python/Android /C++ Demo)https://panjinquan.blog.csdn.net/article/details/115765863 ,提供了C++推理代码和Android Demo

    OpenPose项目Github链接:https://github.com/CMU-Perceptual-Computing-Lab/openpose

    OpenCV实现的Demo链接:https://github.com/PanJinquan/opencv-learning-tutorials/blob/master/opencv_dnn_pro/openpose-opencv/openpose_for_image_test.py


    1、实现原理

    输入一幅图像,经过卷积网络提取特征,得到一组特征图,然后分成两个岔路,分别使用 CNN网络提取Part Confidence Maps 和 Part Affinity Fields;


    得到这两个信息后,我们使用图论中的 Bipartite Matching(偶匹配) 求出Part Association,将同一个人的关节点连接起来,由于PAF自身的矢量性,使得生成的偶匹配很正确,最终合并为一个人的整体骨架;
    最后基于PAFs求Multi-Person Parsing—>把Multi-person parsing问题转换成graphs问题—>Hungarian Algorithm(匈牙利算法)
    (匈牙利算法是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法。)


    2、实现神经网络

    阶段一:VGGNet的前10层用于为输入图像创建特征映射。

    阶段二:使用2分支多阶段CNN,其中第一分支预测身体部位位置(例如肘部,膝部等)的一组2D置信度图(S)。 如下图所示,给出关键点的置信度图和亲和力图 - 左肩。

    第二分支预测一组部分亲和度的2D矢量场(L),其编码部分之间的关联度。 如下图所示,显示颈部和左肩之间的部分亲和力。

    阶段三: 通过贪心推理解析置信度和亲和力图,对图像中的所有人生成2D关键点。


    3.OpenCV-OpenPose实现推理代码

    # -*-coding: utf-8 -*-
    """
        @Project: python-learning-notes
        @File   : openpose_for_image_test.py
        @Author : panjq
        @E-mail : pan_jinquan@163.com
        @Date   : 2019-07-29 21:50:17
    """
    
    import cv2 as cv
    import os
    import glob
    
    BODY_PARTS = {"Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
                  "LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
                  "RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
                  "LEye": 15, "REar": 16, "LEar": 17, "Background": 18}
    
    POSE_PAIRS = [["Neck", "RShoulder"], ["Neck", "LShoulder"], ["RShoulder", "RElbow"],
                  ["RElbow", "RWrist"], ["LShoulder", "LElbow"], ["LElbow", "LWrist"],
                  ["Neck", "RHip"], ["RHip", "RKnee"], ["RKnee", "RAnkle"], ["Neck", "LHip"],
                  ["LHip", "LKnee"], ["LKnee", "LAnkle"], ["Neck", "Nose"], ["Nose", "REye"],
                  ["REye", "REar"], ["Nose", "LEye"], ["LEye", "LEar"]]
    
    
    def detect_key_point(model_path, image_path, out_dir, inWidth=368, inHeight=368, threshhold=0.2):
        net = cv.dnn.readNetFromTensorflow(model_path)
        frame = cv.imread(image_path)
        frameWidth = frame.shape[1]
        frameHeight = frame.shape[0]
        scalefactor = 2.0
        net.setInput(
            cv.dnn.blobFromImage(frame, scalefactor, (inWidth, inHeight), (127.5, 127.5, 127.5), swapRB=True, crop=False))
        out = net.forward()
        out = out[:, :19, :, :]  # MobileNet output [1, 57, -1, -1], we only need the first 19 elements
        assert (len(BODY_PARTS) == out.shape[1])
        points = []
        for i in range(len(BODY_PARTS)):
            # Slice heatmap of corresponging body's part.
            heatMap = out[0, i, :, :]
            # Originally, we try to find all the local maximums. To simplify a sample
            # we just find a global one. However only a single pose at the same time
            # could be detected this way.
            _, conf, _, point = cv.minMaxLoc(heatMap)
            x = (frameWidth * point[0]) / out.shape[3]
            y = (frameHeight * point[1]) / out.shape[2]
            # Add a point if it's confidence is higher than threshold.
            points.append((int(x), int(y)) if conf > threshhold else None)
        for pair in POSE_PAIRS:
            partFrom = pair[0]
            partTo = pair[1]
            assert (partFrom in BODY_PARTS)
            assert (partTo in BODY_PARTS)
    
            idFrom = BODY_PARTS[partFrom]
            idTo = BODY_PARTS[partTo]
    
            if points[idFrom] and points[idTo]:
                cv.line(frame, points[idFrom], points[idTo], (0, 255, 0), 3)
                cv.ellipse(frame, points[idFrom], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
                cv.ellipse(frame, points[idTo], (3, 3), 0, 0, 360, (0, 0, 255), cv.FILLED)
    
        t, _ = net.getPerfProfile()
        freq = cv.getTickFrequency() / 1000
        cv.putText(frame, '%.2fms' % (t / freq), (10, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
    
        cv.imwrite(os.path.join(out_dir, os.path.basename(image_path)), frame)
        cv.imshow('OpenPose using OpenCV', frame)
        cv.waitKey(0)
    
    
    def detect_image_list_key_point(image_dir, out_dir, inWidth=480, inHeight=480, threshhold=0.3):
        image_list = glob.glob(image_dir)
        for image_path in image_list:
            detect_key_point(image_path, out_dir, inWidth, inHeight, threshhold)
    
    
    if __name__ == "__main__":
        model_path = "pb/graph_opt.pb"
        # image_path = "body/*.jpg"
        out_dir = "result"
        # detect_image_list_key_point(image_path,out_dir)
        image_path = "./test.jpg"
        detect_key_point(model_path, image_path, out_dir, inWidth=368, inHeight=368, threshhold=0.05)

    参考资料:

    [1].https://blog.csdn.net/m0_38106923/article/details/89416514

    展开全文
  • 人脸关键点检测总结

    万次阅读 多人点赞 2018-05-31 10:38:21
    人脸关键点检测也称为人脸关键点检测、定位或者人脸对齐,是指给定人脸图像,定位出人脸面部的关键区域位置,包括眉毛、眼睛、鼻子、嘴巴、脸部轮廓等。 人脸关键点检测方法大致分为三种: - 基于模型的ASM(Active...
  • 使用Albumentations 对关键点 做增强

    万次阅读 2021-05-20 16:05:34
    您可以对具有关键点的图像使用任何像素级增强,因为像素级增强不会影响关键点。 注意:默认情况下,与关键点配合使用的增强功能不会在转换后更改关键点的标签。 如果要点的标签是特定于侧面的,则可能会引
  • 人体骨骼关键点检测综述

    万次阅读 多人点赞 2018-06-11 12:53:45
    其它机器学习、深度学习算法的全面系统讲解可以阅读《机器学习-原理、算法与应用》,清华大学出版社,雷明著,由SIGAI公众号作者倾力打造。...近年来,随着深度学习技术的发展,人体骨骼关键点检测效果不断...
  • 点云配准中,有时候点云数量太大,需要进行关键点提取,下面介绍几种点云pcl中点云关键点提取算法。 一、iss关键点提取 iss关键点的具体原理可以查看相关论文,下面主要参数设置如下: //iss关键点提取 Point...
  • 人脸关键点定义汇总

    千次阅读 2019-10-23 13:53:53
    前几天看一份代码临时需要找49个人脸关键点位置定义的图片发现怎么百度都搜不到,最后幸好谷歌可以使用了就用谷歌搜到了。所以在这里汇总一下我所知道的人脸关键点的定义和相关的一点东西,以备不时之需。 68个关键...
  • 人体关键点姿态识别

    千次阅读 2020-10-27 18:06:54
    通过检测人体行为表达过程中,每一帧人体姿态关键部位的位置,将人体姿态简化为人体关键点,并通过这些关键点对人体姿态表达的语义进行分类识别。 基于关键点的人体姿态识别可分为两个方面,即静态的人体姿态识别与...
  • 人脸关键点检测 face keypoint detect

    千次阅读 多人点赞 2019-08-18 23:27:39
    人脸关键点检测 人脸关键点检测,广泛使用的数据集是300W 以及300VW, 为68个关键点。 github demos 结构 该文的实现,主要是使用wing loss,多任务学习以及基于头部姿态以及眼睛和嘴巴姿态的数据增强。 模型只使用...
  • 利用openpose跑关键点

    千次阅读 2019-06-10 23:51:27
    这个开源代码写的太详细,功能也集成得比较杂,而我只需要拿来跑一下关键点。因此大部分步骤我都不需要,我觉得有很多人和我一样不需要其他的,因此记录一下我跑通的简化的步骤: Table of Contents 一、克隆代码 ...
  • 人体骨骼关键点检测

    千次阅读 2019-05-16 17:05:27
    AI Challenger 其中的人体骨骼关键点检测主要依赖的技术背景为Human pose estimation。 该领域分为单人和多人两类,根据竞赛数据集来看,该任务为mult-person pose estimation。以下先介绍该竞赛的相技术背景。 --...
  • 一、人脸关键点检测数据库 (2001年发布)BioID :约1000幅图像,每个人脸标定20个关键点。 https://www.bioid.com/About/BioID-Face-Database (2011年发布)LFPW:1132幅图像,每个人脸标定29个关键点 ...
  • 人脸关键点数据集整理

    千次阅读 2019-07-31 20:05:08
    常见的几种关键点数据集有5关键点、21关键点、68关键点、98关键点等。还有一些超过100个关键点的数据集,这些数据集具有商业价值等原因,所以一般都不会公开。 1. 数据集下载: 数据集 介绍 链接 300W ...
  • 开源人脸106关键点

    千次阅读 2020-01-10 18:56:11
    开源人脸106关键点 https://github.com/zeusees/HyperLandmarkgithub地址,高精度https://github.com/lsy17096535/face-landmarkgithub地址,低精度 HyperLandmark-开源人脸106点关键点检测SDK ...
  • 人脸关键点提取(dlib)

    千次阅读 热门讨论 2017-10-12 17:33:29
    人脸关键点检测
  • 人脸关键点对齐

    千次阅读 2018-09-18 16:24:53
    摘要: 从传统方法到深度学习方法,对人脸关键点定位/人脸对齐的发展进行梳理,对该领域中经典的方法,最新成果进行汇总,并给出相应的paper原文,项目主页及代码链接。重点介绍深度学习的几种最新方法。 1. ...
  • DAN —— 人脸关键点

    万次阅读 2017-09-04 16:47:48
    人脸关键点检测的论文。速度略差,但想法不错。 视频中人脸关键点检测往往存在抖动,而常见的深度学习方法又不适合做连续跟踪。 本文提供了一个实现跟踪的思路。文章链接: CVPR Workshop2017《Deep Alignment ...
  • 81个人脸关键点检测

    千次阅读 2019-03-27 20:25:43
    之前运行过Dlib,主要是做了68个人脸关键点的检测,其对应的68个人脸关键点如下图: ​ 其中关于dlib的68个点的使用可参考:https://blog.csdn.net/xingchenbingbuyu/article/details/51116354 本文讲的demo是在...
  • 人体关键点检测数据集

    千次阅读 2020-07-20 11:06:27
    欢迎光临,谢谢指正 数据集 1、MSCOCO 目前COCO keypoint ...而人体关键点检测的任务就是从输入的图片中检测到人体及对应的关键点位置。 MSCOCO样本数多于30W,多人关键点检测的主要数据集,主流数据集; ...
  • 人脸关键点序号

    千次阅读 2019-10-31 18:55:45
    106关键点: forked from 北京智云视图科技有限公司 / HyperLandmark 68和106对应,从0开始编号: 17-19 21-28 22-24 26-74 36-94 39-59 42-27 45-20 31-31 35-93 48-45 54-50 57-32 8 -0* add_new_pic.object...
  • 人脸关键点检测是人脸识别和分析领域中的关键一步,它是诸如自动人脸识别、表情分析、三维人脸重建及三维动画等其它人脸相关问题的前提和突破口。近些年来,深度学习方法由于其自动学习及持续学习能力,已被成功应用...
  • 购买课程后,添加小助手微信(微信号:itxy41)回复【唐宇迪】 进入学习群,获取唐宇迪老师社群答疑 深度学习项目实战-关键点定位课程以人脸关键点检测为背景,选择多阶段检测的网络架构,对于回归以及多label标签...
  • python 实现81个人脸关键点实时检测

    千次阅读 2019-03-26 18:47:21
    python 实现81个人脸关键点实时检测文章目录:一、81个关键点介绍二、81 个关键点的使用 该库也是基于dlib实现的,还有face_recognition也同样是基于dlib来实现的 一、81个关键点介绍 先来仔细看一看这只...
  • 人体关键点检测数据集介绍

    千次阅读 2019-05-22 17:13:39
    一、COCO数据集 ... 训练集和验证集数据整体...每个人体关键点个数的分布情况,其中11-15这个范围的人体是最多的,有接近70000人,6-10其次,超过40000人,后面依次为16-17,2-5,1. K(BLOHKM) = (20000*13 +9*4...
  • 参考: ... ... 1. 导言 人体骨骼关键点对于描述人体姿态,预测人体行为至关重要。因此人体骨骼关键点检测是诸多计算机视觉任务的基础,例如动作分类,异常行为...
  • RetinaFace 人脸关键点

    千次阅读 2019-11-07 16:48:57
    这个113m https://github.com/supernotman/RetinaFace_Pytorch hopenet 可以从别的地方下载,1070 人脸检测30ms ... c++ 106关键点: https://github.com/Char...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,362,625
精华内容 545,050
关键字:

关键点