matlab二值化图像_小白啃骨头之图像识别

news/2024/9/12 17:03:35

829bdd9c7c0019be7c3950ebc2f16d8a.png

小白啃骨头系列是通过案例的分享,描述7是怎么入门某类技术的。下面就请进入正题吧~

相信大家对于有一些名词耳熟能详,可以谈天说地,但是真正想要用起来,却觉得门槛太高,望而却步。如今AI大火,凡是沾点边就感觉高级炸了。什么图像识别,语音识别,自动驾驶等等,今天7,就不怕死的去尝试了这么难啃的骨头,究竟结论怎样呢?我们先看样本骨头。

本次案例的目的是用python3的OpenCV库实现答题卡识别,这里可能要补充一点知识,毕竟对于真小白来说,我们需要名词解释环节。

OpenCV:分为OPEN + CV, open好理解open source即开源,CV指的是计算机视觉(computer version)。OpenCV最早由英特尔公司于1999年启动,后来以BSD许可证授权发行,可以在商业和研究领域中免费使用。简而言之,你做图像识别,或者计算机视觉或者模式识别,那很有可能和它打交道了。OpenCV最早支持C语言,因为就是C写的,而先前很火的OpenCV的例子是用MATLAB开发的,如今Java,Python等都有相关的库可以使用了。

关于各个平台python和OpenCV怎么安装,大家自行Google解决啦。

附上本地示例的原图:

8c1aa21844e0377c7b7b59ab77c8287b.png

解决一个问题,第一步是要有思路。但我相信很多新手对于要识别图像,识别答题卡是没有思路的,没错,要是你有思路那就不是小白了。7对于这艰难的第一步那就是去找文档和开源项目看,总结他们的相同点,整理核心算法思路,梳理整个识别的步骤。然后在debug自己的代码,一边被虐一边进步。

思路有了,下面就要开始敲一敲了。7会给出每一步对应的代码片段帮助大家理解过程。

  • 进行图像灰度,使图像黑白(二值化)

为什么要进行二值化,我认为有两点,一是硬性要求,很多算法要求输入是一个二值化后的图像,俗称黑白图像;二是为了更好地区分主题和背景。比如你需要识别pdf里的文字,如果用彩色图像,那你就要先区分颜色,在处理文字,而实际上对于整个识别目的来说,只需要识别字,并不在意字本身什么颜色,也就是忽略颜色对识别的干扰。那为什么二值化之前要灰度,灰度图像像素介于0-255之间,在二值化的时候我们只需要设定某一个值,高于这个值就是黑,低于这个值则是白。这整个过程过程分为两小步:

  1. 对原图像进行灰度,然后应用高斯模糊使图像模糊一点,去除随机点

通俗的来说就是去噪,为了去除噪点对图像的影响,也就是平时大家P照片时美颜。

# 灰度gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)# 高斯模糊,3 * 3的核,此处核越大就越模糊,即美颜效果越好。blur = cv.GaussianBlur(gray, (3, 3), 0)

      2. 使用自适应阈值设置每个像素为黑色或白色

这一步就是图像二值化,把像素分为0和255两个度,非黑即白。

# 图像二值化binary = cv.adaptiveThreshold(gray, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY_INV, 5, 4)
  • 使用霍夫变换找到图中的直线, 找到直线的交点,形成四边形

对于答题卡来说,因为每个答题卡设计会影响我们的算法,这一步是核心算法,需要定位答题卡的答题范围。在7的示例中,我们采用的答题卡有一个很重要的特点,那就是答题卡区域整个答题卡最大的区域,也就是说,我们通过找出答题卡中的轮廓,找到最大的就是答题的区域了。

# 找到二值化图像所有的轮廓conts = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)[0]# 对轮廓进行反向排序,第一个就是最大的轮廓即示例中答题区域conts = sorted(conts, key=cv.contourArea, reverse=True)
  • 找到四边形轮廓,并对四边形应用透视变换

