若该文为原创文章,未经允许不得转载
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105843092
各位读者,知识无穷而人力有穷,要么改需求,要么找专业人士,要么自己研究
红胖子(红模仿)的博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中...(点击传送门)
上一篇:《OpenCV开发笔记(四十八):红胖子8分钟带你深入了解直方图均衡化(图文并茂+浅显易懂+程序源码)》
下一篇:《OpenCV开发笔记(五十):红胖子8分钟带你深入了解轮廓凸包(图文并茂+浅显易懂+程序源码)》
红胖子来也!!!
前面学了很多概念性的东西,本章开始开始做点实际的东西,车牌识别中,需要将车牌分离出来,一种方式是需要其轮廓,然后将其抠出来,再做其他操作。
轮廓可以理解为是一系列点包围了一个区域,它将一些列边界包围起来,形成的一个区域。
先通过滤波、阈值化的操作,然后寻找轮廓,定位到识别的物体的区域,这样可以将区域标记出来,抠图可以进而后续的二次处理。
(注意:轮廓查找的算法有很多,本篇章使用cv的函数findContours(),所以详解他的原理。)
识别过程如下:
void findContours( InputOutputArray image,
OutputArrayOfArrays contours,
OutputArray hierarchy,
int mode,
int method,
Point offset = Point());
void findContours( InputOutputArray image,
OutputArrayOfArrays contours,
int mode,
int method,
Point offset = Point());
序号 |
枚举 |
值 |
描述 |
1 |
RETR_EXTERNAL |
0 |
仅检索最外层轮廓。 |
2 |
RETR_LIST |
1 |
检索所有轮廓,而不建立任何层次关系 |
3 |
RETR_CCOMP |
2 |
检索所有轮廓并将其组织为两级层次结构。在顶端级别,组件有外部边界。在第二层,有洞的边界。如果在连接组件的孔内有另一个轮廓,则仍然被放在最高层。 |
4 |
RETR_TREE |
3 |
检索所有轮廓并重建嵌套轮廓的完整层次结构 |
5 |
RETR_FLOODFILL |
4 |
输入图像应该是连接的组件或填充功能的结果 |
序号 |
枚举 |
值 |
描述 |
1 |
CHAIN_APPROX_NONE |
0 |
存储所有轮廓点。也就是说,任何2个后续点(x1,y1)和轮廓的(x2,y2)将是水平、垂直或对角线邻接,即,max(abs(x1-x2),abs(y2-y1))==1。 |
2 |
CHAIN_APPROX_SIMPLE |
1 |
压缩水平、垂直和对角线线段,只保留其端点 |
3 |
CHAIN_APPROX_TC89_L1 |
2 |
应用TehChin89近似算法的一种风格 |
4 |
CHAIN_APPROX_TC89_KCOS |
3 |
应用TehChin89近似算法的一种风格 |
void drawContours( InputOutputArray image,
InputArrayOfArrays contours,
int contourIdx,
const Scalar& color,
int thickness = 1,
int lineType = LINE_8,
InputArray hierarchy = noArray(),
int maxLevel = INT_MAX,
Point offset = Point() );
(略,本篇章主要是轮廓,车牌识别),为了避免一些简单的噪声,在这里使用了自适应流行滤波器进行滤波。
参照博文《OpenCV开发笔记(三十五):红胖子8分钟带你深入了解ximgproc扩展模块中的自适应流行滤波器(图文并茂+浅显易懂+程序源码)》
使用合适的方式进行过滤,在这里先转成灰度图,然后使用基础阈值化,自己调整阈值化,达到一个合适的值。
参照博文《OpenCV开发笔记(二十八):带你学习图像识别之阈值化》
使用轮过查找,查找出轮廓,得到轮廓信息,是本篇所关注的。
得到轮廓后,对图像进行分割(抠图),其实轮廓已经得出了基本的图像轮廓信息,抠图然后把该部分最外层轮廓抠出来就是数字和字母了还有一些杂质。
可以分为两步,先抠出来整张图的这个部分(一整张图大小,非抠图部分为黑色),然后在进行一次裁剪,得到实际图像的位置,去掉多余的部分(其实就是ROI感兴趣的区域,此处不在赘述),如下图:
(略,识别部分很多方式:模版、特征点、深度学习等等,后续写到实际开发部分详解后会与此处进行关联)。
void OpenCVManager::testFindContours()
{
QString fileName1 =
"E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/5.jpg";
cv::Mat srcMat = cv::imread(fileName1.toStdString());
cv::Mat dstMat;
int width = 300;
int height = 200;
cv::resize(srcMat, srcMat, cv::Size(width, height));
cv::String windowName = _windowTitle.toStdString();
cvui::init(windowName);
cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2,
srcMat.rows * 5),
srcMat.type());
int sigmaS = 100;
int sigmaR = 1.0;
int thresh = 215;
int maxval = 255;
while(true)
{
// 刷新全图黑色
windowMat = cv::Scalar(0, 0, 0);
// 原图复制
cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);
cv::Mat tempMat;
{
{
cvui::printf(windowMat, 75 + width * 1, 40 + height * 0, "sigmaS");
cvui::trackbar(windowMat, 75 + width * 1, 50 + height * 0, 165, &sigmaS, 101, 10000);
cvui::printf(windowMat, 75 + width * 1, 90 + height * 0, "sigmaR");
cvui::trackbar(windowMat, 75 + width * 1, 100, 165 + height * 0, &sigmaR, 1, 100);
// 使用自适应流形应用高维滤波。
cv::Ptr pAdaptiveManifoldFilter
= cv::ximgproc::createAMFilter(sigmaS/100.0f, sigmaR/100.0f, true);
pAdaptiveManifoldFilter->filter(srcMat, tempMat);
// 效果图copy
mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, tempMat, 1.0f, 0.0f, mat);
}
// 转为灰度图像
cv::cvtColor(tempMat, tempMat, cv::COLOR_BGR2GRAY);
{
// 调整阈值化的参数thresh
cvui::printf(windowMat, 75 + width * 1, 20 + height * 1, "thresh");
cvui::trackbar(windowMat, 75 + width * 1, 40 + height * 1, 165, &thresh, 0, 255);
// 调整阈值化的参数maxval
cvui::printf(windowMat, 75 + width * 1, 80 + height * 1, "maxval");
cvui::trackbar(windowMat, 75 + width * 1, 100 + height * 1, 165, &maxval, 0, 255);
// 阈值化
cv::threshold(tempMat, tempMat, thresh, maxval, cv::THRESH_BINARY);
// 效果图copy
mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
// 转还图像
cv::Mat grayMat;
cv::cvtColor(tempMat, grayMat, cv::COLOR_GRAY2BGR);
cv::addWeighted(mat, 0.0f, grayMat, 1.0f, 0.0f, mat);
}
// 寻找轮廓
{
qDebug() << __FILE__ << __LINE__;
std::vector> contours;
std::vector hierarchy;
// 查找轮廓
cv::findContours(tempMat, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);
// 遍历所有顶层轮廓,并绘制出来
dstMat = srcMat.clone();
cv::Mat emptyMat = srcMat.clone();
emptyMat = cv::Scalar(0,0,0);
qDebug() << __FILE__ << __LINE__;
// 轮廓contours[i]对应4个hierarchy元素hierarchy[i][0]~ hierarchy[i][3],
// hierarchy[i][0]表示后一个轮廓的索引编号
// hierarchy[i][1]前一个轮廓的索引编号
// hierarchy[i][2]父轮廓的索引编号
// hierarchy[i][3]内嵌轮廓的索引编号
for(int index = 0; index >=0; index = hierarchy[index][0])
{
if(hierarchy.size() <= 0)
{
break;
}
cv::Scalar color;
if(index < hierarchy.size() / 3)
{
color = cv::Scalar(250 / (hierarchy.size() / 3) * index, 255, 255);
}else if(index < hierarchy.size() / 3 * 2)
{
color = cv::Scalar(255, 250 / (hierarchy.size() / 3) * (index - hierarchy.size() / 3), 255);
}else
{
color = cv::Scalar(255, 255, 250 /
(hierarchy.size() / 3 == 0? 1 : hierarchy.size() / 3) * (index - hierarchy.size() / 3 * 2));
}
// 绘制轮廓里面的第几个
cv::drawContours(dstMat, contours, index, color, CV_FILLED, 8, hierarchy);
cv::drawContours(emptyMat, contours, index, color, CV_FILLED, 8, hierarchy);
qDebug() << __FILE__ << __LINE__ << "index =" << index << "total =" << hierarchy.size();
}
// 效果图copy
mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, emptyMat, 1.0f, 0.0f, mat);
// 效果图copy
mat = windowMat(cv::Range(srcMat.rows * 4, srcMat.rows * 5),
cv::Range(srcMat.cols * 0, srcMat.cols * 1));
cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
}
}
// 更新
cvui::update();
// 显示
cv::imshow(windowName, windowMat);
// esc键退出
if(cv::waitKey(25) == 27)
{
break;
}
}
}
对应版本号v1.44.0
上一篇:《OpenCV开发笔记(四十八):红胖子8分钟带你深入了解直方图均衡化(图文并茂+浅显易懂+程序源码)》
下一篇:《OpenCV开发笔记(五十):红胖子8分钟带你深入了解轮廓凸包(图文并茂+浅显易懂+程序源码)》
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客导航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105843092