【OpenCV实现图像阈值处理】

文章目录

    • 概要
    • 简单阈值调整
    • 自适应阈值调整
    • 大津(Otsu's)阈值法
    • Otsu's 二值化是如何工作的

概要

OpenCV库中的图像处理技术,主要分为几何变换、图像阈值调整和平滑处理三个部分。

在几何变换方面,OpenCV提供了cv.warpAffine和cv.warpPerspective函数,用于实现仿射变换和透视变换。这些技术包括缩放、平移、旋转等,通过变换矩阵的运用,可以实现图像的各种变换操作。

图像阈值调整是将图像的像素值按照一定规则进行二值化处理,OpenCV提供了cv.threshold函数,支持多种阈值处理类型,如二值化、反二值化、截断、阈值以下置零等。还有自适应阈值调整,它可以根据图像的局部特性动态调整阈值,适用于光照不均匀的情况。

另外,介绍了大津(Otsu’s)阈值法,该方法是一种自动确定全局阈值的技术。通过计算图像的直方图,找到最佳阈值,实现图像的二值化处理。

简单阈值调整

简单的阈值调整,自适应阈值和大津阈值法。
函数 cv.threshold 和 cv.adaptiveThreshold

在图像处理中,阈值调整是一种基本技术。其核心思想是对图像的每个像素应用相同的阈值规则,如果像素值低于阈值,就将其设置为0,反之则设置为最大值。OpenCV提供了用于阈值调整的函数cv.threshold。该函数的第一个参数是源图像,必须是灰度图像;第二个参数是阈值,用于区分像素值;第三个参数是最大值,当像素值超过阈值时,会被设置为这个值。OpenCV还提供了不同的阈值调整类型,通过第四个参数来选择。常用的阈值调整类型包括:

cv.THRESH_BINARY:超过阈值的像素值设为最大值,其他设为0。
cv.THRESH_BINARY_INV:超过阈值的像素值设为0,其他设为最大值。
cv.THRESH_TRUNC:超过阈值的像素值设为阈值,其他像素值不变。
cv.THRESH_TOZERO:超过阈值的像素值不变,其他设为0。
cv.THRESH_TOZERO_INV:超过阈值的像素值设为0,其他不变。

这些类型的具体应用可以根据需求选择。cv.threshold函数返回两个输出:第一个是使用的阈值,第二个是阈值化后的图像。选择合适的阈值调整类型和阈值参数可以有效地处理图像,提取出感兴趣的信息。详细了解每种类型的使用场景,可以参考OpenCV的相关文档以获取更多信息。

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt# 读取灰度图像
img = cv.imread('img.png', 0)# 使用cv.threshold进行阈值调整,得到不同类型的阈值化图像
ret, thresh1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
ret, thresh2 = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
ret, thresh3 = cv.threshold(img, 127, 255, cv.THRESH_TRUNC)
ret, thresh4 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO)
ret, thresh5 = cv.threshold(img, 127, 255, cv.THRESH_TOZERO_INV)# 设置图像标题
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']# 将图像和标题放入列表中
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]# 使用for循环显示图像和标题
for i in range(6):plt.subplot(2, 3, i + 1)  # 2行3列的子图中的第i+1个plt.imshow(images[i], 'gray', vmin=0, vmax=255)  # 显示灰度图像,灰度范围0-255plt.title(titles[i])  # 设置子图标题plt.xticks([]), plt.yticks([])  # 隐藏坐标轴# 显示图像
plt.show()

我们使用 plt.subplot() 函数来排列图像。
这段代码输出这个结果。
在这里插入图片描述

自适应阈值调整

在图像处理中,使用全局阈值可能不适用于所有情况。例如,当图像在不同区域具有不同的光照条件时,使用固定阈值可能导致不准确的结果。为了解决这个问题,我们可以采用自适应阈值调整的方法。这种方法根据像素周围的小区域确定每个像素的阈值,因此,同一张图像的不同区域可以获得不同的阈值,从而更好地适应图像中的光照变化。

在OpenCV中,cv.adaptiveThreshold函数用于实现自适应阈值调整。该函数接受三个主要参数:

