Opencv识别激光线检测人的位置

编程入门 行业动态 更新时间:2024-10-27 11:23:33

Opencv识别<a href=https://www.elefans.com/category/jswz/34/1770096.html style=激光线检测人的位置"/>

Opencv识别激光线检测人的位置

刚接触openCV,还是智能跟随小车的项目。使用摄像头加线状激光发射器做人的位置检测。

工具:850nm光波段,500mw线状激光发射器,100度窄带850或者广谱加850摄像头。
项目完成情况及功能:我做的部分是在框出人的前提下,提取人身上的激光线,现在的进度是大体一完成,精度也还可以,但是不适用在室外强光下使用。
项目算法思路:
基于论文ROI区域的查找方法,首先我们的激光是线状的,水平发射出去,如果在太阳光不太强的情况下,那么我们的激光在每一列应该是最亮的点,也就是灰度值最大,这样我们就可以遍历每一列找出灰度值最大的点。
但是由于激光打出去照射在人的身上会形成光斑,所以我们可以把每一列相同的最大的点只取最后一个,这样就可以解决光斑的问题,不需要再用灰度重心法,或者极值法。
在实际应用中可能光斑比较分散,导致光斑的上边沿和下边沿都有分布每列最大灰度值的点,所以还有设置一个宽度是框内大小,高度是20像素点的区域,要用这个区域来遍历整个框,最后统计哪一行里面包含的最大灰度值的点最多,就说明激光线在这个区域的可能性最大,最后取平均值确定激光线的位置。 虽然方法比较简单,但是却比较精准实用。
我也尝试过其他的几种方法,有下面三种:
一:阈值加sobel卷积和霍夫变换 此方法步骤是:
1、灰度处理。 2、sobel算子卷积。 3、阈值处理 4、霍夫变换找直线。 方法用自定义的sobel算子效果还算好一点。 但是sobel算子和激光线的光斑终究会把激光线变得弯曲,弯曲之后会和霍夫变换相矛盾,还是无法检测的准确。
二:基于hessian矩阵的steger算法 此算法利用的是hessian矩阵的各向异性,找出在X方向和Y方向的特征向量值,最后比较哪个大就用哪个特征向量作为法线的方向,最后用steger求出中心点,也可以达到亚像素级别。 这种方法在室内用,检测光斑用着还可以,但是对于漫反射或者室外效果不好。
三:使用大阈值加形状检测来识别光斑,激光线,这种方法适用的场景更加单一,必须用阈值把除激光线以外的东西全通过大阈值(最少200),然后二值化处理掉,只留下激光,然后用findcounts检测出轮廓,最后图像拟合,画出形状,求出周长,算中心点。

    总结:后三种方法都不好用,当然我的最前面的方法在强光下也无法使用,而且还必须检测到人的坐标的前提下还有待完善,还请大家指点。

下面是源码和测试效果。
我的gethub源码是:.git

