#include "stdafx.h"
#include <cv.h>
#include <highgui.h>
#include <math.h>
int main(int argc, char* argv[])
{
//=======================================================
//图像缩小
//=======================================================
IplImage *src = 0; //源图像指针
IplImage *dst = 0; //目标图像指针
float scale = 0.2; //缩放倍数为0.2倍
CvSize dst_cvsize; //目标图像尺寸
/* the first command line parameter must be image file name */
if ( argc == 2 && (src = cvLoadImage(argv[1], -1))!=0 )
{
//如果命令行传递了需要打开的图片就无须退出,所以注释掉下面一行!
//return -1;
}
else
{
src = cvLoadImage("003.jpg"); //载入工作目录下文件名为“tiger.jpg”的图片。
}
dst_cvsize.width = src->width * scale; //目标图像的宽为源图象宽的scale倍
dst_cvsize.height = src->height * scale; //目标图像的高为源图象高的scale倍
dst = cvCreateImage( dst_cvsize, src->depth, src->nChannels); //构造目标图象
cvResize(src, dst, CV_INTER_LINEAR); //缩放源图像到目标图像
//IplImage-->cv::Mat转换
cv::Mat suoxiao;
suoxiao=cv::Mat(dst);
//保存缩小后的照片
cv::imwrite("缩小照片.jpg",suoxiao);
//=======================================================
//图像预处理
//=======================================================
cv::Mat image=cv::imread("缩小照片.jpg");
// 彩色转灰度,BGR颜色空间
cvtColor(image,image,CV_BGR2GRAY);
//进行灰度拉伸,强化车牌边缘,注意:这里处理的图像只为切割车牌做一张清楚的车牌二值化图像,并不参与图像预处理
cv::imwrite("灰度化图像.jpg",image);
IplImage* imga=cvLoadImage("灰度化图像.jpg", 0);
IplImage *tmp = cvCloneImage(imga);
cvMorphologyEx(imga, imga, tmp, NULL, CV_MOP_GRADIENT, 1);
;
//IplImage-->cv::Mat转换
cv::Mat ss;
ss=cv::Mat(imga);
//阀值化灰度拉伸后的车牌,这里的阀值不能太高也不能太低,在35--55左右对所有车牌几乎都能显示得比较清晰
cv::Mat catEdgedd;
threshold(ss,catEdgedd,45,255,cv::THRESH_BINARY);
cv::namedWindow("待切割车牌图片");cv::imshow("待切割车牌图片",catEdgedd);
//保存待切割车牌图片
cv::imwrite("待切割车牌图片.jpg",catEdgedd);
/* 低通滤波--这里使用的为中值滤波
cv::Mat image1;
cv::blur(image,image1,cv::Size(5,5));
*/
//中值滤波--这里使用的为中值滤波,注意:这里的输入变量仍为灰度化的图像image
cv::Mat image2;
cv::medianBlur(image,image2,5);
//边缘检测
//cv::Mat catEd;
//morphologyEx(image2,catEd,cv::MORPH_GRADIENT,cv::Mat());
//sobel变换竖向边缘检测滤波,进行2次--这里没有使用边缘检测
cv::Mat sobel;
cv::Sobel(image2,sobel,CV_8U,1,0,3,0.4,128);
cv::Mat sobel1;
cv::Sobel(sobel,sobel1,CV_8U,1,0,3);
// 阈值化--阀值为实验数据,暂定120
cv::Mat catEdge;
threshold(sobel1,catEdge,120,255,cv::THRESH_BINARY);
// 定义结构元素做开操作和闭操作
cv::Mat se(13,13,CV_8U,cv::Scalar(1));
cv::Mat closed;
cv::morphologyEx(catEdge,closed,cv::MORPH_CLOSE,se);
cv::Mat opened;
cv::morphologyEx(closed,opened,cv::MORPH_OPEN,se);
//保存和显示形态学处理后的图片,可以不显示图片所以加注释
cv::imwrite("开闭后图片.jpg",opened);
//cv::namedWindow("开闭后图片");cv::imshow("开闭后图片",opened);
//cvWaitKey(-1);
//=======================================================
//车牌轮廓定位
//车牌提取
//=======================================================
IplImage* plate_image;//分割出的车牌图像
IplImage* src1=cvLoadImage("开闭后图片.jpg", 0);
//为轮廓显示图像申请空间,3通道图像,以便用彩色显示
IplImage* dst1 = cvCreateImage( cvGetSize(src1), 8, 3);
//创建内存块,将该块设置成默认值,当前默认大小为64k
CvMemStorage* storage = cvCreateMemStorage(0);
//可动态增长元素序列
CvSeq* contour = 0;
//在二值图像中寻找轮廓
cvFindContours( src1, storage,&contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
cvZero( dst1 );//清空数组
cvCvtColor(src1,dst1,CV_GRAY2BGR);
//可存放在1-,2-,3-,4-TUPLE类型的捆绑数据的容器
CvScalar color = CV_RGB( 255, 0, 0);
for( ; contour != 0; contour = contour->h_next)
{
CvRect aRect = cvBoundingRect( contour, 1 ); //使用边界框的方式,取得轮廓的最小矩形
int tmparea=aRect.width*aRect.height;
float fact=float(float(aRect.width)/float(aRect.height));
if (fact>=3.0 && fact<=6.0&& tmparea>=1600&&tmparea<=9500)
{
cvRectangle(dst1,cvPoint(aRect.x,aRect.y),cvPoint(aRect.x+aRect.width ,aRect.y+aRect.height),color,2);
//切割出车牌
IplImage* src2=cvLoadImage("待切割车牌图片.jpg", 0);
cvSetImageROI(src2,aRect);
plate_image= cvCreateImage(cvSize(aRect.width,aRect.height),8,1);
cvCopy(src2,plate_image);
//cvNot(plate_image,plate_image);//车牌图像颜色反转
}
}
//显示画出轮廓后的图像,即车牌定位后的图像
cvNamedWindow("车牌定位",1);
cvShowImage("车牌定位",dst1);
//显示切割出来的车牌
cvNamedWindow("车牌切割",1);
cvShowImage("车牌切割",plate_image);
//IplImage-->cv::Mat类的转换,并保存车牌切割图片
cv::Mat ll;
ll=cv::Mat(plate_image);
cv::imwrite("车牌切割.jpg",ll);
//cvWaitKey(0);
/*cvDestroyWindow("车牌定位");
cvReleaseImage(&dst1);
cvDestroyWindow("车牌切割");
cvReleaseImage(&plate_image);*/
//=======================================================
//车牌倾斜校正
//=======================================================
//倾斜校正
IplImage* plate_image1=cvLoadImage("车牌切割.jpg", 0);
IplImage *cor =cvCreateImage(cvGetSize(plate_image1),8,1);
CvScalar s,s_new;
double num=0;
double leftaverage =0;
double rightaverage =0;
int iHeight= plate_image1->height;
int iWidth= plate_image1->width;
double slope =0;
int pix_new;
//计算前半部分的斜率
for(int ht=0;ht<iHeight;ht++)
{
for (int wt=0;wt<iWidth/6;wt++ )
{
s=cvGet2D(plate_image1,ht,wt);
if(0==s.val[0])
{
num+=iWidth/2-wt;
leftaverage+=ht*(iWidth/2-wt);
}
}
}
leftaverage/=num;
num=0;
//计算后半部分的斜率
for(int ht=0;ht<iHeight;ht++)
{
for (int wt=(iWidth/6)*5;wt<iWidth;wt++)
{
s=cvGet2D(plate_image1,ht,wt);
if(0==s.val[0])
{
num+=iWidth/2-wt;
rightaverage+=ht*(iWidth/2-wt);
}
}
}
rightaverage/=num;
//求出斜率,并对斜率做适当缩放,以避免校正过量
slope=(leftaverage-rightaverage)/(iWidth/2)*1.2;
//图像映射
for(int ht=0;ht<iHeight;ht++)
{
for(int wt=0;wt<iWidth/2;wt++)
{
pix_new=int((ht-(wt-iWidth/2)*slope));
if(pix_new<0||pix_new>=iHeight)
{
s.val[0]=255;
cvSet2D(cor,ht,wt,s);
}
else
{
s=cvGet2D (plate_image1,pix_new,wt);
s_new.val[0]=s.val[0];
cvSet2D(cor,ht,wt,s_new);
}
}
}
for(int ht=0;ht<iHeight;ht++)
{
for(int wt=iWidth/2;wt<iWidth;wt++)
{
pix_new=int((ht-(wt-iWidth/2)*(slope)));
if(pix_new<0||pix_new>=iHeight)
{
s.val[0]=255;
cvSet2D(cor,ht,wt,s);
}
else
{
s=cvGet2D(plate_image1,pix_new,wt);
s_new.val[0]=s.val[0];
cvSet2D(cor,ht,wt,s);
}
}
}
cvNot(cor,cor);
cvErode(cor,cor,0,1);
cvDilate(cor,cor);
//显示图像
cvNamedWindow("倾斜校正",1);
cvShowImage("倾斜校正",cor);
cvWaitKey(-1);
cvDestroyWindow("倾斜校正");
cvReleaseImage(&cor);
cvDestroyWindow("车牌定位");
cvReleaseImage(&dst1);
cvDestroyWindow("车牌切割");
cvReleaseImage(&plate_image);
return 0;
}
评论0