这篇文章给大家介绍利用OpenCV怎么对车牌的字符进行分割,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
10年积累的成都网站建设、成都网站制作经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先做网站设计后付款的网站建设流程,更有烈山免费网站建设让你可以放心的选择与我们合作。。
检测轮廓进行分割
边缘检测
对图像进行边缘检测,这里采用的是 Canny 边缘检测,处理后的结果如下:
可以看到每个字的边缘都被描绘出来了,接下来就将每个字的轮廓获取出来。
检测轮廓
直接使用 findContours() 将所有轮廓提取出来,再将其在原图中画出来看看效果:
可以看到不仅仅是每个字被框出来了,还有内部以及图像中表现特殊部分的轮廓也有,接下来我们就根据每个字的大致大小筛选出我们想要的结果:
这样看起来是不是就成功了,然后根据轮廓位置将每个字提取出来就行了,不过在这里每个轮廓的前后顺序不一定是图像中的位置,这里我使用每个轮廓左上角横坐标 x 的大小来排序。
完整代码:
#include#include #include #include #include
像素值判断进行分割
分割方法:首先判断每一列的像素值大于 0 的像素个数超过5个时,认为此列是有数字的,记录每列像素是否大于 5,产生一个数组。
// 确认为 1 的像素 int pixrow[1000]; for (int i = 0; i < roi_col - 1; i++) { for (int j = 0; j < roi_row - 1; j++) { pix = img_threadhold.at(j, i); pixrow[i] = 0; if (pix > 0) { pixrow[i] = 1; break; } } } // 对数组进行滤波,减少突变概率 for (int i = 2; i < roi_col - 1 - 2; i++) { if ((pixrow[i - 1] + pixrow[i - 2] + pixrow[i + 1] + pixrow[i + 2]) >= 3) { pixrow[i] = 1; } else if ((pixrow[i - 1] + pixrow[i - 2] + pixrow[i + 1] + pixrow[i + 2]) <= 1) { pixrow[i] = 0; } }
之后记录像素为 0 和 1 所连续的长度来计算字符的宽度,最后用宽度的大小来筛选字符。
// 确认字符位置 int count = 0; bool flage = false; for (int i = 0; i < roi_col - 1; i++) { pix = pixrow[i]; if (pix == 1 && !flage) { flage = true; position1[count] = i; continue; } if (pix == 0 && flage) { flage = false; position2[count] = i; count++; } if (i == (roi_col - 2) && flage) { flage = false; position2[count] = i; count++; } }
分割出的结果:
完整代码:
#include#include #include #include using namespace std; using namespace cv; int main() { Mat img = imread("number.jpg"); Mat gray_img; // 生成灰度图像 cvtColor(img, gray_img, CV_BGR2GRAY); // 高斯模糊 Mat img_gau; GaussianBlur(gray_img, img_gau, Size(3, 3), 0, 0); // 阈值分割 Mat img_threadhold; threshold(img_gau, img_threadhold, 0, 255, THRESH_BINARY + THRESH_OTSU); // 判断字符水平位置 int roi_col = img_threadhold.cols, roi_row = img_threadhold.rows, position1[50], position2[50], roi_width[50]; uchar pix; // 确认为 1 的像素 int pixrow[1000]; for (int i = 0; i < roi_col - 1; i++) { for (int j = 0; j < roi_row - 1; j++) { pix = img_threadhold.at (j, i); pixrow[i] = 0; if (pix > 0) { pixrow[i] = 1; break; } } } // 对数组进行滤波,减少突变概率 for (int i = 2; i < roi_col - 1 - 2; i++) { if ((pixrow[i - 1] + pixrow[i - 2] + pixrow[i + 1] + pixrow[i + 2]) >= 3) { pixrow[i] = 1; } else if ((pixrow[i - 1] + pixrow[i - 2] + pixrow[i + 1] + pixrow[i + 2]) <= 1) { pixrow[i] = 0; } } // 确认字符位置 int count = 0; bool flage = false; for (int i = 0; i < roi_col - 1; i++) { pix = pixrow[i]; if (pix == 1 && !flage) { flage = true; position1[count] = i; continue; } if (pix == 0 && flage) { flage = false; position2[count] = i; count++; } if (i == (roi_col - 2) && flage) { flage = false; position2[count] = i; count++; } } // 记录所有字符宽度 for (int n = 0; n < count; n++) { roi_width[n] = position2[n] - position1[n]; } // 减去较大值、最小值,计算平均值用字符宽度来筛选 int max = roi_width[0], max_index = 0; int min = roi_width[0], min_index = 0; for (int n = 1; n < count; n++) { if (max < roi_width[n]) { max = roi_width[n]; max_index = n; } if (min > roi_width[n]) { min = roi_width[n]; min_index = n; } } int index = 0; int new_roi_width[50]; for (int i = 0; i < count; i++) { if (i == min_index || i == max_index) {} else { new_roi_width[index] = roi_width[i]; index++; } } // 取后面三个值的平均值 int avgre = (int)((new_roi_width[count - 3] + new_roi_width[count - 4] + new_roi_width[count - 5]) / 3.0); // 字母位置信息确认,用宽度来筛选 int licenseX[10], licenseW[10], licenseNum = 0; int countX = 0; for (int i = 0; i < count; i++) { if (roi_width[i] >(avgre - 8) && roi_width[i] < (avgre + 8)) { licenseX[licenseNum] = position1[i]; licenseW[licenseNum] = roi_width[i]; licenseNum++; countX++; continue; } if (roi_width[i] > (avgre * 2 - 10) && roi_width[i] < (avgre * 2 + 10)) { licenseX[licenseNum] = position1[i]; licenseW[licenseNum] = roi_width[i]; licenseNum++; } } // 截取字符 Mat number_img = Mat(Scalar(0)); for (int i = 0; i < countX; i++) { Rect choose_rect(licenseX[i], 0, licenseW[i], gray_img.rows); number_img = gray_img(choose_rect); imshow("number" + to_string(i), number_img); // imwrite("number" + to_string(i) + ".jpg", number_img); } waitKey(0); return 0; }
关于利用OpenCV怎么对车牌的字符进行分割就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。