车牌定位html5,OpenCV下车牌定位算法实现代码(一)

#ifdef _CH_

#pragma package 

#endif

#ifndef _EiC

#include "cv.h"

#include "highgui.h"

#include 

#include 

#include 

#endif

intthresh = 50;

IplImage* img = 0;

IplImage* img0 = 0;

CvMemStorage* storage = 0;

CvPoint pt[4];

constchar* wndname ="Square Detection Demo";

// helper function:

// finds a cosine of angle between vectors

// from pt0->pt1 and from pt0->pt2

doubleangle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 )

{

doubledx1 = pt1->x - pt0->x;

doubledy1 = pt1->y - pt0->y;

doubledx2 = pt2->x - pt0->x;

doubledy2 = pt2->y - pt0->y;

return(dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);

}

// returns sequence of squares detected on the image.

// the sequence is stored in the specified memory storage

CvSeq* findSquares4( IplImage* img, CvMemStorage* storage )

{

CvSeq* contours;

inti, c, l, N = 11;

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

IplImage* timg = cvCloneImage( img );// make a copy of input image

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

IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 );

IplImage* tgray;

CvSeq* result;

doubles, t;

// create empty sequence that will contain points -

// 4 points per square (the square's vertices)

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

// select the maximum ROI in the image

// with the width and height divisible by 2

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

// down-scale and upscale the image to filter out the noise

cvPyrDown( timg, pyr, 7 );

cvPyrUp( pyr, timg, 7 );

tgray = cvCreateImage( sz, 8, 1 );

// find squares in every color plane of the image