#include <opencv2\opencv.hpp>
#include <iostream>
#include <time.h>
using namespace std;
using namespace cv;
void gamma_correct(Mat& img, Mat& dst, double gamma) {Mat temp;CvMat tmp;img.convertTo(temp, CV_32FC1, 1.0 / 255.0, 0.0);tmp = temp;cvPow(&tmp, &tmp, gamma);temp.convertTo(dst, CV_8UC1, 255.0, 0.0);
}
int main(void)
{int max[2000];VideoCapture cap;cap.open(0); //打开摄像头namedWindow("input image", CV_WINDOW_AUTOSIZE);//namedWindow(output_title, 0);while (1){Mat src1;Mat src;vector<int> max1;int max_arry[2][1920] = {0};//src1 = imread("./photo/34.bmp", 1);//src1 = imread("./室外/2019-08-22-58.bmp", 1);//src = src1;cap >> src1; //读取当前帧src = src1;//double t = (double)getTickCount();imshow("input image", src);if (!src.data) {printf("could not load image...\n");return -1;}double t = 0;t = (double)getTickCount();int src_width  = src.cols;int src_height = src.rows;cvtColor(src, src, CV_BGR2GRAY);//equalizeHist(src, src);//imshow("直方图均衡化", gray);//gamma_correct(src, src, 2.0);                                  //gamma用来对亮的进行加强,对暗的地方进行抑制//imshow("伽马校正",src);//erode(src_gray, src_gray, structureElement);//Mat structureElement = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1));//dilate(src, src, structureElement); //膨胀//erode(src, src, structureElement);  //腐蚀  腐蚀的效果在视频中还不错//erode(src, src, structureElement);  //腐蚀//erode(src, src, structureElement);  //腐蚀//erode(src, src, structureElement);  //腐蚀//GaussianBlur(src, src, Size(0, 0), 6, 6);  //视频中,高斯滤波效果还可以//medianBlur(src, src, 3);//中值滤波,没必要//imwrite("./photo/3_1.jpg", src);int height = 400, width = 200;int  initial_X = (src_width - width) / 2, initial_Y = 50;Rect rect(initial_X, initial_Y, width, height);          //左上坐标(x,y)和矩形的长(x)宽(y)rectangle(src1, rect, Scalar(255, 0, 0), 1, 1, 0);//int th;//Mat src2;//th = threshold(src, src2, 0, 255, CV_THRESH_OTSU);    //大律法也可以考虑不再使用printf("th is:%d\n",th);//imshow("大律法", src2);//printf("cow and row is %d,%d\n", src.cols, src.rows);//printf("灰度和画框:%f ms\n", (getTickCount() - t)*(1000) / getTickFrequency());//t= (double)getTickCount();uchar *pValue;int value_store = 0;for (int i = 0; i < src.cols; i++)                 //cols是列数,640{max[i] = 0;value_store = 0;pValue = src.ptr<uchar>(0);for (int j = 0; j < src.rows; j++)            //rows是行,480  Mat访问坐标是x y反着写的。{//pValue = src.ptr<uchar>(j);if ((pValue[i] >= value_store) && (pValue[i] > 150))     //150为最低的阈值{value_store = pValue[i];max[i] = j;}pValue += src_width;}max_arry[0][i]=i;max_arry[1][i]= max[i];}for (int k = 0; k <src_width; k++){Point rpt;rpt.x = max_arry[0][k];             // max1[2 * k + 0];rpt.y = max_arry[1][k];             // max1[2 * k + 1];circle(src1, rpt, 0, Scalar(0, 0, 255));}int Max_sopt[2][1080] = { 0 };      //分成(src_height-20)段,int Max_order = 0;int Max_store = 0;int lengh = 20;                     //每段宽度是20个像素点,可以更改for (int j = 0; j < (src_height- lengh); j++){for (int i = initial_X; i <= width+ initial_X; i++){if ((max_arry[1][i] > (j + lengh)) && (max_arry[1][i] <= (j + lengh*2))){Max_sopt[0][j]++;                    //每个段的个数Max_sopt[1][j] += max_arry[1][i];    //每个段的总和}}if (Max_sopt[0][j]>Max_store ){Max_store = Max_sopt[0][j];Max_order = j;                    //记录下哪一个段的点数最多}}if ((Max_sopt[1][Max_order] > 0) && (Max_sopt[0][Max_order] > 0))Max_sopt[1][Max_order] = Max_sopt[1][Max_order] / Max_sopt[0][Max_order];//得到平均值,可以画点Point rpt2;rpt2.x = width / 2 + initial_X;rpt2.y = Max_sopt[1][Max_order];circle(src1, rpt2, 10, Scalar(255, 0, 255));imshow("result", src1);printf("%f ms, X:%d,Y:%d\n", (getTickCount() - t)*(1000) / getTickFrequency(), rpt2.x, rpt2.y);waitKey(60);}//system("pause");return 0;
}

测试效果,方框是框出来的,中间圆点是激光线坐标点。


更多推荐

Opencv识别激光线检测人的位置

本文发布于:2024-02-10 13:19:55,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1675684.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:激光   位置   Opencv

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!