python的opencv操作记录11——阈值分割
文章目录
- 传统图像处理分割
- 阈值分割
- 一个应用场景
- opencv库中的阈值分割
- 固定阈值
- THRESH_OTSU 大津法阈值
- 自适应阈值
传统图像处理分割
现在提到图像分割,很多人会直接想到当前火爆的深度学习的各种分割网络,比如实例分割,语义分割等。其实在传统的图像处理领域,也有一些分割算法,这些算法在通用的分割上来说没有深度网络的普适性好,但是在某些特殊场景是一个更轻量级的解决方案。也是图像处理学习过程中的毕竟之路。
阈值分割
阈值分割是一个基本的图像处理算法,思路很简单:
将图像中每个像素的像素值和阈值进行比较,高于阈值的是一类,低于阈值的是一类。
这样的算法一般有两种应用场景:
- 提取前景或者背景
- 二值化处理
一个应用场景
我在实际工作中,碰到了一个实际场景,我觉得就是可以用这个阈值分割来解决的,而不需要使用比较重的深度网络来解决。
问题是要定位一个试管中试剂的位置信息,设备中拍摄的图像如下图所示:
从图中可以分析,这条分界线实际上是很容易判断出来的,而且前景和背景的像素值差距非常大,所以我当时考虑的就是直接用阈值分割来实现。
opencv库中的阈值分割
在opencv库中,用于阈值分割的函数是:cv2.threshold.
该函数的接受4个参数:
- src, 图像数据,为单通道图像。
- thresh,阈值。
- maxval,最大像素值
- type,阈值分割方法。
最后的这个参数,是因为阈值分割有很多中方法,在opencv的官网上描述的非常清楚:
实际上就是根据像素值与阈值的关系,来获取最终目标图像的像素值规则。这里就不一个一个说了。我提一下我自己用到的几个方法,以及在这个试管工作中的效果。
另外,我还用到一些其他的方法,把试管的感兴趣区域确定和提取出来了,这里就说了,和这一篇文章的关系不大。
固定阈值
上面提到了,因为分界线非常明显,所以我想着直接尝试出一个固定的阈值来做分割,看能不能达到自己想要的效果。
代码如下:
if __name__ == '__main__':img = cv2.imread("images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 如果大于阈值,赋值为255,小于阈值,赋值为0ret, binary = cv2.threshold(grey, 60, 255, cv2.THRESH_BINARY)cv2.imshow("result", binary)cv2.waitKey()cv2.destroyAllWindows()
效果不太理想,最上面的这个界限不是很清楚(虽然通过拟合可以基本确定),而且中间的一些杂志部分去除的不是很好(后续需要用到,所以在这一步想一次搞定)。
所以再试试其他的方法看看。
尝试了TRUNC和TOZERO的方式,如下图:
我理解实际上就是把目标图像的前景和背景的像素值拉的不是很大而已,对我想要的效果帮助不大。
而且我通过修改阈值,把60这个值改大改小效果仍然不佳,就只能谋求其他方法了。
THRESH_OTSU 大津法阈值
这个分割方法和上述的分割方法不一样,上述的分割方法的阈值是固定的,而这个方法的阈值时需要通过一些计算才能得到的,这种计算方式就是大津法。
大津法的原理和思路如下(单通道):
- 大津法的思路就是要找到一个阈值,根据这个阈值划分成两类(A, B)之后,这A, B两类像素值的方差最大。那么问题就变成两个:
- 如何计算A,B两类像素的方差。
- 使用最快速的方法找到让方差最大的那个阈值。
- 一张M * N大小的图像,假设阈值为k。
- 那么大于k的像素点(如果是BINARY的方法则表示前景,否则就是反过来,下同)的个数N0N_0N0,小于k的像素点的个数为N0N_0N0。那么前景分类的像素点在整张图像中的占比就为ω0=N0M∗N\omega_0=\frac{N_0}{M * N}ω0=M∗NN0,背景的就是ω1=N1M∗N\omega_1=\frac{N_1}{M * N}ω1=M∗NN1.
- 大于k的像素点的平均灰度值可计为u0u_0u0,小于的平均灰度值可计为u1u_1u1
- 整张图像的平均灰度为uuu
- 那么现在可以回答上面的第一个问题,两类像素的方差定位为
g=ω0(u0−u)2+ω1(u1−u)2g = \omega_0(u_0-u)^2 + \omega_1(u_1-u)^2g=ω0(u0−u)2+ω1(u1−u)2 - 大津法就是要找到这个最大的g值。那么第二个问题来了,怎么去算这个g值。最简单的办法就是遍历,让k从0到255,依次计算这个g值,哪个最大,阈值就取那个k。opencv是不是这么实现的不知道,有兴趣的可以去翻翻源码。
通过大津法计算得到阈值之后,还要确定是使用哪种分类方法,所以代码可以写成:
if __name__ == '__main__':img = cv2.imread("images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 先使用大津法计算阈值,然后再分类# 如果大于阈值,赋值为255,小于阈值,赋值为0ret, binary = cv2.threshold(grey, 60, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)cv2.imshow("result", binary)cv2.waitKey()cv2.destroyAllWindows()
图是下图:
我感觉上面的那条分界线更加分明和分布平均一点。
自适应阈值
上面的几种方法里的思路里基本上都是一个阈值在应用与整个图像的分割,不管是自己手动设的,还是通过某种方法计算出来的。但是一旦确定后,这个阈值就会应用到整张图像中去。
在opencv中还提供了一种阈值分割方法,这个阈值在整张图像的分割操作中是变化的,是 根据该像素周边的邻居像素(neighborhood pix)值来确定该像素的比较阈值,然后再根据之前的阈值比较逻辑来确定是前景类还是后台类。
opencv中的这个函数是adaptiveThreshold,这个函数有下面几个参数:
- src,源图像,为灰度图。
- maxValue, 最大值
- adaptiveMethod,根据邻居像素如何计算这个阈值,也就是说确定这个邻域像素的计算方法。
- ADAPTIVE_THRESH_MEAN_C,邻域的像素计算平均值作为阈值(减去一个偏移量)
- ADAPTIVE_THRESH_GAUSSIAN_C,邻域的像素通过一个高斯核作为掩码来计算权重值作为阈值(减去一个偏移量)。根据不同的blockSize,opencv会调用getGaussianKernel这个来获取这个高斯核,有兴趣可以具体了解下高斯核的生成原理和逻辑。
- thresholdType,确定阈值之后的分类方式,就支持两种:THRESH_BINARY(大于阈值取255,小于取0),THRESH_BINARY_INV(大于阈值取0,小于取255)
- blockSize, 这个邻域的边长,一般是3,5,7.和图像中的卷积核类似。
- C,上面计算阈值过程中提到的偏移量。
我在我的工程里试了一下:
if __name__ == '__main__':img = cv2.imread("/Users/zoulei/files/personal/blog/images/tubeImg.jpeg")grey = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 如果大于阈值,赋值为255,小于阈值,赋值为0# ret, binary = cv2.threshold(grey, 60, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)# 自适应阈值分割binary = cv2.adaptiveThreshold(grey, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 15, 2)cv2.imshow("result", binary)cv2.waitKey()cv2.destroyAllWindows()
效果如下:
试过蛮多的blockSize,基本上都是这个效果。和我想要的效果完全不符合,所以这个方法对我来说没什么用。
这个方法应该是用于做对比度较大的图像杂质分割会比较有用,我这个工程里暂时没有用到,有兴趣的朋友可以去试一下。
当然,最后我自己的解决方案是选择用OTSU大津法的阈值分割方法,再加上对分界线的一些拟合方法和一些逻辑判断来解决我自己的问题。
相关文章:
python的opencv操作记录11——阈值分割
文章目录传统图像处理分割阈值分割一个应用场景opencv库中的阈值分割固定阈值THRESH_OTSU 大津法阈值自适应阈值传统图像处理分割 现在提到图像分割,很多人会直接想到当前火爆的深度学习的各种分割网络,比如实例分割,语义分割等。其实在传统…...
Python-项目实战--飞机大战-英雄登场(7)
目标设计英雄和子弹类使用pygame.key.get_pressed()移动英雄发射子弹1.设计英雄和子弹类1.1英雄需求游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像素英雄每隔0.5秒发射一次子弹,每次连发三枚子弹英雄默认不会移动,需…...
寒假安全作业nginx-host绕过实例复现
1.测试环境搭建 LNMP架构的话,肯定就是linux、nginx、mysql、php四大组件。在后面的复现中我们还会用到https的一部分知识,故这里的nginx就需要使用虚拟主机并且配置https证书,且具有php解析功能。 1.1 基础nginx配置 #1.创建web目录 mkdir …...
RocketMQ-消息消费模式 顺序消费
RocketMQ-消息消费模式 顺序消费RocketMQ-消息消费模式集群模式集群模式的演示(本身就默认)Rocketmq存储队列广播模式顺序消费如何改实现顺序消费RocketMQ-消息消费模式 集群模式 在消费模式为集群的情况下,如果机器是集群的,消息只会给集群中的其中一台机器消费到 集群模…...
一、Java并发编程之线程、synchronized
黑马课程 文章目录1. Java线程1.1 创建和运行线程方法一:Thread方法二:Runnable(推荐)lambda精简Thread和runnable原理方法三:FutureTask配合Thread1.2 查看进程和线程的方法1.3 线程运行原理栈与栈帧线程上下文切换1.…...
12.hadoop系列之MapReduce分区实践
本文我们学习MapReduce默认分区以及自定义分区实践 当我们要求将统计结果按照条件输出到不同文件(分区),比如按照统计结果将手机归属地不同省份输出到不同文件中(分区) 1.默认Partitioner分区 public class HashPartitioner<K, V> extends Partitioner<…...
有了独自开,一个人就是一个团队
文章目录 简单介绍优点 优秀案例平台福利总结 简单介绍 独自开是一个基于商品与服务交易全流程的PaaS开发平台。对于开发者,独自开可以协助开发者一个人独自开发一套系统。 优点 独自开有独创的分层标准化平台架构,可以满足系统的任何个性化需求。 …...
web期末复习 2023.02.11
文章目录Web 的概念Web 组成用户通过浏览器请求资源的过程:HTML 超文本标记语言CSS插入样式表的方法有三种:对象,类,实例一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:JavaScript 用法什么是 Java Server Pages?JSP 注释JSP 的 J…...
第44章 用户密码实体及其约束规则的定义实现
1 说明: 由当前程序需要兼容实现多种用户密码的加密操作,所以必须把“CustomerPassword”定义为实体类,该类用于用于把加密方式、密钥及其加密后的密码持久化到“CustomerPassword”表中,以便用为用户登录操作提供验证支撑。 如果…...
聊聊并发与锁
持续坚持原创输出,点击蓝字关注我吧1.并发与并行并发可以充分地利用 CPU 资源,一般都会使用多线程实现。多线程的作用是提高任务的平均执行速度,但是会导致程序可理解性变差,编程难度加大。关于对并发与并行的概念,大家…...
开源项目 —— 原生JS实现斗地主游戏 ——代码极少、功能都有、直接粘贴即用
目录 效果如下 目录结构 GameEntity.js GrawGame.js konva.min.js PlayGame.js veriable.js index.html 结语: 前期回顾 卡通形象人物2 写代码-睡觉 丝滑如德芙_0.活在风浪里的博客-CSDN博客本文实现了包含形象的卡通小人吃、睡、电脑工作的网页动画https://…...
Linux第四讲
目录 四、shell脚本 4.1 shell和shell脚本 4.2 脚本语言分类 4.2.1 编译型语言 4.2.2 解释型语言 4.2.3 脚本语言 4.3 shell常见种类 4.3.1 shell分类介绍 4.3.2 查看bash版本 4.3.3 sh和bash的关系 4.4 脚本书写规范 4.4.1 选择解释器 4.4.2 开发规范 4.5 shell…...
Redis 持久化
持久化是指数据写到物理硬盘里,即便程序崩溃、或者电脑重启,依然能够恢复。Redis提供了两种持久化机制:RDB和AOF。 RDB(Redis Database): RDB文件相当于内存快照,保存了某个时间点数据库信息。使用RDB文件恢复很简单,将…...
Python语言零基础入门教程(十三)
Python 字典(Dictionary) 字典是另一种可变容器模型,且可存储任意类型对象。 字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中 ,格式如下所示: d {key1 : value1, key2 : …...
江苏五年制专转本应该复习几轮?
五年制专转本应该复习几轮? 据调查统计:2022年专转本17%的考生复习三轮及以上,23%的考生复习了两轮。这两类的考生录取率高至85%。可见复习轮数多,专转本上岸的概率也大。综合多方因素,建议同学们专转本复习四轮&#…...
微信小程序的优化方案之主包与分包的研究
什么是分包? 某些情况下,开发者需要将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。 在构建小程序分包项目时,构建会输出一个或多个分包。每个使用分包小程序必定含有一个主包。所谓的…...
从手工测试转型web自动化测试继而转型成专门做自动化测试的学习路线。
在开始之前先自学两个工具 商业web自动化测试工具请自学QTP;QTP的学习可以跳过,我是跳过了的。 开源web自动化测试工具请自学Selenium;我当年是先学watir(耗时1周),再学selenium(也耗时1周&…...
【计组笔记03】计算机组成原理之系统五大部件介绍、主存模型和CPU结构介绍
这篇文章,主要介绍计算机组成原理之系统五大部件、主存模型和CPU结构。 目录 一、计算机五大部件 1.1、体系结构 (1)冯诺依曼体系结构...
微信小程序解析用户加密数据
微信公众号 IT果果日记前言在上一篇文章“微信小程序如何获取用户信息”中我们完成了用户明文数据的校验工作,本文将学习解密用户的非明文用户信息,也就是获取用户的openId和unionId。解密调用wx.getUserProfile后将返回encryptedData和iv两个数据。encr…...
毕业四年换了3份软件测试工作,我为何仍焦虑?
今天一看日历:2023.2.11 ,才突然意识到自己毕业已经四年了。四年时间里一直在测试行业摸爬滚打,现在是时候记录一下了。 下面我来分享下我这4年软件测试经验及成长历程,或许能帮助你解决很多工作中的迷惑。 01、我是如何开始做…...
嵌入式C基础知识(7)
是否可以传递任何参数并从 ISR 返回值不可以。不能传递任何参数并从 ISR 返回值。 ISR 不返回任何内容,并且不允许传递任何参数。 当硬件或软件事件发生时调用 ISR,而代码不会调用它。 这就是为什么不向 ISR 传递参数的原因。 由于代码不调用 ISR&#x…...
大数据系列之:安装pulsar详细步骤
大数据系列之:安装pulsar详细步骤一、Pulsar版本和jdk对应关系二、安装JDK三、设置和激活jdk环境变量四、下载和解压Pulsar五、查看Pulsar目录六、启动Pulsar standalone cluster七、创建Kafka Topic八、往Topic写入数据九、消费pulsar的Topic一、Pulsar版本和jdk对…...
色彩-基础理论
颜色三大指标 色相 色相是颜色的一个属性,只有黑白灰没有色相这个属性(那银灰色是什么?) 颜色的相貌,指的也是给颜色一个名字 例如:暗红、酒红、土黄、墨绿 饱和度 颜色的鲜艳程度 纯度 饱和度主要取决于含色成分和消色成分&a…...
1629_MIT_6.828_xv6_chapter1操作系统的组织
全部学习汇总:GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 这一次整理一下操作系统组织相关的知识,主要还是xv6教学操作系统相关的知识。当然,很多知识在这类技术领域是通用的。 1. 操作系统的主要功能…...
基于Golang哈希算法监控配置文件变化
SHA(secure hashing algorithm)表示安全哈希算法.SHA是MD5的修正版本,用于数据摘要和认证。哈希和加密类似,唯一区别是哈希是单项的,即哈希后的数据无法解密。SHA有不同的算法,主要包括SHA-1, SHA-2, SHA-256, SHA-512, SHA-224, …...
关于一笔画问题的一些思考(欧拉路Fleury算法、逐步插入回路法、以及另一种可能的解法)
前言这是一个经典的图论问题了最近复习离散的时候又恰好看到了,发现自己以前的解法似乎有点bug然后开始出反例卡自己,结果发现卡不掉?然后再好好想了想,发现这个看起来有问题的做法可能确实没问题。注意:欧拉路、欧拉回…...
vlookup怎么用详细步骤,看这一篇就够了
1、vlookup函数:使用方法 以下便是vlookup函数,功能、语法和参数用法: excel函数vlookup 2、vlookup函数:查询参数 首先,选中F2单元格,然后在编辑栏输入函数公式:VLOOKUP(E2,B&…...
雅思经验(9)之小作文常用词汇总结
写作:关于趋势的上升和下降在小作文中,真的是非常常见的,所以还是要积累一下。下面给出了很多词,但是在雅思写作中并不是词越丰富,分数就越高的。雅思写作强调的是准确性:在合适的地方用合适的词和句法。不…...
【Python语言基础】——Python NumPy 数组创建
Python语言基础——Python NumPy 数组创建 文章目录 Python语言基础——Python NumPy 数组创建一、Python NumPy 数组创建一、Python NumPy 数组创建 创建 NumPy ndarray 对象 NumPy 用于处理数组。 NumPy 中的数组对象称为 ndarray。 我们可以使用 array() 函数创建一个 NumP…...
【大数据】Hadoop-Kms 安装及相关详细配置,看完你就会了
简介 Hadoop KMS是基于Hadoop的KeyProvider API的加密密钥管理服务器,它提供了使用REST API通过HTTP进行通信的客户端和服务器组件。 客户端是一个KeyProvider实现,使用KMS HTTP REST API与KMS交互。 KMS及其客户端具有内置的安全性,它们支…...
为什么不做网站做公众号/鄂州seo
错误放在最开始: //原来头文件是这么写的: public:inline bool operator(Snapshot const&); //后来的cpp文件是这么写的: inline bool Snapshot::operator(Snapshot const&snap) { 然后报错是这样的: undefined refe…...
wordpress微信博客模板下载/国际新闻今天
1.编写HelloJNI.java文件(包名为JNI)package JNI;public class HelloJNI{static{System.load("/root/lib/goodluck.so"); //使用绝对路径加载名称为goodluck.so的库文件// System.loadLibrary("goodluck"); //使用默认路径加载}public native static…...
公司网站建设模板/百度搜索如何去广告
http://edu.163.com/10/1213/16/6NQ0FMHK00293KTO_3.html 三、经济学 经济学完全有资格排在第三位。学习经济学的人,不会搞经济!我这里说的“搞经济”,涵义是很狭义的,就是不会挣钱,更不会赚钱。我本人就是学经济的&am…...
济宁网站建设公司/希爱力双效片副作用
Qt是一个跨平台C图形用户界面应用程序开发框架,使用它不仅可以方便地开发GUI程序,也可以开发非GUI程序,可以一次编写,处处编译。今天遇到的问题比较怪异,我开发的是一个桌面版订单管理系统,整体架构就是一个…...
自己做网站 赚钱/网站站外优化推广方式
感谢原作者雪兰,http://yupeizhi.blog.51cto.com/3157367/1413886DHCP配置的过程:1、DHCP客户端以广播的方式向网络中的DHCP服务器发送出DHCP Discover数据包;2、DHCP服务器在收到DHCP Discover数据包后,回应一个DHCP Offer数据包…...
快速提高网站排名/广州网站排名优化公司
一 重试框架之Spring-Retry Spring Retry 为 Spring 应用程序提供了声明性重试支持。 它用于Spring批处理、Spring集成、Apache Hadoop(等等)。它主要是针对可能抛出异常的一些调用操作,进行有策略的重试 1. Spring-Retry的普通使用方式 准备工作 我们只需要加上依赖: <d…...