欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

OpenCV3實(shí)現(xiàn)車牌識(shí)別(C++版)

 更新時(shí)間:2022年08月01日 11:59:00   作者:給我高高飛起來(lái)啊  
這篇文章主要為大家詳細(xì)介紹了OpenCV3實(shí)現(xiàn)車牌識(shí)別功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了OpenCV3實(shí)現(xiàn)車牌識(shí)別的具體代碼,供大家參考,具體內(nèi)容如下

車牌識(shí)別(基于OpenCV3.4.7+VS2017)

視頻識(shí)別

藍(lán)色車牌識(shí)別

視覺(jué)入坑的第一個(gè)Demo(注釋很詳細(xì)),因?yàn)楸救酥巴涎?,一直沒(méi)能寫詳細(xì)實(shí)現(xiàn)博客,先將代碼貼出來(lái)供大家交流,個(gè)人認(rèn)為精華部分在字符切割(直接用指針遍歷像素加限制條件切割),車牌模板已上傳,整個(gè)工程也已上傳,后續(xù)完善各環(huán)節(jié)實(shí)現(xiàn)步驟詳解。

頭文件:Global.h

#ifdef GLOBAL

extern int flag_1;
extern bool flag;
extern bool specialFlag;
extern int captureRead
extern string carPlate;
extern char test[10];


extern struct stu1
{
?? ?char number;
?? ?Mat image;
?? ?double matchDegree;
};
extern struct ?stu
{
?? ?Mat image;
?? ?double matchDegree;
};

#endif

唯一的.cpp文件:PlateIdentify.cpp(說(shuō)實(shí)話,這Demo挺 “C” 的)

#include <opencv2/opencv.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include"Global.h"
#include <windows.h>
#include <string>

using namespace std;
using namespace cv;

void fillHole(const Mat srcBw, Mat &dstBw); ? ? ? ? ? //填補(bǔ)算法
Mat cutOne(Mat cutImage); ? ? ? ? //邊框切割算法
void CharCut(Mat srcImage); ? ? ? ? ? ?//單個(gè)字符切割算法
Mat Location(Mat srcImage); ? ? ? ? ? ?//圖像識(shí)別算法
void SingleCharCut(Mat doubleImage, int k1, int k2);
void ShowChar();
void MatchProvince();
void MatchNumber();
void readProvince();
void readNumber();
void VideoShow(Mat videoImage);
void GetStringSize(HDC hDC, const char* str, int* w, int* h);
void putTextZH(Mat &dst, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline);


int flag_1; ? ? ? ? ?//判斷是否傾斜,需不需要二次定位車牌
bool flag; ? ? ? //判斷提取是否成功
bool specialFlag = false; ? ?//針對(duì)嵌套車牌
int captureRead = 0;
int videoFlag = 0;
string carPlateProvince = " ";
string carPlate = " ";
char test[10];
vector<Mat> ?singleChar; ? ? ? ? //字符圖片容器

