[opencv][C++][车牌识别][切除车牌边框和钉子]车牌识别之分割字符

这张车牌是一张网图。
opencv2最高版本opencv2.4.13.6
到了腐蚀膨胀这一步,结果如下图所示:

去除车牌的边框和钉子,结果如下图所示:

最后将识别到的图片拼起来,结果如下图所示:间距方面就不调了,能看就行

#include
#include
#include
#include #include
#include
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;
}
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