为什么要进行透视变换?这里的透视变换是四点透视,透视变化是一种投影。大家可以思考一个例子,如果我们因为角度问题是不是在扫描矩形图片的时候并不是一个矩形,可能是个梯形,这与实际不符,算法需要规避这种角度问题,所以有了变化操作,而四点透视就是为了把一个梯形拉成一个矩形(可能比较抽象,如果不能理解,大家可以尝试用手机从非物体正上方的位置拍一张照感受下)

# 多边形拟合,我们找到的轮廓都是有像素点构成的,计算机只能处理像素,# 在计算机眼里并没有直线曲线之分。peri = 0.01 * cv.arcLength(cont, True)approx = cv.approxPolyDP(cont, peri, True# 判断是否为四边形if len(approx) == 4:    # 四点透视变换    ox = four_point_transform(image, approx.reshape(4, -1))
  • 使用霍夫变换找到图中的答案轮廓

有了轮廓的概念,其实答案框也是一个一个的轮廓,通过答案框长宽比例来过滤掉非答题框的轮廓。

for c in cnts:  # 对每一个轮廓进行长宽比过滤,找到所有答案框的位置  x, y, w, h = cv.boundingRect(c)  ar = w / float(h)  if 80 >= w >= 46 and h >= 30 and 1.2 <= ar <= 1.9:      cv.rectangle(question, (x, y), (x + w, y + h), (0, 0, 255), 2)      question_choices.append(c)
  • 区分答题框是否填充

这里我们采用在答题框轮廓中像素点进行反向排序,像素最多的即为填涂的选项(这里只适用于单选题)

for (i, q) in enumerate(np.arange(0, len(question_choices), 12)):    if i <= 10:         line_cnts = question_choices[q:q + 12]        line_cnts = contours.sort_contours(line_cnts, method="left-to-right")[0]        # 取出i行,第k题        for (k, m) in enumerate(np.arange(0, len(line_cnts), 4)):            ticket_num = i + k * 17 + 1            bubble_rows = []            m_cnts = line_cnts[m:m + 4]            # print("{}: {}".format(i, len(m_cnts)))            # 取出k题 j选项            for j, c in enumerate(m_cnts):                mask = np.zeros(tx.shape, dtype=tx.dtype)                cv.drawContours(mask, [c], -1, 255, -1)                mask = cv.bitwise_and(binary, binary, mask=mask)                total = cv.countNonZero(mask)                bubble_rows.append((total, j))            bubble_rows = sorted(bubble_rows, key=lambda x: x[0], reverse=True)            choice_num = bubble_rows[0][1]            student_answer.append((ticket_num, answer_format.get(choice_num)))

上面的算法写的比较初学者,大神们看看就行了f38a86e643689b4df1d7a5951e47342a.png

  • 最后我们打印出题号和答案

    # 比较简单就不赘述了    for item in student_answer:        print("题号: {} 答案:{}".format(item[0], item[1]))    return {"答题卡答案": [{'题号': x[0], '答案': x[1]} for x in student_answer]}

以上就是小白啃骨头的过程,完整代码会重新整理后放到GitHub上。由于本文涉及的内容比较专业,如果有说错的还请各路大神不吝赐教,早日指正!

推荐阅读

(点击标题可跳转阅读)

最详细、最完整的相机标定讲解

深度学习+机器视觉=下一代检测

视觉检测系统最经典的结构你了解吗?

机器视觉技术的十大应用领域

工业相机和普通相机究竟有什么不同?

基于机器视觉和深度学习的智能缺陷检测

波士顿等移动机器人的视觉算法解析

2020年37个人工智能技术发展趋势

机器视觉的光源选型及打光方案分析

光学三维测量技术及应用

国内80%搞机器视觉的工程师,走的路子是错的!

视觉+机器人,如何实现连接器的自动装配?

机器视觉技术发展的五大趋势

搞懂机器视觉基本内容,这份PPT就够了

机器视觉:PC式视觉系统与嵌入式视觉系统区别  

基于HALCON的机器视觉开发,C++或C#如何选择? 

3D视觉技术在机器人抓取作业中的应用实例

