前言:工程应用中时常用到视觉定位,比如电路板上都会预留一个定位点,便于设备识别坐标位置,便于SMT机器判断该将电子元器件贴到哪个位置。对于摄像头测试也是如此,测试手机或平板摄像头,通常会选一张固定的图纸,然后根据所拍摄的图片进行分析。由于环境存在误差,对图片不能千篇一律的按照固定位置解析,总是存在一定的角度倾斜,所以解析图片前,先进行视觉定位是必须要做的一步。本文通过OpenCV 开源图像库实现圆形的坐标定位来示例计算机视觉在工程中的实际应用。
方法/步骤
1
准备一张示例图片,如图示,图片中存在方形,多变形,不规则图形,圆形,且颜色各异。 下面介绍如何定位图中的两个圆。此图片大家可以使用windows自带的小画家来画,注意画圆的时候按shift键可以画出正圆。
引用OpenCV 头文件和库文件,并且包含vector, 后面要用到。
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#pragma comment (lib,"opencv_core244d.lib")
#pragma comment (lib,"opencv_highgui244d.lib")
#pragma comment (lib,"opencv_imgproc244d.lib")
using namespace std;
using namespace cv;
3
加载待处理图片,为了便于显示,对图片进行缩放,其实缩放这个小技巧还可以提高后续的处理速度。然后对图片进行灰度处理,然后对图片记性二值化处理,去掉饱和度较低的部分,利用HoughCircles函数,提取轮廓为圆的部分。
注意调整HoughCirles函数的几个参数,可以抓到不同的结果,要耐心根据实际情况调整。
Mat resized;
resize(src,resized,Size(src.cols/ratio,src.rows/ratio));
int w=resized.size().width;
int h=resized.size().height;
Mat gray;
cvtColor(resized,gray,CV_BGR2GRAY);
blur(gray,gray,Size(3,3));
threshold(gray,gray,160,255,THRESH_BINARY_INV);
blur(gray,gray,Size(3,3));
vector<Vec3f> circles;
HoughCircles(gray,circles,CV_HOUGH_GRADIENT,2,h/4,25,100,h/32,h/8);
vector<Vec3f>::const_iterator it=circles.begin();
while(it!=circles.end())
{
circle(resized,Point((*it)[0],(*it)[1]),2,Scalar(0,0,255),2);
circle(resized,Point((*it)[0],(*it)[1]),(*it)[2],Scalar(0,0,255),2);
++it;
}
namedWindow("src");
imshow("src",resized);
namedWindow("resized");
imshow("resized",gray);
waitKey(0);
4代码解读:
使用HoughCircles必须注意,传入的第一个参数必须是灰度图,根据需要设置其参数,参数2 :累加器分辨率, 参数3: 两个圆之间的最小距离,参数4:Canny 高阀值,参数5:最小投票数,参数6,7:最小,最大半径。
函数抓取的圆保存到向量circles中, Vec3f 是个3个变量的结构体Vec3f[0] ,Vec3f[1] 对应圆心坐标值,Vec3f[2] 对应圆心半径。
为了显示结果, 使用circle函数画出圆心和圆,颜色使用红色。
但是摄像头拍照不比电脑作图,实际拍照会受光照条件和强度的影响,导致抓取结果偏差很大。 如下图,实际拍摄的图可能有阴影投射,灰度处理后影响值得抓取。使用上述代码,却抓到了7个圆,实际只需要左右2个,所以可以根据坐标将不需要的过滤掉。