本文实例为大家分享了opencv实现矩形检测的具体代码,供大家参考,具体内容如下
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
//////////////////////////////////////////////////////////////////
//函数功能:用向量来做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 = (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);//余弦值
return acos(angle_line)*180/3.141592653;
}
//////////////////////////////////////////////////////////////////
//函数功能:采用多边形检测,通过约束条件寻找矩形
//输入: img 原图像
// storage 存储
// minarea,maxarea 检测矩形的最小/最大面积
// minangle,maxangle 检测矩形边夹角范围,单位为角度
//输出: 矩形序列
//////////////////////////////////////////////////////////////////
CvSeq* findSquares4( IplImage* img, CvMemStorage* storage ,int minarea, int maxarea, int minangle, int maxangle)
{
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 = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 ); //金字塔滤波3通道图像中间变量
IplImage* tgray = cvCreateImage( sz, 8, 1 ); ;
CvSeq* result;
double s, t;
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, (l+1)*255/N, 255, CV_THRESH_BINARY );
cvFindContours( gray, storage, &contours, sizeof(CvContour),CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );
while( contours )
{ //多边形逼近
result = cvApproxPoly( contours, sizeof(CvContour), storage,CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );
//如果是凸四边形并且面积在范围内
if( result->total == 4 && fabs(cvContourArea(result,CV_WHOLE_SEQ)) > minarea && fabs(cvContourArea(result,CV_WHOLE_SEQ)) < maxarea && cvCheckContourConvexity(result) )
{
s = 0;
//判断每一条边
for( int i = 0; i < 5; i++ )
{
if( i >= 2 )
{ //角度
t = fabs(angle( (CvPoint*)cvGetSeqElem( result, i ),(CvPoint*)cvGetSeqElem( result, i-2 ),(CvPoint*)cvGetSeqElem( result, i-1 )));
s = s > t ? s : t;
}
}
//这里的S为直角判定条件 单位为角度
if( s > minangle && s < maxangle )
for( int i = 0; i < 4; i++ )
cvSeqPush( squares,(CvPoint*)cvGetSeqElem( result, i ));
}
contours = contours->h_next;
}
}
}
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( wndname, cpy );
cvReleaseImage( &cpy );
}
int main()
{
CvCapture* capture = cvCreateCameraCapture(0);
IplImage* img0 = 0;
CvMemStorage* storage = 0;
int c;
const char* wndname = "Square Detection Demo"; //窗口名称
storage = cvCreateMemStorage(0);
cvNamedWindow( wndname, 1 );
while (true)
{
img0 = cvQueryFrame(capture);
drawSquares( img0, findSquares4( img0, storage, 100, 2000, 80, 100), wndname );
cvClearMemStorage( storage ); //清空存储
c = cvWaitKey(10);
if( c == 27 )
break;
}
cvReleaseImage( &img0 );
cvClearMemStorage( storage );
cvDestroyWindow( wndname );
return 0;
}
|
效果:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/qq_15947787/article/details/51085352








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。