关于easypr中闭运算内核大小的选取
easypr中,选用HSV颜色进行车牌定位,在H、S、V范围内的像素点置为255,其余0,随后进行闭运算,扩大车牌连通域。
在闭运算中,内核大小选取十分重要,源码中选取10,2作为内核大小,这是为什么呢?
车牌长宽比大致5:1,但是内核大小为什么不用5,1呢,太小,形不成大的连通域,看下图:
void colorMatch(const Color r)
{
// if use adaptive_minsv
// min value of s and v is adaptive to h
const float max_sv = 255;
const float minref_sv = 64;
const float minabs_sv = 95; //95;
// H range of blue
const int min_blue = 100; // 100
const int max_blue = 140; // 140
// H range of yellow
const int min_yellow = 15; // 15
const int max_yellow = 40; // 40
// H range of white
const int min_white = 0; // 15
const int max_white = 30; // 40
Mat src,src_hsv;
src = imread("car6.jpg", 1);
// convert to HSV space
cvtColor(src, src_hsv, CV_BGR2HSV);
std::vector<cv::Mat> hsvSplit;
split(src_hsv, hsvSplit);
equalizeHist(hsvSplit[2], hsvSplit[2]);
merge(hsvSplit, src_hsv);
int min_h = 0;
int max_h = 0;
switch (r) {
case BLUE:
min_h = min_blue;
max_h = max_blue;
break;
case YELLOW:
min_h = min_yellow;
max_h = max_yellow;
break;
case WHITE:
min_h = min_white;
max_h = max_white;
break;
default:
// Color::UNKNOWN
break;
}
float diff_h = float((max_h - min_h) / 2);
float avg_h = min_h + diff_h;
int channels = src_hsv.channels();
int nRows = src_hsv.rows;
// consider multi channel image
int nCols = src_hsv.cols * channels;
if (src_hsv.isContinuous()) {
nCols *= nRows;
nRows = 1;
}
int i, j;
uchar* p;
float s_all = 0;
float v_all = 0;
float count = 0;
for (i = 0; i < nRows; ++i) {
p = src_hsv.ptr<uchar>(i);
for (j = 0; j < nCols; j += 3) {
int H = int(p[j]); // 0-180
int S = int(p[j + 1]); // 0-255
int V = int(p[j + 2]); // 0-255
s_all += S;
v_all += V;
count++;
bool colorMatched = false;
if (H > min_h && H < max_h) {
float Hdiff = 0;
if (H > avg_h)
Hdiff = H - avg_h;
else
Hdiff = avg_h - H;
float Hdiff_p = float(Hdiff) / diff_h;
float min_sv = 0;
if (1)//颜色正,最小值可以到1/2,不正,最小值为1
min_sv =
minref_sv -
minref_sv / 2 *
(1
- Hdiff_p); // inref_sv - minref_sv / 2 * (1 - Hdiff_p)
else
min_sv = minabs_sv; // add
if ((S > min_sv && S < max_sv) && (V > min_sv && V < max_sv))
colorMatched = true;
}
if (colorMatched == true) {
p[j] = 0;
p[j + 1] = 0;
p[j + 2] = 255;
}
else {
p[j] = 0;
p[j + 1] = 0;
p[j + 2] = 0;
}
}
}
Mat src_grey,match;
std::vector<cv::Mat> hsvSplit_done;
split(src_hsv, hsvSplit_done);
src_grey = hsvSplit_done[2];
//imshow("src_grey", src_grey);
match = src_grey;
//imshow("match", match);
Mat src_threshold;//此步骤进行不进行好像没有区别
threshold(match, src_threshold, 0, 255,
CV_THRESH_OTSU + CV_THRESH_BINARY);
imshow("src_threshold", src_threshold);
Mat img1, img2;
Mat element = getStructuringElement(MORPH_RECT, Size(10, 2));//内核 车牌的长宽比大约 5:1,这样可以方便提取车牌,10:2比5:1可以形成更大的连通域
morphologyEx(src_threshold, img1, MORPH_CLOSE, element);//闭运算
imshow("img1", img1);
}
原图:
HSV匹配后:
内核10,2:
内核5,1:
内核20,4:
内核20,4时,效果更好,但是不一定适用于其他车牌不明显的场景(距离摄像头过远),拍得车牌很小。
综合考虑,选用10,2.