基于机器视觉的粗糙度检测方案

机器视觉常用图像软件对比及分析

工业相机编程流程及SDK接口使用汇总

c21faee98d8b150b09ac60c3d2a1abd4.gif End c21faee98d8b150b09ac60c3d2a1abd4.gif

声明:部分内容来源于网络,仅供读者学习、交流之目的。文章版权归原作者所有。如有不妥,请联系删除。

7cacf0ac788f06fde3e6efc48226752c.png


http://lihuaxi.xjx100.cn/news/275834.html

相关文章

拿来就能用!如何用 AI 算法提高安全运维效率?

作者 | 黄龙责编 | 伍杏玲来源 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 在整个安全工作中&#xff0c;安全运维是不可或缺的一环&#xff0c;其目的是保证各项安全工作持续有效地运作。除了对外的沟通和业务对接相关工作&#xff0c;大部分安全运维的日常工作相…

流水账(4)---礼拜二---“抗议,我不是电工!”

礼拜二&#xff0c;今天。 6点半起床&#xff0c;9点钟到东郊。 上午帮东郊重装一台电脑。郁闷&#xff0c;我在那边一直就被当作修电脑的工人用了。还想起一个很有意思的误会。 一次&#xff0c;我和老师说&#xff0c;你知道罢&#xff0c;东郊还有一个fudan的法硕在那…

ipad无法与itunes同步,提示因为这台电脑不再被授权使用在此ipad上购买的项目解决方案...

1、iOS设备用数据线连接到电脑&#xff1b;2、打开电脑上的iTunes 11&#xff0c;按CtrlB键调出菜单栏&#xff0c;按CtrlS键调出边栏&#xff1b;在边栏的 设备 下面看到你的iOS设备&#xff1b;3、点击菜单栏中的商店&#xff0c;点击 对这台电脑授权&#xff0c;输入你的App…

GitHub 中文文档正式发布

点击上方“方志朋”&#xff0c;选择“设为星标”回复”666“获取新整理的面试资料中国作为全球最大的人口大国&#xff0c;所属开发者在 GitHub 上的占比自然也少不了。近几年&#xff0c;随着 GitHub 在国内的不断推广普及&#xff0c;不少开发者都开始纷纷采用 GitHub 来作为…

基于 CNN 特征区域进行目标检测

点击上方“小白学视觉”&#xff0c;选择加"星标"或“置顶”重磅干货&#xff0c;第一时间送达目标检测是目前计算机视觉领域最热门的技术之一&#xff0c;该领域的研究一直在以非常快的速度进行。但究竟什么是物体检测&#xff1f;对象检测处理通过给定输入&#xf…

android中textcolor属性,android – EditText和TextView textColorPrimary不遵循API lt;21的主题颜色...

在设计工具栏视图以使其适用于API 21及以下版本时存在一些问题,但我认为我有这个styles.xmlcolor/colorPrimarycolor/colorPrimaryDarkcolor/colorPrimarycolor/whitecolor/grey这在我的screen1.xml工具栏中xmlns:android"http://schemas.android.com/apk/res/android&quo…

Hive的“rowid”

玩过Oracle的同学一定知道rowidobjectidfile#block#row#这个概念,其实在Hive里也有“Rowid”. Hive里有虚拟列的概念&#xff0c;类似于Oracle里的伪列&#xff0c;其中三个虚拟列是&#xff1a;INPUT__FILE__NAME&#xff0c;BLOCK__OFFSET__INSIDE__FILE&#xff0c;ROW__OFF…

欧拉、欧几里得、笛卡尔都没能解决的数学问题,他探索了新的方案

萧箫 发自 凹非寺量子位 报道 | 公众号 QbitAI欧拉、欧几里得、笛卡尔、尼科马修斯都没能解决的千年数学问题&#xff0c;还有破解的可能吗&#xff1f;还真有可能。最近&#xff0c;一位名为佩斯尼尔森 &#xff08;Pace Nielsen&#xff09;的数学家开辟了一种新方法&#xf…