使用opencv库实现对数码管的识别(含代码)

引言

本文是笔者在参加夏令营时对负责项目的一个总结,这个项目的主要内容就是使用摄像头对着一块装有几段数码管的板子,然后识别出数码管所呈现的数字。其实这个项目整体并不难,opencv库 在这个项目中主要是对图片进行处理,获取紧贴数码管数字的一个矩形区域。之后就需要其他算法来进行处理,本文我使用了比较简单但十分有效的穿线法,也是网上很多类似问题的解决方法。后续我可能会使用其他方法来解决这个问题.

导入库并定义命名空间

#include 
#include  

using namespace cv;
using namespace std;

导入图片

Mat g_srcImage;
g_srcImage = imread( "p1.png", 1 );
imshow("原始图",g_srcImage);                       //显示原始图

对图片进行处理

  • opencv库 中有许多简单但十分实用的工具来处理图片,像霍夫变换,角点提取,我在这里主要使用hsv通道处理,canny边缘检测,轮廓获取等几种工具.

1.原始图有可能尺寸大小不合适,可以使用resize函数进行调整

//获取图片的高和宽,方便按比例进行尺寸调整
int w = g_srcImage.cols;
int h = g_srcImage.rows;

resize(g_srcImage,g_srcImage,Size(500,500*h/w));

2.将图片原通道转换为hsv通道,如果原图不是rgb通道,可以修改cvtColor函数中最后一个参数.

Mat hsv;
cvtColor(g_srcImage,hsv,COLOR_BGR2HSV);
//转换为hsv空间

3.最关键的一步!!

  • 下列代码可以通过筛选图片中hsv三个通道的值来将数码管处像素值变为最大,其余地方变为最小,从而将图片中数码管与其他部分区分开.
  • 为什么要使用hsv通道来筛选呢?因为hsv分别指色调,饱和度,亮度,而数码管是发光的,用饱和度和亮度来筛选数码管处的像素点效果比较好.
  • 筛选的原理是分别为hsv三个通道的值设置上下限,三个通道的值都在上限与下限值之间的变为最大,否则变为最小.
  • 上下限的选择需要自己实地进行测量.
//设置hsv的上下限  
	int iLowH = 59;    
    int iHighH =255;    
    int iLowS = 159;     
    int iHighS = 255;    
    int iLowV = 190;    
    int iHighV = 255;

//分离通道
vector  hsvsplit;
split(inputt,hsvsplit);

//筛选
inRange(inputt,Scalar(iLowH,iLowS,iLowV),Scalar(iHighH,iHighS,iHighV),hsv);
  • 上述代码可以实现的效果如下:

使用opencv库实现对数码管的识别(含代码)_第1张图片 使用opencv库实现对数码管的识别(含代码)_第2张图片

4.对图片进行膨胀操作,边缘检测,轮廓获取,再用矩形将轮廓框起来.

	Mat threshold_output;
	vector> contours;
	vector hierarchy;
	
	threshold( hsv, threshold_output, 180, 255, THRESH_BINARY );
	
	Mat Imageg = threshold_output.clone();
	
	//imshow( "边缘图", threshold_output );
	
	findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
	
	
	vector > contours_poly( contours.size() );
	vector boundRect( contours.size() );
	
	for( unsigned int i = 0; i < contours.size(); i++ )
	{ 
		approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
		boundRect[i] = boundingRect( Mat(contours_poly[i]) );
	}
	Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
	for( int unsigned i = 0; i(), 0, Point() );
		rectangle( threshold_output, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
	}
  • 前四步都是对图片的处理,整体代码如下:
#include 
#include  

using namespace cv;
using namespace std;

