一、車牌的識別和校正
本文采用一工程多專案模式,以代碼呈現,因還未接觸MFC,所以敬請見諒,之后會繼續學習,不斷完善代碼,
車牌識別借鑒于CSDN博主吾理小子的博客,表達由衷的感謝!https://blog.csdn.net/qq_39960119/article/details/83930112
對其中的一些引數和定義做了一些修改,增加了對傾斜圖片的修正,不過鄙人對于傾斜角度引數的理解依舊不到位,因此對于角度的處理還是不太理解,屬實慚愧,
#include <iostream>
#include <opencv2\opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat OriginalImg;
OriginalImg = imread("TestPhoto.jpg", IMREAD_COLOR);//讀取原始彩色影像
if (OriginalImg.empty()) //判斷影像對否讀取成功
{
cout << "錯誤!讀取影像失敗\n";
return -1;
}
// imshow("原圖", OriginalImg); //顯示原始影像
cout << "Width:" << OriginalImg.rows << "\tHeight:" << OriginalImg.cols << endl;//列印長寬
Mat ResizeImg;
//if (OriginalImg.cols > 640)
resize(OriginalImg, ResizeImg, Size(640, 640 * OriginalImg.rows / OriginalImg.cols));
imshow("尺寸變換圖", ResizeImg);
unsigned char pixelB, pixelG, pixelR; //記錄各通道值
unsigned char DifMax = 65; //基于顏色區分的閾值設定
unsigned char B = 200, G = 80, R = 50; //各通道的閾值設定,針對與藍色車牌
Mat BinRGBImg = ResizeImg.clone(); //二值化之后的影像
int i = 0, j = 0;
for (i = 0; i < ResizeImg.rows; i++) //通過顏色分量將圖片進行二值化處理
{
for (j = 0; j < ResizeImg.cols; j++)
{
pixelB = ResizeImg.at<Vec3b>(i, j)[0]; //獲取圖片各個通道的值
pixelG = ResizeImg.at<Vec3b>(i, j)[1];
pixelR = ResizeImg.at<Vec3b>(i, j)[2];
if (abs(pixelB - B) < DifMax && abs(pixelG - G) < DifMax && abs(pixelR - R) < DifMax)
{ //將各個通道的值和各個通道閾值進行比較
BinRGBImg.at<Vec3b>(i, j)[0] = 255; //符合顏色閾值范圍內的設定成白色
BinRGBImg.at<Vec3b>(i, j)[1] = 255;
BinRGBImg.at<Vec3b>(i, j)[2] = 255;
}
else
{
BinRGBImg.at<Vec3b>(i, j)[0] = 0; //不符合顏色閾值范圍內的設定為黑色
BinRGBImg.at<Vec3b>(i, j)[1] = 0;
BinRGBImg.at<Vec3b>(i, j)[2] = 0;
}
}
}
imshow("基于顏色資訊二值化", BinRGBImg); //顯示二值化處理之后的影像
Mat BinOriImg; //形態學處理結果影像
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3)); //設定形態學處理窗的大小
dilate(BinRGBImg, BinOriImg, element,Point(-1, -1), 5); //進行多次膨脹操作
erode(BinOriImg, BinOriImg, element,Point(-1,-1),5); //進行多次腐蝕操作
imshow("形態學處理后", BinOriImg); //顯示形態學處理之后的影像
//--------------------------------------------------------------------------
double length, area, rectArea; //定義輪廓周長、面積、外界矩形面積
double rectDegree = 0.0; //矩形度=外界矩形面積/輪廓面積,比值越大說明效果越好
double long2Short = 0.0; //體態比=長邊/短邊
CvRect rect; //外界矩形:結構體包含x,y坐標,width和height
CvBox2D box, boxTemp; //外接矩形
CvPoint2D32f pt[4]; //矩形定點變數
double axisLong = 0.0, axisShort = 0.0; //矩形的長邊和短邊
/*double axisLongTemp = 0.0, axisShortTemp = 0.0;*///矩形的長邊和短邊
double LengthTemp; //中間變數
float angle = 0; //記錄車牌的傾斜角度
bool TestPlantFlag = 0; //車牌檢測成功標志位
cvtColor(BinOriImg, BinOriImg, CV_BGR2GRAY); //將形態學處理之后的影像轉化為灰度影像
threshold(BinOriImg, BinOriImg, 100, 255, THRESH_BINARY); //灰度影像二值化,//OTSU演算法(雙峰圖效果明顯)
CvMemStorage *storage = cvCreateMemStorage(0);//跟堆疊類似
CvSeq * seq = 0; //創建一個序列,CvSeq本身就是一個可以增長的序列,不是固定的序列
CvSeq * tempSeq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);//以點坐標形式,序列頭大小,儲存元素大小,儲存在之前的容器里
int cnt = cvFindContours(&(IplImage(BinOriImg)), storage, &seq, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
//第一個引數是IplImage指標型別,將MAT強制轉換為IplImage指標型別
//回傳輪廓的數目
//獲取二值影像中輪廓的個數
cout << "number of contours " << cnt << endl; //列印輪廓個數
for (tempSeq = seq; tempSeq != NULL; tempSeq = tempSeq->h_next)
{
length = cvArcLength(tempSeq); //獲取輪廓周長
area = cvContourArea(tempSeq); //獲取輪廓面積
if (area > 800 && area < 50000) //矩形區域面積大小判斷
{
rect = cvBoundingRect(tempSeq, 1);//計算矩形邊界
boxTemp = cvMinAreaRect2(tempSeq, 0); //獲取輪廓的矩形
cvBoxPoints(boxTemp, pt); //獲取矩形四個頂點坐標
angle = boxTemp.angle; //得到車牌傾斜角度
axisLong = sqrt(pow(pt[1].x - pt[0].x, 2) + pow(pt[1].y - pt[0].y, 2)); //計算長軸(勾股定理)
axisShort = sqrt(pow(pt[2].x - pt[1].x, 2) + pow(pt[2].y - pt[1].y, 2)); //計算短軸(勾股定理)
Point2d points;
vector<Point>dots;
for (int i = 0; i < 4; i++)
{
points.x = pt[i].x;
points.y = pt[i].y;
dots.push_back(points);
}
RotatedRect rect = minAreaRect(dots);
if (axisShort > axisLong) //短軸大于長軸,交換資料
{
LengthTemp = axisLong;
axisLong = axisShort;
axisShort = LengthTemp;
}
else
angle += 90;
rectArea = axisLong * axisShort; //計算矩形的面積
rectDegree = area / rectArea; //計算矩形度(比值越接近1說明越接近矩形)
long2Short = axisLong / axisShort; //計算長寬比
if (long2Short > 2.2 && long2Short < 3.8 && rectDegree > 0.63 && rectDegree < 1.37 && rectArea > 2000 && rectArea < 50000)
{
Mat GuiRGBImg = ResizeImg.clone();
TestPlantFlag = true; //檢測車牌區域成功
for (int i = 0; i < 4; ++i) //劃線框出車牌區域
cvLine(&(IplImage(GuiRGBImg)), cvPointFrom32f(pt[i]), cvPointFrom32f(pt[((i + 1) % 4) ? (i + 1) : 0]), CV_RGB(255, 0, 0));//實作閉口畫線
imshow("提取車牌結果圖", GuiRGBImg); //顯示最終結果圖
if (angle != 0)
{
Point2f center(pt->x + (axisLong / 2), pt->y - (axisLong / 2));
Mat warp = getRotationMatrix2D(center, angle, 1.0);
warpAffine(OriginalImg, OriginalImg, warp, Size(640, 640 * OriginalImg.rows / OriginalImg.cols));//不設定會出現記憶體問題
resize(OriginalImg, OriginalImg, Size(640, 640 * OriginalImg.rows / OriginalImg.cols));
imshow("旋轉后的原圖", OriginalImg);
imwrite("affineimg.jpg", OriginalImg);
}
else
{
Mat img_ROI = GuiRGBImg(Rect(pt->x+2, pt->y - axisShort+2, axisLong, axisShort));//提取感興趣區域這里+2是為了修正紅色矩形邊框
imshow("車牌", img_ROI);
resize(img_ROI, img_ROI, Size(354, 118));
imshow("車牌2", img_ROI);
imwrite("affineimg.jpg", img_ROI);
}
cout << "傾斜角度:" << angle << endl;
}
}
}
waitKey();
return 0;
}
代碼運行效果圖如下:

