谈谈NiTE 2手部跟踪在彩色图像上的显示

主要内容:

  • NiTE2手部跟踪流程
  • 代码演示
  • 总结

一、NiTE2手部跟踪流程

  我自己都感觉到天天在重复着相同的代码,但我觉得没什么不好的,对于新东西的学习只有在重复再重复的过程中,才能积累经验,较少犯“低级错误”的几率,所以在开始之前,让我们再熟练熟练NITE 2的手部跟踪流程,主要包括以下几个步骤:

  1. 初始化NITE环境: nite::NiTE::initialize();

  2. 创建HandTracker手部跟踪器: HandTracker mHandTracker; mHandTracker.create(&mDevice);

  3. 设定手势探测(GESTURE_WAVE、GESTURE_CLICK和GESTURE_HAND_RAISE):mHandTracker.startGestureDetection( GESTURE_WAVE );等等;

  4. 创建并读取HandTracker Frame信息:HandTrackerFrameRef mHandFrame;  mHandTracker.readFrame( &mHandFrame );

  5. 整个界面帧信息进行分析,统计得到符合的手势信息:const nite::Array<GestureData>& aGestures = mHandFrame.getGestures();

  6. 通过跟踪得到的手势信息,开始对该特定手进行手部跟踪:const Point3f& rPos = rGesture.getCurrentPosition();HandId mHandID;  mHandTracker.startHandTracking( rPos, &mHandID );

  7. 读取并统计目前被跟踪的手信息:const nite::Array<HandData>& aHands = mHandFrame.getHands();

  8. 确定手部是否属于跟踪状态,开始自己的操作:

  if( rHand.isTracking() )
     {
      // 得到手心坐标
      const Point3f& rPos = rHand.getPosition();

    。。。

    }

  9. 关闭跟踪器:mHandTracker.destroy();

  10. 最后关闭NITE环境:nite::NiTE::shutdown();

二、代码演示

  在谈谈NITE 2与OpenCV结合的第一个程序和谈谈NITE 2与OpenCV结合提取指尖坐标中我们都是在深度图像中对获得的手部信息进行处理,但不知道在彩色图像中,手部跟踪获得手心坐标是怎么样的?是否也和深度图像显示一样,能够很好的定位到真正的手心中?为了回答自己的这些问题,模仿谈谈人体骨骼坐标在彩色图像中显示中的方法,将通过NiTE2手部跟踪得到的手心坐标映射到彩色图像和深度图像中,并显示对比。具体解释和代码如下:

#include "stdafx.h"
#include <iostream>// OpenCV 头文件
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>#include <OpenNI.h>
#include <NiTE.h>using namespace std;
using namespace openni;
using namespace nite;int main( int argc, char **argv )
{// 初始化OpenNI
    OpenNI::initialize();// 打开Kinect设备
    Device  mDevice;mDevice.open( ANY_DEVICE );// 创建深度数据流
    VideoStream mDepthStream;mDepthStream.create( mDevice, SENSOR_DEPTH );// 设置VideoMode模式
    VideoMode mDepthMode;mDepthMode.setResolution( 640, 480 );mDepthMode.setFps( 30 );mDepthMode.setPixelFormat( PIXEL_FORMAT_DEPTH_1_MM );mDepthStream.setVideoMode(mDepthMode);// 同样的设置彩色数据流
    VideoStream mColorStream;mColorStream.create( mDevice, SENSOR_COLOR );// 设置VideoMode模式
    VideoMode mColorMode;mColorMode.setResolution( 640, 480 );mColorMode.setFps( 30 );mColorMode.setPixelFormat( PIXEL_FORMAT_RGB888 );mColorStream.setVideoMode( mColorMode);// 设置深度图像映射到彩色图像
    mDevice.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR );// 为了得到骨骼数据,先初始化NiTE
    NiTE::initialize();// 创建HandTracker跟踪器
    HandTracker mHandTracker;mHandTracker.create(&mDevice);// 设定手势探测(GESTURE_WAVE、GESTURE_CLICK和GESTURE_HAND_RAISE)
    mHandTracker.startGestureDetection( GESTURE_WAVE );mHandTracker.startGestureDetection( GESTURE_CLICK );//mHandTracker.startGestureDetection( GESTURE_HAND_RAISE );
