Advertisement

opencv 识别长方形_OpenCV 圆与矩形识别的方法

阅读量:

最近参与的一个项目应用了图像识别技术。由于之前完全没有接触过OpenCV工具,在多方学习与实践中逐步掌握了基础操作方法。通过查阅各种教程资料以及实践操作,在经过一段时间的学习努力后终于基本掌握了相关知识。

整个具体的流程大致上是先获取原始图像数据,在此基础上依次执行以下操作:首先将原始图像转换为二值化灰度图(cvtColor),随后运用高斯滤波器(GaussianBlur)对图片进行降噪处理;接着通过OpenCV中的cvFindContours函数来进行轮廓检测;最后完成形状分析过程(shape detection)。

大多数教程很专业,各种参数分析看不懂,经过各种搜索终于是搞懂了。

识别圆

在识别圆方面,OpenCV有内置的方法:霍夫圆变化:

HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);

参数分析:

edges:灰度图像

circles: std::vector circles;数组,用来存储圆的坐标信息

Hough梯度变换:该Hough变换类型仅支持这一种形式(对应于21HT算法),如[Yuen03]所述,默认采用此方法

1.5:累加器图像的分辨率,1的时候是与获取到的图像相同,1.5就是1.5倍

10:圆与圆的最小距离,两个圆心距离如果在范围内则被认定为1个圆

200:100-200两个参数选就够了

100:预设为100值。当数值较小时(即数值较低时),圆的识别精度会有所下降。当实际存在的圆形数量较多时(比如存在多个实际圆形导致部分边缘被误判为圆形),可能会出现部分边缘被误判为圆形的情况。

最后两个参数分别是识别 圆的最小,最大的面积。

矩形识别

矩形识别并没有内置方法,需要自己手写。

最主要的方法是二值化。通过二值化来调节识别的强度。

cvThreshold(tgray, gray, 75, 250, CV_THRESH_BINARY);

参数分析:

src:原始数组 (单通道 , 8-bit of 32-bit 浮点数)。

dst:输出数组,必须与 src 的类型一致,或者为 8-bit。

threshold:阈值

max_value:使用 CV_THRESH_BINARY 和 CV_THRESH_BINARY_INV 的最大值。

threshold_type:阈值类型

设阈值类型为二元阈值:当src(x,y)大于阈值时,dst(x,y)设为最大值;否则, dst(x,y)置零;

当src(x,y)超过threshold时,则dst(x,y)被赋值为0;否则,则被赋值为max_value。

threshold_type=CV_THRESH_TRUNC: if src(x,y) > threshold, set dst(x,y) to the maximum value; otherwise, retain the original intensity of src(x,y).

当threshold_type设置为CV_thresh_tozero时, 如果源坐标点src(x y)的值大于阈值, 则将目标坐标点dst(x y)赋值为源坐标点的值; 否则则将目标坐标点dst(x y)赋值为零.

当源图像像素值大于阈值时(threshold_type=CV_THRESH_TOZERO_INV),目标图像像素置零;否则不进行处理。

效果图如下:

在矩形识别里面的二值化图:

圆识别:

源码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#pragma comment(lib,"ws2_32.lib")

#include

using namespace cv;

//

//函数功能:用向量来做COSα=两向量之积/两向量模的乘积求两条线段夹角

//输入: 线段3个点坐标pt1,pt2,pt0,最后一个参数为公共点

//输出: 线段夹角,单位为角度

//

double angle(CvPoint* pt1, CvPoint* pt2, CvPoint* pt0)

{

double dx1 = pt1->x - pt0->x;

double dy1 = pt1->y - pt0->y;

double dx2 = pt2->x - pt0->x;

double dy2 = pt2->y - pt0->y;

double angle_line = (dx1dx2 + dy1 * dy2) / sqrt((dx1dx1 + dy1 * dy1)(dx2dx2 + dy2 * dy2) + 1e-10);//余弦值

return acos(angle_line) * 180 / 3.141592653;

}

//

//函数功能:采用多边形检测,通过约束条件寻找矩形

//输入: img 原图像

// storage 存储

// minarea,maxarea 检测矩形的最小/最大面积

// minangle,maxangle 检测矩形边夹角范围,单位为角度

//输出: 矩形序列

//

CvSeq* squareFinder(IplImage* image, CvMemStorage* storage, int minimumAndMaximumAreaRange[2], int minimumAndMaximumAngleRange[2], int(&pointsOfInterest)[30])

{

CvSeq* contours;//边缘

int N = 6; //阈值分级

CvSize sz = cvSize(img->width & -2, img->height & -2);

IplImage* timg = cvCloneImage(img);//拷贝一次img

IplImage* gray = cvCreateImage(sz, 8, 1); //img灰度图

IplImage* pyr = cv::createImage(cv::size(sz.width / 2, sz.height / 2), 8, 3); //金字塔滤波器的3通道中间变量

IplImage* tgray = cvCreateImage(sz, 8, 1); ;

CvSeq* result;

double s, t;

int sk = 0;

CvSeq* squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage);

cvSetImageROI(timg, cvRect(0, 0, sz.width, sz.height));

//金字塔滤波

cvPyrDown(timg, pyr, 7);

cvPyrUp(pyr, timg, 7);

//在3个通道中寻找矩形

for (int c = 0; c < 3; c++) //对3个通道分别进行处理