for( c = 0; c 

{

// extract the c-th color plane

cvSetImageCOI( timg, c+1 );

cvCopy( timg, tgray, 0 );

// try several threshold levels

for( l = 0; l 

{

// hack: use Canny instead of zero threshold level.

// Canny helps to catch squares with gradient shading

if( l == 0 )

{

// apply Canny. Take the upper threshold from slider

// and set the lower to 0 (which forces edges merging)

cvCanny( tgray, gray,60, 180, 3 );

// dilate canny output to remove potential

// holes between edge segments

cvDilate( gray, gray, 0, 1 );

}

else

{

//apply threshold if l!=0:

//tgray(x,y) = gray(x,y) 

//cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY );

cvThreshold( tgray, gray, 50, 255, CV_THRESH_BINARY );

}

// find contours and store them all as a list

cvFindContours( gray, storage, &contours,sizeof(CvContour),

CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );

// test each contour

while( contours )

{

// approximate contour with accuracy proportional

// to the contour perimeter

result = cvApproxPoly( contours,sizeof(CvContour), storage,

CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 );

// square contours should have 4 vertices after approximation

// relatively large area (to filter out noisy contours)

// and be convex.

// Note: absolute value of an area is used because

// area may be positive or negative - in accordance with the

// contour orientation

if( result->total == 4 &&

fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 &&

cvCheckContourConvexity(result) )

{

s = 0;

for( i = 0; i 

{

// find minimum angle between joint

// edges (maximum of cosine)

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;

}

}

// if cosines of all angles are small

// (all angles are ~90 degree) then write quandrange

// vertices to resultant sequence

if( s 

for( i = 0; i 

cvSeqPush( squares,

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

}

// take the next contour

contours = contours->h_next;

}

}

}

// release all the temporary images

cvReleaseImage( &gray );

cvReleaseImage( &pyr );

cvReleaseImage( &tgray );

cvReleaseImage( &timg );

returnsquares;

}

// the function draws all the squares in the image

voiddrawSquares( IplImage* img, CvSeq* squares )

{

CvSeqReader reader;

IplImage* cpy = cvCloneImage( img );

inti;

// initialize reader of the sequence

cvStartReadSeq( squares, &reader, 0 );

// read 4 sequence elements at a time (all vertices of a square)

for( i = 0; i total; i += 4 )

{

CvPoint* rect = pt;

intcount = 4;

// read 4 vertices

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 );

// draw the square as a closed polyline

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

}

// show the resultant image

cvShowImage( wndname, cpy );

cvReleaseImage( &cpy );

}

voidon_trackbar(inta )

{

if( img )

drawSquares( img, findSquares4( img, storage ) );

}

char* names[] = {"pic1.png","pic2.png","pic3.png",

"pic4.png","pic5.png","pic6.png", 0 };

intmain(intargc,char** argv)

{

inti, c;

// create memory storage that will contain all the dynamic data

storage = cvCreateMemStorage(0);

for( i = 0; names[i] != 0; i++ )

{

// load i-th image

img0 = cvLoadImage( names[i], 1 );

if( !img0 )

{

printf("Couldn't load %s\n", names[i] );

continue;

}

img = cvCloneImage( img0 );

// create window and a trackbar (slider) with parent "image" and set callback

// (the slider regulates upper threshold, passed to Canny edge detector)

cvNamedWindow( wndname,0 );

cvCreateTrackbar("canny thresh", wndname, &thresh, 1000, on_trackbar );

// force the image processing

on_trackbar(0);

// wait for key.

// Also the function cvWaitKey takes care of event processing

c = cvWaitKey(0);

// release both images

cvReleaseImage( &img );

cvReleaseImage( &img0 );

// clear memory storage - reset free space position

cvClearMemStorage( storage );

if( c == 27 )break;

}

cvDestroyWindow( wndname );

return0;

}

#ifdef _EiC

main(1,"squares.c");

#endif

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
车牌定位与分割是计算机视觉中的一个重要应用,可以应用于交通管理、车辆管理等领域。下面是一个基于C++和OpenCV车牌定位与分割的代码实现。 1. 车牌定位 采用基于颜色的车牌定位方法,步骤如下: 1)将图像转换为HSV空间,提取出蓝色色调的区域; 2)对提取出的区域进行形态学操作(膨胀、腐蚀),消除噪声; 3)使用轮廓查找算法,找到符合车牌形状的轮廓; 4)利用矩形包围框框出车牌区域。 代码如下: ```c++ Mat image = imread("car.jpg"); Mat hsv; cvtColor(image, hsv, COLOR_BGR2HSV); Mat mask; inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask); Mat kernel = getStructuringElement(MORPH_RECT, Size(19, 5)); morphologyEx(mask, mask, MORPH_CLOSE, kernel); vector<vector<Point>> contours; findContours(mask, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE); vector<RotatedRect> rects; for (auto contour : contours) { RotatedRect rect = minAreaRect(contour); if (rect.size.width > image.cols / 2 && rect.size.height > 10) { float ratio = rect.size.width / rect.size.height; if (ratio > 2 && ratio < 5) { rects.push_back(rect); } } } for (auto rect : rects) { Point2f points[4]; rect.points(points); for (int i = 0; i < 4; i++) { line(image, points[i], points[(i + 1) % 4], Scalar(0, 0, 255), 2); } } imshow("result", image); waitKey(); ``` 2. 车牌分割 采用基于垂直投影的车牌分割方法,步骤如下: 1)将车牌区域图像转换为灰度图; 2)对图像进行二值化处理; 3)计算垂直投影直方图; 4)根据垂直投影直方图确定字符的位置,并进行分割。 代码如下: ```c++ Mat gray; cvtColor(image, gray, COLOR_BGR2GRAY); threshold(gray, gray, 0, 255, THRESH_BINARY | THRESH_OTSU); Mat hist = Mat::zeros(Size(gray.cols, 1), CV_32SC1); for (int j = 0; j < gray.cols; j++) { for (int i = 0; i < gray.rows; i++) { if (gray.at<uchar>(i, j) == 0) { hist.at<int>(j)++; } } } int left = 0, right = 0; bool flag = false; vector<Rect> chars; for (int j = 0; j < hist.cols; j++) { if (!flag && hist.at<int>(j) > 0) { flag = true; left = j; } else if (flag && hist.at<int>(j) == 0) { flag = false; right = j; if (right - left > 10) { chars.push_back(Rect(left, 0, right - left, gray.rows)); } } } for (auto rect : chars) { rectangle(image, rect, Scalar(0, 0, 255), 2); } imshow("result", image); waitKey(); ``` 以上就是车牌定位与分割的C++和OpenCV实现代码。需要注意的是,对于不同的车牌颜色和形状,可能需要调整代码中的阈值和参数,才能得到较好的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值