opencv实现车牌识别之车牌号定位_1
转载文章:http://blog.csdn.net/u011630458/article/details/43604689
简介
按照在哪里跌倒就在哪里爬起来的精神,本章继续做车牌号的检测识别。所有步骤分为3步完成:车牌号定位,车牌号字符分割、字符识别。 本章为第一部分:车牌号定位。
效果演示
正式开始讲解之前,先看下车牌号定位出来的效果演示。注:本文所有图片均来源于网络。
如图所示,定位到车牌号之后,将车牌号用黄色框选起来,同时将该车牌复制为新图片显示出来。
代码及实现原理讲解
图像灰阶/二值化
首先也是常用的操作,将图像灰阶化,然后从像素值为255一侧开始,以累积像素占总像素5%的的地方作为二值化的阀值,进而获得对应的二值化图像。 对应代码如下:
- void pic_gray(Mat& mat1, Mat& mat2){
- IplImage pI = mat1;
- uchar* ptr;
- CvScalar s;
- int width = mat1.rows;
- int height = mat1.cols;
- mat2 = cv::Mat(width, height, CV_8UC1, 1);
- ptr = mat2.ptr(0);
- for(int i = 0; i < width; i++){
- for(int j=0; j<height; j++){
- s = cvGet2D(&pI,i,j);
- int grayScale = (int)(s.val[0]*0.299 + s.val[1]*0.587 + s.val[2]*0.114);
- ptr[i*height+j] = grayScale;
- }
- }
- }
- int histogram_Calculate(Mat& mat1, int number){
- Mat gray_hist;
- int histSize = 255;
- float range[] = { 0, 255 } ;
- const float* histRange = { range };
- bool uniform = true;
- bool accumulate = false;
- int width, height;
- int i, j;
- uchar* ptr = mat1.ptr(0);
- long int pixel_all = 0, pixel_Calc = 0;
- calcHist(&mat1, 1, 0, Mat(), gray_hist, 1, &histSize, &histRange, uniform, accumulate);
- width = gray_hist.rows;
- height = gray_hist.cols;
- for(i=0; i<=width; i++){
- pixel_all += ptr[i];
- }
- for(i=0; i<=width; i++){
- pixel_Calc += ptr[255 - i];
- if(((pixel_Calc * 100) / pixel_all) > number){
- i = 255 - i;
- break;
- }
- }
- return i;
- }
- void pic_Thresholding(Mat& mat1, int threshold){
- uchar* ptr = mat1.ptr(0);
- int width = mat1.rows;
- int height = mat1.cols;
- for(int i = 0; i < width; i++){
- for(int j=0;j<height;j++){
- if(ptr[i*height+j] > 125){
- ptr[i*height+j] = 255;
- }else{
- ptr[i*height+j] = 0;
- }
- }
- }
- }
- #include <opencv2/core/core.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <math.h>
- #include <string.h>
- #include <opencv/cv.h>
- #include <stdio.h>
- #include "lib/normal.h"
- #define DEBUG
- #ifdef DEBUG
- #define DE(format, ...) printf(format, ## __VA_ARGS__)
- #else
- #define DE(format, ...) while(0)
- #endif
- int main(int argc,char *argv[]){
- int threshold = 0;
- Mat img = cv::imread(argv[1]);
- double x_beta;
- int width = img.rows;
- int height = img.cols;
- int** selection_1, selection_Number_1;
- int** address_1, address_Number_1;
- int i, j, color_num, box_flag;
- Mat img_3, img_4, img_5;
- Mat img_2;
- char str[2];
- Point s1, s2;
- Scalar color = Scalar( 0, 255, 255);
- namedWindow("img");
- imshow("img",img);
- pic_gray(img, img_2);
- threshold = histogram_Calculate(img_2, 5);
- DE("threshold:%d\n",threshold);
- pic_Thresholding(img_2, threshold);
- namedWindow("tmp");
- imshow("tmp", img_2);
- waitKey(0);
- return 0;
- }
void pic_gray(Mat& mat1, Mat& mat2){IplImage pI = mat1;uchar* ptr;CvScalar s;
int width = mat1.rows;
int height = mat1.cols;mat2 = cv::Mat(width, height, CV_8UC1, 1);
ptr = mat2.ptr(0);
for(int i = 0; i < width; i++){for(int j=0; j<height; j++){ s = cvGet2D(&pI,i,j);int grayScale = (int)(s.val[0]*0.299 + s.val[1]*0.587 + s.val[2]*0.114);ptr[i*height+j] = grayScale;}
}
} int histogram_Calculate(Mat& mat1, int number){ Mat gray_hist; int histSize = 255; float range[] = { 0, 255 } ; const float* histRange = { range }; bool uniform = true; bool accumulate = false; int width, height; int i, j; uchar* ptr = mat1.ptr(0); long int pixel_all = 0, pixel_Calc = 0;
calcHist(&mat1, 1, 0, Mat(), gray_hist, 1, &histSize, &histRange, uniform, accumulate);width = gray_hist.rows;
height = gray_hist.cols;for(i=0; i<=width; i++){pixel_all += ptr[i];
}for(i=0; i<=width; i++){pixel_Calc += ptr[255 - i];if(((pixel_Calc * 100) / pixel_all) > number){i = 255 - i;break; }
}
return i;
}void pic_Thresholding(Mat& mat1, int threshold){ uchar* ptr = mat1.ptr(0); int width = mat1.rows; int height = mat1.cols;
for(int i = 0; i < width; i++){for(int j=0;j<height;j++){if(ptr[i*height+j] > 125){ptr[i*height+j] = 255; }else{ptr[i*height+j] = 0; }}
}
}
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <math.h> #include <string.h> #include <opencv/cv.h> #include <stdio.h> #include "lib/normal.h" #define DEBUG #ifdef DEBUG #define DE(format, ...) printf(format, ## __VA_ARGS__) #else #define DE(format, ...) while(0) #endif int main(int argc,char *argv[]){ int threshold = 0; Mat img = cv::imread(argv[1]); double x_beta; int width = img.rows; int height = img.cols; int** selection_1, selection_Number_1; int** address_1, address_Number_1; int i, j, color_num, box_flag; Mat img_3, img_4, img_5; Mat img_2; char str[2]; Point s1, s2; Scalar color = Scalar( 0, 255, 255); namedWindow("img"); imshow("img",img); pic_gray(img, img_2); threshold = histogram_Calculate(img_2, 5); DE("threshold:%d\n",threshold); pic_Thresholding(img_2, threshold); namedWindow("tmp"); imshow("tmp", img_2); waitKey(0); return 0; }
首先pic_gray来讲源图像img,转化为灰阶图像img_2;接着用histogram_Calculate函数,以5%的比例算出二值化的阀值threshold,最后用pic_Thresholding, 二值化图像。效果演示如下:
图像分割
车牌是使用是蓝底白字,而这个二值化图像img_2中,蓝色的背景被去除了,留下了白色的字。而根据车牌的特点,每一行中蓝色和白色的交替应该至少是7次。 转化在这个img_2的二值图像中,则表示在车牌所在的行中,像素值的跳变至少是7次。所以根据这个特性,可以将图像中,可能是车牌号所在位置的图像分割出来。 使用的代买如下:
- int** selection_Function_1(Mat& mat1, int* number){
- int **a, i, j, flag, num = 0, enter_flag = 0;
- int width = mat1.rows;
- int height = mat1.cols;
- uchar* ptr = mat1.ptr(0);
- a = (int**)malloc(width * sizeof(int*));
- for(i=0; i<width; i++){
- flag = 0;
- for(j=0; j< height-1; j++){
- if(ptr[i*height + j] != ptr[i*height + j +1]){
- flag += 1;
- }
- }
- if((flag >= 7) && (enter_flag == 0)){
- a[num] = (int* )malloc(2 * sizeof(int));
- a[num][0] = i;
- enter_flag = 1;
- }else if((enter_flag != 0) && (flag < 7)){
- if(i - a[num][0] < 8){
- continue;
- }
- a[num][1] = i - 1;
- num ++;
- enter_flag = 0;
- }
- }
- *number = num;
- return a;
- }
- void pic_cutting(Mat& mat1, Mat& pic_cutting, int** selection, int number){
- int real_height = mat1.cols;
- IplImage pI_1 = mat1;
- IplImage pI_2;
- IplImage pI_3;
- CvScalar s;
- pic_cutting = cv::Mat(selection[number][1] - selection[number][0], real_height, CV_8UC3, 1);
- pI_2 = pic_cutting;
- for(int i = selection[number][0]; i < selection[number][1]; i++){
- for(int j=0; j<real_height; j++){
- s = cvGet2D(&pI_1, i, j);
- cvSet2D(&pI_2, i-selection[number][0], j, s);
- }
- }
- }
- int main(int argc,char *argv[]){
- …………….
- selection_1 = selection_Function_1(img_2, &selection_Number_1);
- for(i=0; i< selection_Number_1; i++){
- DE(”selection_1[%d]:%d, %d\n”, i, selection_1[i][0], selection_1[i][1]);
- }
- for(i=0; i<selection_Number_1; i++){
- pic_cutting(img, img_3, selection_1, i);
- sprintf(str, ”%d”, i);
- namedWindow(str);
- imshow(str, img_3);
- }
- waitKey(0);
- return 0;
- }
int** selection_Function_1(Mat& mat1, int* number){int **a, i, j, flag, num = 0, enter_flag = 0;int width = mat1.rows;int height = mat1.cols;uchar* ptr = mat1.ptr(0);a = (int**)malloc(width * sizeof(int*));for(i=0; i<width; i++){flag = 0;for(j=0; j< height-1; j++){if(ptr[i*height + j] != ptr[i*height + j +1]){flag += 1; }}if((flag >= 7) && (enter_flag == 0)){a[num] = (int* )malloc(2 * sizeof(int));a[num][0] = i;enter_flag = 1;}else if((enter_flag != 0) && (flag < 7)){if(i - a[num][0] < 8){continue; }a[num][1] = i - 1;num ++;enter_flag = 0;}}*number = num;return a;
}
void pic_cutting(Mat& mat1, Mat& pic_cutting, int** selection, int number){int real_height = mat1.cols;IplImage pI_1 = mat1;IplImage pI_2;IplImage pI_3;CvScalar s;pic_cutting = cv::Mat(selection[number][1] - selection[number][0], real_height, CV_8UC3, 1);pI_2 = pic_cutting;for(int i = selection[number][0]; i < selection[number][1]; i++){for(int j=0; j<real_height; j++){s = cvGet2D(&pI_1, i, j);cvSet2D(&pI_2, i-selection[number][0], j, s);}}
}int main(int argc,char *argv[]){................selection_1 = selection_Function_1(img_2, &selection_Number_1);for(i=0; i< selection_Number_1; i++){DE("selection_1[%d]:%d, %d\n", i, selection_1[i][0], selection_1[i][1]); }for(i=0; i<selection_Number_1; i++){pic_cutting(img, img_3, selection_1, i);sprintf(str, "%d", i);namedWindow(str);imshow(str, img_3);}waitKey(0);return 0;
}
首先使用函数selection_Function_1,将二值图像img_2中连续出现了至少七次跳变行的图像行开始位置与结束位置保存到二维数组selection_1,img_2中一共有 多少次出现满足连续出现至少七次跳变行图像的统计保存在selection_Number_1中。接着函数pic_cutting用img源图像长度作为新图像长度,用selection_1中保存的行开始,结束位置作为新图像宽度,从源图像中将对应位置的图像复制到img_3 中。显示效果如下:
从显示效果途中,我们看到原图像被分割为了6张图片,车牌在第五张图片中。
图片筛选
从车牌号特性知道,车牌的背景为蓝色。这里就是检测分割出来的图片中,蓝色占的数量,将不满足要求的图片抛弃掉。 接着将筛选出来的图片,再一次灰阶、二值化。 代码如下:
- int choice_Color(Mat& mat1, int color_Start, int color_End){
- int width = mat1.rows;
- int height = mat1.cols;
- uchar* ptr = mat1.ptr(0);
- IplImage pI_1;
- int flag[width];
- int num, i, j, num_width = 0;
- CvScalar s;
- pI_1 = mat1;
- cvCvtColor(&pI_1, &pI_1, CV_BGR2HSV);
- for(i=0; i<width; i++){
- num = 0;
- for(j=0; j<height; j++){
- s = cvGet2D(&pI_1, i, j);
- if((s.val[0] >= color_Start) && (s.val[0] <= color_End)){
- num += 1;
- }
- }
- if(num > 20){
- flag[i] = 1;
- num_width += 1;
- }else{
- flag[i] = 0;
- }
- num = 0;
- }
- return num_width;
- }
- int main(int ragc, char** argv){
- ……….
- for(i=0; i<selection_Number_1; i++){
- pic_cutting(img, img_3, selection_1, i);
- color_num = choice_Color(img_3, 110, 120); //蓝色为H:110–120
- DE(”color_num:%d\n”, color_num);
- if(color_num > 5){
- IplImage pI_1 = img_3;
- cvCvtColor(&pI_1, &pI_1, CV_HSV2BGR);
- pic_gray(img_3, img_3);
- threshold = histogram_Calculate(img_3, 3);
- pic_Thresholding(img_3, threshold);
- sprintf(str, ”%d”, i);
- namedWindow(str);
- imshow(str, img_3);
- }
- }
- waitKey(0);
- return 0;
- }
int choice_Color(Mat& mat1, int color_Start, int color_End){int width = mat1.rows;int height = mat1.cols;uchar* ptr = mat1.ptr(0);IplImage pI_1;int flag[width];int num, i, j, num_width = 0;CvScalar s;pI_1 = mat1;cvCvtColor(&pI_1, &pI_1, CV_BGR2HSV);for(i=0; i<width; i++){num = 0;for(j=0; j<height; j++){s = cvGet2D(&pI_1, i, j);if((s.val[0] >= color_Start) && (s.val[0] <= color_End)){num += 1; }}if(num > 20){flag[i] = 1;num_width += 1;}else{flag[i] = 0;}num = 0;}return num_width;
}int main(int ragc, char** argv){..........for(i=0; i<selection_Number_1; i++){pic_cutting(img, img_3, selection_1, i);color_num = choice_Color(img_3, 110, 120); //蓝色为H:110--120DE("color_num:%d\n", color_num);if(color_num > 5){IplImage pI_1 = img_3;cvCvtColor(&pI_1, &pI_1, CV_HSV2BGR);pic_gray(img_3, img_3);threshold = histogram_Calculate(img_3, 3);pic_Thresholding(img_3, threshold);sprintf(str, "%d", i);namedWindow(str);imshow(str, img_3);}}waitKey(0);return 0;
}
使用choice_Color将分割出来的每张图片img_3都依次转化为HSV,然后根据H来检测出图像中蓝色像素超过20的行数,并将该数据返回到color_num中。 接着判断如果color_num 大于了5行就表示该图像不能抛弃。 演示效果如下:
因为该图像中,蓝色干扰背景相当多,所以该步骤,只筛选丢弃了最后一张图片。
opencv实现车牌识别之车牌号定位_1相关推荐
- 纯手码 | 基于OpenCV的车牌识别(Sobel、颜色定位),绝对实用
车牌识别大体上需要经历过Sobel定位.颜色定位.SVM对定位来的候选车牌进行评测,给出评分,最后通过提取HOG特征按照训练模型进入ANN识别. 这一章节介绍 定位相关的逻辑代码,其中定位用到 Sob ...
- 基于OpenCV的车牌识别(Sobel、颜色定位)
车牌识别大体上需要经历过Sobel定位.颜色定位.SVM对定位来的候选车牌进行评测,给出评分,最后通过提取HOG特征按照训练模型进入ANN识别. 这一章节介绍 定位相关的逻辑代码,其中定位用到 Sob ...
- Python 基于 opencv 的车牌识别系统, 可以准确识别车牌号
大家好,我是程序员徐师兄,6 年大厂程序员经验,点击关注我 简介 毕业设计基于Opencv的车牌识别系统 车牌搜索识别找出某个车牌号 对比识别车牌系统 车牌数据库认证系统 车牌图文搜索系统 车牌数据库 ...
- 2021-01-07 python opencv实现车牌识别 颜色定位
python opencv实现车牌识别 颜色定位 主要代码参考https://blog.csdn.net/wzh191920/article/details/79589506 GitHub:https ...
- 基于OpenCV的车牌识别的设计与实现
随着大数据和互联网技术的快速发展,利用人工智能技术实现车牌信息的自动识别推荐成为研究的热门话题.通过对基于OpenCV的车牌识别系统的网站功能需要进行讨论研究,这种跨平台计算机视觉和机器学习非常适用于 ...
- Python+Opencv简易车牌识别(二):形态学运算,HSV颜色空间筛选与图像分割
注:这是依然一个简单的车牌识别demo 1.前言 在上一篇Python+Opencv简易车牌识别(一):基于HSV颜色空间的图像分割中,我们讲了如何仅基于颜色来进行简单粗暴的车牌分割.今天我们考虑对图 ...
- 【树莓派开发】02-基于OpenCV的车牌识别处理(LPR)
[说明]:疫情期间比较闲学习了python.LPR这个东西,基于OpenCV已经做过很多遍了,通过这个小项目利用树莓派来熟悉Python编程,而且通过实际操作可以掌握一些具体的细节与技巧,这里我将整个 ...
- 【开源分享】基于Python+OpenCV+PyQt5车牌识别(GUI界面)
亲测无错:基于Python+OpenCV+PyQt5车牌识别(GUI界面)绝对可以用的!!!!! 基于Python+OpenCV+PyQt5车牌识别(GUI界面) 参考文档
- spring boot + maven + opencv 车牌识别系统,包含车牌检测、车牌号识别训练
yx-image-recognition 介绍 这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目 包含车牌识别.人脸识别等功能,贯穿样本处理.模 ...
最新文章
- Python-Django配置阿里大于的短信验证码接口
- 游戏开发中的图像生成
- 下载了一堆mysql_干掉一堆mysql数据库,仅需这样一个shell脚本
- wxWidgets:文档/视图框架
- IE8“开发人员工具”(下)
- react使用less预编译语言和本地代理配置
- (原)MongoDB在系统中的使用
- Socket编程例子
- 【微信小程序】自己的小程序跳转到京东小程序商品详情页
- realtek是什么意思_Realtek高清晰音频管理器 全解析
- Arduino ESP8266 AP Web 服务器示例程序
- CIS-Linux Centos7最新基线标准进行系统层面基线检测
- 【推荐】我的FLASH情结2010——浅谈FLASH WEB GAME与创业(3)
- 使用xlsxwriter简单的将截图插入excel表格中
- 新手上路vscode+php|php文档格式化与代码重构
- 话费充值API接口源码文档
- 我们把AI画图玩坏了,这60张图片又惊悚又可爱
- 用python实现简单飞行棋
- JavaScript图片弹窗
- 将IP地址更新到3323域名