二、獲取車牌
此處是對修正后的原圖進行的處理,提取為354×118像素的車牌校正后的圖片
識別與提取的代碼上面寫過了,拿過來用就行,
Mat img_ROI = GuiRGBImg(Rect(pt->x - axisLongTemp+2, pt->y - axisShortTemp+2, axisLongTemp-5, axisShortTemp-5));//提取感興趣區域
imshow("車牌", img_ROI);
resize(img_ROI, img_ROI, Size(354, 118));
imshow("車牌2", img_ROI);
imwrite("img_ROI.jpg", img_ROI);
運行結果如下:
二·1 邊緣檢測法
借鑒于CSDN博主Nine-days的部分代碼,并做了一些完善和普適兼容,表達由衷的感謝!https://blog.csdn.net/u011808673/article/details/78510692
int main()
{
Mat OriginalImg;
OriginalImg = imread("blurcar.jpg", IMREAD_COLOR);//讀取原始彩色影像
if (OriginalImg.empty()) //判斷影像對否讀取成功
{
cout << "錯誤!讀取影像失敗\n";
return -1;
}
cout << "Width:" << OriginalImg.rows << "\tHeight:" << OriginalImg.cols << endl;//列印長寬
Mat ResizeImg;
resize(OriginalImg, ResizeImg, Size(640, 640 * OriginalImg.rows / OriginalImg.cols));
imshow("尺寸變換圖", ResizeImg);
Mat gray_img;
cvtColor(ResizeImg, gray_img, CV_RGB2GRAY);
Mat blur_img;
blur(gray_img, blur_img, Size(3, 3));
Mat candy_img;
Canny(blur_img, candy_img, 300, 100, 3);
imshow("test", candy_img);
//形態學處理
//圖片膨脹處理
Mat dilate_image, erode_image, BinOriImg;
//自定義 核進行 x 方向的膨脹腐蝕
Mat elementX = getStructuringElement(MORPH_RECT, Size(22, 1));
Mat elementY = getStructuringElement(MORPH_RECT, Size(1, 20));
Point point(-1, -1);
dilate(candy_img, dilate_image, elementX, point, 2);
erode(dilate_image, erode_image, elementX, point, 4);
dilate(erode_image, dilate_image, elementX, point, 2);
//自定義 核進行 Y 方向的膨脹腐蝕
erode(dilate_image, erode_image, elementY, point, 1);
dilate(erode_image, BinOriImg, elementY, point, 2);
imwrite("dilate_image.jpg", BinOriImg);
//噪聲處理
//平滑處理 中值濾波
Mat blur_image;
medianBlur(BinOriImg, blur_image, 15);
medianBlur(blur_image, blur_image, 15);
imshow("test2", blur_image);
接下來就是對處理過的影像進行車牌提取,代碼上面寫過了,拿來用就行,運行結果如下圖:
三、字符分割
此字符分割解決了垂直投影切割“川”字和其他易于被分割錯誤的漢字的問題,簡化了對于車牌中的點被分割的問題,
借鑒于博主lxx_123456的文章,表達由衷的感謝!https://blog.csdn.net/lxx_123456/article/details/79078570
#define _CRT_SECURE_NO_WARNINGS
#define cols_value 0 //cols:2 row:1對于edge搜索
#define row_value 0 //對于川來說不需要去邊框
#include <opencv2/opencv.hpp>
#include <math.h>
#include<vector>
#include<cv.h>
using namespace cv;
using namespace std;
vector<Mat> verticalProjectionMat(Mat Image)//封裝垂直投影
{
int perPixelValue;//每個像素的值
int width = Image.cols;
int height = Image.rows;
printf("圖片的寬%d圖片的高%d", width, height);
int* projectValArry = new int[width];//創建用于儲存每列白色像素個數的陣列
memset(projectValArry, 0, width * 4);//初始化陣列
for (int col = 0; col < width; col++)//列
{
int cols_convert_num = 0;
for (int i = 0; i < height - 1; i++)
{
if (Image.at<uchar>(i, col) != Image.at<uchar>(i + 1, col))
cols_convert_num++;
}
if (cols_convert_num < cols_value)
{
continue;
}
for (int row = 0; row < height; row++)//行
{
int row_convert_num = 0;
for (int j = 0; j < width - 1; j++)
{
if (Image.at<uchar>(row,j) != Image.at<uchar>(row,j+1))
row_convert_num++;
}
if (row_convert_num < row_value)
{
continue;
}
perPixelValue = Image.at<uchar>(row, col);//每個像素的值
//if (perPixelValue == 0)//如果是白底黑字
if (perPixelValue == 255)//如果是黑底白字
{
projectValArry[col]++;//列上的疊加
}
}
}
Mat verticalProjectionMat(height, width, CV_8U, Scalar(255));//垂直投影的畫布
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
perPixelValue = 255; //背景設定為白色
verticalProjectionMat.at<uchar>(i, j) = perPixelValue;//遍歷設定背景顏色
}
}
for (int i = 0; i < width; i++)//垂直投影直方圖
{
for (int j = 0; j < projectValArry[i]; j++)
{
perPixelValue = 0; //直方圖設定為黑色
verticalProjectionMat.at<uchar>(height - 1 - j, i) = perPixelValue;
}
}
imshow("垂直投影", verticalProjectionMat);//以上是如何讓這個畫布形成的呢
Rect rect(0, 0, 120, 40);
Mat image_cut = Mat(verticalProjectionMat, rect);
Mat image_copy = image_cut.clone();
//imshow("切割圖片", image_copy);
vector<Mat> roiList;//用于儲存分割出來的每個字符
int startIndex = 0;//記錄進入字符區的索引
int endIndex = 0;//記錄進入空白區域的索引
bool inBlock = false;//是否遍歷到了字符區內
for (int i = 0; i < Image.cols; i++)//cols=width
{
if (!inBlock && projectValArry[i] != 0)//進入字符區
{
inBlock = true;
startIndex = i;
}
else if (projectValArry[i] ==0 && inBlock)//進入空白區
{
while (i < Image.cols / 7)//分割漢字
{
i++;
}
endIndex = i;
inBlock = false;
Mat roiImg = Image(Range(0, Image.rows), Range(startIndex, endIndex + 1));
roiList.push_back(roiImg);
}
}
delete[] projectValArry;
return roiList;
}
int main()
{
Point point(-1, -1);
//Mat Image = imread("E:\\LicenseRecognition\\EdgeSearch\\EdgeSearch\\img_ROI.jpg");
Mat Image = imread("E:\\LicenseRecognition\\EdgeSearch\\GetPointedLabel\\img_ROI.jpg");//可用不同的路徑
Mat Image1;
cvtColor(Image, Image1, CV_BGR2GRAY);
imshow("灰度化", Image1);
Mat Image2;
threshold(Image1, Image2, 158, 255, CV_THRESH_BINARY);//二值化//100,255 Edge//157,255顏色分割 162edge分割
imshow("二值化", Image2);
Mat Image3;
Mat element = getStructuringElement(MORPH_RECT, Size(1,1));
morphologyEx(Image2, Image3, MORPH_OPEN, element,point,4);//開運算
imshow("開運算", Image3);
int size = 0;
char szName[30] = { 0 };
vector<Mat> b = verticalProjectionMat(Image3);
for (int j = 0; j < b.size(); j++)
{
if (j == 2)//去除車牌中的點
{
continue;
}
sprintf(szName, "vertical_%d.jpg", j);
resize(b[j], b[j],Size(20, 40));//不可調整順序,不然質量差
imshow(szName, b[j]);
imwrite(szName, b[j]);
}
waitKey(0);
}
分割效果:
四、模板匹配以及識別
借鑒于某車牌識別系統開源原始碼中模板匹配及識別一小部分,
缺點1:8與B、5與6的識別不夠準確(因為是像素相減),幸好鄙人多測驗了幾張圖,發現8與B、5與6的判斷標準恰巧是相反的,算作投機取巧,此為學習研究人士的大忌,若無奈之才疏學淺,實不可取,
缺點2:識別的漢字有限,代碼后加了其他省份的車牌漢字可用作代碼識別修改
如有大佬有解決缺點完善代碼之法可以積極評論指正,在下感激不盡!
//此為head.h頭檔案
#pragma once
#include "cv.h"
#include "highgui.h"
struct pattern
{
double feature[33]; //樣本的特征向量
int number; //待識別字符在樣本庫中的序列號
};
//定義特征提取函式
void GetFeature(IplImage *src, pattern &pat);
#define _CRT_SECURE_NO_WARNINGS
#include "head.h"
#include<opencv2/opencv.hpp>
#include<cstring>
#include<highgui/highgui.hpp>
using namespace cv;
using namespace std;
void GetFeature(IplImage* src, pattern &pat)
{
CvScalar s;
int i, j;
for (i = 0; i < 33; i++)
pat.feature[i] = 0.0;
//影像大小是20*40大小的,分成25塊
//********第一行***********
//第一塊
for (j = 0; j < 8; j++)
{
for (i = 0; i < 4; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[0] += 1.0;
}
}
//第二塊
for (j = 0; j < 8; j++)
{
for (i = 4; i < 8; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[1] += 1.0;
}
}
//第三塊
for (j = 0; j < 8; j++)
{
for (i = 8; i < 12; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[2] += 1.0;
}
}
//第四塊
for (j = 0; j < 8; j++)
{
for (i = 12; i < 16; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[3] += 1.0;
}
}
//第五塊
for (j = 0; j < 8; j++)
{
for (i = 16; i < 20; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[4] += 1.0;
}
}
//********第二行***********
//第六塊
for (j = 8; j < 16; j++)
{
for (i = 0; i < 4; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[5] += 1.0;
}
}
//第七塊
for (j = 8; j < 16; j++)
{
for (i = 4; i < 8; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[6] += 1.0;
}
}
//第八塊
for (j = 8; j < 16; j++)
{
for (i = 8; i < 12; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[7] += 1.0;
}
}
//第九塊
for (j = 8; j < 16; j++)
{
for (i = 12; i < 16; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[8] += 1.0;
}
}
//第十塊
for (j = 8; j < 16; j++)
{
for (i = 16; i < 20; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[9] += 1.0;
}
}
//********第三行***********
//第十一塊
for (j = 16; j < 24; j++)
{
for (i = 0; i < 4; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[10] += 1.0;
}
}
//第十二塊
for (j = 16; j < 24; j++)
{
for (i = 4; i < 8; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[11] += 1.0;
}
}
//第十三塊
for (j = 16; j < 24; j++)
{
for (i = 8; i < 12; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[12] += 1.0;
}
}
//第十四塊
for (j = 16; j < 24; j++)
{
for (i = 12; i < 16; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[13] += 1.0;
}
}
//第十五塊
for (j = 16; j < 24; j++)
{
for (i = 16; i < 20; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[14] += 1.0;
}
}
//********第四行***********
//第十六塊
for (j = 24; j < 32; j++)
{
for (i = 0; i < 4; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[15] += 1.0;
}
}
//第十七塊
for (j = 24; j < 32; j++)
{
for (i = 4; i < 8; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[16] += 1.0;
}
}
//第十八塊
for (j = 24; j < 32; j++)
{
for (i = 8; i < 12; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[17] += 1.0;
}
}
//第十九塊
for (j = 24; j < 32; j++)
{
for (i = 12; i < 16; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[18] += 1.0;
}
}
//第二十塊
for (j = 24; j < 32; j++)
{
for (i = 16; i < 20; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[19] += 1.0;
}
}
//********第五行***********
//第二十一塊
for (j = 32; j < 40; j++)
{
for (i = 0; i < 4; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[20] += 1.0;
}
}
//第二十二塊
for (j = 32; j < 40; j++)
{
for (i = 4; i < 8; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[21] += 1.0;
}
}
//第二十三塊
for (j = 32; j < 40; j++)
{
for (i = 8; i < 12; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[22] += 1.0;
}
}
//第二十四塊
for (j = 32; j < 40; j++)
{
for (i = 12; i < 16; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[23] += 1.0;
}
}
//第二十五塊
for (j = 32; j < 40; j++)
{
for (i = 16; i < 20; i++)
{
s = cvGet2D(src, j, i);
if (s.val[0] == 255)
pat.feature[24] += 1.0;
}
}
//下面統計方向交點特征
for (i = 0; i < 20; i++)
{
s = cvGet2D(src, 8, i);
if (s.val[0] == 255)
pat.feature[25] += 1.0;
}
for (i = 0; i < 20; i++)
{
s = cvGet2D(src, 16, i);
if (s.val[0] == 255)
pat.feature[26] += 1.0;
}
for (i = 0; i < 20; i++)
{
s = cvGet2D(src, 24, i);
if (s.val[0] == 255)
pat.feature[27] += 1.0;
}
for (i = 0; i < 20; i++)
{
s = cvGet2D(src, 32, i);
if (s.val[0] == 255)
pat.feature[28] += 1.0;
}
for (j = 0; j < 40; j++)
{
s = cvGet2D(src, j, 4);
if (s.val[0] == 255)
pat.feature[29] += 1.0;
}
for (j = 0; j < 40; j++)
{
s = cvGet2D(src, j, 8);
if (s.val[0] == 255)
pat.feature[30] += 1.0;
}
for (j = 0; j < 40; j++)
{
s = cvGet2D(src, j, 12);
if (s.val[0] == 255)
pat.feature[31] += 1.0;
}
for (j = 0; j < 40; j++)
{
s = cvGet2D(src, j, 16);
if (s.val[0] == 255)
pat.feature[32] += 1.0;
}
}
int main()
{
IplImage * dst_image[7];
dst_image[0]= cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_0.jpg", 0);
dst_image[1] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_1.jpg", 0);
dst_image[2] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_3.jpg", 0);
dst_image[3] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_4.jpg", 0);
dst_image[4] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_5.jpg", 0);
dst_image[5] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_6.jpg", 0);
dst_image[6] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterSeperate\\vertical_7.jpg", 0);
IplImage * char_sample[34];//字符樣本影像陣列
IplImage * hanzi_sample[9];//漢字樣本影像陣列
pattern char_pattern[34];//定義字符樣品庫結構陣列
pattern hanzi_pattern[9];//定義漢字樣品庫結構陣列
pattern TestSample[7];//定義待識別字符結構陣列
//載入字符模板
char_sample[0] = cvLoadImage("template\\0.bmp", 0);
char_sample[1] = cvLoadImage("template\\1.bmp", 0);
char_sample[2] = cvLoadImage("template\\2.bmp", 0);
char_sample[3] = cvLoadImage("template\\3.bmp", 0);
char_sample[4] = cvLoadImage("template\\4.bmp", 0);
char_sample[5] = cvLoadImage("template\\5.bmp", 0);
char_sample[6] = cvLoadImage("template\\6.bmp", 0);
char_sample[7] = cvLoadImage("template\\7.bmp", 0);
char_sample[8] = cvLoadImage("template\\8.bmp", 0);
char_sample[9] = cvLoadImage("template\\9.bmp", 0);
char_sample[10] = cvLoadImage("template\\A.bmp", 0);
char_sample[11] = cvLoadImage("template\\B.bmp", 0);
char_sample[12] = cvLoadImage("template\\C.bmp", 0);
char_sample[13] = cvLoadImage("template\\D.bmp", 0);
char_sample[14] = cvLoadImage("template\\E.bmp", 0);
char_sample[15] = cvLoadImage("template\\F.bmp", 0);
char_sample[16] = cvLoadImage("template\\G.bmp", 0);
char_sample[17] = cvLoadImage("template\\H.bmp", 0);
char_sample[18] = cvLoadImage("template\\J.bmp", 0);
char_sample[19] = cvLoadImage("template\\K.bmp", 0);
char_sample[20] = cvLoadImage("template\\L.bmp", 0);
char_sample[21] = cvLoadImage("template\\M.bmp", 0);
char_sample[22] = cvLoadImage("template\\N.bmp", 0);
char_sample[23] = cvLoadImage("template\\P.bmp", 0);
char_sample[24] = cvLoadImage("template\\Q.bmp", 0);
char_sample[25] = cvLoadImage("template\\R.bmp", 0);
char_sample[26] = cvLoadImage("template\\S.bmp", 0);
char_sample[27] = cvLoadImage("template\\T.bmp", 0);
char_sample[28] = cvLoadImage("template\\U.bmp", 0);
char_sample[29] = cvLoadImage("template\\V.bmp", 0);
char_sample[30] = cvLoadImage("template\\W.bmp", 0);
char_sample[31] = cvLoadImage("template\\X.bmp", 0);
char_sample[32] = cvLoadImage("template\\Y.bmp", 0);
char_sample[33] = cvLoadImage("template\\Z.bmp", 0);
//載入漢字模板
hanzi_sample[0] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\川.bmp", 0);
hanzi_sample[1] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\鄂.bmp", 0);
hanzi_sample[2] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\黑.bmp", 0);
hanzi_sample[3] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\京.bmp", 0);
hanzi_sample[4] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\遼.bmp", 0);
hanzi_sample[5] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\瓊.bmp", 0);
hanzi_sample[6] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\湘.bmp", 0);
hanzi_sample[7] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\粵.bmp", 0);
hanzi_sample[8] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\浙.bmp", 0);
//hanzi_sample[0] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\川a.bmp", 0);
//hanzi_sample[1] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\鄂a.bmp", 0);
//hanzi_sample[2] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\黑a.bmp", 0);
//hanzi_sample[3] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\京a.bmp", 0);
//hanzi_sample[4] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\遼a.bmp", 0);
//hanzi_sample[5] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\瓊a.bmp", 0);
//hanzi_sample[6] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\湘a.bmp", 0);
//hanzi_sample[7] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\粵a.bmp", 0);
//hanzi_sample[8] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\浙a.bmp", 0);
//hanzi_sample[9] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\蘇a.bmp", 0);
//hanzi_sample[10] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\藏a.bmp", 0);
//hanzi_sample[11] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\甘a.bmp", 0);
//hanzi_sample[12] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\贛a.bmp", 0);
//hanzi_sample[13] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\桂a.bmp", 0);
//hanzi_sample[14] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\滬a.bmp", 0);
//hanzi_sample[15] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\吉a.bmp", 0);
//hanzi_sample[16] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\冀a.bmp", 0);
//hanzi_sample[17] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\津a.bmp", 0);
//hanzi_sample[18] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\晉a.bmp", 0);
//hanzi_sample[19] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\魯a.bmp", 0);
//hanzi_sample[20] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\蒙a.bmp", 0);
//hanzi_sample[21] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\閩a.bmp", 0);
//hanzi_sample[22] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\寧a.bmp", 0);
//hanzi_sample[23] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\青a.bmp", 0);
//hanzi_sample[24] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\陜a.bmp", 0);
//hanzi_sample[25] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\皖a.bmp", 0);
//hanzi_sample[26] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\新a.bmp", 0);
//hanzi_sample[27] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\渝a.bmp", 0);
//hanzi_sample[28] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\豫a.bmp", 0);
//hanzi_sample[29] = cvLoadImage("E:\\LicenseRecognition\\EdgeSearch\\CharacterMatching\\template\\云a.bmp", 0);
//提取字符樣本特征
for (int i = 0; i < 34; i++)
{
GetFeature(char_sample[i], char_pattern[i]);
}
//提取漢字字符特征
for (int i = 0; i < 9; i++)
{
GetFeature(hanzi_sample[i], hanzi_pattern[i]);
}
//提取待識別字符特征
for (int i = 0; i < 7; i++)
{
GetFeature(dst_image[i], TestSample[i]);
}
//進行模板匹配
double min = 100000.0;
for (int num = 0; num < 1; num++)
{
for (int i = 0; i < 9; i++)
{
double diff = 0.0;
for (int j = 0; j < 25; j++)
{
diff += fabs(TestSample[num].feature[j] - hanzi_pattern[i].feature[j]);
}
for (int j = 25; j < 33; j++)
{
diff += fabs(TestSample[num].feature[j] - hanzi_pattern[i].feature[j]) * 9;
}
if (diff < min)
{
min = diff;
TestSample[num].number = i;
}
}
}
for (int num = 1; num < 7; num++)
{
double min_min = 1000000.0;
for (int i = 0; i < 34; i++)
{
double diff_diff = 0.0;
for (int j = 0; j < 25; j++)
{
diff_diff += fabs(TestSample[num].feature[j] - char_pattern[i].feature[j]);
}
for (int j = 25; j < 33; j++)
{
diff_diff += fabs(TestSample[num].feature[j] - char_pattern[i].feature[j]);
}
if (diff_diff < min_min)
{
min_min = diff_diff;
TestSample[num].number = i;
}
}
}
String result = "";//存放識別出的字符
for (int i = 0; i < 1; i++)
{
switch (TestSample[i].number)
{
case 0:
result += "川";
break;
case 1:
result += "鄂";
break;
case 2:
result += "黑";
break;
case 3:
result += "京";
break;
case 4:
result += "遼";
break;
case 5:
result += "瓊";
break;
case 6:
result += "湘";
break;
case 7:
result += "粵";
break;
case 8:
result += "浙";
break;
default:
cout<<("識別失敗")<<endl;
break;
}
}
for (int i = 1; i < 7; i++)
{
switch (TestSample[i].number)
{
case 0:
result += "0";
break;
case 1:
result += "1";
break;
case 2:
result += "2";
break;
case 3:
result += "3";
break;
case 4:
result += "4";
break;
case 5:
result += "6";
break;
case 6:
result += "5";
break;
case 7:
result += "7";
break;
case 8:
result += "B";
break;
case 9:
result += "9";
break;
case 10:
result += "A";
break;
case 11:
result += "8";
break;
case 12:
result += "C";
break;
case 13:
result += "D";
break;
case 14:
result += "E";;
break;
case 15:
result += "F";
case 16:
result += "G";
break;
case 17:
result += "H";
break;
case 18:
result += "J";
break;
case 19:
result += "K";
break;
case 20:
result += "L";
break;
case 21:
result += "M";
break;
case 22:
result += "N";
break;
case 23:
result += "P";
break;
case 24:
result += "Q";
break;
case 25:
result += "R";
break;
case 26:
result += "S";
break;
case 27:
result += "T";
break;
case 28:
result += "U";
break;
case 29:
result += "U";
break;
case 30:
result += "W";
break;
case 31:
result += "X";
break;
case 32:
result += "Y";
break;
case 33:
result += "Z";
break;
default:
cout<<("識別失敗");
break;
}
}
cout<<"車牌的最終結果為:"<<result<<endl;//顯示結果
system("pause");
return 0;
}
需要template模板,網上下載即可

結果效果:
五、總結
特別感謝CSDN博主吾理小子、CSDN博主Nine-days、CSDN博主lxx_123456等
也感謝CSDN全體制作OpenCV車牌識別有關博客的博主,為此博客奠定了知識基礎,此博客僅供學習使用,希望可以給著急于做出車牌識別的朋友一點靈感,不足之處可以指出,如對讀者朋友們有用,希望可以點個贊,
六、感悟
這是我第一次通過觀摩借鑒復用各位CSDN大佬們的博客文章以及開源代碼整合而成的專案,算是我代碼路上一個開始,自此逐漸擺脫了拘泥于書本知識而非親身實踐的學習惡習,搞車牌識別專案的時候會遇到很多很多困難與疑惑,通過找博客和參考其他博主的經驗和教訓來解決自己的困難,比起我之前遇到困難就退縮,只想白嫖成果要好千萬倍(雖然這個也白嫖了很多),希望可以和CSDN上的兄弟們一起進步共同加油!
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/78184.html
標籤:其他
