首页 > 编程语言 >OpenCV实战案例——直线检测[C++]

OpenCV实战案例——直线检测[C++]

时间:2024-06-11 16:13:25浏览次数:26  
标签:实战 Mat 代码 imshow mSrc C++ OpenCV 图像 mMorph

0.前言
本文以实战案例为背景,一步步讲述如何使用计算机图像处理相关知识提取图片中英语填空题答题线。

1.需求背景
某公司打算设计一款英语题目批改APP,要求学生上传英语填空题图片,然后该APP自动标注答题线位置(使用红线标注),方便后续定位和批改答案。下图(图1-1)为某一学生上传的英语填空题图片。

该APP的预期效果如下图(图1-2)所示。

2.解决思路

  • 首先应该将图片转换为灰度图再经过阈值处理转换为二值图。
  • 由于图片中存在较多英文字符,如果直接使用霍夫直线检测效果并不显著。
  • 寻找一种方法能够将英文等字符去除,仅留下直线特征。本文采取形态学操作实现该步骤。
  • 将大多干扰因素去除后使用霍夫变换提取直线效果更佳。
  • 最后在原图像中标注即可。

3.代码解释

点击查看代码
//读取图像
Mat mSrc = imread(path1, ImreadModes::IMREAD_COLOR);
imshow("源图像", mSrc);
上述代码读取了学生上传的图片,显示结果如下图(图3-1)所示。

点击查看代码
//灰度
Mat mGray;
cvtColor(mSrc, mGray, ColorConversionCodes::COLOR_BGR2GRAY);
imshow("灰度", mGray);
上述代码将原图转换为灰度图片,显示结果如下图(图3-2)所示。

点击查看代码
//二值
Mat mBin;
threshold(mGray, mBin, 114, 255, ThresholdTypes::THRESH_BINARY_INV);
imshow("二值", mBin);
上述代码讲灰度图像经过阈值化处理转换为二值图像,图像阈值为114,像素点灰度高于114的像素点值为0,像素点小于等于114的像素点值变为255,ThresholdTypes为二值反转类型,其实现原理如下图(图3-3)所示。


程序显示结果如下图(图3-4)所示。

点击查看代码
//形态学操作 开+膨胀
Mat mMorph;
Mat mOpenKernal= getStructuringElement(MorphShapes::MORPH_RECT, Size(10, 1));
morphologyEx(mBin, mMorph, MorphTypes::MORPH_OPEN, mOpenKernal, Point(-1, -1), 2);
Mat mDilateKernal = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));
dilate(mMorph, mMorph, mDilateKernal);
imshow("形态学", mMorph);
上述代码设置卷积核大小为10*1(宽度为10,高度为1),对二值图像执行开操作运算,执行后的效果是去除了英文等字符,保留图像中的直线特征,再将图像执行膨胀操作,其目的是增强二值图像中直线的纹理特征,使得图像中直线“变粗”更容易提取。最终显示结果如下图(图3-5)所示。

从图3-5可以很清晰地看到原图像中英语答题线被提取出来了,其余次要特征被过滤掉了。这里得出一个重要的实用结论:进行形态学开操作时,卷积核为横向或纵向时分别能够保留二值图中的横向纹理或纵向纹理,感兴趣的读者可以私下设计实验进行探究。

点击查看代码
//霍夫直线
vector<Vec4f> vLines;
HoughLinesP(mMorph, vLines, 1, CV_PI / 180.0, 1);
for (Vec4f& v : vLines)
{
	line(mSrc, Point(v[0], v[1]), Point(v[2], v[3]), Scalar(0, 0, 255), 2);
}
imshow("结果", mSrc);
上述代码使用霍夫直线算法提取图3-5中的直线并将提取到的直线绘制到原图像上。vLines中的每个元素类型是Vec4f,每一条线段可以被两个点表示,分别为(x1,y1)、(x2,y2),代码中v[0]表示x1、v[1]表示y1、v[2]表示x2、v[3]表示y2。代码显示结果如下图(图3-6)所示。

至此结束。

4.完整代码