int main()
{
    Mat g_srcImage;
    g_srcImage = imread( "num.jpeg", 1 );

    //获取图片的高和宽,方便按比例进行尺寸调整
    int w = g_srcImage.cols;
    int h = g_srcImage.rows;
    resize(g_srcImage,g_srcImage,Size(250,250*h/w));

    imshow("原始图",g_srcImage);                       //显示原始图
    
    Mat hsv;
    cvtColor(g_srcImage,hsv,COLOR_BGR2HSV);
    //转换为hsv空间

    //设置hsv的上下限  
    int iLowH = 59;    
    int iHighH =255;    
    int iLowS = 159;     
    int iHighS = 255;    
    int iLowV = 190;    
    int iHighV = 255;

    //分离通道
    vector  hsvsplit;
    split(g_srcImage,hsvsplit);

    //筛选
    inRange(g_srcImage,Scalar(iLowH,iLowS,iLowV),Scalar(iHighH,iHighS,iHighV),hsv);
    //imshow("hsv效果图",hsv);

    //形态学变换
    Mat element=getStructuringElement(MORPH_RECT,Size(5,5));//获取核
    dilate(hsv,hsv,element); //膨胀
    //imshow("膨胀效果图",hsv);

    Mat threshold_output;
	vector> contours;
	vector hierarchy;
	
	threshold( hsv, threshold_output, 180, 255, THRESH_BINARY );
	
	Mat Imageg = threshold_output.clone();
	
	imshow( "边缘图", threshold_output );
	
	
	
	findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
	
	
	vector > contours_poly( contours.size() );
	vector boundRect( contours.size() );
	
	for( unsigned int i = 0; i < contours.size(); i++ )
	{ 
		approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
		boundRect[i] = boundingRect( Mat(contours_poly[i]) );
	}
	Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
	for( int unsigned i = 0; i(), 0, Point() );
		rectangle( threshold_output, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
	}

    imshow("效果图",threshold_output);
    waitKey(0);

}
  • 效果如下:
    使用opencv库实现对数码管的识别(含代码)_第3张图片 使用opencv库实现对数码管的识别(含代码)_第4张图片
    5.接下来就是要对矩形进行遍历,用穿线法判断是否为数字,是哪个数字.(穿线法的原理这里先不讲,以后补充)

最终代码:

#include 
#include  

using namespace cv;
using namespace std;

bool cross(Mat image,int x1,int y1,int x2,int y2);
int getnum(Mat image);
int getgrey(Mat image,int x,int y);

int main()
{
    Mat g_srcImage;
    g_srcImage = imread( "num.jpeg", 1 );

    //获取图片的高和宽,方便按比例进行尺寸调整
    int w = g_srcImage.cols;
    int h = g_srcImage.rows;
    resize(g_srcImage,g_srcImage,Size(250,250*h/w));

    imshow("原始图",g_srcImage);                       //显示原始图
    
    Mat hsv;
    cvtColor(g_srcImage,hsv,COLOR_BGR2HSV);
    //转换为hsv空间

    //设置hsv的上下限  
    int iLowH = 59;    
    int iHighH =255;    
    int iLowS = 159;     
    int iHighS = 255;    
    int iLowV = 190;    
    int iHighV = 255;

    //分离通道
    vector  hsvsplit;
    split(g_srcImage,hsvsplit);

    //筛选
    inRange(g_srcImage,Scalar(iLowH,iLowS,iLowV),Scalar(iHighH,iHighS,iHighV),hsv);
    //imshow("hsv效果图",hsv);

    //形态学变换
    Mat element=getStructuringElement(MORPH_RECT,Size(5,5));//获取核
    dilate(hsv,hsv,element); //膨胀
    //imshow("膨胀效果图",hsv);

    Mat threshold_output;
	vector> contours;
	vector hierarchy;
	
	threshold( hsv, threshold_output, 180, 255, THRESH_BINARY );
	
	Mat Imageg = threshold_output.clone();
	
	imshow( "边缘图", threshold_output );
	
	
	
	findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
	
	
	vector > contours_poly( contours.size() );
	vector boundRect( contours.size() );
	
	for( unsigned int i = 0; i < contours.size(); i++ )
	{ 
		approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
		boundRect[i] = boundingRect( Mat(contours_poly[i]) );
	}
	Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
	for( int unsigned i = 0; i(), 0, Point() );
		rectangle( threshold_output, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
	}

    imshow("效果图",threshold_output);


Rect roirect;
for (int unsigned i = 0;i3.5&& (double(boundRect[i].height)/double(boundRect[i].width))<5)
		{
			roirect = boundRect[i];
			Mat final;
			final = Imageg(roirect);
			int num;
			num = 1;

		}
		else if ((double(boundRect[i].height)/double(boundRect[i].width))>1.35&& (double(boundRect[i].height)/double(boundRect[i].width))<2.4)
		{
			roirect = boundRect[i];
			Mat final;
			final = Imageg(roirect);
			int num;
            num = getnum(final);
            
            if (num != -1)
            {
                cout <<"get the num: "<200)return true;
        }
        return false;
    }
    else
    {
        for (int x = x1;x200)return true;
        }
        return false;
        
    }

}




