目录
1、最近要做一个Unity中显示相机画面中手指的最高点,然后有蝴蝶飞上去的项目,所以涉及到了OpenCV在Unity中的使用+OpenCV获取手指的最高点等等
1、如何利用opencv的库测量手指长度 [问题点数:20分]:
①总结:good:有实现方法,能借鉴,将原本代码稍微修改了一下,运行效果如下:
6、python-opencv2利用cv2.findContours()函数来查找检测物体的轮廓
①总结:pass:自己复制下来后运行到一些地方就会直接报错,无法执行下去
9、OpenCV3之——查找并绘制轮廓findContours()和drawContours()
①总结:good:可以实现,值得参考,总共2个程序,运行如下图:
10、OpenCV简单粗糙的指尖检测方法(FingerTips Detection)
①总结:good:代码1、代码2、修改后运行摄像头的运行效果如下图:
①总结:good:代码按照截图抄下来,运行如下、抄写的代码如下;but:有时候运行一段时间会出现vector超出数组长度
13、OpenCV简单粗糙的指尖检测方法(FingerTips Detection)
①总结:good:代码能够直接运行,代码1+代码2运行如下图;but:背景不要有类肤色,如果有,就需要加其他信息来排除干扰
①总结:good:运行结果如下,需要将图片保存下来,路径修改一下;but:曾经将其修改为相机的,但是受周围环境的影响太大了:
16、在C#中使用OpenCV(使用OpenCVSharp)
①总结:good:下载的工程运行效果如下图:打开相机+识别相机画面中的人脸;but:发布到了安卓手机上面,发现和电脑端不一样,点击按钮没有反应,只有相机画面
一、目的:
1、最近要做一个Unity中显示相机画面中手指的最高点,然后有蝴蝶飞上去的项目,所以涉及到了OpenCV在Unity中的使用+OpenCV获取手指的最高点等等
一、参考:
1、如何利用opencv的库测量手指长度 [问题点数:20分]:
https://bbs.csdn.net/topics/392569485
①总结:pass:只说了思想,没有实现的方法,
2、opencv实现简单手指位置识别
https://blog.csdn.net/u013294888/article/details/73477734
①总结:good:有实现方法,能借鉴,将原本代码稍微修改了一下,运行效果如下:
// FingerRecognition.cpp : 定义控制台应用程序的入口点。
//
//
//整体思路:
//
//1.过滤噪声
//
//2.由于RGB颜色的离散性转换为HSV通道
//
//3.对HSV空间进行量化,得到2值图像,亮的部分为手的形状
//
//4.去除杂点造成的伪轮廓,留下手的真实轮廓
//
//5.对凸出点连线
//
//6.最高点到底部中点的连线即为手指方向
//
部分代码:
//将MFC实现部分给省略了,给出了完整的opencv部分代码,可以参考实现。
#include "stdafx.h"
#include "stdlib.h"
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
int main()
{
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
return -1;
}
//
cv::Mat frame;
cv::Mat frameHSV;
//
std::vector< std::vector<cv::Point> > OriginalContours;//轮廓
std::vector< cv::Vec4i > hierarchy; // 轮廓的结构信息
//
std::vector< std::vector<cv::Point> > FinalContours;// 筛选后的轮廓
std::vector< cv::Point > hull; // 凸包络的点集
//
//CString Str;
string Str;
int i, j;
int Width = cap.get(CV_CAP_PROP_FRAME_WIDTH), Height = cap.get(CV_CAP_PROP_FRAME_HEIGHT);
float fHeight = ((float)2 / 3 - (float)1 / 7) * Height;
//
//while (0 == pDlg->m_bStopFlag)
while (1)
{
cap >> frame;
if (frame.empty())
{
break;
}
//左右翻转
cv::flip(frame, frame, 1);
//中值滤波,用了这个下面的其他滤波全部异常
//medianBlur(frame, frame, 10);
//高斯滤波
cv::GaussianBlur(frame, frame, cv::Size(7, 7), 1.5, 1.5);
//通道转换
cv::cvtColor(frame, frameHSV, CV_BGR2HSV);
//imshow("frameHSV", frameHSV);
/*
S = 符号整型 U = 无符号整型 F = 浮点型
E.g.:
CV_8UC1 是指一个8位无符号整型单通道矩阵,
CV_32FC2是指一个32位浮点型双通道矩阵
CV_8UC1 CV_8SC1 CV_16U C1 CV_16SC1
CV_8UC2 CV_8SC2 CV_16UC2 CV_16SC2
CV_8UC3 CV_8SC3 CV_16UC3 CV_16SC3
CV_8UC4 CV_8SC4 CV_16UC4 CV_16SC4
CV_32SC1 CV_32FC1 CV_64FC1
CV_32SC2 CV_32FC2 CV_64FC2
CV_32SC3 CV_32FC3 CV_64FC3
CV_32SC4 CV_32FC4 CV_64FC4
*/
// 对HSV空间进行量化,得到2值图像,亮的部分为手的形状
cv::Mat mask(frame.rows, frame.cols, CV_8UC1);
//inRange(frameHSV, cv::Scalar(0, 30, 30), cv::Scalar(40, 170, 256), mask);
inRange(frameHSV, cv::Scalar(5, 30, 30), cv::Scalar(40, 170, 256), mask);
//
// 腐蚀:去除小亮点 膨胀:连接区块
cv::erode(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 1);
//cv::dilate(mask, mask, cv::Mat(5, 5, CV_8U), cv::Point(-1, -1), 2);
//imshow("frameHSV", frameHSV);
//imshow("mask", mask);
OriginalContours.clear();
hierarchy.clear();
FinalContours.clear();
// 得到手的轮廓
cv::findContours(mask, OriginalContours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
// 去除伪轮廓
for (i = 0; i < OriginalContours.size(); i++)
{
if (fabs(cv::contourArea(cv::Mat(OriginalContours[i]))) > 25000)
{
FinalContours.push_back(OriginalContours[i]);
}
}
// 画轮廓
cv::drawContours(frame, FinalContours, -1, cv::Scalar(0, 0, 255), 3);
// 得到轮廓的凸包络
int hullcount;
int iNumOfContours = FinalContours.size();
cv::Point top;
for (j = 0; j < iNumOfContours; j++)
{
convexHull(cv::Mat(FinalContours[j]), hull, true);
hullcount = (int)hull.size();
//
for (i = 0; i<hullcount - 1; i++)
{
cv::line(frame, hull[i + 1], hull[i], cv::Scalar(255, 0, 0), 2, CV_AA);
}
cv::line(frame, hull[hullcount - 1], hull[0], cv::Scalar(255, 0, 0), 2, CV_AA);
//画点
// GetTopPoint(hull, hullcount, top);
cv::line(frame, top, top, cv::Scalar(255, 0, 255), 18, CV_AA);
cv::line(frame, top, cv::Point(Width / 2, Height), cv::Scalar(0, 255, 255), 2, CV_AA);
//
if (1 == iNumOfContours)
{
//pDlg->m_FingerPosition.bChanged = 1;
//pDlg->m_FingerPosition.top = ((float)top.y - (float)Height / 7) / fHeight;
//pDlg->m_FingerPosition.left = (float)top.x / (float)Width;
}
}
//
cv::line(frame, cv::Point(0, Height / 7), cv::Point(Width, Height / 7), cv::Scalar(255, 255, 255), 2, CV_AA);
cv::line(frame, cv::Point(0, 2 * Height / 3), cv::Point(Width, 2 * Height / 3), cv::Scalar(255, 255, 255), 2, CV_AA);
imshow("frame", frame);
cv::waitKey(33);
}
return 0;
}
3、基于 OpenCv 和 Python 的手指识别及追踪
https://www.leiphone.com/news/201808/hWpuSivLzkKrqSCs.html
①总结:pass:没有实现的方法,
4、opencv 手势识别
https://www.cnblogs.com/snake-hand/p/3187044.html
①总结:pass:没有实现的方法,
5、OpenCV+python手势识别框架和实例讲解
https://www.jb51.net/article/144995.htm
①总结:待整理
6、python-opencv2利用cv2.findContours()函数来查找检测物体的轮廓
https://blog.csdn.net/hjxu2016/article/details/77833336
①总结:pass:python写的,暂时在c++中实现不了
7、OpenCV FindContours使用
https://blog.csdn.net/ktigerhero3/article/details/88314729
①总结:good:第一个、第二个运行效果如下图,可以参考:
8、关于findContours的一些知识点
https://blog.csdn.net/m0_37350758/article/details/82016820
①总结:pass:自己复制下来后运行到一些地方就会直接报错,无法执行下去
9、OpenCV3之——查找并绘制轮廓findContours()和drawContours()
https://blog.csdn.net/qq_35294564/article/details/82947011
①总结:good:可以实现,值得参考,总共2个程序,运行如下图:
10、OpenCV简单粗糙的指尖检测方法(FingerTips Detection)
https://blog.csdn.net/ytffhew/article/details/84076849
①总结:pass:代码执行不了,很乱
11、使用opencv提取手部信息
https://blog.csdn.net/zhyh1435589631/article/details/53293211
①总结:good:代码1、代码2、修改后运行摄像头的运行效果如下图:
12、手势检测及手掌质心的运动轨迹(opencv)
https://blog.csdn.net/logan_lin/article/details/79517571
①总结:good:代码按照截图抄下来,运行如下、抄写的代码如下;but:有时候运行一段时间会出现vector超出数组长度
//成功:显示视频中手势
//参考:https://blog.csdn.net/logan_lin/article/details/79517571
#include "stdafx.h"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
Point Ycrcb_Otsu_detect(Mat & src);
Point image_centrt(Mat& src, vector<vector<Point>>&filterContours, Mat&output_mask);
int main()
{
VideoCapture cap;
cap.open(0);
if (!cap.isOpened())
{
cout << "相机没有打开!"<<endl;
return -1;
}
Mat frame;
Mat HSV;
Mat Ycrcb;
Point center;
vector<Point> center_all;
while (1)
{
cap >> frame;
center = Ycrcb_Otsu_detect(frame);
center_all.push_back(center);
if (center_all.size()!=1)
{
for (int i=0;i<center_all.size()-1;i++)
{
line(frame, center_all[i], center_all[i + 1], Scalar(128, 255, 128), 2);
}
}
imshow("frame", frame);
waitKey(100);
}
return 0;
}
Point Ycrcb_Otsu_detect(Mat & src)
{
Mat ycrcb_image;
GaussianBlur(src, src, Size(7, 7), 3, 3);
cvtColor(src, ycrcb_image, CV_BGR2YCrCb);
Mat detect;
vector <Mat> channels;
split(ycrcb_image, channels);
Mat output_mask = channels[1];
threshold(output_mask, output_mask, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU);
src.copyTo(detect, output_mask);
imshow("Ycrcb_output_mask", output_mask);
vector<vector<Point>> contours;
vector<vector<Point>> filterContours;
vector<Vec4i> hierarchy;
findContours(output_mask, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
int index;
for (int i=0;i<contours.size();i++)
{
int square = fabs(contourArea(Mat(contours[i])));
if (fabs(contourArea(Mat(contours[i])))>100&&fabs((contourArea(Mat(contours[i])))>10000)) //数字根据实际情况调整
{
filterContours.push_back(contours[i]);
index = i;
}
}
drawContours(src, filterContours, -1, Scalar(0, 255, 255), 3);
Point center;
center = image_centrt(src, filterContours, output_mask);
return center;
}
Point image_centrt(Mat& src, vector<vector<Point>>&filterContours, Mat&output_mask)
{
Point center;
if (filterContours.size()!=0)
{
Moments moment = moments(output_mask, true); //求取质心
center = Point(moment.m10 / moment.m00, moment.m01 / moment.m00);
circle(src, center, 5, Scalar(0, 0, 255), CV_FILLED);
vector<Point> hull;
vector<int> hull_i;
vector<Vec4i> defect;
for (int i=0;i<filterContours.size();i++)
{
convexHull(Mat(filterContours[i]), hull, true);
convexHull(Mat(filterContours[i]), hull_i, false);
convexityDefects(Mat(filterContours[i]), hull_i, defect);
int hullcount = (int)hull.size();
for (int j=0;j<hullcount-1;j++)
{
circle(src, hull[j], 3, Scalar(255, 0, 0), CV_FILLED);
}
vector<Vec4i>::iterator d = defect.begin();
while (d != defect.end())
{
Vec4i& v = (*d);
int startidex = v[0];
Point ptStart(filterContours[i][startidex]); //一堆凸包中的第一个点
int endidx = v[i];
Point ptEnd(filterContours[i][endidx]); //一堆凸包中的最后以恶搞点
int faridx = v[2];
Point ptFar(filterContours[i][faridx]); //凹点
int depth = v[3] / 256; //凹点和凸点的距离
if (depth>20&&depth<140)
{
line(src, ptStart, ptFar, CV_RGB(0, 255, 0), 2);
line(src, ptEnd, ptFar, CV_RGB(0, 255, 0), 2);
circle(src, ptStart, 4, Scalar(255, 0, 100), 2);
circle(src, ptEnd, 4, Scalar(255, 0, 100), 2);
circle(src, ptFar, 4, Scalar(100, 0, 255), 2);
}
d++;
}
}
}
return center;
}
13、OpenCV简单粗糙的指尖检测方法(FingerTips Detection)
https://blog.csdn.net/augusdi/article/details/8865589
①总结:good:代码能够直接运行,代码1+代码2运行如下图;but:背景不要有类肤色,如果有,就需要加其他信息来排除干扰
14、用opencv检测convexity defects
http://blog.csdn.net/lichengyu/article/details/38392473
①总结:good:运行结果如下,需要将图片保存下来,路径修改一下;but:曾经将其修改为相机的,但是受周围环境的影响太大了:
15、基于OpenCVSharp的图像处理软件
https://blog.csdn.net/you_big_father/article/details/86088531
①总结:good;了解了有C#封装好的OpenCV;
16、在C#中使用OpenCV(使用OpenCVSharp)
https://www.cnblogs.com/jsxyhelu/p/9669583.html
①总结:good:了解有C#封装好的OpenCV;
17、Unity使用OpenCvSharp人脸识别
https://blog.csdn.net/AWNUXCVBN/article/details/51629404
①总结:good:下载的工程运行效果如下图:打开相机+识别相机画面中的人脸;but:发布到了安卓手机上面,发现和电脑端不一样,点击按钮没有反应,只有相机画面