mHandTracker.setSmoothingFactor(0.1f);// 创建深度图像显示cv::namedWindow("Depth Image", CV_WINDOW_AUTOSIZE);// 创建彩色图像显示cv::namedWindow( "Hand Image",  CV_WINDOW_AUTOSIZE );// 环境初始化后,开始获取深度数据流和彩色数据流
    mDepthStream.start();mColorStream.start();// 获得最大深度值int iMaxDepth = mDepthStream.getMaxPixelValue();while( true ){// 创建OpenCV::Mat,用于显示彩色数据图像
        cv::Mat cImageBGR;// 读取深度数据帧信息流
        VideoFrameRef mDepthFrame;mDepthStream.readFrame(&mDepthFrame);// 读取彩色数据帧信息流
        VideoFrameRef mColorFrame;mColorStream.readFrame( &mColorFrame );//将深度数据转换成OpenCV格式const cv::Mat mImageDepth( mDepthFrame.getHeight(), mDepthFrame.getWidth(), CV_16UC1, (void*)mDepthFrame.getData());// 为了让深度图像显示的更加明显一些,将CV_16UC1 ==> CV_8U格式
        cv::Mat mScaledDepth;mImageDepth.convertTo( mScaledDepth, CV_8U, 255.0 / iMaxDepth );// 将彩色数据流转换为OpenCV格式,记得格式是:CV_8UC3(含R\G\B)const cv::Mat mImageRGB( mColorFrame.getHeight(), mColorFrame.getWidth(),CV_8UC3, (void*)mColorFrame.getData() );// RGB ==> BGR
        cv::cvtColor( mImageRGB, cImageBGR, CV_RGB2BGR );// 读取帧信息
        HandTrackerFrameRef mHandFrame;mHandTracker.readFrame( &mHandFrame );// 整个界面帧信息进行分析,找到符合的手势const nite::Array<GestureData>& aGestures = mHandFrame.getGestures();for( int i = 0; i < aGestures.getSize(); ++ i ){const GestureData& rGesture = aGestures[i];// 得到的手势信息中还包含了当前手势的坐标位置const Point3f& rPos = rGesture.getCurrentPosition();cout << " 手势位置为: (" << rPos.x << ", " << rPos.y << ", " << rPos.z << ")" << endl;// 得到手势识别后,开始手部跟踪
            HandId mHandID;mHandTracker.startHandTracking( rPos, &mHandID );cout << "确定手势位置,开始手部跟踪" << endl;}const nite::Array<HandData>& aHands = mHandFrame.getHands();for( int i = 0; i < aHands.getSize(); ++ i ){const HandData& rHand = aHands[i];if( rHand.isNew() )cout << " Start tracking";else if( rHand.isLost() )cout << " Lost";// 确定手部是否属于跟踪状态if( rHand.isTracking() ){// 得到手心坐标const Point3f& rPos = rHand.getPosition();cout << " at " << rPos.x << ", " << rPos.y << ", " << rPos.z;cv::Point2f aPoint;mHandTracker.convertHandCoordinatesToDepth(rPos.x, rPos.y, rPos.z, &aPoint.x, &aPoint.y);// 将手心坐标映射到彩色图像和深度图像中cv::circle( cImageBGR, aPoint, 3, cv::Scalar( 0, 0, 255 ), 4 );cv::circle( mScaledDepth, aPoint, 3, cv::Scalar(0, 0, 255), 4);// 在彩色图像中画出手的轮廓边
                cv::Point2f ctlPoint, ctrPoint, cdlPoint, cdrPoint;ctlPoint.x = aPoint.x - 100;ctlPoint.y = aPoint.y - 100;ctrPoint.x = aPoint.x - 100;ctrPoint.y = aPoint.y + 100;cdlPoint.x = aPoint.x + 100;cdlPoint.y = aPoint.y - 100;cdrPoint.x = aPoint.x + 100;cdrPoint.y = aPoint.y + 100;cv::line( cImageBGR, ctlPoint, ctrPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( cImageBGR, ctlPoint, cdlPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( cImageBGR, cdlPoint, cdrPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( cImageBGR, ctrPoint, cdrPoint, cv::Scalar( 255, 0, 0 ), 3 );// 在深度图像中画出手的轮廓边
                cv::Point2f mtlPoint, mtrPoint, mdlPoint, mdrPoint;mtlPoint.x = aPoint.x - 100;mtlPoint.y = aPoint.y - 100;mtrPoint.x = aPoint.x - 100;mtrPoint.y = aPoint.y + 100;mdlPoint.x = aPoint.x + 100;mdlPoint.y = aPoint.y - 100;mdrPoint.x = aPoint.x + 100;mdrPoint.y = aPoint.y + 100;cv::line( mScaledDepth, mtlPoint, mtrPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( mScaledDepth, mtlPoint, mdlPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( mScaledDepth, mdlPoint, mdrPoint, cv::Scalar( 255, 0, 0 ), 3 );cv::line( mScaledDepth, mtrPoint, mdrPoint, cv::Scalar( 255, 0, 0 ), 3 );}}// 显示图像cv::imshow( "Depth Image", mScaledDepth );cv::imshow( "Hand Image", cImageBGR );// 按键“q”退出循环if( cv::waitKey( 1 ) == 'q' )break;}// 先销毁手部跟踪器
    mHandTracker.destroy();// 销毁彩色数据流和深度数据流
    mColorStream.destroy();mDepthStream.destroy();// 关闭Kinect设备
    mDevice.close();// 关闭NITE和OpenNI环境
    NiTE::shutdown();OpenNI::shutdown();return 0;
}

程序运行结果见下图:

接着画出手部运动轨迹,直接上代码:

#include <array>
#include <iostream>
#include <map>
#include <vector>// OpenCV 头文件
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>// NiTE 头文件
#include <OpenNI.h>
#include <NiTE.h>using namespace std;
using namespace openni;
using namespace nite;int main( int argc, char **argv )
{// 初始化OpenNI
    OpenNI::initialize();// 打开Kinect设备
    Device  mDevice;mDevice.open( ANY_DEVICE );// 创建深度数据流
    VideoStream mDepthStream;mDepthStream.create( mDevice, SENSOR_DEPTH );// 设置VideoMode模式
    VideoMode mDepthMode;mDepthMode.setResolution( 640, 480 );mDepthMode.setFps( 30 );mDepthMode.setPixelFormat( PIXEL_FORMAT_DEPTH_1_MM );mDepthStream.setVideoMode(mDepthMode);// 同样的设置彩色数据流
    VideoStream mColorStream;mColorStream.create( mDevice, SENSOR_COLOR );// 设置VideoMode模式
    VideoMode mColorMode;mColorMode.setResolution( 640, 480 );mColorMode.setFps( 30 );mColorMode.setPixelFormat( PIXEL_FORMAT_RGB888 );mColorStream.setVideoMode( mColorMode);// 设置深度图像映射到彩色图像
    mDevice.setImageRegistrationMode( IMAGE_REGISTRATION_DEPTH_TO_COLOR );// 初始化 NiTEif( NiTE::initialize() != nite::STATUS_OK ){cerr << "NiTE initial error" << endl;return -1;}// 创建HandTracker跟踪器
    HandTracker mHandTracker;if( mHandTracker.create() != nite::STATUS_OK ){cerr << "Can't create user tracker" << endl;return -1;}// 设定手势探测(GESTURE_WAVE、GESTURE_CLICK和GESTURE_HAND_RAISE)
    mHandTracker.startGestureDetection( GESTURE_WAVE );mHandTracker.startGestureDetection( GESTURE_CLICK );//mHandTracker.startGestureDetection( GESTURE_HAND_RAISE );
mHandTracker.setSmoothingFactor(0.1f);// 创建深度图像显示cv::namedWindow("Depth Image", CV_WINDOW_AUTOSIZE);// 创建彩色图像显示cv::namedWindow( "Color Image",  CV_WINDOW_AUTOSIZE );// 保存点坐标map< HandId,vector<cv::Point2f> > mapHandData;vector<cv::Point2f> vWaveList;vector<cv::Point2f> vClickList;cv::Point2f ptSize( 3, 3 );array<cv::Scalar,8>    aHandColor;aHandColor[0] = cv::Scalar( 255, 0, 0 );aHandColor[1] = cv::Scalar( 0, 255, 0 );aHandColor[2] = cv::Scalar( 0, 0, 255 );aHandColor[3] = cv::Scalar( 255, 255, 0 );aHandColor[4] = cv::Scalar( 255, 0, 255 );aHandColor[5] = cv::Scalar( 0, 255, 255 );aHandColor[6] = cv::Scalar( 255, 255, 255 );aHandColor[7] = cv::Scalar( 0, 0, 0 );// 环境初始化后,开始获取深度数据流和彩色数据流
    mDepthStream.start();mColorStream.start();// 获得最大深度值int iMaxDepth = mDepthStream.getMaxPixelValue();// startwhile( true ){// 创建OpenCV::Mat,用于显示彩色数据图像
        cv::Mat cImageBGR;// 读取彩色数据帧信息流
        VideoFrameRef mColorFrame;mColorStream.readFrame( &mColorFrame );// 将彩色数据流转换为OpenCV格式,记得格式是:CV_8UC3(含R\G\B)const cv::Mat mImageRGB( mColorFrame.getHeight(), mColorFrame.getWidth(),CV_8UC3, (void*)mColorFrame.getData() );// RGB ==> BGR
        cv::cvtColor( mImageRGB, cImageBGR, CV_RGB2BGR );// 获取手Frame
        HandTrackerFrameRef mHandFrame;if( mHandTracker.readFrame( &mHandFrame ) == nite::STATUS_OK ){openni::VideoFrameRef mDepthFrame = mHandFrame.getDepthFrame();// 将深度数据转换成OpenCV格式const cv::Mat mImageDepth( mDepthFrame.getHeight(), mDepthFrame.getWidth(), CV_16UC1, (void*)mDepthFrame.getData() );// 为了让深度图像显示的更加明显一些,将CV_16UC1 ==> CV_8U格式
            cv::Mat mScaledDepth, mImageBGR;mImageDepth.convertTo( mScaledDepth, CV_8U, 255.0 / 10000 );// 将灰度图转换成BGR格式,为了画出点的颜色坐标和轨迹
            cv::cvtColor( mScaledDepth, mImageBGR, CV_GRAY2BGR );// 检测手势const nite::Array<GestureData>& aGestures = mHandFrame.getGestures();for( int i = 0; i < aGestures.getSize(); ++ i ){const GestureData& rGesture = aGestures[i];const Point3f& rPos = rGesture.getCurrentPosition();cv::Point2f rPos2D;mHandTracker.convertHandCoordinatesToDepth( rPos.x, rPos.y, rPos.z, &rPos2D.x, &rPos2D.y );// 画点switch( rGesture.getType() ){case GESTURE_WAVE:vWaveList.push_back( rPos2D );break;case GESTURE_CLICK:vClickList.push_back( rPos2D );break;}// 手部跟踪
                HandId mHandID;if( mHandTracker.startHandTracking( rPos, &mHandID ) != nite::STATUS_OK )cerr << "Can't track hand" << endl;}// 得到手心坐标const nite::Array<HandData>& aHands = mHandFrame.getHands();for( int i = 0; i < aHands.getSize(); ++ i ){const HandData& rHand = aHands[i];HandId uID = rHand.getId();if( rHand.isNew() ){mapHandData.insert( make_pair( uID, vector<cv::Point2f>() ) );}if( rHand.isTracking() ){// 将手心坐标映射到彩色图像和深度图像中const Point3f& rPos = rHand.getPosition();cv::Point2f rPos2D;mHandTracker.convertHandCoordinatesToDepth( rPos.x, rPos.y, rPos.z, &rPos2D.x, &rPos2D.y );mapHandData[uID].push_back( rPos2D );}if( rHand.isLost() )mapHandData.erase( uID );}// 画点和轨迹for( auto itHand = mapHandData.begin(); itHand != mapHandData.end(); ++ itHand ){const cv::Scalar& rColor = aHandColor[ itHand->first % aHandColor.size() ];const vector<cv::Point2f>& rPoints = itHand->second;for( int i = 1; i < rPoints.size(); ++ i ){cv::line( mImageBGR, rPoints[i-1], rPoints[i], rColor, 2 );cv::line( cImageBGR, rPoints[i-1], rPoints[i], rColor, 2 );}}// 画 click gesture 轨迹for( auto itPt = vClickList.begin(); itPt != vClickList.end(); ++ itPt ){cv::circle( mImageBGR, *itPt, 5, cv::Scalar( 0, 0, 255 ), 2 );cv::circle( cImageBGR, *itPt, 5, cv::Scalar( 0, 0, 255 ), 2 );}// 画 wave gesture 轨迹for( auto itPt = vWaveList.begin(); itPt != vWaveList.end(); ++ itPt ){cv::rectangle( mImageBGR, *itPt - ptSize, *itPt + ptSize, cv::Scalar( 0, 255, 0 ), 2 );cv::rectangle( cImageBGR, *itPt - ptSize, *itPt + ptSize, cv::Scalar( 0, 255, 0 ), 2 );}// 显示imagecv::imshow( "Depth Image", mImageBGR );cv::imshow("Color Image", cImageBGR);mHandFrame.release();}else{cerr << "Can't get new frame" << endl;}// 按键“q”退出循环if( cv::waitKey( 1 ) == 'q' )break;}mHandTracker.destroy();mColorStream.destroy();NiTE::shutdown();OpenNI::shutdown();return 0;
}

运行结果:

三、总结

  最后说明的是:根据自己的感觉写代码,没做封装、优化、重构,完全是面向过程,而且肯定还存在细节的问题,会在后面进一步优化的。    写的粗糙,欢迎指正批评~~~

转载于:https://www.cnblogs.com/yemeishu/archive/2013/01/29/2881445.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/266462.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 应用是单机集群_【架构】Tomcat单机部署多应用Windows

Tomcat单机部署多应用-Windows1、添加新增的Tomcat相关环境变量CATALINA_BASE C:\tomcat1CATALINA_HOME C:\tomcat1TOMCAT_HOME C:\tomcat1CATALINA_2_BASE C:\tomcat2CATALINA_2_HOME C:\tomcat2TOMCAT_2_HOME C:\tomcat22、第一个tomcat不变3、打开第二个tomcat目录bin…

java long类型转string_JavaSE的学习——数据类型

数据类型分为基本数据类型和引用数据类型两大类在下面数据类型的介绍中只会介绍8种基本数据类型和引用数据类型中的类类型中的一个类String基本数据类型1. 计算机中的存储单位8bit 1byte 1024byte 1KB 1024KB 1M1024M 1GB1024GB 1T2. 整数型数据byte short int long1.long…

DWTagList

2019独角兽企业重金招聘Python工程师标准>>> DWTagList 根据给定的 NSArray 数组来创建标签列表&#xff0c;可自定义字体、颜色和其他属性。 转载:http://www.adobex.com/ios/source/details/00000820.htm 转载于:https://my.oschina.net/u/868244/blog/106245

爬虫(爬虫原理与数据抓取)

通用爬虫和聚焦爬虫 根据使用场景&#xff0c;网络爬虫可分为 通用爬虫 和 聚焦爬虫 两种. 通用爬虫 通用网络爬虫 是 捜索引擎抓取系统&#xff08;Baidu、Google、Yahoo等&#xff09;的重要组成部分。主要目的是将互联网上的网页下载到本地&#xff0c;形成一个互联网内容的…

SQL Server Insert 操作效率(堆表 VS 聚集索引表)

“SQL Server的Insert操作在堆表或者聚集索引表的时候&#xff0c;哪个效率更高&#xff1f;为什么高&#xff1f;” 之前有同事问过我这个问题&#xff0c;为了确保日志库的记录效率&#xff0c;于是我做了简单测试了&#xff0c;首先要先强调几点概念&#xff1a; 堆表&#…

electron 打包_Vue3+Electron整合方式

教程源码&#xff1a;nofacer/vue3-electron​github.com之前写过一篇文章Vue结合Electron构建跨平台应用&#xff08;TDD&#xff09;。当时的方法后来发现了一个问题&#xff0c;就是打包后的应用拿到其他机子上没法用&#xff0c;原因在于index.html的地址是个绝对路径&…

Linux按照时间顺序列出文件

按照递增时间顺序列出所有文件 ls -ltr -l表示列出长串数据&#xff0c;-t表示按照时间顺序&#xff0c;-r表示将排序的结果反向输出 按照时间递减的顺序列出所有文件 ls -lt 转载于:https://www.cnblogs.com/yongjieShi/p/9395932.html

RestKit

2019独角兽企业重金招聘Python工程师标准>>> Restkit 是一个开源的 objective-c 框架&#xff0c;允许在 iOS 和 Mac OS X 的 Objective-C 中与 RESTful Web 服务进行交互&#xff0c;包含简单的 HTTP request/response API &#xff0c;带有强大的对象映射系统用于…

全国计算机等级考试题库二级C操作题100套(第41套)

更多干货推荐可以去牛客网看看&#xff0c;他们现在的IT题库内容很丰富&#xff0c;属于国内做的很好的了&#xff0c;而且是课程刷题面经求职讨论区分享&#xff0c;一站式求职学习网站&#xff0c;最最最重要的里面的资源全部免费&#xff01;&#xff01;&#xff01;点击进…

2012年终总结 二

2019独角兽企业重金招聘Python工程师标准>>> 接上文。。。 经过一些搜索和了解之后&#xff0c;最后选定了我现在这个公司。现在&#xff0c;至少我没有感觉到我选错。 刚近公司&#xff0c;进行了新人的入职培训1天&#xff0c;这个主要是了解公司状况。而后&…

python语言包括哪些实现_Python语言基础考察点:python语言基础常见考题(一)

一、python是静态还是动态类型&#xff1f;是强类型还是弱类型&#xff1f; 1、动态强类型语言(不少人误以为是弱类型) 不要傻傻分不清 2、动态还是静态指的是编译期还是运行期确定类型 3、强类型指的是不会发生隐式类型转换 若类型语言强类型语言4、python作为后端语言优缺点 …

由于开发者通过接口修改了菜单配置_开发者说:Seata 0.7.0 版本,你 get 'Metrics' 技能了吗?...

从用户的视角来感受一个开源项目的成长&#xff0c;是我们推出「开发者说」专栏的初衷&#xff0c;即在开发者进行开源项目选型时&#xff0c;提供更为立体的项目信息。专栏所有内容均来自作者原创/投稿&#xff0c;本文是「开发者说」的第9篇&#xff0c;作者郑扬勇&#xff0…

Java 多线程(三) 线程的生命周期及优先级

Java 多线程&#xff08;三&#xff09; 线程的生命周期及优先级 线程的生命周期 线程的生命周期&#xff1a;一个线程从创建到消亡的过程。 如下图&#xff0c;表示线程生命周期中的各个状态&#xff1a; 线程的生命周期可以分为四个状态&#xff1a; 1.创建状态&#xff1a; …

eclipse 导入maven项目_手把手的Spring Boot Web 项目教程,Hello Spring Boot

在开始之前&#xff0c;我们需要去创建一个SpringBoot项目&#xff0c;大家可以去 http://start.spring.io/ 这个网站生成一个项目。如图&#xff0c;这边可以对SpringBoot项目进行详细设置&#xff1a;下面这个web一定要勾选&#xff1a;SpringBoot版本号选择1.5.10全部设置好…

ASP.Net中实现中英文复合检索文本框

前段时间&#xff0c;写一个用户部门的管理页面&#xff0c;需要对后台获取的用户数据实现英汉检索功能。  同时&#xff0c;选定一个选项之后&#xff0c;需要触发事件与后台交互&#xff0c;将该用户所在的部门显示到页面右边的ListBox控件中。 一、Dojo的FilteringSelect组…

sklearn 安装_初识sklearn

我的主业是互联网运营&#xff0c;业余的python爱好者&#xff0c;学习python已经快两年&#xff0c;主攻网络爬虫与数据分析&#xff0c;爬虫能使用代理ip、打码平台、OCR识别、基本的js逆向处理反爬&#xff1b;数据分析主要使用pandas与pyecharts进行可视化&#xff0c;我的…

[工具库]JOJSONBuilder工具类——一键把多个bean对象数据转换为JSON格式数据

本人大四即将毕业的准程序员&#xff08;JavaSE、JavaEE、android等&#xff09;一枚&#xff0c;小项目也做过一点&#xff0c;于是乎一时兴起就写了一些工具。 我会在本博客中陆续发布一些平时可能会用到的工具。 代码质量可能不是很好&#xff0c;大家多担待&#xff01; 代…

mysql long类型_怒肝两个月MySQL源码,我总结出这篇2W字的MySQL协议详解(超硬核干货)!!...

点击上方蓝色“冰河技术”&#xff0c;关注并选择“设为星标”持之以恒&#xff0c;贵在坚持&#xff0c;每天进步一点点&#xff01;作者个人研发的在高并发场景下&#xff0c;提供的简单、稳定、可扩展的延迟消息队列框架&#xff0c;具有精准的定时任务和延迟队列处理功能。…

状压dp之二之三 炮兵阵地/玉米田 By cellur925

一、简单的状压dp 玉米田 题目描述 Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares…

LockSupport的源码实现原理以及应用

一、为什么使用LockSupport类 如果只是LockSupport在使用起来比Object的wait/notify简单&#xff0c; 那还真没必要专门讲解下LockSupport。最主要的是灵活性。 上边的例子代码中&#xff0c;主线程调用了Thread.sleep(1000)方法来等待线程A计算完成进入wait状态。如果去掉Thr…