《ofo车牌识别》研发心得05-图像处理第3阶段:将7个数字抠出来并提取特征
【摘要】 图像处理的第3阶段是将7个数字抠出来并提取特征
s2-01将车牌抠出来
由于第一阶段裁出来的是彩色,需要进用新的参数进行处理。
而取边缘算法改为Canny(做到这时才知有这个算法......想重构,不过己经来不及),效果相当好。
来自,http://www.kongzhi.net/cases/caseview.php?id=2368 的说法:
Roberts算子检测方法对具有陡峭的低噪声的图像处理效果较好,但是利用roberts算子提取边缘的结果是边缘比较粗,因此边缘的定位不是很准确。
Sobel算子检测方法对灰度渐变和噪声较多的图像处理效果较好,sobel算子对边缘定位不是很准确,图像的边缘不止一个像素。
Prewitt算子检测方法对灰度渐变和噪声较多的图像处理效果较好。但边缘较宽,而且间断点多。
Laplacian算子法对噪声比较敏感,所以很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。
Canny方法不容易受噪声干扰,能够检测到真正的弱边缘。优点在于,使用两种不同的阈值分别检测强边缘和弱边缘,并且当弱边缘和强边缘相连时,才将弱边缘包含在输出图像中。
cv::medianBlur(ofo7CharReProcessImg,ofo7CharReProcessImg,11);//中值滤波
cv::cvtColor(ofo7CharReProcessImg,ofo7CharReProcessImg,COLOR_BGR2GRAY);//转灰度
cv::Canny(ofo7CharReProcessImg,ofo7CharReProcessImg,50,150,3);//取边缘
闭操作,用一个长条形将7个数字连起来
Mat elementOfo7CharReProcess = cv::getStructuringElement(MORPH_RECT,Size(25,1));//设置膨胀参数
cv::dilate(ofo7CharReProcessImg,ofo7CharReProcessImg,elementOfo7CharReProcess); //膨胀
接下来就是外接矩形,并判断是否为车牌
cv::threshold(ofo7CharReProcessImg,ofo7CharReProcessImg,0,255,CV_THRESH_OTSU+CV_THRESH_BINARY); //再次二值化,为绘制矩形做准备
vector< vector< Point> > contoursOfo7CharFind; //存放指针
cv::findContours(ofo7CharReProcessImg,contoursOfo7CharFind,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE); //找轮廓
for (int i=0;i<contoursOfo7CharFind.size();i++)
{
//绘制最小外接矩形
cv::Rect rectOfo7CharFind=cv::boundingRect(contoursOfo7CharFind[i]);
//判断是否为7个字符
if(
(((float(rectOfo7CharFind.width))/rectOfo7CharFind.height)>3.2)&&
(((float(rectOfo7CharFind.width))/rectOfo7CharFind.height)<4.8)&&
((rectOfo7CharFind.width>distanceQRx)||(rectOfo7CharFind.width>distanceQRy))
)
{
cv::rectangle(ofo7CharReProcessImg,rectOfo7CharFind,Scalar(255,255,255));
cout<<"Draw7Char: "<< rectOfo7CharFind.width <<"*"<<rectOfo7CharFind.height<<endl;
Ofo7CharX=rectOfo7CharFind.x;
Ofo7CharY=rectOfo7CharFind.y;
Ofo7CharWidth=rectOfo7CharFind.width;
Ofo7CharHeight=rectOfo7CharFind.height;
Ofo7CharFind++;
}
}
if(Ofo7CharFind!=1)
{
cout<<"ERROR:Can't Find OFO 7 Char position"<<endl;
continue;
}
s2-02将车牌抠出来
cv::Rect maskOfo7CharReProcessImg(Ofo7CharX, Ofo7CharY, Ofo7CharWidth,Ofo7CharHeight);
cv::Mat croppedOfo7CharReProcessImg(cropReProcessImg, maskOfo7CharReProcessImg);
s2-03将7个数字找出来并存放在数组中
cv::medianBlur(char7findImg,char7findImg,5);//中值滤波
cv::cvtColor(char7findImg,char7findImg,COLOR_BGR2GRAY);
cv::threshold(char7findImg,char7findImg,0,255,CV_THRESH_OTSU+CV_THRESH_BINARY); //再次二值化,为绘制矩形做准备
char7findImg.copyTo(char7findImgBw);
vector< vector< Point> > contourschar7findImg; //存放指针
cv::findContours(char7findImg,contourschar7findImg,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE); //找轮廓
for (int i=0;i<contourschar7findImg.size();i++)
{
//绘制最小外接矩形
cv::Rect rectRotateReProcess=cv::boundingRect(contourschar7findImg[i]);
if (
(((float(rectRotateReProcess.height))/rectRotateReProcess.width)>1.5)&&
(((float(rectRotateReProcess.height))/rectRotateReProcess.width)<4)&&
(rectRotateReProcess.height>((char7findImg.rows)*0.67))
)
{
cv::rectangle(char7findImg,rectRotateReProcess,Scalar(255,255,255));
charList[charListCount][1]=rectRotateReProcess.x;
charList[charListCount][2]=rectRotateReProcess.y;
charList[charListCount][3]=rectRotateReProcess.width;
charList[charListCount][4]=rectRotateReProcess.height;
charListCount++;
}
}
if(charListCount!=7)
{
cout<<"ERROR: Can't find ALL 7 char"<<endl;
continue;
}
s2-04根据x坐标,将数组重排(因为找出来的不是从左到右)
//冒泡排序
int charSortTemp[5];
for (int i=0;i<7;i++)
{
for (int j=i+1;j<7;j++)
{
if(charList[i][1]>charList[j][1])
{
for(int k=0;k<5;k++)
{
charSortTemp[k]=charList[i][k];
charList[i][k]=charList[j][k];
charList[j][k]=charSortTemp[k];
}
}
}
}
s2-05将7个数字抠出来,并resize成 32*72
for (int i=0;i<7;i++)
{
cout<<filename[i]<<endl;
cv::Rect maskCharList(charList[i][1],charList[i][2],charList[i][3],charList[i][4]);
cv::Mat croppedChar(croppedCharTempImg, maskCharList);
croppedChar.copyTo(croppedCharListImg[i]);
cv::resize(croppedCharListImg[i],croppedCharListImg[i],Size(32,72),0,0,INTER_CUBIC);
}
s2-06 将Mat矩阵转换成二维矩阵,因为Mat矩阵只能用一维指针来操作,太麻烦了
int imgArray[7][72][32];
for(int i=0;i<7;i++)
{
//先二值化
cv::threshold(croppedCharListImg[i],croppedCharListImg[i],0,255,CV_THRESH_OTSU+CV_THRESH_BINARY);
croppedCharListImg[i].convertTo(croppedCharListImg[i],CV_8U);
cv::MatIterator_<cv::Vec3b> it = croppedCharListImg[i].begin<cv::Vec3b>();
int t=0;
for(;it!=croppedCharListImg[i].end<cv::Vec3b>();it++)
{
if((((*it)[0])==255)&&(((*it)[1])==255)&&(((*it)[2])==255))
{
imgArray[i][t/32][t%32]=1;
} else {
imgArray[i][t/32][t%32]=0;
}
t++;
}
}
s2-07计算feature2(8*8区域中白点数)
int feature2Extract[7][32/8*72/8];
for (int i=0;i<7;i++)
{
int arrayNum=0;
for(int j=0;j<72;j=j+8)
{
for (int k=0;k<32;k=k+8)
{
int countBW=0;
for (int lj=0;lj<8;lj++)
{
for(int lk=0;lk<8;lk++)
{
if ((imgArray[i][j+lj][k+lk])==1)
{
countBW++;
}
}
}
feature2Extract[i][arrayNum]=countBW;
arrayNum++;
}
}
}
至此图像预处理搞定,可以扔进libsvm做训练了。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)