基于OpenCV的水电表的刻度数读取及识别

基于OpenCV的水电表的刻度数读取及识别

本文分享一个机器视觉检测的小项目,目的是读取并识别水电表的读数。如下图:

图1.         

图2.

图一水表,生活中主要是关注数码表的数字部分,另外带有指针的四个部分可以忽略;

图二电表,既要关注数码表的数字部分,也要关注带指针的部分。

本文主要分享图二中电表两部分读数的读取及识别。首先解决带指针部分的刻度读取识别,然后再分享数码表部分的数字读取识别。

一、指针部分的刻度读取识别

思路分析:

指针部分的刻度读取识别,大体分为三步:

1、//步骤一:找到目标区域,截取ROI,并进行倾斜矫正,得到包含目标的图像.

2、//步骤二:对步骤一中得到图像进行处理,获得包含长指针和刻度的最终目标图像.

3、//步骤三:对步骤二中得到的图像进行处理,识别指针刻度数.

先上结果图像,再详解步骤分析。

原图:图3.       

最终结果图像:图4.

左边是原始图像,右边是经过处理之后、识别出刻度盘读数的图像。下面来进行一步步的拆解分析。

1、//步骤一:找到目标区域,截取ROI,并进行倾斜矫正,得到包含目标的图像.

1.1 截取包含目标的ROI区域

由于表盘本身是圆形的,所以根据这个特点,先制作一个圆形的mask,并进行位与操作,即可截取得到表盘的中间圆形玻璃部分。(也可以在原图上拟合找圆,然后截取包含目标的圆形区域)

//制作一个圆形mask图像
cv::Mat mask(i_Rows, i_Cols, CV_8UC1, cv::Scalar(0, 0, 0));
cv::circle(mask, cv::Point(i_Rows/2, i_Cols/2), (i_Rows/2 - 15), cv::Scalar(255, 255, 255), -1); 

//执行位操作
cv::Mat roiIMG;
cv::bitwise_and(srcIMG, mask, roiIMG);

mask图像:图5.     

ROI图像:图6.

1.2 倾斜矫正

二值化后,查找连通域,根据连通域大小(周长、面积……),筛选出表盘刻度部分;

表盘刻度图像:图7.     

最小外接矩形(红色):图8. 绿色:外接矩形.

可以看出表盘刻度图像,背景干净,前景目标明显突出。我们可以直接求取其最小外接矩形,根据最小外接矩形得到其倾斜角度、旋转中心。然后进行旋转矫正即可。

//获取旋转中心、旋转角度
vector<cv::RotatedRect> box(contours.size()); //定义最小外接矩形集合
cv::Point2f rect[4];
double angle=0.0;
cv::Point2f center;

//经过筛选之后,这里 1==contours.size() .
for (int i = 0; i < contours.size(); i++)
{
	box[i] = minAreaRect(cv::Mat(contours[i]));//计算每个轮廓的最小外接矩形
	angle = box[i].angle;//倾斜角度
	center = box[i].center;//定义旋转中心坐标
	box[i].points(rect);//把最小外接矩形四个端点复制给rect数组
	
    std::cout << "angle=" << angle << std::endl;

	//最小外接矩形的宽高.
	char q_width[20], q_height[20];
	sprintf_s(q_width, "width=%0.2f", box[i].size.width);
	sprintf_s(q_height, "height=%0.2f", box[i].size.height);

	circle(src_copy, cv::Point(box[i].center.x, box[i].center.y), 5, cv::Scalar(0, 0, 255), -1, 8); //绘制最小外接矩形的中心点
	for (int j = 0; j < 4; j++)
	{
		cv::line(src_copy, rect[j], rect[(j + 1) % 4], cv::Scalar(0, 0, 255), 2, 8); //绘制最小外接矩形每条边
		cv::namedWindow("rectLined", 0);
		cv::imshow("rectLined", src_copy);
		cv::waitKey(0);
	}
	//在图像上绘制文字
	cv::putText(src_copy, q_width, Point(235, 260), FONT_HERSHEY_COMPLEX_SMALL, 0.85, Scalar(0, 255, 0), 2, 8);
	cv::putText(src_copy, q_height, cv::Point(235, 285), FONT_HERSHEY_COMPLEX_SMALL, 0.85, cv::Scalar(0, 255, 0), 2, 8);

}

矫正之后的图像:图9.   

矫正后的图像:图10.

//进行旋转矫正
//图像围绕center旋转degree角度(原尺寸)    
void f_rotateImage2(Mat src, Mat& img_rotate, Point2f center, double angle)
{
	//最小外接矩形的中心点为旋转中心坐标

	//经验值
	if (0 < abs(angle) && abs(angle) <= 45) //逆时针
		angle = angle;
	else if (45 < abs(angle) && abs(angle) < 90) //顺时针
		angle = 90 - abs(angle);

	//Point2f center = box[i].center;//最小外接矩形的中心点为旋转中心坐标
	double angle0 = angle;
	double scale = 1;
	Mat roateM;
	roateM = getRotationMatrix2D(center, angle0, scale); //获得旋转矩阵
	warpAffine(src, img_rotate, roateM, src.size()); //利用放射变换进行旋转

	//imshow("f_img_rotate2", img_rotate);
	//waitKey(0);
}

2、//步骤二:对步骤一中得到图像进行处理,获得包含长指针和刻度的最终目标图像.

步骤一中的图9即为步骤二中的输入图像。经过二值化、寻找连通域、筛选(周长/面积等),即可得到下图:图11

最终目标图像:图11.                            

图12.

步骤二与步骤一也可以一起处理,在步骤一中通过二值化后,也可得到图12,经过筛选和旋转矫正后,亦可得到图11。

3、//步骤三:对步骤二中得到的图像进行处理,识别指针刻度数.

步骤三的输入图像为步骤二中的图11。经过左右边界点查找、筛选,指针上的点查找、筛选,并将筛选后的点(图13红色点)进行直线拟合,即可得到图14中的三条绿色直线。

筛选后的点:图13.         

直线拟合:图14.

有了三条直线,通过夹角、及刻度与夹角的比例关系,即可算出当前的刻度值是多少。(图14中红字即为当前刻度读数)

源码下载地址:基于OpenCV的水电表的刻度数读取及识别waterMeter.zip

二、数码表部分的数字读取识别

数码表部分的数字读取及识别。

【第二部分在整理中,待续……】

YOLO 教程:https://www.youtube.com/watch?v=_FNfRtXEbr4

数据集:https://ieee-dataport.org/open-access/water-meter-dataset

参考文献:

1、基于计算机视觉的水表读数读取 | 案例分享

【穷且益坚,不坠青云之志。】

  • 5
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值