图像识别(7)——静态图片识别LED灯+Canny阈值调节+圆心打点

博主QQ:1356438802

QQ群:473383394——UVC&OpenCV473383394


平台:Win7 64bits + Visual Studio 2012 + OpenCV 2.4.10



《OpenCV3编程入门-毛星云》PDF 将近看了两个月,终于要开始实践了。其实大部分人应该是一边学习一边实践,我呢,反正有时间,就强迫自己耐住性子,慢慢研究,慢慢融会贯通,并且一个个技术点去思考,它能干嘛用?它能不能满足我的需求?大家在看我前面的文章,可以发现我针对每个技术都有一些笔记和自己的思考。


图像识别(1)——手写笔&手势识别这篇文章中,有分析:

在微投的交互功能中,都要用到图像识别。手写笔上有一个红外LED灯,当把摄像头的曝光度调低时,整个画面就只有这个红外的亮点。手势动作识别,就需要从整个帧画面中提取出手的形状,并且拟合出手的运动轨迹,从而判断是哪种手势,再让系统进行响应。显而易见,手写笔的识别应该相对简单,所以我们来挑软的柿子捏,哈哈...


我们现在就开始捏软柿子了!

首先我的思路是,要找到LED灯的圆心或者重心,来代表LED灯在图片中的坐标点。找到两种大概觉得可以的方法,8.3.3章节中minEnclosingCircle()函数用来寻找轮廓的面积最小包围圆形(得到圆心),8.4.1章节中moments()函数可以用来计算轮廓形状的重心。


于是,我找到USB摄像头先把曝光值调到低,依次截取了几张图片,作为实验标本。

Exposure = -6


Exposure = -7


Exposure = -8


Exposure = -9


Exposure = -10


Exposure = -11



从上面的图片中可以看出,曝光值越低,背景越来越弱,最后只剩下我们要的LED灯光点,但是如果继续调低,则连LED光点都会丢失。


接下来我拿《OpenCV3编程入门-毛星云》源码案例中“【70】查找并绘制轮廓综合示例”作为基础来修改,如下。

//--------------------------------------【程序说明】-------------------------------------------
//		程序说明:《OpenCV3编程入门》OpenCV2版书本配套示例程序70
//		程序描述:查找并绘制轮廓综合示例
//		开发测试所用操作系统: Windows 7 64bit
//		开发测试所用IDE版本:Visual Studio 2010
//		开发测试所用OpenCV版本:	2.4.9
//		2014年06月 Created by @浅墨_毛星云
//		2014年11月 Revised by @浅墨_毛星云
//------------------------------------------------------------------------------------------------
//---------------------------------【头文件、命名空间包含部分】----------------------------
//		描述:包含程序所使用的头文件和命名空间
//------------------------------------------------------------------------------------------------
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <atltrace.h>
using namespace cv;
using namespace std;
//-----------------------------------【宏定义部分】-------------------------------------------- 
//		描述:定义一些辅助宏 
//------------------------------------------------------------------------------------------------ 
#define WINDOW_NAME1 "【原始图窗口】"			//为窗口标题定义的宏 
#define WINDOW_NAME2 "【轮廓图】"					//为窗口标题定义的宏 
//-----------------------------------【全局变量声明部分】--------------------------------------
//		描述:全局变量的声明
//-----------------------------------------------------------------------------------------------
Mat g_srcImage; 
Mat g_grayImage;
int g_nThresh = 80;
int g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector<vector<Point>> g_vContours;
vector<Vec4i> g_vHierarchy;
//-----------------------------------【全局函数声明部分】--------------------------------------
//		描述:全局函数的声明
//-----------------------------------------------------------------------------------------------
static void ShowHelpText( );
void on_ThreshChange(int, void* );
//-----------------------------------【main( )函数】--------------------------------------------
//		描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
	//【0】改变console字体颜色
	system("color 1F"); 
	//【0】显示欢迎和帮助文字
	ShowHelpText( );
	//LPCWSTR *str = LPCWSTR("11111111\n");
	//OutputDebugString(str);
	// 加载源图像
	g_srcImage = imread( "LED_IMG\\1.jpg", 1 );
	if(!g_srcImage.data ) { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; } 
	// 转成灰度并模糊化降噪
	cvtColor( g_srcImage, g_grayImage, CV_BGR2GRAY );
	blur( g_grayImage, g_grayImage, Size(3,3) );
	printf("2222222\n");
	// 创建窗口
	namedWindow( WINDOW_NAME1, CV_WINDOW_AUTOSIZE );
	imshow( WINDOW_NAME1, g_srcImage );
	printf("33333333\n");
	//创建滚动条并初始化
	createTrackbar( "canny阈值", WINDOW_NAME1, &g_nThresh, g_nThresh_max, on_ThreshChange );
	on_ThreshChange( 0, 0 );
	printf("4444444444\n");
	waitKey(0);
	return(0);
}
//-----------------------------------【on_ThreshChange( )函数】------------------------------  
//      描述:回调函数
//----------------------------------------------------------------------------------------------  
void on_ThreshChange(int, void* )
{
	// 用Canny算子检测边缘
	Canny( g_grayImage, g_cannyMat_output, g_nThresh, g_nThresh*2, 3 );
	// 寻找轮廓
	findContours( g_cannyMat_output, g_vContours, g_vHierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
	//对给定的 2D 点集,寻找最小面积的包围圆
	Point2f center;
	float radius = 0;
	// 绘出轮廓
	Mat drawing = Mat::zeros( g_cannyMat_output.size(), CV_8UC3 );
	for( int i = 0; i< g_vContours.size(); i++ )
	{
		Scalar color = Scalar( g_rng.uniform(0, 255), g_rng.uniform(0,255), g_rng.uniform(0,255) );//任意值
		drawContours( drawing, g_vContours, i, color, 1, 8, g_vHierarchy, 0, Point() );
		//对给定的 2D 点集,寻找最小面积的包围圆
		minEnclosingCircle(Mat(g_vContours[i]), center, radius);
		//画出圆心
		circle( drawing, center, 1, color, CV_FILLED, CV_AA );
		//绘制出最小面积的包围圆
		//circle(drawing, center, cvRound(radius), color, 1, CV_AA);
	}
	// 显示效果图
	imshow( WINDOW_NAME2, drawing );
}
//-----------------------------------【ShowHelpText( )函数】----------------------------------  
//      描述:输出一些帮助信息  
//----------------------------------------------------------------------------------------------  
static void ShowHelpText()  
{  
	//输出欢迎信息和OpenCV版本
	printf("\n\n\t\t\t非常感谢购买《OpenCV3编程入门》一书!\n");
	printf("\n\n\t\t\t此为本书OpenCV2版的第70个配套示例程序\n");
	printf("\n\n\t\t\t   当前使用的OpenCV版本为:" CV_VERSION );
	printf("\n\n  ----------------------------------------------------------------------------\n");
	//输出一些帮助信息  
	printf(   "\n\n\t欢迎来到【在图形中寻找轮廓】示例程序~\n\n");  
	printf(   "\n\n\t按键操作说明: \n\n"  
		"\t\t键盘按键任意键- 退出程序\n\n"  
		"\t\t滑动滚动条-改变阈值\n" );  
} 

编译运行,可以看到,图片中LED灯光点的中心,有一个圆点,就是我们计算出来的圆心,然后绘制得到。

实验结果忘记截图了,我就不晒图了,大家拿代码去运行就能看到结果。


上面可能有些函数的使用,大家不理解,我也没办法了,因为我已经通读了书本,不理解就只能去看书了。




相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页