代码拉取完成,页面将自动刷新
/*********************************
* 车牌检测函数,通过阈值分割结合
* HSV通道分离划定车牌边界,并设定
* 阈值提取最优轮廓
* @ELVIS-W
* date:2019/9/23
* *******************************/
#include "license_plate_detection.h"
License_plate_detection::License_plate_detection()
{
}
cv::Mat License_plate_detection::detection(cv::Mat input_image)
{
//梯度检测图像
input_image.copyTo(image_grad);
cv::cvtColor(image_grad, image_grad, CV_BGR2GRAY);
image_grad.convertTo(image_grad, CV_32FC1);
//sobel图像滤波
sobelx = (cv::Mat_<float>(3, 3) << -0.125, 0, 0.125, -0.25, 0, 0.25, -0.125, 0, 0.125);
cv::filter2D(image_grad, image_grad, image_grad.type(), sobelx);
cv::multiply(image_grad, image_grad, mul_image);
double threshold = scaleValue * mean(mul_image).val[0];//4 * img_s的平均值-阈值
cv::Mat resultImage = cv::Mat::zeros(mul_image.size(), mul_image.type());
float* pDataimg_s = (float*)(mul_image.data);
float* pDataresult = (float*)(resultImage.data);
const int height = image_grad.rows;
const int width = image_grad.cols;
//非极大值抑制 + 阈值分割
for (size_t i = 1; i < height-1; i++)
{
for (size_t j = 1; j < width-1; j++)
{
bool b1 = (pDataimg_s[i*height + j] > pDataimg_s[i*height + j - 1]);
bool b2 = (pDataimg_s[i*height + j] > pDataimg_s[i*height + j + 1]);
bool b3 = (pDataimg_s[i*height + j] > pDataimg_s[(i - 1)*height + j]);
bool b4 = (pDataimg_s[i*height + j] > pDataimg_s[(i + 1)*height + j]);
pDataresult[i*height + j] = 255 * ((pDataimg_s[i*height + j] > threshold) && ((b1&&b2) || (b3&&b4)));
}
}
resultImage.convertTo(resultImage, CV_8UC1);
//HSV通道提取
input_image.copyTo(image_hsv);
cv::cvtColor(image_hsv, img_hsv, CV_BGR2HSV);
std::vector<cv::Mat> hsv_vec;
cv::split(img_hsv, hsv_vec);
img_h = hsv_vec[0];
img_s = hsv_vec[1];
img_v = hsv_vec[2];
img_h.convertTo(img_h, CV_32F);
img_s.convertTo(img_s, CV_32F);
img_v.convertTo(img_v, CV_32F);
cv::normalize(img_h, img_h, 0, 1, cv::NORM_MINMAX);
cv::normalize(img_s, img_s, 0, 1, cv::NORM_MINMAX);
cv::normalize(img_v, img_v, 0, 1, cv::NORM_MINMAX);
cv::Mat img_vblue = ((img_h > 0.45)&(img_h < 0.75)&(img_s > 0.15)&(img_v > 0.25));//蓝色通道提取
cv::Mat vbule_gradient = cv::Mat::zeros(image_hsv.size(), CV_8UC1);
for (size_t i = 1; i < height-1; i++){
for (size_t j = 1; j < width-1; j++){ //梯度和蓝色区域重合的部分,也可以用上面的矩形3X3的判断
vbule_gradient.at<uchar>(i, j) = (resultImage.at<uchar>(i, j) == 255 && img_vblue.at<uchar>(i,j) != 0) ? 255 : 0;
}
}
//形态学,轮廓提取车牌
cv::morphologyEx(vbule_gradient, morph, cv::MORPH_CLOSE, cv::Mat::ones(2, 25, CV_8UC1));
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
cv::findContours(morph, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_SIMPLE, cv::Point(-1, -1));
cv::Rect rec_adapt;
for (size_t i = 0; i < contours.size(); i++)
{
//----矩形区域非零像素占总的比例,防止有较大的空白区域干扰检测结果
//----矩形的长宽限制,也可以再增加额外条件:长宽比例等
int true_pix_count = cv::countNonZero(morph(boundingRect(contours[i])));
double true_pix_rate = static_cast<double>(true_pix_count) / static_cast<double>(cv::boundingRect(contours[i]).area());
if (cv::boundingRect(contours[i]).height > 10&& cv::boundingRect(contours[i]).width > 30 && true_pix_rate > 0.6)
{
rec_adapt = cv::boundingRect(contours[i]);
break;
// drawContours(morph, contours, static_cast<int>(i), cv::Scalar(255, 255, 255), 2);
}
}
return input_image(rec_adapt);
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。