adaptiveMethod: 它决定了阈值如何被计算。cv.ADAPTIVE_THRESH_MEAN_C:阈值是邻域像素的平均值减去常数C。cv.ADAPTIVE_THRESH_GAUSSIAN_C:阈值是邻域像素的高斯加权平均值减去常数C。blockSize: 它指定了邻域的大小。该值定义了算法在图像中寻找阈值时所考虑的像素邻域范围。C: 它是一个常数,用于从计算得到的阈值中减去,可以调整阈值的灵敏度。

通过调整这些参数,我们可以更精确地适应不同区域的光照变化,从而得到更准确的图像处理结果。


import cv2 as cv
import numpy as np
from matplotlib import pyplot as pltimg = cv.imread('img.png', 0)
img = cv.medianBlur(img, 5)ret, th1 = cv.threshold(img, 127, 255, cv.THRESH_BINARY)
th2 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_MEAN_C, \cv.THRESH_BINARY, 11, 2)
th3 = cv.adaptiveThreshold(img, 255, cv.ADAPTIVE_THRESH_GAUSSIAN_C, \cv.THRESH_BINARY, 11, 2)titles = ['Original Image', 'Global Thresholding (v = 127)','Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']images = [img, th1, th2, th3]for i in range(4):plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')plt.title(titles[i])plt.xticks([]),plt.yticks([])plt.show()

在这里插入图片描述

大津(Otsu’s)阈值法

在全局阈值调整中,我们必须手动选择一个适当的阈值来将图像分为目标和背景。然而,在某些情况下,我们无法确定最佳的阈值,尤其是当图像具有复杂的光照变化或噪声时。在这种情况下,使用大津(Otsu)阈值法是一个更好的选择。

大津阈值法适用于具有双峰直方图(即具有两个明显峰值)的图像。在这种情况下,图像的直方图将具有两个主要的峰值,分别代表目标和背景像素的灰度级别。大津方法的目标是找到一个最佳的阈值,将这两个峰值之间的灰度级别作为分割点。

在OpenCV中,我们使用cv.threshold()函数,并将cv.THRESH_OTSU作为阈值类型的额外参数传递。大津算法会自动确定最佳阈值,并将其作为函数的返回值。这样,我们就不需要手动选择阈值,而是依赖算法找到最适合的分割点,使图像的分割更准确。


import cv2 as cvimport numpy as npfrom matplotlib import pyplot as pltimg = cv.imread('img.png',0)# 全局阈值ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)# Otsu'sret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# 高斯后Otsu'sblur = cv.GaussianBlur(img,(5,5),0)ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)# 展示所有图片images = [img, 0, th1,img, 0, th2,blur, 0, th3]titles = ['Original Noisy Image','Histogram','Global Thresholding(v=127)','Original Noisy Image','Histogram',"Otsu's Thresholding",'Gaussian filtered Image','Histogram',"Otsu's Thresholding"]for i in range(3):plt.subplot(3,3,i*3+1),plt.imshow(images[i*3],'gray')plt.title(titles[i*3]), plt.xticks([]), plt.yticks([])plt.subplot(3,3,i*3+2),plt.hist(images[i*3].ravel(),256)plt.title(titles[i*3+1]), plt.xticks([]), plt.yticks([])plt.subplot(3,3,i*3+3),plt.imshow(images[i*3+2],'gray')plt.title(titles[i*3+2]), plt.xticks([]), plt.yticks([])plt.show()

在这里插入图片描述

Otsu’s 二值化是如何工作的

Otsu’s二值化算法是一种自动确定图像阈值的方法。该算法的目标是找到一个阈值 tt,使得将图像的灰度级别分为两个类别(背景和前景),并且这两个类别的内部方差最小。

在具体实现中,我们首先计算图像的直方图,该直方图显示了不同灰度级别的像素数量。接着,算法尝试在直方图中找到两个主要的峰值,这两个峰值分别代表了背景和前景像素的灰度级别。然后,Otsu’s算法尝试选择一个阈值 tt,将这两个峰值之间的灰度级别作为分割点。

为了选择最佳的阈值 tt,算法将尝试所有可能的阈值,并计算对应的两个类别的内部方差。内部方差越小,说明两个类别之间的差异越小,图像分割得越好。最终,选择使内部方差最小的阈值 tt 作为最佳阈值,将图像二值化。
在这里插入图片描述

这种方法的核心思想是通过寻找使得两个类别差异最小的阈值,实现图像的自动分割。对于了解过线性规划或神经网络的人来说,这个思想可能更容易理解。