int getnum(Mat image)
{


 int h = image.rows;
int w = image.cols;


int result;

bool a1,a2,a3,a4,a5,a6,a7;



if(cross(image,int(0.5*w),0,int(0.5*w),int(0.25*h)))a1 = true;
else a1=false;
if(cross(image,0,int(0.25*h),int(0.5*w),int(0.25*h)))a2 = true;
else a2=false;
if(cross(image,int(0.5*w),int(0.25*h),int(w),int(0.25*h)))a3 = true;
else a3=false;

if(cross(image,int(0.5*w),int(0.25*h),int(0.5*w),int(0.75*h)))a4 = true;
else a4=false;
if(cross(image,0,int(0.75*h),int(0.5*w),int(0.75*h)))a5 = true;
else a5=false;
if(cross(image,int(0.5*w),int(0.75*h),int(w),int(0.75*h)))a6 = true;
else a6=false;
if(cross(image,int(0.5*w),int(0.75*h),int(0.5*w),int(h)))a7 = true;
else a7=false;

if(a1 !=0&&a2 ==0&&a3 !=0&&a4 !=0&&a5 !=0&&a6 ==0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 2;
else if(a1 !=0&&a2 ==0&&a3 !=0&&a4 !=0&&a5 ==0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 3;
else if(a1 ==0&&a2 !=0&&a3 !=0&&a4 !=0&&a5 ==0&&a6 !=0&&a7 ==0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 4;
else if(a1 !=0&&a2 !=0&&a3 ==0&&a4 !=0&&a5 ==0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 5;
else if(a1 !=0&&a2 !=0&&a3 ==0&&a4 !=0&&a5 !=0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 6;
else if(a1 !=0&&a2 ==0&&a3 !=0&&a4 ==0&&a5 ==0&&a6 !=0&&a7 ==0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 7;
else if(a1 !=0&&a2 ==0&&a3 !=0&&a4 ==0&&a5 ==0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 7;
else if(a1 !=0&&a2 !=0&&a3 !=0&&a4 !=0&&a5 !=0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 8;
else if(a1 !=0&&a2 !=0&&a3 !=0&&a4 !=0&&a5 ==0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 9;
else if(a1 !=0&&a2 !=0&&a3 !=0&&a4 ==0&&a5 !=0&&a6 !=0&&a7 !=0&&(getgrey(image,w*0.5,h*0.25) <= 150)&&(getgrey(image,w*0.5,h*0.75) <= 150)) result = 0;
else 
{
	result = -1;
}

//cout <<"result"<::iterator it = image.begin();
    
Mat_::iterator itend = image.end();    
int pixel = *(it + y * w + x);
return pixel; 
}

结果:

get the num: 8
get the num: 8
get the num: 5
get the num: 8
get the num: 6
get the num: 8
get the num: 9
get the num: 0

你可能感兴趣的:(opencv,c++,图像处理)