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

12 篇文章 0 订阅
5 篇文章 0 订阅

在这里插入图片描述
这张车牌是一张网图。
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;
}

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值