import cv2 as cv
import numpy as np
img = cv.imread('img.png',0)
blur = cv.GaussianBlur(img,(5,5),0)# 求归一化直方图及其累积分布函数hist = cv.calcHist([blur],[0],None,[256],[0,256])
hist_norm = hist.ravel()/hist.sum()
Q = hist_norm.cumsum()bins = np.arange(256)fn_min = np.inf
thresh = -1for i in range(1,256):p1,p2 = np.hsplit(hist_norm,[i]) # 概率q1,q2 = Q[i],Q[255]-Q[i] # 类型总和if q1 < 1.e-6 or q2 < 1.e-6:continueb1,b2 = np.hsplit(bins,[i]) # weights# 寻找均值和方差m1,m2 = np.sum(p1*b1)/q1, np.sum(p2*b2)/q2v1,v2 = np.sum(((b1-m1)**2)*p1)/q1,np.sum(((b2-m2)**2)*p2)/q2# 计算最小化函数fn = v1*q1 + v2*q2if fn < fn_min:fn_min = fnthresh = i# 使用 OpenCV 函数找到 otsu 的阈值ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)print( "{} {}".format(thresh,ret) )
# 显示原始图像和Otsu's 二值化结果
cv.imshow('Original Image', img)
cv.imshow('Otsu Thresholding', otsu)
cv.waitKey(0)
cv.destroyAllWindows()

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/118610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(链表) 25. K 个一组翻转链表 ——【Leetcode每日一题】

❓ 25. K 个一组翻转链表 难度&#xff1a;困难 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么请将最后剩余的节点保…

Kotlin基础——函数、变量、字符串模板、类

函数、变量、字符串模板、类 函数变量字符串模板类 函数 函数组成为 fun 函数名(参数名: 参数类型, …): 返回值{} fun max(a: Int, b: Int): Int {return if (a > b) a else b }上面称为代码块函数体&#xff0c;当函数体由单个表达式构成时&#xff0c;可简化为表达式函…

FreeRTOS 计数型信号量 详解

目录 什么是计数型信号量&#xff1f; 计数型信号量相关 API 函数 1. 创建计数型信号量 2. 释放二值信号量 3. 获取二值信号量 计数型信号量实操 什么是计数型信号量&#xff1f; 计数型信号量相当于队列长度大于1 的队列&#xff0c;因此计数型信号量能够容纳多个资源&a…

Azure - 机器学习:创建机器学习所需资源,配置工作区

目录 一、Azure机器学习工作区与计算实例简要介绍工作区计算实例 二、创建工作区1. 登录到 Azure 机器学习工作室2. 选择“创建工作区”3. 提供以下信息来配置新工作区&#xff1a;4. 选择“创建”以创建工作区 三、创建计算实例四、工作室实战4.1 工作室快速导览4.2 从示例笔记…

css 雷达扫描图

