int scale = SOBEL_SCALE;
int delta = SOBEL_DELTA;
int ddepth = SOBEL_DDEPTH;
if( !src.data )
{ return -1; }
//高斯模糊。Size中的数字影响车牌定位的效果。
GaussianBlur( src, src_blur, Size(m_GaussianBlurSize, m_GaussianBlurSize),
0, 0, BORDER_DEFAULT );
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_GaussianBlur" << ".jpg";
imwrite(ss.str(), src_blur);
}
/// Convert it to gray
cvtColor( src_blur, src_gray, CV_RGB2GRAY );
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_gray" << ".jpg";
imwrite(ss.str(), src_gray);
}
// RGB颜色初定位
// http://wenku.baidu.com/view/2329e5d2360cba1aa811da65.html?re=view
// RGB -> HSV
// 蓝 黄 白 黑
//H 200~255 25~55 / /
//S 0.4~1 0.4~1 0~0.1 /
//V 0.3~1 0.3~1 0.9~1 0~0.35
//cvCvtColor(src,dst,CV_BGR2HSV);
//其中,src为三通道的,dst也为三通道的,
//OPENCV 中 H、S、V、顺序分别为3*x+0 3*x+1 3*x+2
//opencv中的 H分量是 0~180, S分量是0~255, V分量是0~255
//但是HSV颜色空间却规定的是,H范围0~360,S范围0~1,V范围0~1
//所以你需要自己转换一下,H*2,S/255, V/255
// 默认蓝色车牌
cv::Mat tmp;
cv::cvtColor(src, tmp, CV_BGR2HSV);
vector<Mat> hsvSplit;
split(tmp, hsvSplit);
cv::Mat dst_blue(src.rows, src.cols, CV_8UC1);
cv::Mat dst_yellow(src.rows, src.cols, CV_8UC1);
for(int i = 0; i<tmp.rows; i++)
{
for(int j = 0; j<tmp.cols; j++)
{
int nH = hsvSplit[0].at<uchar>(i, j)*2;
float fS = hsvSplit[1].at<uchar>(i, j)/255.0;
float fV = hsvSplit[2].at<uchar>(i, j)/255.0;
if(nH>=200 && nH<=255 && fS>=0.4 && fS<=1 && fV>=0.3 && fV<=1) // 蓝色
dst_blue.at<uchar>(i, j) = 255;
else
dst_blue.at<uchar>(i, j) = 0;
}
}
Mat element_blue = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
morphologyEx(dst_blue, dst_blue, MORPH_CLOSE, element_blue);
//Find 轮廓 of possibles plates
cv::Mat con_blue = dst_blue.clone();
vector< vector< Point> > contours_blue;
findContours(con_blue,
contours_blue, // a vector of contours
CV_RETR_EXTERNAL, // 提取外部轮廓
CV_CHAIN_APPROX_NONE); // all pixels of each contours
//Start to iterate to each contour founded
vector<vector<Point> >::iterator itb = contours_blue.begin();
//Remove patch that are no inside limits of aspect ratio and area.
int tb = 0;
vector<cv::Rect> rects_blue;
while(itb != contours_blue.end())
{
//Create bounding rect of object
RotatedRect mr = minAreaRect(Mat(*itb));
//large the rect for more
if(!verifySizes(mr))
{
cv::Mat& roi = dst_blue(mr.boundingRect());
roi.setTo(0);
}
else
{
rects_blue.push_back(mr.boundingRect());
}
++itb;
}
//////////////////////////////////////////////////////////////////////////
for(int i = 0; i<tmp.rows; i++)
{
for(int j = 0; j<tmp.cols; j++)
{
int nH = hsvSplit[0].at<uchar>(i, j)*2;
float fS = hsvSplit[1].at<uchar>(i, j)/255.0;
float fV = hsvSplit[2].at<uchar>(i, j)/255.0;
if(nH>=25 && nH<=55 && fS>=0.4 && fS<=1 && fV>=0.3 && fV<=1) // 黄色
dst_yellow.at<uchar>(i, j) = 255;
else
dst_yellow.at<uchar>(i, j) = 0;
}
}
Mat element_yellow = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
morphologyEx(dst_yellow, dst_yellow, MORPH_CLOSE, element_blue);
//Find 轮廓 of possibles plates
cv::Mat con_yellow = dst_yellow.clone();
vector< vector< Point> > contours_yellow;
findContours(con_yellow,
contours_yellow, // a vector of contours
CV_RETR_EXTERNAL, // 提取外部轮廓
CV_CHAIN_APPROX_NONE); // all pixels of each contours
//Start to iterate to each contour founded
vector<vector<Point> >::iterator ity = contours_yellow.begin();
//Remove patch that are no inside limits of aspect ratio and area.
tb = 0;
vector<cv::Rect> rects_yellow;
while(ity != contours_yellow.end())
{
//Create bounding rect of object
RotatedRect mr = minAreaRect(Mat(*ity));
//large the rect for more
if(!verifySizes(mr))
{
cv::Mat& roi = dst_yellow(mr.boundingRect());
roi.setTo(0);
}
else
{
dst_yellow.push_back(mr.boundingRect());
}
++ity;
}
/// Generate grad_x and grad_y
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// Gradient X
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
/// Gradient Y
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
/// Total Gradient (approximate)
addWeighted( abs_grad_x, SOBEL_X_WEIGHT, abs_grad_y, SOBEL_Y_WEIGHT, 0, grad );
//Laplacian( src_gray, grad_x, ddepth, 3, scale, delta, BORDER_DEFAULT );
//convertScaleAbs( grad_x, grad );
cv::Mat out_blue;
cv::multiply(grad, dst_blue, out_blue);
cv::Mat out_yellow;
cv::multiply(grad, dst_yellow, out_yellow);
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_Sobel_blue" << ".jpg";
imwrite(ss.str(), out_blue);
ss << "image/tmp/debug_Sobel_yellow" << ".jpg";
imwrite(ss.str(), out_yellow);
}
Mat img_threshold_blue;
Mat img_threshold_yellow;
threshold(out_blue, img_threshold_blue, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
threshold(out_yellow, img_threshold_yellow, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
//threshold(grad, img_threshold, 75, 255, CV_THRESH_BINARY);
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_threshold_blue" << ".jpg";
imwrite(ss.str(), img_threshold_blue);
ss << "image/tmp/debug_threshold_yellow" << ".jpg";
imwrite(ss.str(), img_threshold_yellow);
}
Mat element = getStructuringElement(MORPH_RECT, Size(m_MorphSizeWidth, m_MorphSizeHeight) );
morphologyEx(img_threshold_blue, img_threshold_blue, MORPH_CLOSE, element);
morphologyEx(img_threshold_yellow, img_threshold_yellow, MORPH_CLOSE, element);
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_morphology_blue" << ".jpg";
imwrite(ss.str(), img_threshold_blue);
ss << "image/tmp/debug_morphology_yellow" << ".jpg";
imwrite(ss.str(), img_threshold_yellow);
}
//Find 轮廓 of possibles plates
contours_blue.clear();
findContours(img_threshold_blue,
contours_blue, // a vector of contours
CV_RETR_EXTERNAL, // 提取外部轮廓
CV_CHAIN_APPROX_NONE); // all pixels of each contours
contours_yellow.clear();
findContours(img_threshold_yellow,
contours_yellow, // a vector of contours
CV_RETR_EXTERNAL, // 提取外部轮廓
CV_CHAIN_APPROX_NONE); // all pixels of each contours
Mat result;
if(m_debug)
{
//// Draw blue contours on a white image
src.copyTo(result);
drawContours(result, contours_blue,
-1, // draw all contours
Scalar(0,0,255), // in blue
1); // with a thickness of 1
drawContours(result, contours_yellow,
-1, // draw all contours
Scalar(0, 0, 255), // in blue
1); // with a thickness of 1
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_Contours" << ".jpg";
imwrite(ss.str(), result);
}
//Start to iterate to each contour founded
itb = contours_blue.begin();
vector<RotatedRect> rects;
//Remove patch that are no inside limits of aspect ratio and area.
int t = 0;
while (itb != contours_blue.end())
{
//Create bounding rect of object
RotatedRect mr = minAreaRect(Mat(*itb));
//large the rect for more
if( !verifySizes(mr))
{
itb = contours_blue.erase(itb);
}
else
{
++itb;
rects.push_back(mr);
}
}
ity = contours_yellow.begin();
while(ity != contours_yellow.end())
{
//Create bounding rect of object
RotatedRect mr = minAreaRect(Mat(*ity));
//large the rect for more
if(!verifySizes(mr))
{
ity = contours_yellow.erase(ity);
}
else
{
++ity;
rects.push_back(mr);
}
}
int k = 1;
for(int i=0; i< rects.size(); i++)
{
RotatedRect minRect = rects[i];
if(verifySizes(minRect))
{
// rotated rectangle drawing
// Get rotation matrix
// 旋转这部分代码确实可以将某些倾斜的车牌调整正,
// 但是它也会误将更多正的车牌搞成倾斜!所以综合考虑,还是不使用这段代码。
// 2014-08-14,由于新到的一批图片中发现有很多车牌是倾斜的,因此决定再次尝试
// 这段代码。
if(m_debug)
{
Point2f rect_points[4];
minRect.points( rect_points );
for( int j = 0; j < 4; j++ )
line( result, rect_points[j], rect_points[(j+1)%4], Scalar(0,255,255), 1, 8 );
}
float r = (float)minRect.size.width / (float)minRect.size.height;
float angle = minRect.angle;
Size rect_size = minRect.size;
if (r < 1)
{
angle = 90 + angle;
swap(rect_size.width, rect_size.height);
}
//如果抓取的方块旋转超过m_angle角度,则不是车牌,放弃处理
if (angle - m_angle < 0 && angle + m_angle > 0)
{
//Create and rotate image
Mat rotmat = getRotationMatrix2D(minRect.center, angle, 1);
Mat img_rotated;
warpAffine(src, img_rotated, rotmat, src.size(), CV_INTER_CUBIC);
Mat resultMat;
resultMat = showResultMat(img_rotated, rect_size, minRect.center, k++);
resultVec.push_back(resultMat);
}
}
}
if(m_debug)
{
stringstream ss(stringstream::in | stringstream::out);
ss << "image/tmp/debug_result" << ".jpg";
imwrite(ss.str(), result);
}
return 0;