int main(int argc, char *argv[])
{
?? ?//計(jì)時(shí)開始
?? ?double time0 = static_cast<double>(getTickCount());

?? ?//視頻操作
?? ?VideoCapture capture("1.mp4");
?? ?Mat srcImage;
?? ?Mat theFirst;
?? ?int singleCharLength;

?? ?//讀取字符圖片
?? ?readProvince();
?? ?readNumber();

?? ?while (1) {
?? ??? ?capture >> srcImage;
?? ??? ?try {

?? ??? ??? ?if (!srcImage.data) { printf("視頻識(shí)別結(jié)束 ? ?\n"); return 0; }

?? ??? ??? ?if (srcImage.rows >= srcImage.cols)
?? ??? ??? ?{
?? ??? ??? ??? ?resize(srcImage, srcImage, Size(640, 640 * srcImage.rows / srcImage.cols));
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?resize(srcImage, srcImage, Size(400 * srcImage.cols / srcImage.rows, 400));
?? ??? ??? ?}

?? ??? ??? ?//車牌定位

?? ??? ??? ?theFirst = Location(srcImage);

?? ??? ??? ?if (flag)
?? ??? ??? ?{
?? ??? ??? ??? ?if (flag_1 == 1) ? ? ? ? ? ? ? ? ? ? ?//旋轉(zhuǎn)后要再次定位去上下雜邊
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?theFirst = Location(theFirst);
?? ??? ??? ??? ??? ?flag_1 = 0;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?if (flag)
?? ??? ??? ?{
?? ??? ??? ??? ?//車牌切割(切割上下邊,去除干擾)
?? ??? ??? ??? ?theFirst = cutOne(theFirst);
?? ??? ??? ??? ?//單個(gè)字符切割
?? ??? ??? ??? ?CharCut(theFirst);
?? ??? ??? ??? ?singleCharLength = singleChar.size();
?? ??? ??? ??? ?printf("采取字符輪廓數(shù) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? %d\n", singleCharLength);
?? ??? ??? ??? ?ShowChar();
?? ??? ??? ??? ?if (singleCharLength >= 7)
?? ??? ??? ??? ?{

?? ??? ??? ??? ??? ?MatchProvince();
?? ??? ??? ??? ??? ?MatchNumber();
?? ??? ??? ??? ?}

?? ??? ??? ??? ?singleChar.clear();
?? ??? ??? ?}

?? ??? ?}
?? ??? ?catch (Exception e) {

?? ??? ??? ?cout << "Standard ecxeption : " << e.what() << " \n" << endl;

?? ??? ?}

?? ??? ?if (waitKey(30) >= 0)
?? ??? ??? ?break;
?? ??? ?//延時(shí)30ms

?? ?}
?? ??? ?//imwrite("match\\xxxxxx.bmp", singleChar[2]);


?? ? ? ? ? ? ? ? ? ?
?? ?time0 = ((double)getTickCount() - time0) / getTickFrequency();
?? ?cout << "運(yùn)行時(shí)間" << time0 << "秒" << endl;


?? ?waitKey(0);
}

void fillHole(const Mat srcBw, Mat &dstBw)
{
?? ?Size imageSize = srcBw.size();
?? ?Mat Temp = Mat::zeros(imageSize.height + 2, imageSize.width + 2, srcBw.type());//延展圖像
?? ?srcBw.copyTo(Temp(Range(1, imageSize.height + 1), Range(1, imageSize.width + 1)));

?? ?cv::floodFill(Temp, Point(0, 0), Scalar(255));

?? ?Mat cutImg;//裁剪延展的圖像
?? ?Temp(Range(1, imageSize.height + 1), Range(1, imageSize.width + 1)).copyTo(cutImg);

?? ?dstBw = srcBw | (~cutImg);
}

Mat Location(Mat srcImage)
{
?? ?//判斷變量重賦值
?? ?flag = false;

?? ?//用于旋轉(zhuǎn)車牌
?? ?int?? ?imageWidth, imageHeight; ? ? ? ? ? ?//輸入圖像的長(zhǎng)和寬
?? ?imageWidth = srcImage.rows; ? ? ? ? ? ? ? ? //獲取圖片的寬
?? ?imageHeight = srcImage.cols; ? ? ? ? ? ? ? ? //獲取圖像的長(zhǎng)
?? ?//!!!!!!!!!!!!!!!!!!!
?? ?Mat blueROI = srcImage.clone();
?? ?cvtColor(blueROI, blueROI, CV_BGR2HSV);
?? ?//namedWindow("hsv圖");
?? ?//imshow("hsv圖", blueROI);
?? ?//中值濾波操作
?? ?medianBlur(blueROI, blueROI, 3);
?? ?//namedWindow("medianBlur圖");
?? ?//imshow("medianBlur圖", blueROI);
?? ?//將藍(lán)色區(qū)域二值化
?? ?inRange(blueROI, Scalar(100, 130, 50), Scalar(124, 255, 255), blueROI);
?? ?//namedWindow("blue圖");
?? ?//imshow("blue圖", blueROI);

?? ?Mat element1 = getStructuringElement(MORPH_RECT, Size(2, 2)); ? ? //size()對(duì)速度有影響
?? ?morphologyEx(blueROI, blueROI, MORPH_OPEN, element1);
?? ?//namedWindow("0次K運(yùn)算后圖像");
?? ?//imshow("0次K運(yùn)算后圖像", blueROI);

?? ?Mat element0 = getStructuringElement(MORPH_ELLIPSE, Size(10, 10)); ? ? //size()對(duì)速度有影響
?? ?morphologyEx(blueROI, blueROI, MORPH_CLOSE, element0);
?? ?//namedWindow("0次閉運(yùn)算后圖像");
?? ?//imshow("0次閉運(yùn)算后圖像", blueROI);
?? ?vector<vector<Point>> contours;

?? ?findContours(blueROI, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);


?? ?int cnt = contours.size();
?? ?cout << "number of contours ? " << cnt << endl; ?//打印輪廓個(gè)數(shù)
?? ?if (cnt == 0)
?? ?{
?? ??? ?if (!flag) ? ? ? ?//在視頻中顯示
?? ??? ?{
?? ??? ??? ?cout << "圖中無(wú)車牌 ? ? ? " << endl;
?? ??? ??? ?//namedWindow("提取車牌結(jié)果圖");
?? ??? ??? ?//imshow("提取車牌結(jié)果圖", srcImage); ? ?//顯示最終結(jié)果圖
?? ??? ??? ?VideoShow(srcImage);
?? ??? ??? ?return ?srcImage;
?? ??? ?}
?? ?}

?? ?double area;
?? ?double longside, temp, shortside, long2short;
?? ?float ?angle = 0;
?? ?Rect rect;
?? ?RotatedRect box; ? ?//可旋轉(zhuǎn)的矩形盒子
?? ?Point2f vertex[4]; ? ? ? ?//四個(gè)頂點(diǎn)

?? ?Mat image = srcImage.clone(); ? ? ? ?//為后來(lái)顯示做準(zhǔn)備
?? ?Mat ?rgbCutImg; ? ? ? ? ? ? ? ? ? ? ? //車牌裁剪圖

?? ?//box.points(vertex); ? ? ? ? ? ?//獲取矩形四個(gè)頂點(diǎn)坐標(biāo)
?? ?//length=arcLength(contour[i]); ? ? ? ? ? ? ? ? ? ? ? ?//獲取輪廓周長(zhǎng)
?? ?//area=contourArea(contour[i]); ? ? ? ? ? ? ? ? ? ? ? ?//獲取輪廓面積
?? ?//angle=box.angle; ? ? ? ? ? //得到車牌傾斜角度

?? ?for (int i = 0; i < cnt; i++)
?? ?{
?? ??? ?area = contourArea(contours[i]); ? ? ? ? ? ? ?//獲取輪廓面積
?? ??? ?if (area > 600 && area < 15000) ? ? //矩形區(qū)域面積大小判斷
?? ??? ?{
?? ??? ??? ?rect = boundingRect(contours[i]); ? ?//計(jì)算矩形邊界
?? ??? ??? ?box = minAreaRect(contours[i]); ? ? ?//獲取輪廓的矩形
?? ??? ??? ?box.points(vertex); ? ? ? ? ? ? ? ? ?//獲取矩形四個(gè)頂點(diǎn)坐標(biāo)
?? ??? ??? ?angle = box.angle; ? ? ? ? ? ? ? ? ? //得到車牌傾斜角度

?? ??? ??? ?longside = sqrt(pow(vertex[1].x - vertex[0].x, 2) + pow(vertex[1].y - vertex[0].y, 2));
?? ??? ??? ?shortside = sqrt(pow(vertex[2].x - vertex[1].x, 2) + pow(vertex[2].y - vertex[1].y, 2));
?? ??? ??? ?if (shortside > longside) ? //短軸大于長(zhǎng)軸,交換數(shù)據(jù)
?? ??? ??? ?{
?? ??? ??? ??? ?temp = longside;
?? ??? ??? ??? ?longside = shortside;
?? ??? ??? ??? ?shortside = temp;
?? ??? ??? ??? ?cout << "交換" << endl;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ??? ?angle += 90;
?? ??? ??? ?long2short = longside / shortside;
?? ??? ??? ?if (long2short > 1.5 && long2short < 4.5)
?? ??? ??? ?{
?? ??? ??? ??? ?flag = true;
?? ??? ??? ??? ?for (int i = 0; i < 4; ++i) ? ? ? //劃線框出車牌區(qū)域
?? ??? ??? ??? ??? ?line(image, vertex[i], vertex[((i + 1) % 4) ? (i + 1) : 0], Scalar(0, 255, 0), 1, CV_AA);


?? ??? ??? ??? ?if (!flag_1) ? ? ? ?//在視頻中顯示
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?printf("提取成功\n");
?? ??? ??? ??? ??? ?/*namedWindow("提取車牌結(jié)果圖");
?? ??? ??? ??? ??? ?imshow("提取車牌結(jié)果圖", image); ?*/ ?//顯示最終結(jié)果圖
?? ??? ??? ??? ??? ?VideoShow(image);
?? ??? ??? ??? ?}

?? ??? ??? ??? ?rgbCutImg = srcImage(rect);
?? ??? ??? ??? ?//namedWindow("車牌圖");
?? ??? ??? ??? ?//imshow("車牌圖", rgbCutImg);//裁剪出車牌?? ?
?? ??? ??? ??? ?break; ? ? ? ? ? ? ?//退出循環(huán),以免容器中變量變換
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?cout << "傾斜角度:" << angle << endl;
?? ?if (flag ?&& ?fabs(angle) > 0.8) ? ? ? ?//車牌過(guò)偏,轉(zhuǎn)一下 ? ? ? ? ? ? ? ?偏移角度小時(shí)可不調(diào)用,后續(xù)找到合適范圍再改進(jìn)
?? ?{
?? ??? ?flag_1 = 1;
?? ??? ?Mat RotractImg(imageWidth, imageHeight, CV_8UC1, Scalar(0, 0, 0)); ? ? ? //傾斜矯正圖片
?? ??? ?Point2f center = box.center; ? ? ? ? ? //獲取車牌中心坐標(biāo)
?? ??? ?Mat M2 = getRotationMatrix2D(center, angle, 1); ? ? ? //計(jì)算旋轉(zhuǎn)加縮放的變換矩陣?
?? ??? ?warpAffine(srcImage, RotractImg, M2, srcImage.size(), 1, 0, Scalar(0)); ? ? ? //進(jìn)行傾斜矯正
?? ??? ?//namedWindow("傾斜矯正后圖片",0);
?? ??? ?//imshow("傾斜矯正后圖片", RotractImg);
?? ??? ?rgbCutImg = RotractImg(rect); ? ? ?//截取車牌彩色照片
?? ??? ?//namedWindow("矯正后車牌照");
?? ??? ?//imshow("矯正后車牌照", rgbCutImg);
?? ??? ??? ?/*cout << "矩形中心:" << box.center.x << "," << box.center.y << endl;*/
?? ??? ?return ?rgbCutImg;
?? ?}

?? ?if (flag == false) {
?? ??? ?printf("提取失敗\n"); ? ? ? ? ? ? ? ? ? ? ?//后期加邊緣檢測(cè)法識(shí)別
?? ??? ?if (!flag_1) ? ? ? ?//在視頻中顯示
?? ??? ?{
?? ??? ??? ?/*namedWindow("提取車牌結(jié)果圖");
?? ??? ??? ?imshow("提取車牌結(jié)果圖", image); */ ? //顯示最終結(jié)果圖
?? ??? ??? ?VideoShow(image);
?? ??? ?}
?? ?}
?? ?return rgbCutImg;
}

Mat cutOne(Mat cutImage)
{
?? ?//打印車牌長(zhǎng)寬
?? ?try {
?? ??? ?/*cout << " ? ? ? ? ? cutImage.rows ?: ? " << cutImage.rows << endl;
?? ??? ?cout << " ? ? ? ? ? cutImage.cols ?: ? " << cutImage.cols << endl;*/
?? ??? ?if(cutImage.rows >= cutImage.cols)
?? ??? ?resize(cutImage, cutImage, Size(320, 320 * cutImage.rows / cutImage.cols));
?? ?}
?? ?catch (Exception e)
?? ?{
?? ??? ?resize(cutImage, cutImage, Size(320, 100));
?? ?}
?? ?/*namedWindow("Resize車牌圖");
?? ?imshow("Resize車牌圖", cutImage);*/
?? ?int height = cutImage.rows;
?? ?cout << "\tHeight:" << height << "\tWidth:" << 320 << endl;
?? ?if (height < 86)
?? ?{
?? ??? ?//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!處理新型嵌套車牌!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
?? ??? ?printf("嵌套車牌\n");
?? ??? ?specialFlag = true;

?? ?}

?? ?Mat whiteROI = cutImage.clone();

?? ?if (specialFlag)
?? ?{
?? ??? ?cvtColor(whiteROI, whiteROI, CV_BGR2HSV);
?? ??? ?//將白色區(qū)域二值化
?? ??? ?//inRange(whiteROI, Scalar(0, 0, 0), Scalar(130, 50, 245), whiteROI); ? ? ?//增大 S 即飽和度可以使hsv白色檢測(cè)范圍更大
?? ??? ?inRange(whiteROI, Scalar(0, 0, 0), Scalar(180, 100, 245), whiteROI);
?? ??? ?//namedWindow("specialFlagwhiteROI圖");
?? ??? ?//imshow("specialFlagwhiteROI圖", whiteROI);
?? ?}
?? ?else
?? ?{
?? ??? ?GaussianBlur(whiteROI, whiteROI, Size(3, 3), 0, 0);
?? ??? ?/*namedWindow("GaussianBlur車牌圖");
?? ??? ?imshow("GaussianBlur車牌圖", whiteROI);*/

?? ??? ?cvtColor(whiteROI, whiteROI, CV_BGR2HSV);

?? ??? ?//medianBlur(whiteROI, whiteROI, 3);
?? ??? ?//namedWindow("Src_medianBlur圖");
?? ??? ?//imshow("Src_medianBlur圖", whiteROI);

?? ??? ?//將白色區(qū)域二值化
?? ??? ?//inRange(whiteROI, Scalar(0, 0, 10), Scalar(180, 30, 255), whiteROI); ? ? ?//增大 S 即飽和度可以使hsv白色檢測(cè)范圍更大
?? ??? ?inRange(whiteROI, Scalar(0, 0, 10), Scalar(180, 120, 255), whiteROI);
?? ??? ?//namedWindow("whiteROI圖");
?? ??? ?//imshow("whiteROI圖", whiteROI);
?? ?}


?? ?/*
?? ?Mat element0 = getStructuringElement(MORPH_ELLIPSE, Size(4, 4)); ? ? //size()對(duì)速度有影響
?? ?morphologyEx(whiteROI, whiteROI, MORPH_OPEN, element0);
?? ?namedWindow("OPEN圖");
?? ?imshow("OPEN圖", whiteROI);
?? ?*/
?? ?Mat dstImage = cutImage.clone();
?? ?vector<vector<Point>> contours;
?? ?findContours(whiteROI, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
?? ?drawContours(dstImage, contours, -1, Scalar(0, 0, 255), 1);
?? ?//namedWindow("疑似字符輪廓識(shí)別圖");
?? ?//imshow("疑似字符輪廓識(shí)別圖", dstImage);
?? ?inRange(dstImage, Scalar(0, 0, 255), Scalar(0, 0, 255), dstImage);
?? ?//namedWindow("字符大輪廓圖");
?? ?//imshow("字符大輪廓圖", dstImage);
?? ?/*fillHole(dstImage, dstImage);
?? ?namedWindow("填補(bǔ)輪廓后圖");
?? ?imshow("填補(bǔ)輪廓后圖", dstImage);*/

?? ?int row1 = 2;
?? ?int row2 = dstImage.rows;
?? ?int rowMax = dstImage.rows - 1; ? ? ? ? ? ?//開區(qū)間,防止越界
?? ?int colMax = dstImage.cols - 1; ? ? ? ? ? ?//開區(qū)間,防止越界
?? ?int addFirst = 10;
?? ?int addFirst0 = 0;
?? ?int addFirst1 = 0;
?? ?int addFirst2 = 0;
?? ?//測(cè)中間像素
?? ?//dstImage.at<uchar>(rowMax-1, colMax-1);
?? ?//cout << "Width:" << j << endl;

?? ?int addFirstTemp = addFirst; ? ? ? ? ?//第一次用時(shí)已經(jīng)改變數(shù)值,容易忽略?。。。。?

?? ?uchar* data;

?? ?//裁剪上下邊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
?? ?//上邊
?? ?for (int i = 2; i < rowMax / 3; i++, addFirst1 = 0) ? ? ? ? ? ? ? ? ? ? ? ? ? // ? 6 ? ? 剛剛好
?? ?{
?? ??? ?data = dstImage.ptr<uchar>(i);
?? ??? ?for (int j = 2; j < colMax; j++)
?? ??? ?{
?? ??? ??? ?if (data[j] == 255)
?? ??? ??? ?{
?? ??? ??? ??? ?addFirst1++;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if (addFirst1 < addFirst) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在行
?? ??? ?{
?? ??? ??? ?row1 = i;
?? ??? ??? ?addFirst = addFirst1 + 3;
?? ??? ??? ?//cout << "行頭" << row1 << endl;
?? ??? ??? ?//flag_x = 1;
?? ??? ?}
?? ?}
?? ?//下邊
?? ?for (int i = rowMax - 2; i > rowMax - rowMax / 4; i--, addFirst2 = 0) ? ? ? ? ? ? ? ?// ? 6 ? ? 剛剛好
?? ?{
?? ??? ?data = dstImage.ptr<uchar>(i);
?? ??? ?for (int j = 2; j < colMax; j++)
?? ??? ?{
?? ??? ??? ?if (data[j] == 255)
?? ??? ??? ?{
?? ??? ??? ??? ?addFirst2++;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if (addFirst2 < addFirstTemp) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在行
?? ??? ?{
?? ??? ??? ?row2 = i;
?? ??? ??? ?addFirstTemp = addFirst2 + 3;
?? ??? ??? ?//cout << "行底" << row2 << endl;
?? ??? ??? ?//flag_y = 1;
?? ??? ?}
?? ?}


?? ?int orow;
?? ?orow = row2 - row1;
?? ?Mat w_image;
?? ?Mat ?rgb_w_image;
?? ?w_image = dstImage(Rect(0, row1, colMax, orow));
?? ?rgb_w_image = cutImage(Rect(0, row1, colMax, orow));
?? ?//namedWindow("裁剪上下圖");
?? ?//imshow("裁剪上下圖", w_image);

?? ?int rowMax_ALT = w_image.rows - 1; ? ? ? ? ? ?//開區(qū)間,防止越界(注意,裁剪完上下后要重新寫行和寬,因?yàn)樾泻蛯捯呀?jīng)改變)
?? ?int colMax_ALT = w_image.cols - 1; ? ? ? ? ? ?//開區(qū)間,防止越界(注意,裁剪完上下后要重新寫行和寬,因?yàn)樾泻蛯捯呀?jīng)改變)
?? ?int col_1 = 2;
?? ?int col_2 = w_image.cols;
?? ?int add = 2;
?? ?int add1 = 0;
?? ?int add2 = 0;

?? ?int addTemp = add; ? ? ? ?//第一次用時(shí)已經(jīng)改變數(shù)值,容易忽略?。。。。?

?? ?//裁剪左右邊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
?? ?//左邊
?? ?//for (int i = 0; i < colMax_ALT / 18; i++, add1 = 0) ? ? ? ? ? ? ? ? ? ? ? ? ? // ? ? ? 剛剛好
?? ?//{
?? ?//?? ?for (int j = 2; j < rowMax_ALT; j++)
?? ?//?? ?{
?? ?//?? ??? ?data = dstImage.ptr<uchar>(j);
?? ?//?? ??? ?if (data[i] == 255)
?? ?//?? ??? ?{
?? ?//?? ??? ??? ?add1++;
?? ?//?? ??? ?}
?? ?//?? ?}
?? ?//?? ?if (add1 < add) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在列
?? ?//?? ?{
?? ?//?? ??? ?col_1 = i;
?? ?//?? ??? ?add = add1 + 1;
?? ?//?? ?}
?? ?//}
?? ?//右邊
?? ?if (specialFlag)
?? ?{
?? ??? ?for (int i = colMax_ALT; i > colMax_ALT - colMax_ALT / 18; i--, add2 = 0) ? ? ? ? ? ? ? ?// ? ? ? ?剛剛好
?? ??? ?{
?? ??? ??? ?for (int j = 2; j < rowMax_ALT; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = dstImage.ptr<uchar>(j);
?? ??? ??? ??? ?if (data[i] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?add2++;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?if (add2 < addTemp) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在列
?? ??? ??? ?{
?? ??? ??? ??? ?col_2 = i;
?? ??? ??? ??? ?addTemp = add2 + 1;
?? ??? ??? ??? ?//cout << "行底" << row2 << endl;
?? ??? ??? ?}
?? ??? ?}
?? ?}
?? ?int o_col;
?? ?o_col = col_2 - col_1;

?? ?Mat H_image;
?? ?H_image = w_image(Rect(col_1, 0, o_col, rowMax_ALT));
?? ?rgb_w_image = rgb_w_image(Rect(col_1, 0, o_col, rowMax_ALT));
?? ?//namedWindow("再裁剪左右圖");
?? ?//imshow("再裁剪左右圖", H_image);
?? ?//namedWindow("裁剪后彩圖");
?? ?//imshow("裁剪后彩圖", rgb_w_image);

?? ?return rgb_w_image;
}

void CharCut(Mat srcImage)
{
?? ?resize(srcImage, srcImage, Size(320, 320 * srcImage.rows / srcImage.cols));
?? ?//namedWindow("Resize車牌圖");
?? ?//imshow("Resize車牌圖", srcImage);
?? ?GaussianBlur(srcImage, srcImage, Size(3, 3), 0, 0);
?? ?/*namedWindow("GaussianBlur車牌圖");
?? ?imshow("GaussianBlur車牌圖", srcImage);
*/
?? ?medianBlur(srcImage, srcImage, 3);
?? ?//namedWindow("Src_medianBlur圖");
?? ?//imshow("Src_medianBlur圖", srcImage);

?? ?cvtColor(srcImage, srcImage, CV_BGR2HSV);


?? ?//將白色區(qū)域二值化
?? ?Mat doubleImage;
?? ?//inRange(srcImage, Scalar(0, 0, 10), Scalar(180, 75, 255), doubleImage); ? ? ?//增大 S 即飽和度可以使hsv白色檢測(cè)范圍更大
?? ?inRange(srcImage, Scalar(0, 0, 0), Scalar(180, 125, 245), doubleImage);
?? ?namedWindow("doubleImage圖");
?? ?imshow("doubleImage圖", doubleImage);

?? ?int colTemp = 0;
?? ?int rowMax = doubleImage.rows;
?? ?int colMax = doubleImage.cols;
?? ?int addFirst = 0;
?? ?int add = 0;
?? ?int k1 = 0;
?? ?int k2;
?? ?int kTemp = 0;
?? ?int times = 0;
?? ?int oneCutEnd = 0;
?? ?float t = 1.0;
?? ?uchar* data;

?? ?cout << "Test: ? ? ? ? ? ?" << specialFlag << endl;


?? ?//針對(duì)嵌套車牌處理
?? ?if (specialFlag)
?? ?{
?? ??? ?for (int i = 2; i < colMax; i++, addFirst = 0, add = 0)
?? ??? ?{
?? ??? ??? ?for (int j = rowMax / 10.8; j < rowMax - rowMax / (10.8*t); j++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = doubleImage.ptr<uchar>(j);
?? ??? ??? ??? ?if (data[i - 1] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?addFirst++; ? ? ? ? ? ? ? ? ? ? ? ? ? ? //統(tǒng)計(jì)前一列
?? ??? ??? ??? ?}
?? ??? ??? ?}

?? ??? ??? ?for (int j = rowMax / 10.8; j < rowMax - rowMax / (10.8*t); j++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = doubleImage.ptr<uchar>(j);
?? ??? ??? ??? ?if (data[i] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?add++; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?//統(tǒng)計(jì)后一列
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?//省份字符分開切割
?? ??? ??? ?if (!times)
?? ??? ??? ?{
?? ??? ??? ??? ?if (!oneCutEnd && (!addFirst ?&& ?add))
?? ??? ??? ??? ??? ?k1 = i - 1;
?? ??? ??? ??? ?if (addFirst && !add)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?k2 = i;
?? ??? ??? ??? ??? ?oneCutEnd = 1;
?? ??? ??? ??? ??? ?if (k2 - k1 > colMax / 11.25)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?times = 1;
?? ??? ??? ??? ??? ??? ?if (k2 - k1 < colMax / 5.625)
?? ??? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ?i = 2;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?} ? ? ? ? //切割其他字符
?? ??? ??? ?else {

?? ??? ??? ??? ?if (!addFirst ?&& ?add)
?? ??? ??? ??? ??? ?k1 = i - 1;
?? ??? ??? ??? ?if (addFirst && !add)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?k2 = i;
?? ??? ??? ??? ??? ?if (k2 - k1 > colMax / 32)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?if (k2 - k1 < colMax / 5.625)
?? ??? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ??? ?else ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //針對(duì)嵌套車牌下部連接過(guò)靠上
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?i = k1;
?? ??? ??? ??? ??? ??? ??? ?t -= 0.1;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ?{ ? //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!處理中間分割點(diǎn)與‘ 1 '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
?? ??? ??? ??? ??? ??? ?for (int a = k1; a <= k2; a++)
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?data = doubleImage.ptr<uchar>(rowMax / 5);
?? ??? ??? ??? ??? ??? ??? ?if (data[a] == 255)
?? ??? ??? ??? ??? ??? ??? ??? ?kTemp++;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?if (kTemp > 0)
?? ??? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ??? ?kTemp = 0;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}

?? ??? ??? ?}

?? ??? ?}

?? ??? ?k2 = colMax;
?? ??? ?if (k2 - k1 > colMax / 32)
?? ??? ??? ?SingleCharCut(doubleImage, k1, k2);

?? ??? ?specialFlag = false;

?? ?}
?? ?else {
?? ??? ?for (int i = 2; i < colMax; i++, addFirst = 0, add = 0)
?? ??? ?{
?? ??? ??? ?for (int j = rowMax / 12.8; j < rowMax - rowMax / 12.8; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = doubleImage.ptr<uchar>(j);
?? ??? ??? ??? ?if (data[i - 1] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?addFirst++;
?? ??? ??? ??? ?}
?? ??? ??? ?}

?? ??? ??? ?for (int j = rowMax / 12.8; j < rowMax - rowMax / 12.8; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = doubleImage.ptr<uchar>(j);
?? ??? ??? ??? ?if (data[i] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?add++;
?? ??? ??? ??? ?}
?? ??? ??? ?}


?? ??? ??? ?if (!times)
?? ??? ??? ?{
?? ??? ??? ??? ?if (!oneCutEnd && (!addFirst ?&& ?add))
?? ??? ??? ??? ??? ?k1 = i - 1;
?? ??? ??? ??? ?if (addFirst && !add)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?k2 = i;
?? ??? ??? ??? ??? ?oneCutEnd = 1;
?? ??? ??? ??? ??? ?if (k2 - k1 > colMax / 11.25)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?times = 1;
?? ??? ??? ??? ??? ??? ?if (k2 - k1 < colMax / 5.625)
?? ??? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ??? ??? ?i = 2;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?else {

?? ??? ??? ??? ?if (!addFirst ?&& ?add)
?? ??? ??? ??? ??? ?k1 = i - 1;
?? ??? ??? ??? ?if (addFirst && !add)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?k2 = i;
?? ??? ??? ??? ??? ?if (k2 - k1 > colMax / 32)
?? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ?else
?? ??? ??? ??? ??? ?{ ? //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!處理中間分割點(diǎn)與‘ 1 '!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
?? ??? ??? ??? ??? ??? ?for (int a = k1; a <= k2; a++)
?? ??? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ??? ?data = doubleImage.ptr<uchar>(rowMax / 5);
?? ??? ??? ??? ??? ??? ??? ?if (data[a] == 255)
?? ??? ??? ??? ??? ??? ??? ??? ?kTemp++;
?? ??? ??? ??? ??? ??? ?}
?? ??? ??? ??? ??? ??? ?if (kTemp > 0)
?? ??? ??? ??? ??? ??? ??? ?SingleCharCut(doubleImage, k1, k2);
?? ??? ??? ??? ??? ??? ?kTemp = 0;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}

?? ??? ??? ?}

?? ??? ?}
?? ?}
}

void SingleCharCut(Mat doubleImage, int k1, int k2)
{
?? ?//printf("k1 = %d ,k2 = %d\n", k1, k2);


?? ?int rowMax = doubleImage.rows;
?? ?Mat image;
?? ?image = doubleImage(Rect(k1, 0, k2 - k1, rowMax));

?? ?int row1 = 0;
?? ?int row2 = image.rows;
?? ?rowMax = image.rows - 1; ? ? ? ? ? ?//開區(qū)間,防止越界
?? ?int colMax = image.cols; ? ? ? ? ? ?//開區(qū)間,防止越界
?? ?int addFirst = 2;
?? ?int addFirst1 = 0;
?? ?int addFirst2 = 0;
?? ?uchar* data;
?? ?//測(cè)中間像素
?? ?//image.at<uchar>(rowMax-1, colMax-1);
?? ?//cout << "Width:" << j << endl;

?? ?int addFirstTemp = addFirst; ? ? ? ? ?//第一次用時(shí)已經(jīng)改變數(shù)值,容易忽略?。。。?!

?? ?//裁剪上下邊。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
?? ?//上邊
?? ?for (int i = 0; i < rowMax / 4; i++, addFirst1 = 0) ? ? ? ? ? ? ? ? ? ? ? ? ? // ? 6 ? ? 剛剛好
?? ?{
?? ??? ?data = image.ptr<uchar>(i);
?? ??? ?for (int j = 0; j < colMax; j++)
?? ??? ?{
?? ??? ??? ?if (data[j] == 255)
?? ??? ??? ?{
?? ??? ??? ??? ?addFirst1++;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if (addFirst1 < addFirst) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在行
?? ??? ?{
?? ??? ??? ?row1 = i;
?? ??? ??? ?addFirst = addFirst1 + 1;
?? ??? ?}
?? ?}

?? ?//下邊
?? ?for (int i = rowMax; i > rowMax - rowMax / 4; i--, addFirst2 = 0) ? ? ? ? ? ? ? ?// ? 6 ? ? 剛剛好
?? ?{
?? ??? ?data = image.ptr<uchar>(i);
?? ??? ?for (int j = 2; j < colMax; j++)
?? ??? ?{
?? ??? ??? ?if (data[j] == 255)
?? ??? ??? ?{
?? ??? ??? ??? ?addFirst2++;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?if (addFirst2 < addFirstTemp) ? ? ? ? ? ? ? ? ? ? ? //篩選最小值所在行
?? ??? ?{
?? ??? ??? ?row2 = i;
?? ??? ??? ?addFirstTemp = addFirst2 + 1;
?? ??? ?}
?? ?}

?? ?int orow;
?? ?orow = row2 - row1;
?? ?Mat w_image;
?? ?w_image = image(Rect(0, row1, colMax, orow));
?? ?singleChar.push_back(w_image);

}

void ShowChar()
{
?? ?int length = singleChar.size();
?? ?for (int i = 0; i < length; i++) {

?? ??? ?resize(singleChar[i], singleChar[i], Size(20, 40)); ? ? ? ? ? //字符圖像歸一化

?? ??? ?//namedWindow(to_string(i) + "圖");
?? ??? ?//imshow(to_string(i) + "圖", singleChar[i]);
?? ?}
}


//讀取省份模板
struct ?stu
{
?? ?Mat image;
?? ?double matchDegree;
};
struct ?stu first[35];
void readProvince()
{
?? ?int i = 0;
?? ?//讀取字符
?? ?{
?? ??? ?first[i].image = imread("match\\zw1.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw2.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw3.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw4.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw5.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw6.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw7.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw8.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw9.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw10.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw11.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw12.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw13.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw14.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw15.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw16.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw17.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw18.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw19.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw20.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw21.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw22.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw23.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw24.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw25.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw26.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw27.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw28.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw29.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw30.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw31.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw32.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw33.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw34.bmp", 0);
?? ??? ?i++;
?? ??? ?first[i].image = imread("match\\zw35.bmp", 0);
?? ?}


}


//識(shí)別省份字符
void MatchProvince()
{
?? ?int rowMax = 40;
?? ?int colMax = 20;
?? ?int add = 0;
?? ?int addTemp = 0;
?? ?Mat absCutImage;
?? ?double temp;
?? ?int index = 0;
?? ?uchar* data;

?? ?for (int i = 0; i < rowMax; i++)
?? ?{
?? ??? ?data = singleChar[0].ptr<uchar>(i);
?? ??? ?for (int j = 0; j < colMax; j++)
?? ??? ?{
?? ??? ??? ?if (data[j] == 255)
?? ??? ??? ?{
?? ??? ??? ??? ?add++;
?? ??? ??? ?}
?? ??? ?}
?? ?}

?? ?int firstLength = end(first) - begin(first);
?? ?//printf("數(shù)組長(zhǎng)度1 ? ? ? ? %d\n",firstLength);
?? ?for (int x = 0; x < firstLength; x++, addTemp = 0)
?? ?{
?? ??? ?absCutImage = abs(first[x].image - singleChar[0]);

?? ??? ?for (int i = 0; i < rowMax; i++)
?? ??? ?{
?? ??? ??? ?data = absCutImage.ptr<uchar>(i);
?? ??? ??? ?for (int j = 0; j < colMax; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?if (data[j] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?addTemp++;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?temp = 1.0 - 1.0*addTemp / add;
?? ??? ?if (temp <= 1)
?? ??? ??? ?first[x].matchDegree = temp;
?? ??? ?else
?? ??? ??? ?first[x].matchDegree = 0;


?? ??? ?if (x > 0 && first[x].matchDegree > first[index].matchDegree)
?? ??? ??? ?index = x;
?? ?}

?? ?/*absCutImage = abs(singleChar[0] - first[index].image);
?? ?namedWindow("省份圖片相減后圖" + to_string(0));
?? ?imshow("省份圖片相減后圖" + to_string(0), absCutImage);*/

?? ?printf("省份字符最大匹配度: ?%lf\n", first[index].matchDegree);

?? ?switch (index) {
?? ?case 0:
?? ??? ?printf("藏");
?? ??? ?carPlateProvince += "藏";
?? ??? ?break;
?? ?case 1:
?? ??? ?printf("川");
?? ??? ?carPlateProvince += "川";
?? ??? ?break;
?? ?case 2:
?? ??? ?printf("鄂");
?? ??? ?carPlateProvince += "鄂";
?? ??? ?break;
?? ?case 3:
?? ??? ?printf("甘");
?? ??? ?carPlateProvince += "甘";
?? ??? ?break;
?? ?case 4:
?? ??? ?printf("贛");
?? ??? ?carPlateProvince += "贛";
?? ??? ?break;
?? ?case 5:
?? ??? ?printf("貴");
?? ??? ?carPlateProvince += "貴";
?? ??? ?break;
?? ?case 6:
?? ??? ?printf("桂");
?? ??? ?carPlateProvince += "桂";
?? ??? ?break;
?? ?case 7:
?? ??? ?printf("黑");
?? ??? ?carPlateProvince += "黑";
?? ??? ?break;
?? ?case 8:
?? ??? ?printf("瀘");
?? ??? ?carPlateProvince += "瀘";
?? ??? ?break;
?? ?case 9:
?? ??? ?printf("吉");
?? ??? ?carPlateProvince += "吉";
?? ??? ?break;
?? ?case 10:
?? ??? ?printf("翼");
?? ??? ?carPlateProvince += "翼";
?? ??? ?break;
?? ?case 11:
?? ??? ?printf("津");
?? ??? ?carPlateProvince += "津";
?? ??? ?break;
?? ?case 12:
?? ??? ?printf("晉");
?? ??? ?carPlateProvince += "晉";
?? ??? ?break;
?? ?case 13:
?? ??? ?printf("京");
?? ??? ?carPlateProvince += "京";
?? ??? ?break;
?? ?case 14:
?? ??? ?printf("遼");
?? ??? ?carPlateProvince += "遼";
?? ??? ?break;
?? ?case 15:
?? ??? ?printf("魯");
?? ??? ?carPlateProvince += "魯";
?? ??? ?break;
?? ?case 16:
?? ??? ?printf("蒙");
?? ??? ?carPlateProvince += "蒙";
?? ??? ?break;
?? ?case 17:
?? ??? ?printf("閩");
?? ??? ?carPlateProvince += "閩";
?? ??? ?break;
?? ?case 18:
?? ??? ?printf("寧");
?? ??? ?carPlateProvince += "寧";
?? ??? ?break;
?? ?case 19:
?? ??? ?printf("青");
?? ??? ?carPlateProvince += "青";
?? ??? ?break;
?? ?case 20:
?? ??? ?printf("瓊");
?? ??? ?carPlateProvince += "瓊";
?? ??? ?break;
?? ?case 21:
?? ??? ?printf("陜");
?? ??? ?carPlateProvince += "陜";
?? ??? ?break;
?? ?case 22:
?? ??? ?printf("蘇");
?? ??? ?carPlateProvince += "蘇";
?? ??? ?break;
?? ?case 23:
?? ??? ?printf("皖");
?? ??? ?carPlateProvince += "皖";
?? ??? ?break;
?? ?case 24:
?? ??? ?printf("湘");
?? ??? ?carPlateProvince += "湘";
?? ??? ?break;
?? ?case 25:
?? ??? ?printf("新");
?? ??? ?carPlateProvince += "新";
?? ??? ?break;
?? ?case 26:
?? ??? ?printf("渝");
?? ??? ?carPlateProvince += "渝";
?? ??? ?break;
?? ?case 27:
?? ??? ?printf("豫");
?? ??? ?carPlateProvince += "豫";
?? ??? ?break;
?? ?case 28:
?? ??? ?printf("粵");
?? ??? ?carPlateProvince += "粵";
?? ??? ?break;
?? ?case 29:
?? ??? ?printf("云");
?? ??? ?carPlateProvince += "云";
?? ??? ?break;
?? ?case 30:
?? ??? ?printf("浙");
?? ??? ?carPlateProvince += "浙";
?? ??? ?break;
?? ?case 31:
?? ??? ?printf("湘");
?? ??? ?carPlateProvince += "湘";
?? ??? ?break;
?? ?case 32:
?? ??? ?printf("湘");
?? ??? ?carPlateProvince += "湘";
?? ??? ?break;
?? ?case 33:
?? ??? ?printf("魯");
?? ??? ?carPlateProvince += "魯";
?? ??? ?break;
?? ?case 34:
?? ??? ?printf("粵");
?? ??? ?carPlateProvince += "粵";
?? ??? ?break;
?? ?}
?? ?printf("\n");
}

//讀取字母和數(shù)字模板
struct stu1
{
?? ?char number;
?? ?Mat image;
?? ?double matchDegree;
};
struct stu1 second[49];
void readNumber()
{
?? ?for (int i = 0; i < 10; i++) {
?? ??? ?second[i].image = imread("match\\" + to_string(i) + ".bmp", 0);
?? ??? ?second[i].number = 48 + i;
?? ?}

?? ?//讀取字符
?? ?{
?? ??? ?int i = 10;
?? ??? ?second[i].image = imread("match\\6a.bmp", 0);
?? ??? ?second[i].number = '6';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\3a.bmp", 0);
?? ??? ?second[i].number = '3';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\P1.bmp", 0);
?? ??? ?second[i].number = 'P';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\8b.bmp", 0);
?? ??? ?second[i].number = '8';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\K1.bmp", 0);
?? ??? ?second[i].number = 'K';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\9a.bmp", 0);
?? ??? ?second[i].number = '9';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\B2.bmp", 0);
?? ??? ?second[i].number = 'B';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\G1.bmp", 0);
?? ??? ?second[i].number = 'G';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\T1.bmp", 0);
?? ??? ?second[i].number = 'T';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\B1.bmp", 0);
?? ??? ?second[i].number = 'B';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\8a.bmp", 0);
?? ??? ?second[i].number = '8';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\1a.bmp", 0);
?? ??? ?second[i].number = '1';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\7a.bmp", 0);
?? ??? ?second[i].number = '7';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\D1.bmp", 0);
?? ??? ?second[i].number = 'D';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\0a.bmp", 0);
?? ??? ?second[i].number = '0';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\A.bmp", 0);
?? ??? ?second[i].number = 'A';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\B.bmp", 0);
?? ??? ?second[i].number = 'B';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\C.bmp", 0);
?? ??? ?second[i].number = 'C';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\D.bmp", 0);
?? ??? ?second[i].number = 'D';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\E.bmp", 0);
?? ??? ?second[i].number = 'E';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\F.bmp", 0);
?? ??? ?second[i].number = 'F';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\G.bmp", 0);
?? ??? ?second[i].number = 'G';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\H.bmp", 0);
?? ??? ?second[i].number = 'H';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\J.bmp", 0);
?? ??? ?second[i].number = 'J';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\K.bmp", 0);
?? ??? ?second[i].number = 'K';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\L.bmp", 0);
?? ??? ?second[i].number = 'L';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\M.bmp", 0);
?? ??? ?second[i].number = 'M';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\N.bmp", 0);
?? ??? ?second[i].number = 'N';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\P.bmp", 0);
?? ??? ?second[i].number = 'P';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\Q.bmp", 0);
?? ??? ?second[i].number = 'Q';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\R.bmp", 0);
?? ??? ?second[i].number = 'R';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\S.bmp", 0);
?? ??? ?second[i].number = 'S';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\T.bmp", 0);
?? ??? ?second[i].number = 'T';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\U.bmp", 0);
?? ??? ?second[i].number = 'U';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\V.bmp", 0);
?? ??? ?second[i].number = 'V';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\W.bmp", 0);
?? ??? ?second[i].number = 'W';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\X.bmp", 0);
?? ??? ?second[i].number = 'X';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\Y.bmp", 0);
?? ??? ?second[i].number = 'Y';
?? ??? ?i++;
?? ??? ?second[i].image = imread("match\\Z.bmp", 0);
?? ??? ?second[i].number = 'Z';

?? ?}


}


//識(shí)別其他字符
void MatchNumber()
{
?? ?int rowMax = 40;
?? ?int colMax = 20;
?? ?int add = 0;
?? ?int addTemp = 0;
?? ?Mat absCutImage;
?? ?double temp;
?? ?int index = 0;
?? ?int length = singleChar.size();
?? ?int secondLength = end(second) - begin(second);
?? ?//printf("數(shù)組長(zhǎng)度2 ? ? ? ? %d ? \n", secondLength);

?? ?uchar* data;
?? ?int q = 0;

?? ?for (int y = 1; y < length; y++, add = 0, index = 0)
?? ?{
?? ??? ?if (y > 6) ? ? ? ? ? ? ? ?//防止多讀
?? ??? ??? ?break;
?? ??? ?//統(tǒng)計(jì)要讀取字符的白色像素總值
?? ??? ?for (int i = 0; i < rowMax; i++)
?? ??? ?{
?? ??? ??? ?data = singleChar[y].ptr<uchar>(i);
?? ??? ??? ?for (int j = 0; j < colMax; j++)
?? ??? ??? ?{
?? ??? ??? ??? ?if (data[j] == 255)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?add++;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}


?? ??? ?
?? ??? ?//逐個(gè)字符識(shí)別
?? ??? ?for (int x = 0; x < secondLength; x++, addTemp = 0)
?? ??? ?{

?? ??? ??? ?absCutImage = abs(singleChar[y] - second[x].image);

?? ??? ??? ?//統(tǒng)計(jì)相減之后的圖像白色像素總值
?? ??? ??? ?for (int i = 0; i < rowMax; i++)
?? ??? ??? ?{
?? ??? ??? ??? ?data = absCutImage.ptr<uchar>(i);
?? ??? ??? ??? ?for (int j = 0; j < colMax; j++)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?if (data[j] == 255)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?addTemp++;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ??? ?temp = 1.0 - 1.0*addTemp / add;
?? ??? ??? ?if (temp <= 1 && temp > 0)
?? ??? ??? ??? ?second[x].matchDegree = temp;
?? ??? ??? ?else
?? ??? ??? ??? ?second[x].matchDegree = 0;

?? ??? ??? ?//獲取最大匹配度對(duì)應(yīng)索引index
?? ??? ??? ?if (x > 0 && second[x].matchDegree > second[index].matchDegree)
?? ??? ??? ??? ?index = x;
?? ??? ?}
?? ??? ?absCutImage = abs(singleChar[y] - second[index].image);
?? ??? ?/*?? ?namedWindow("圖片相減后圖"+to_string(y));
?? ??? ??? ?imshow("圖片相減后圖" + to_string(y), absCutImage);*/
?? ??? ?printf("最大匹配度: ?%lf\n", second[index].matchDegree);
?? ??? ?printf("對(duì)應(yīng)字符: ? ?%c\n", second[index].number);
?? ??? ?test[q] = second[index].number;
?? ??? ?//printf("\ntest11111 ? ? ? ? ? %c\n", test[q]);
?? ??? ?q++;
?? ?}
?? ?test[q] = '\0';
?? ?//printf("\ntest22222 ? ? ? ? ? %c\n", test[q-1]);
?? ?//cout<< ?"xxxxxxxxxxxxxx"<<carPlate<<endl;
}

void VideoShow(Mat videoImage)
{
?? ?/*if(videoFlag==0)*/
?? ?//carPlate = "京A J9846";
?? ?
?? ??? ?carPlate += test;
?? ??? ?carPlateProvince += carPlate;
?? ?/*carPlate.copy(test,strlen(test));*/
?? ?cout << ?carPlateProvince << endl;
?? ?cout << ?carPlateProvince.length() << endl;
?? ?if(carPlateProvince.length()<10)
?? ??? ?putTextZH(videoImage, "Not Plate!", Point(490, 20), Scalar(0, 0, 255), 30, "Arial", false, false);
?? ?else
?? ??? ?putTextZH(videoImage, carPlateProvince.c_str(), Point(490, 20), Scalar(0, 0, 255), 30, "Arial", false, false);
?? ?/*else if(videoFlag==1)*/

?? ?namedWindow("提取車牌結(jié)果圖");
?? ?imshow("提取車牌結(jié)果圖", videoImage);
?? ?carPlateProvince = " ";
?? ?carPlate = " ";
}


void GetStringSize(HDC hDC, const char* str, int* w, int* h)
{
?? ?SIZE size;
?? ?GetTextExtentPoint32A(hDC, str, strlen(str), &size);
?? ?if (w != 0) *w = size.cx;
?? ?if (h != 0) *h = size.cy;
}

void putTextZH(Mat &dst, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline)
{

?? ?CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));
?? ?int x, y, r, b;
?? ?if (org.x > dst.cols || org.y > dst.rows) return;
?? ?x = org.x < 0 ? -org.x : 0;
?? ?y = org.y < 0 ? -org.y : 0;
?? ?LOGFONTA lf;
?? ?lf.lfHeight = -fontSize;
?? ?lf.lfWidth = 0;
?? ?lf.lfEscapement = 0;
?? ?lf.lfOrientation = 0;
?? ?lf.lfWeight = 5;
?? ?lf.lfItalic = italic; ? //斜體
?? ?lf.lfUnderline = underline; //下劃線
?? ?lf.lfStrikeOut = 0;
?? ?lf.lfCharSet = DEFAULT_CHARSET;
?? ?lf.lfOutPrecision = 0;
?? ?lf.lfClipPrecision = 0;
?? ?lf.lfQuality = PROOF_QUALITY;
?? ?lf.lfPitchAndFamily = 0;
?? ?strcpy_s(lf.lfFaceName, fn);

?? ?HFONT hf = CreateFontIndirectA(&lf);
?? ?HDC hDC = CreateCompatibleDC(0);
?? ?HFONT hOldFont = (HFONT)SelectObject(hDC, hf);

?? ?int strBaseW = 0, strBaseH = 0;
?? ?int singleRow = 0;
?? ?char buf[1 << 12];
?? ?strcpy_s(buf, str);
?? ?char *bufT[1 << 12]; ?// 這個(gè)用于分隔字符串后剩余的字符,可能會(huì)超出。
?? ?//處理多行
?? ?{
?? ??? ?int nnh = 0;
?? ??? ?int cw, ch;

?? ??? ?const char* ln = strtok_s(buf, "\n", bufT);
?? ??? ?while (ln != 0)
?? ??? ?{
?? ??? ??? ?GetStringSize(hDC, ln, &cw, &ch);
?? ??? ??? ?strBaseW = max(strBaseW, cw);
?? ??? ??? ?strBaseH = max(strBaseH, ch);

?? ??? ??? ?ln = strtok_s(0, "\n", bufT);
?? ??? ??? ?nnh++;
?? ??? ?}
?? ??? ?singleRow = strBaseH;
?? ??? ?strBaseH *= nnh;
?? ?}

?? ?if (org.x + strBaseW < 0 || org.y + strBaseH < 0)
?? ?{
?? ??? ?SelectObject(hDC, hOldFont);
?? ??? ?DeleteObject(hf);
?? ??? ?DeleteObject(hDC);
?? ??? ?return;
?? ?}

?? ?r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
?? ?b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
?? ?org.x = org.x < 0 ? 0 : org.x;
?? ?org.y = org.y < 0 ? 0 : org.y;

?? ?BITMAPINFO bmp = { 0 };
?? ?BITMAPINFOHEADER& bih = bmp.bmiHeader;
?? ?int strDrawLineStep = strBaseW * 3 % 4 == 0 ? strBaseW * 3 : (strBaseW * 3 + 4 - ((strBaseW * 3) % 4));

?? ?bih.biSize = sizeof(BITMAPINFOHEADER);
?? ?bih.biWidth = strBaseW;
?? ?bih.biHeight = strBaseH;
?? ?bih.biPlanes = 1;
?? ?bih.biBitCount = 24;
?? ?bih.biCompression = BI_RGB;
?? ?bih.biSizeImage = strBaseH * strDrawLineStep;
?? ?bih.biClrUsed = 0;
?? ?bih.biClrImportant = 0;

?? ?void* pDibData = 0;
?? ?HBITMAP hBmp = CreateDIBSection(hDC, &bmp, DIB_RGB_COLORS, &pDibData, 0, 0);

?? ?CV_Assert(pDibData != 0);
?? ?HBITMAP hOldBmp = (HBITMAP)SelectObject(hDC, hBmp);

?? ?//color.val[2], color.val[1], color.val[0]
?? ?SetTextColor(hDC, RGB(255, 255, 255));
?? ?SetBkColor(hDC, 0);
?? ?//SetStretchBltMode(hDC, COLORONCOLOR);

?? ?strcpy_s(buf, str);
?? ?const char* ln = strtok_s(buf, "\n", bufT);
?? ?int outTextY = 0;
?? ?while (ln != 0)
?? ?{
?? ??? ?TextOutA(hDC, 0, outTextY, ln, strlen(ln));
?? ??? ?outTextY += singleRow;
?? ??? ?ln = strtok_s(0, "\n", bufT);
?? ?}
?? ?uchar* dstData = (uchar*)dst.data;
?? ?int dstStep = dst.step / sizeof(dstData[0]);
?? ?unsigned char* pImg = (unsigned char*)dst.data + org.x * dst.channels() + org.y * dstStep;
?? ?unsigned char* pStr = (unsigned char*)pDibData + x * 3;
?? ?for (int tty = y; tty <= b; ++tty)
?? ?{
?? ??? ?unsigned char* subImg = pImg + (tty - y) * dstStep;
?? ??? ?unsigned char* subStr = pStr + (strBaseH - tty - 1) * strDrawLineStep;
?? ??? ?for (int ttx = x; ttx <= r; ++ttx)
?? ??? ?{
?? ??? ??? ?for (int n = 0; n < dst.channels(); ++n) {
?? ??? ??? ??? ?double vtxt = subStr[n] / 255.0;
?? ??? ??? ??? ?int cvv = vtxt * color.val[n] + (1 - vtxt) * subImg[n];
?? ??? ??? ??? ?subImg[n] = cvv > 255 ? 255 : (cvv < 0 ? 0 : cvv);
?? ??? ??? ?}

?? ??? ??? ?subStr += 3;
?? ??? ??? ?subImg += dst.channels();
?? ??? ?}
?? ?}

?? ?SelectObject(hDC, hOldBmp);
?? ?SelectObject(hDC, hOldFont);
?? ?DeleteObject(hf);
?? ?DeleteObject(hBmp);
?? ?DeleteDC(hDC);
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • c++ priority_queue用法入門超詳細(xì)教程

    c++ priority_queue用法入門超詳細(xì)教程

    priority_queue即優(yōu)先級(jí)隊(duì)列,它的使用場(chǎng)景很多,它底層是用大小根堆實(shí)現(xiàn)的,可以用log(n)的時(shí)間動(dòng)態(tài)地維護(hù)數(shù)據(jù)的有序性,這篇文章主要介紹了c++ priority_queue用法入門超詳細(xì)教程,需要的朋友可以參考下
    2023-12-12
  • Qt實(shí)現(xiàn)繪制一個(gè)簡(jiǎn)單多邊形的示例代碼

    Qt實(shí)現(xiàn)繪制一個(gè)簡(jiǎn)單多邊形的示例代碼

    QT提供了圖形繪制接口QPainter,通過(guò)該接口可以繪制多種圖形,包括多邊形。本文就來(lái)利用它實(shí)現(xiàn)繪制一個(gè)簡(jiǎn)單的多邊形,感興趣的可以嘗試一下
    2022-11-11
  • 淺談C++有理數(shù)的表達(dá)和計(jì)算

    淺談C++有理數(shù)的表達(dá)和計(jì)算

    這篇文章主要為大家詳細(xì)介紹了C++有理數(shù)的表達(dá)和計(jì)算,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 在C++中反射調(diào)用.NET的方法(三)

    在C++中反射調(diào)用.NET的方法(三)

    在.NET與C++之間傳輸集合數(shù)據(jù)的方法是怎么樣的呢?接下來(lái)通過(guò)本文給大家分享在C++中反射調(diào)用.NET(三),需要的朋友參考下吧
    2017-02-02
  • 淺析c#中如何在form的webbrowser控件中獲得鼠標(biāo)坐標(biāo)

    淺析c#中如何在form的webbrowser控件中獲得鼠標(biāo)坐標(biāo)

    以下是對(duì)c#中如何在form的webbrowser控件中獲得鼠標(biāo)坐標(biāo)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下
    2013-07-07
  • C++ 虛函數(shù)的詳解及簡(jiǎn)單實(shí)例

    C++ 虛函數(shù)的詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了C++ 虛函數(shù)的詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 大家注意vector, list, set, map成員函數(shù)erase

    大家注意vector, list, set, map成員函數(shù)erase

    set和map是由紅黑樹來(lái)實(shí)現(xiàn)的,當(dāng)erase的時(shí)候迭代器就失效了,也就是說(shuō)我們要在迭代器失效之前保留一個(gè)副本,根據(jù)這個(gè)副本我們才能繼續(xù)遍歷下一個(gè)元素
    2013-09-09
  • C++深入分析講解類的知識(shí)點(diǎn)

    C++深入分析講解類的知識(shí)點(diǎn)

    C++類,是指系統(tǒng)在第一次在程序中遇到一個(gè)類時(shí)為這個(gè)類建立它的所有類變量的拷貝 - 這個(gè)類的所有實(shí)例共享它的類變量
    2022-06-06
  • 詳解C/C++內(nèi)存管理

    詳解C/C++內(nèi)存管理

    內(nèi)存管理是C++最令人切齒痛恨的問(wèn)題,也是C++最有爭(zhēng)議的問(wèn)題,C++高手從中獲得了更好的性能,更大的自由,今天給大家分享C/C++內(nèi)存管理的實(shí)例代碼,需要的朋友參考下吧
    2021-06-06
  • C語(yǔ)言超詳細(xì)講解隊(duì)列的實(shí)現(xiàn)及代碼

    C語(yǔ)言超詳細(xì)講解隊(duì)列的實(shí)現(xiàn)及代碼

    隊(duì)列(Queue)與棧一樣,是一種線性存儲(chǔ)結(jié)構(gòu),它具有如下特點(diǎn):隊(duì)列中的數(shù)據(jù)元素遵循“先進(jìn)先出”(First?In?First?Out)的原則,簡(jiǎn)稱FIFO結(jié)構(gòu)。在隊(duì)尾添加元素,在隊(duì)頭刪除元素
    2022-04-04

最新評(píng)論