html 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>css 雷达扫描</title><style>* {margin: 0;padding: 0;}body {background: #000000;height: 100vh;display: flex;align-items…

021-Qt 配置GitHub Copilot

Qt 配置GitHub Copilot 文章目录 Qt 配置GitHub Copilot项目介绍 GitHub Copilot配置 GitHub CopilotQt 前置条件升级QtGitHub Copilot 前置条件激活的了GitHub Copilot账号安装 Neovim 启用插件&#xff0c;重启Qt配置 GitHub Copilo安装Nodejs下载[copilot.vim](https://gith…

互联网Java工程师面试题·Spring篇·第五弹

目录 1、什么是 spring? 2、使用 Spring 框架的好处是什么&#xff1f; 3、Spring 由哪些模块组成? 4、核心容器&#xff08;应用上下文) 模块。 5、BeanFactory – BeanFactory 实现举例。 6、XMLBeanFactory 7、解释 AOP 模块 8、解释 JDBC 抽象和 DAO 模块。 9、…

SD-WAN让跨境网络访问更快、更安全!

目前许多外贸企业都面临着跨境网络不稳定、不安全的问题&#xff0c;给业务合作带来了很多困扰。但是&#xff0c;现在有一个解决方案能够帮助您解决这些问题&#xff0c;让您的跨境网络访问更快、更安全&#xff0c;那就是SD-WAN&#xff01; 首先&#xff0c;让我们来看看SD-…

用VSCODE启动Java项目

下载插件 推荐下载插件 启动 在vscode中打开项目或将项目拖进vscode,等进度条加载完成即成启动项目

使用 excel 快速拼接省市区镇街村居五级区划完整名称

你知道的越多&#xff0c;你不知道的越多 点赞再看&#xff0c;养成习惯 如果您有疑问或者见解&#xff0c;欢迎指教&#xff1a; 企鹅&#xff1a;869192208 文章目录 前言数据准备excel 函数附件 前言 之前做了国家区划的映射关系&#xff0c;在其过程中&#xff0c;使用代码…

机器学习实验三:决策树-隐形眼镜分类(判断视力程度)

决策树-隐形眼镜分类&#xff08;判断视力程度&#xff09; Title : 使用决策树预测隐形眼镜类型 # Description :隐形眼镜数据是非常著名的数据集 &#xff0c;它包含很多患者眼部状况的观察条件以及医生推荐的隐形眼镜类型 。 # 隐形眼镜类型包括硬材质 、软材质以及不适合佩…

Kafka入门04——原理分析

目录 01理解Topic和Partition Topic(主题) Partition(分区) 02理解消息分发 消息发送到分区 消费者订阅和消费指定分区 总结 03再均衡(rebalance) 再均衡的触发 分区分配策略 RangeAssignor(范围分区) RoundRobinAssignor(轮询分区) StickyAssignor(粘性分区) Re…

MR混合现实情景实训教学系统在旅游管理专业中的应用

在旅游管理专业中&#xff0c;MR混合现实情景实训教学系统的主要应用包括但不限于以下几个方面&#xff1a; 1. 实地考察的替代&#xff1a;对于一些无法实地考察的景点或设施&#xff0c;学生可以通过MR系统进行虚拟参观&#xff0c;从而了解其实际情况。这不仅可以减少时间和…

人工智能基础_机器学习003_有监督机器学习_sklearn中线性方程和正规方程的计算_使用sklearn解算八元一次方程---人工智能工作笔记0042

然后我们再来看看,如何使用sklearn,来进行正规方程的运算,当然这里 首先要安装sklearn,这里如何安装sklearn就不说了,自己查一下 首先我们还是来计算前面的八元一次方程的解,但是这次我们不用np.linalg.solve这个 解线性方程的方式,也不用 直接 解正规方程的方式: 也就是上面…

【STM32】GPIO控制LED(HAL库版)

STM32最新固件库v3.5/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com) STM32最新固件库v3.5/Libraries/STM32F10x_StdPeriph_Driver/src/stm32f10x_gpio.c 林何/STM32F103C8 - 码云 - 开源中国 (gitee.…

代码随想录二刷 Day50

198.打家劫舍 这个题一开始由于给出来的例子陷入了思维误区&#xff0c;以为结果就是每隔一个取一个&#xff0c;其实有可能中间隔很多个。比如一下这个例子 下面这种写法不对。 class Solution { public:int rob(vector<int>& nums) {int odd_sum 0;int even_su…

Loop Copilot:AI驱动,小白也能自己生成音乐?

01 项目介绍 Loop Copilot是一个使用自然语言生成音乐的系统。它不仅允许你使用自然语言来生成你想要的音乐风格、节奏或旋律&#xff0c;还支持通过多轮对话对已生成的音乐进行进一步的编辑和修改。包括对生成的音乐进行编辑修改、添加或删除乐器、加入音效等。 02 工作流程…

Spring Boot实战 | 如何整合高性能数据库连接池HikariCP

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…

国密 SM2 SSL 证书 Nginx 安装指南 linux版

一、获取国密证书 1、在您完成申请西部GDCA服务器证书的流程后&#xff0c;下载证书将获取一个证书包&#xff0c;有以下 *.***.com_sign.crt&#xff1a;签名证书 *.***.com_sign.key&#xff1a;签名证书私钥 *.***.com_encrypt.crt&#xff1a;加密证书 *.***.com_encr…

【C++笔记】如何用检查TCP或UDP端口是否被占用

一、检查步骤 使用socket函数创建socket_fd套接字。使用sockaddr_in结构体配置协议和端口号。使用bind函数尝试与端口进行绑定&#xff0c;成功返回0表示未被占用&#xff0c;失败返回-1表示已被占用。 二、步骤详解 2.1 socket函数 socket 函数是用于创建套接字的函数&…