点击查看代码
	//读取图像
	Mat mSrc = imread(path1, ImreadModes::IMREAD_COLOR);
	imshow("源图像", mSrc);

	//灰度
	Mat mGray;
	cvtColor(mSrc, mGray, ColorConversionCodes::COLOR_BGR2GRAY);
	imshow("灰度", mGray);

	//二值
	Mat mBin;
	threshold(mGray, mBin, 114, 255, ThresholdTypes::THRESH_BINARY_INV);
	imshow("二值", mBin);

	//形态学操作 开+膨胀
	Mat mMorph;
	Mat mOpenKernal= getStructuringElement(MorphShapes::MORPH_RECT, Size(10, 1));
	morphologyEx(mBin, mMorph, MorphTypes::MORPH_OPEN, mOpenKernal, Point(-1, -1), 2);
	Mat mDilateKernal = getStructuringElement(MorphShapes::MORPH_RECT, Size(3, 3));
	dilate(mMorph, mMorph, mDilateKernal);
	imshow("形态学", mMorph);

	//霍夫直线
	vector<Vec4f> vLines;
	HoughLinesP(mMorph, vLines, 1, CV_PI / 180.0, 1);
	for (Vec4f& v : vLines)
	{
		line(mSrc, Point(v[0], v[1]), Point(v[2], v[3]), Scalar(0, 0, 255), 2);
	}
	imshow("结果", mSrc);

标签:实战,Mat,代码,imshow,mSrc,C++,OpenCV,图像,mMorph
From: https://www.cnblogs.com/hello-nullptr/p/18242128

相关文章

  • 基于Vue+Node.js的高校学业预警系统+10551(免费领源码)可做计算机毕业设计JAVA、PHP、爬
    NodeJS高校学业预警系统摘 要随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,教育行业当然也不能排除在外。高校学业预警系统是以实际运用为开发背景,运用软件工程开发方法,采用Node.JS技术构建的一个管理系统。......
  • 鸿蒙HarmonyOS实战-窗口管理
    ......
  • 华为OD机试 C++ - 中文分词模拟器
    中文分词模拟器前言:本专栏将持续更新互联网大厂机试真题,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于大厂机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:[email protected];备注:CSDN。题目描述给定一个连续不......
  • 华为OD机试 C++ - 找数字
    找数字前言:本专栏将持续更新互联网大厂机试真题,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于大厂机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:[email protected];备注:CSDN。题目描述小扇和小船今天又玩起来......
  • 华为OD机试 C++ - 根据IP查找城市
    根据IP查找城市前言:本专栏将持续更新互联网大厂机试真题,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于大厂机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:[email protected];备注:CSDN。题目描述某业务需要根据......
  • 华为OD机试 C++ - 文件缓存系统
    文件缓存系统前言:本专栏将持续更新互联网大厂机试真题,并进行详细的分析与解答,包含完整的代码实现,希望可以帮助到正在努力的你。关于大厂机试流程、面经、面试指导等,如有任何疑问,欢迎联系我,wechat:steven_moda;email:[email protected];备注:CSDN。题目描述请设计一个文件缓......
  • C++中的继承
    目录继承的概念及定义继承的概念继承定义定义格式 继承关系和访问限定符继承基类成员访问方式的变化基类和派生类对象赋值转换继承中的作用域派生类的默认成员函数继承与友元继承与静态成员        我们都知道,面向对象的三个基本特征是:封装,继承以及多态......
  • C/C++单元测试如何解决非虚函数对象依赖
    如何解决非虚函数对象依赖随着事物的接触越来越多,了解的越来越深入,我们总会发现一些新的问题或者不足。就像前文提到的一样,我们在面对有对象的虚函数依赖的时候,可以使用gmock框架来为我们提供方便的模拟期望值,以便我们能撇除外界的影响(依赖)从逻辑上设计单元测试并持续的......
  • nw.js 如何调用activeX控件 (控件是C++编写的dll文件)
    ......
  • 深入理解C++中的常量和宏:const、#define、typedef和inline详解
    一、const 与 #define 的区别1.定义方式和类型const 定义的常量是有类型的变量。#define 只是文本替换,不带类型。constintMAX_VALUE=100;//MAX_VALUE是一个整数类型的常量#defineMAX_VALUE100//MAX_VALUE是一个文本替换,它不关联任何类型2.生效......