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源码是:https://github.com/BeiGuoDeXue/Laser-line-extraction.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;
}

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

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]和\[2\]提供了一种使用树莓派和OpenCV识别激光笔的方法。首先,树莓派从摄像头获取图像,并通过鼠标点击来确定需要识别位置。然后,根据点击位置获取该点的HSV色域值,并根据色域值调整识别的颜色范围。接下来,通过骨架化和拟合等操作,可以得到激光线的轮廓。最后,使用Hough变换来检测线,并将检测到的直线在图像上显示出来。 引用\[3\]提供了另一种确定色域值的方法。通过从摄像头获取图像,并将图像转换为HSV色域,可以通过鼠标点击来获取点击位置的HSV值。这样可以确定激光笔的颜色范围。 综上所述,使用OpenCV可以通过树莓派和摄像头来识别激光笔。具体的实现方法可以根据引用\[1\]和\[2\]中的代码进行调整和实验。 #### 引用[.reference_title] - *1* *3* [2021电赛D题:基于互联网的摄像测量系统 思路](https://blog.csdn.net/weixin_50569944/article/details/122407999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [opencv 裂隙检测用红色激光线识别裂隙+opencv骨架化](https://blog.csdn.net/Andrwin/article/details/105797364)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值