1、读取灰度图像,使用threshold将其二值化,选择CV_THRESH_BINARY_INV,使得字符为白色
Mat input = imread("plate.jpg", 0);
Mat img_threshold;
threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);
2、使用findContours接口函数找出各字符的轮廓
vector> contours;
findContours(img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
3、使用boundingRect函数得到各字符的外接矩形,用rectangle抠取字符图像
Rect mr = boundingRect(Mat(*(itc)));
rectangle(result, mr, Scalar(0, 255, 0));
4、使用verifySizes筛选字符图像
bool verifySizes(Mat r)
{
float aspect = 45.0f / 77.0f;
float charAspect = (float)r.cols / (float)r.rows;
float error = 0.35;
float minHeight = 15;
float maxHeight = 28;
//We have a different aspect ratio for number 1, and it can be ~0.2
float minAspect = 0.2;
float maxAspect = aspect + aspect*error;
float area = countNonZero(r);
float bbArea = r.cols*r.rows;
float percPixels = area / bbArea;
if (percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight)
return true;
else
return false;
}
5、对筛选后的字符图像进行预处理
Mat preprocessChar(Mat in)
{
//Remap image
int h = in.rows;
int w = in.cols;
Mat transformMat = Mat::eye(2, 3, CV_32F);
int m = max(w, h);
transformMat.at(0, 2) = m / 2 - w / 2;
transformMat.at(1, 2) = m / 2 - h / 2;
Mat warpImage(m, m, in.type());
warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0));
Mat out;
resize(warpImage, out, Size(20, 20));
return out;
}
6、将预处理后的字符图像及其在原图中的位置保持;因为findcontours算法得出的各字符的轮廓点是随机的,因此需要各字符图像的位置Rect,通过排序,得到真实的车牌字符顺序。
vector> output;
output.push_back(make_pair(auxRoi, mr));
完整代码如下:
#include
#include
using namespace std;
using namespace cv;
bool verifySizes(Mat r);
Mat preprocessChar(Mat in);
int main()
{
vector> output;
Mat input = imread("plate.jpg", 0);
Mat img_threshold;
threshold(input, img_threshold, 60, 255, CV_THRESH_BINARY_INV);
Mat img_contours;
img_threshold.copyTo(img_contours);
vector> contours;
findContours(img_contours, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
Mat result;
img_threshold.copyTo(result);
cvtColor(result, result, CV_GRAY2RGB);
drawContours(result, contours, 6, Scalar(255, 0, 0), 1);
vector>::iterator itc = contours.begin();
while (itc != contours.end())
{
Rect mr = boundingRect(Mat(*(itc)));
rectangle(result, mr, Scalar(0, 255, 0));
Mat auxRoi = img_threshold(mr);
if (verifySizes(auxRoi))
{
auxRoi = preprocessChar(auxRoi);
output.push_back(make_pair(auxRoi, mr));
rectangle(result, mr, Scalar(0, 125, 255));
}
itc++;
}
imshow("result", result);
waitKey(0);
return 0;
}
bool verifySizes(Mat r)
{
//Char sizes 45x77
float aspect = 45.0f / 77.0f;
float charAspect = (float)r.cols / (float)r.rows;
float error = 0.35;
float minHeight = 15;
float maxHeight = 28;
//We have a different aspect ratio for number 1, and it can be ~0.2
float minAspect = 0.2;
float maxAspect = aspect + aspect*error;
//area of pixels
float area = countNonZero(r);
//bb area
float bbArea = r.cols*r.rows;
//% of pixel in area
float percPixels = area / bbArea;
if (percPixels < 0.8 && charAspect > minAspect && charAspect < maxAspect && r.rows >= minHeight && r.rows < maxHeight)
return true;
else
return false;
}
Mat preprocessChar(Mat in)
{
//Remap image
int h = in.rows;
int w = in.cols;
Mat transformMat = Mat::eye(2, 3, CV_32F);
int m = max(w, h);
transformMat.at(0, 2) = m / 2 - w / 2;
transformMat.at(1, 2) = m / 2 - h / 2;
Mat warpImage(m, m, in.type());
warpAffine(in, warpImage, transformMat, warpImage.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0));
Mat out;
resize(warpImage, out, Size(20, 20));
return out;
}