(1)打开摄像头获取输入
VideoCapture capture;
capture.open(0);
if (!capture.isOpened())
{
perror("open camera error!");
}
double rate = 24;
bool stop(false);
Mat frame;
namedWindow("original img");
namedWindow("output img");
int delay = 1000 / rate;
(2)进行肤色检测
Mat img = src.clone();
Mat ycrcb_img;
cvtColor(img, ycrcb_img, COLOR_BGR2YCrCb);
vector<Mat> y_cr_cb;
split(ycrcb_img, y_cr_cb);
Mat CR = y_cr_cb[1];
Mat CB = y_cr_cb[2];
Mat imgout = Mat::zeros(img.size(), CV_8UC1);
for (int i = 0; i < img.rows; i++)
{
for (int j = 0; j < img.cols; j++)
{
if (CR.at<uchar>(i, j) > 133 && CR.at<uchar>(i, j) < 173 && CB.at<uchar>(i, j) > 77 && CB.at<uchar>(i, j) < 127)
{
imgout.at<uchar>(i, j) = 255;
}
}
}
img.copyTo(detected_one, imgout);
(3)获取轮廓和提取特征
threshold(outimg, two_img, 50, 255, THRESH_BINARY);
dilate(two_img, close_noise, Mat());
Canny(two_two_img, Canny_img, 50, 200);
/***傅里叶变换后的系数储存在f[d]中***/
vector<float>f;
vector<float>fd;//最终傅里叶描绘子前14位
Point p;
for (int i = 0; i < max_size; i++)//主要的计算部分
{
float x, y, sumx = 0, sumy = 0;
for (int j = 0; j < max_size; j++)
{
p = contours[contour_num].at(j);
x = p.x;
y = p.y;
sumx += (float)(x * cos(2 * CV_PI * i * j / max_size) + y * sin(2 * CV_PI * i * j / max_size));
sumy += (float)(y * cos(2 * CV_PI * i * j / max_size) - x * sin(2 * CV_PI * i * j / max_size));
}
f.push_back(sqrt((sumx * sumx) + (sumy * sumy)));
}
for (int k = 2; k < 16; k++)//进行归一化,然后放入最终结果中
{
f[k] = f[k] / f[1];
fd.push_back(f[k]);
}
out = Mat::zeros(1, fd.size(), CV_32F);//out是用于输出的手势特征
for (int i = 0; i < fd.size(); i++)
{
out.at<float>(i) = fd[i];
}
这样我们得到了手势的特征。
(1)采集样本手势并提取特征
提前准备好手势图片样本,建议获取不同人正反面手势,然后进行旋转获得更多手势。
void getXML()
{
FileStorage fs("get_xml.xml", FileStorage::WRITE);
if (!fs.isOpened())
{
perror("open xml error!");
}
Mat feture_data;
Mat classes = Mat::zeros(30, 1, CV_8UC1);
char path[100];
Mat img_read;
for (int i = 1; i <= 3; i++)//手势种类
{
for (int j = 1; j <= 10; j++)每个种类个数
{
sprintf_s(path, "sample_picture\\images\\%d_%d.png", i, j);
img_read = imread(path);
Mat back_img;
thre_two(img_read, back_img);
feture_data.push_back(big_contours(back_img));
classes.at<uchar>((i - 1) * 10 + j - 1) = i - 1;
}
}
fs << "Feture_Data" << feture_data;
fs << "Classes" << classes;
fs.release();
}
(2)神经网络训练
void ann_go(Ptr<ANN_MLP>& ann, int numC, int nlay)
{
Mat feture_data, classes;
FileStorage fs("get_xml.xml", FileStorage::READ);
fs["Feture_Data"] >> feture_data;
fs["Classes"] >> classes;
Mat laySize(1, 3, CV_32SC1);
laySize.at<int>(0) = feture_data.cols;
laySize.at<int>(1) = nlay;//24
laySize.at<int>(2) = numC;
ann->setLayerSizes(laySize);
ann->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
ann->setActivationFunction(ANN_MLP::SIGMOID_SYM);
ann->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5000, 0.01));
Mat tranClass;
tranClass.create(feture_data.rows, numC, CV_32FC1);
for (int i = 0; i < feture_data.rows; i++)
{
for (int j = 0; j < tranClass.cols; j++)
{
if (j == (int)classes.at<uchar>(i))
tranClass.at<float>(i, j) = 1;
else
tranClass.at<float>(i, j) = 0;
}
}
ann->train(feture_data, ROW_SAMPLE, tranClass);
}
现在可以开始训练了
getXML();//样本特征数据
Ptr<ANN_MLP> ann = ANN_MLP::create();
ann_go(ann,3,24);//样本特征训练
ann->save("ann_param");//得到神经网络
(1)匹配特征预测结果
我就可以将得到的手势特征与神经网络里的特征数据进行比对,预测出结果了,那我们怎么比对呢,这就需要用到预测函数predict进行预测。最后找到逻辑最大值,作为结果输出:
int contrast_out(Ptr<ANN_MLP>& ann, Mat &img)
{
int result = -1;
Mat output(1,4,CV_32FC1); //1*4矩阵
Mat img_1;
img_1 = big_contours(img);
ann->predict(img_1, output);
Point maxL;
double maxV;
minMaxLoc(output, 0, &maxV, 0 ,&maxL); //对比值,看哪个是最符合的。
result = maxL.x;
return result;
}
(2)输出结果
我们将预测的结果与手势的名称对应上,然后显示到输出窗口上:
void write_num(Mat& img, int p)
{
if (p == 2)
{
putText(img, "4", Point(20, 20), FONT_HERSHEY_PLAIN, 2.0, 255, 2);
}
else if (p == 0)
{
putText(img, "1", Point(20, 20), FONT_HERSHEY_PLAIN, 2.0, 255, 2);
}
else if (p == 1)
{
putText(img, "2", Point(20, 20), FONT_HERSHEY_PLAIN, 2.0, 255, 2);
}
}
这个项目程序可以进行一些简单的手势识别,通过摄像头获取输入数据,用户只需要在摄像头面前摆出手势,程序便可以实时识别用户摆出什么样的手势,用框框住手势,并将与手势对应的手势名称显示出来,但是识别准确率不高,要想提高准确率,可以在神经网络中加入梯度算法,由于楼主接触神经网络不多,也不太懂,欢迎能力强的人加以改进。项目完成得益于借鉴了以下博客的思想,讲得很详细,有需要的同学也可以去看看。源码将稍后上传至我的博客,有需要的同学可以下载。
https://blog.csdn.net/qq_42884797/article/details/110917941?utm_source=app&app_version=4.10.0&code=app_1562916241&uLinkId=usr1mkqgl919blen