这张车牌是一张网图。
opencv2最高版本opencv2.4.13.6
到了腐蚀膨胀这一步,结果如下图所示:
去除车牌的边框和钉子,结果如下图所示:
最后将识别到的图片拼起来,结果如下图所示:间距方面就不调了,能看就行
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
#include <cmath>
#include <cstdlib>
using namespace std;
using namespace cv;
int cmpfunc(const void* a, const void* b)
{
return (*(int*)a - *(int*)b);
}
//去除左边框
int delLeftRow(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = 0; i < roi_row - 1; i++)
{
for (int j = 0; j < roi_col - 1; j++)
{
pix = outputArray.at<uchar>(i, j);
if (pix > 0)
{
cnt++;
break;
}
}
}
int up = (roi_row >> 3) * 7;
if (cnt >= up)
{
cv::Rect m_select;
m_select = Rect(1, 0, outputArray.cols - 1, outputArray.rows);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delLeftRow(outputArray);
}
return 0;
}
//去除右边框
int delRightRow(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = roi_row - 1; i > 0; i--)
{
for (int j = 0; j < roi_col - 1; j++)
{
pix = outputArray.at<uchar>(i, j);
if (pix > 0)
{
cnt++;
break;
}
}
}
int up = (roi_row >> 3) * 7;
if (cnt >= up)
{
cv::Rect m_select;
m_select = Rect(0, 0, outputArray.cols - 1, outputArray.rows);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delRightRow(outputArray);
}
return 0;
}
//去除上边框
int delUpCol(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = 0; i < roi_col - 1; i++)
{
for (int j = 0; j < roi_row - 1; j++)
{
pix = outputArray.at<uchar>(j, i);
if (pix > 0)
{
cnt++;
break;
}
}
}
int up = (roi_col >> 3) * 7;
if (cnt >= up)
{
cv::Rect m_select;
m_select = Rect(0, 1, outputArray.cols, outputArray.rows - 1);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delUpCol(outputArray);
}
return 0;
}
//去除下边框
int delDownCol(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = 0; i < roi_col - 1; i++)
{
for (int j = roi_row - 1; j >= 0; j--)
{
pix = outputArray.at<uchar>(j, i);
if (pix > 0)
{
cnt++;
break;
}
}
}
int up = (roi_col >> 3) * 7;
if (cnt >= up)
{
cv::Rect m_select;
m_select = Rect(0, 0, outputArray.cols, outputArray.rows - 1);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delDownCol(outputArray);
}
//waitKey(0);
return 0;
}
//去除上铆钉
int delUpRivet(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = 0; i < roi_col - 1; i++)
{
pix = outputArray.at<uchar>(0, i);
if (pix > 0)
{
cnt++;
}
}
int quarter = roi_col >> 4;
if (cnt < quarter)
{
cv::Rect m_select;
m_select = Rect(0, 1, outputArray.cols, outputArray.rows - 1);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delUpRivet(outputArray);
}
return 0;
}
//去除下铆钉
int delDownRivet(cv::Mat& outputArray)
{
int roi_col = outputArray.cols;
int roi_row = outputArray.rows;
uchar pix;
int cnt = 0;
for (int i = 0; i < roi_col - 1; i++)
{
pix = outputArray.at<uchar>(roi_row - 1, i);
if (pix > 0)
{
cnt++;
}
}
int quarter = roi_col >> 4;
if (cnt < quarter)
{
cv::Rect m_select;
m_select = Rect(0, 0, outputArray.cols, outputArray.rows - 1);
Mat ROI = outputArray(m_select);
outputArray = ROI;
delDownRivet(outputArray);
}
return 0;
}
int delRectRivet(const cv::Mat& inputArray, cv::Mat& outputArray)
{
outputArray = inputArray;
cv::Rect m_select;
m_select = Rect(0, 0, outputArray.cols >> 1, outputArray.rows);
Mat LROI = outputArray(m_select);
m_select = Rect(outputArray.cols >> 1, 0, outputArray.cols - (outputArray.cols >> 1), outputArray.rows);
Mat RROI = outputArray(m_select);
delLeftRow(LROI);
delRightRow(RROI);
Mat LR;
hconcat(LROI, RROI, LR);
outputArray = LR;
m_select = Rect(0, 0, outputArray.cols, outputArray.rows >> 1);
Mat UROI = outputArray(m_select);
m_select = Rect(0, outputArray.rows >> 1, outputArray.cols, outputArray.rows - (outputArray.rows >> 1));
Mat DROI = outputArray(m_select);
delUpCol(UROI);
delDownCol(DROI);
delUpRivet(UROI);
delDownRivet(DROI);
Mat UD;
vconcat(UROI, DROI, UD);
outputArray = UD;
return 0;
}
int main()
{
Mat img = imread("005.jpg");
Mat gray_img;
// 生成灰度图像
cvtColor(img, gray_img, CV_BGR2GRAY);
//imshow("gray_img", gray_img);
// 高斯模糊
Mat img_gau;
GaussianBlur(gray_img, img_gau, Size(3, 3), 0, 0);
//imshow("img_gau", img_gau);
// 阈值分割
Mat img_threadhold;
threshold(img_gau, img_threadhold, 0, 255, THRESH_BINARY + THRESH_OTSU);
//imshow("img_threadhold", img_threadhold);
//以上几步是参考了大神[Steven·简谈]的代码
//原文链接https://steven-cloud.blog.csdn.net/article/details/109563843
//切割边框&铆钉
Mat img_delRR;
delRectRivet(img_threadhold,img_delRR);
imshow("img_delRR",img_delRR);
//waitKey(0);
//return 0;
int roi_col = img_delRR.cols;
int roi_row = img_delRR.rows;
int posStart[50] = { 0 };
int posEnd[50] = { 0 };
int roi_width[50] = { 0 };
int roi_height[50] = { 0 };
int roi_width_cpy[50] = { 0 };
int roi_height_cpy[50] = { 0 };
uchar pix = 0;
int pixPlane[1000] = {0};//int pixPlane[img_delRR.cols];
//产生投影数组
for (int i = 0; i < roi_col - 1; i++)
{
for (int j = 0; j < roi_row - 1; j++)
{
pix = img_delRR.at<uchar>(j, i);
pixPlane[i] = 0;
if (pix > 0)
{
pixPlane[i] = 1;//投影
break;
}
}
}
//将连续的投影的起始终止坐标以及宽度记录到数组
int count = 0;
bool flage = false;
for (int i = 0; i < roi_col - 1; i++)
{
pix = pixPlane[i];
if (pix == 1 && !flage)
{
flage = true;
posStart[count] = i;
continue;
}
if (pix == 0 && flage)
{
flage = false;
posEnd[count] = i;
count++;
}
if (i == (roi_col - 2) && flage)
{
flage = false;
posEnd[count] = i;
count++;
}
}
// 记录所有字符宽度
for (int n = 0; n < count; n++)
{
roi_width[n] = posEnd[n] - posStart[n];
}
//求出投影高度
for (int k = 0; k < count; k++)
{
int cnt = 0;
for (int i = 0; i < roi_row - 1; i++)
{
for (int j = posStart[k]; j < posEnd[k]; j++)
{
pix = img_delRR.at<uchar>(i, j);
if (pix > 0)
{
cnt++;
break;
}
}
}
roi_height[k] = cnt;
}
//
//求出投影宽度的中位数
memcpy(roi_width_cpy, roi_width, 50 * sizeof(int));
qsort(roi_width_cpy, count, sizeof(int), cmpfunc);
int median_width = roi_width_cpy[count >> 1];
//求出投影高度的中位数
memcpy(roi_height_cpy, roi_height, 50 * sizeof(int));
qsort(roi_height_cpy, count, sizeof(int), cmpfunc);
int median_height = roi_height_cpy[count >> 1];
// 截取字符
int outCnt = 0;
Mat tmp, out;
Mat number_img;
const int cmp_col = roi_col >> 3;//误差范围,自己定就行
const int cmp_row = roi_row >> 2;//误差范围,自己定就行
for (int i = 0; i < count; i++)
{
const int val_col = abs(roi_width[i] - median_width);
const int val_row = abs(roi_height[i] - median_height);
if (val_col < cmp_col && val_row < cmp_row)
{
Rect choose_rect(posStart[i], 0, roi_width[i], img_delRR.rows);
number_img = img_delRR(choose_rect);
//此处不了解怎么写比较好,干脆写成这样把,反正没多少个循环
if (0 == outCnt)
{
tmp = number_img;
}
else
{
hconcat(tmp, number_img, out);
tmp = out;
}
outCnt++;
}
}
imshow("out", out);
if (7 == outCnt)
{
cout << "stand" << endl;
}
else
{
cout << "non-stand!" << endl;
}
waitKey(0);
return 0;
}