{

cvSetImageCOI(timg, c + 1);

cvCopy(timg, tgray, 0); //依次将BGR通道送入tgray

for (int l = 0; l < N; l++)

{

//不同阈值下二值化

cvThreshold(tgray, gray, 75, 250, CV_THRESH_BINARY);

cvShowImage("111", gray);

该算法用于从灰度图像中提取轮廓信息并存储

while (contours)

{ //多边形逼近

计算结果为result = cvApproxPoly(contours, CvPointStorage::DefaultSize, storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*二十分之一, 0);

//如果是凸四边形并且面积在范围内

当结果总共有4个元素,并且其轮廓面积的绝对值大于最小面积且小于最大面积,并且满足凸性检查时

{

s = 0;

//判断每一条边

for (int i = 0; i < 5; i++)

{

if (i >= 2)

{ //角度

t等于绝对值函数作用于三个点计算的角度

s = s > t ? s : t;

}

}

//这里的S为直角判定条件 单位为角度

if (s > minangle && s < maxangle)

{

for (int i = 0; i < 4; i++)

cvSeqPush(squares, (CvPoint*)cvGetSeqElem(result, i));

CvRect rect = cvBoundingRect(contours, 1); // 获取矩形边界框

CvPoint p1;

p1 = cvPoint(rect.x + rect.width / 2, rect.y + rect.height / 2); //矩形中心坐标

std::cout << "X:" << p1.x << "Y:" << p1.y << std::endl;

}

}

contours = contours->h_next;

}

}

std::cout << "圆的数量是"<

temp[26] = sk;

sk = 0;

}

cvReleaseImage(&gray);

cvReleaseImage(&pyr);

cvReleaseImage(&tgray);

cvReleaseImage(&timg);

return squares;

}

//

//函数功能:画出所有矩形

//输入: img 原图像

// squares 矩形序列

// wndname 窗口名称

//输出: 图像中标记矩形

//

void drawSquares(IplImage* img, CvSeq* squares, const char* wndname)

{

CvSeqReader reader;

IplImage* cpy = cvCloneImage(img);

CvPoint pt[4];

int i;

cvStartReadSeq(squares, &reader, 0);

for (i = 0; i < squares->total; i += 4)

{

CvPoint* rect = pt;

int count = 4;

memcpy(pt, reader.ptr, squares->elem_size);

CV_NEXT_SEQ_ELEM(squares->elem_size, reader);

memcpy(pt + 1, reader.ptr, squares->elem_size);

CV_NEXT_SEQ_ELEM(squares->elem_size, reader);

memcpy(pt + 2, reader.ptr, squares->elem_size);

CV_NEXT_SEQ_ELEM(squares->elem_size, reader);

memcpy(pt + 3, reader.ptr, squares->elem_size);

CV_NEXT_SEQ_ELEM(squares->elem_size, reader);

//cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 );

cvPolyLine(cpy, &rect, &count, 1, 1, CV_RGB(rand() & 255, rand() & 255, rand() & 255), 1, CV_AA, 0);//彩色绘制

}

cvShowImage("22", cpy);

cvReleaseImage(&cpy);

}

void SendMessageOne()

{

//开起摄像头

VideoCapture capture;

capture.open(0);

Mat edges; //定义转化的灰度图

if (!capture.isOpened())

namedWindow("【效果图】", CV_WINDOW_NORMAL);

const char* winn = "1111";

if (!capture.isOpened())

//namedWindow(winn, CV_WINDOW_NORMAL);

CvMemStorage* storage = 0;

CvMemStorage* storage = 0;

storage = cvCreateMemStorage(0);

while (1)

{

int Y=0, J=0;

Mat frame;

capture >> frame;

IplImage img0 = frame;

//drawSquares(&img0, findSquares4(&img0, storage, 100, 2000, 80, 100, a), winn);

//cvClearMemStorage(storage); //清空存储

Mat E = frame(Range(1, 320), Range(1, 240));

cvtColor(frame, edges, CV_BGR2GRAY);

//高斯滤波

GaussianBlur(edges, edges, Size(7, 7), 2, 2);

std::vector circles;//存储每个圆的位置信息

//霍夫圆

HoughCircles(edges, circles, CV_HOUGH_GRADIENT, 1.5, 10, 100, 100, 0, 50);

for (size_t i = 0; i < circles.size(); i++)

{

Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));

int radius = cvRound(circles[i][2]);

//std::cout << "圆的X是" << circles[i][0] << "圆的Y是" << circles[i][1] << std:: endl;

//绘制圆轮廓

circle(frame, center, radius, Scalar(155, 50, 255), 3, 8, 0);

int R = frame.at(cvRound(circles[i][1]), cvRound(circles[i][0]))[2];//R

int G = frame.at(cvRound(circles[i][1]), cvRound(circles[i][0]))[1];//G

int B = frame.at(cvRound(circles[i][1]), cvRound(circles[i][0]))[0];//B

int num = R + G + B;

std::cout << "圆心颜色是" << num << std::endl;

}

imshow("【效果图】", frame);

waitKey(30);

}

}

int main()

{

std::thread *a = new std::thread(SendMessageOne);

a->join();

return 0;

}

综上所述,本文的主要内容已经介绍完毕。我们相信这些内容能够为您提供学习上的指导与参考。我们诚挚地期待读者能访问并关注我们的平台。

全部评论 (0)

还没有任何评论哟~