当前位置: 首页 > news >正文

9.3Otsu阈值分割

基本概念

在OpenCV中,Otsu阈值分割是一种全局阈值分割方法,但它会自动选择一个最佳的阈值来分割图像,这个阈值是通过最小化类内方差或等价地最大化类间方差来确定的。OpenCV提供了cv::threshold函数来实现这一功能,其中可以指定cv::THRESH_OTSU作为阈值类型之一。

OpenCV中的Otsu阈值分割

要使用Otsu阈值分割,你需要将cv::threshold函数的thresh参数设置为0(因为Otsu算法会自动计算阈值),并将maxval参数设置为当像素值超过(或小于,取决于threshType)阈值时应该赋予的新值,然后将threshType设置为cv::THRESH_BINARY | cv::THRESH_OTSU。注意,虽然cv::THRESH_OTSU是一个标志,但你需要将它与实际的阈值类型(如cv::THRESH_BINARY)组合使用。

Otsu阈值分割是一种广泛使用的全局阈值选择方法,它自动选择一个阈值来将图像分成两部分:前景和背景。这种方法基于最大类间方差的原则来寻找最优的单阈值,从而将图像二值化。

函数原型

对于cv::threshold函数中与Otsu相关的部分,其原型可以简化为:

double cv::threshold(InputArray src, OutputArray dst,   double thresh, double maxval, int thresholdType)但当你使用Otsu阈值时,thresh参数实际上会被忽略,因为它将由算法自动计算。你主要关心的是返回的阈值(如果thresholdType包含cv::THRESH_OTSU),它可以通过函数的返回值获得。

Otsu's二值化方法是一种自动计算图像最佳阈值的技术,它常用于图像分割。这种方法的目标是找到一个阈值,使得图像分割成前景和背景两部分之后,这两部分之间的类间方差最大。简而言之,Otsu's方法试图找到一个全局阈值,将图像像素分为两个类(前景和背景),使得它们之间的差异最大化。

在OpenCV中,你可以使用cv::threshold函数来应用Otsu's阈值分割。

以下是如何在C++中使用OpenCV实现Otsu's阈值分割的步骤:
步骤 1: 包含必要的头文件
首先,你需要包含OpenCV的头文件。#include <opencv2/opencv.hpp>
using namespace cv;步骤 2: 加载图像
加载你要处理的灰度图像。如果你有一个彩色图像,需要先将其转换为灰度图像。
Mat src = imread("path_to_your_image.jpg", IMREAD_GRAYSCALE);
if (src.empty()) {std::cout << "Error opening image" << std::endl;return -1;
}步骤 3: 应用Otsu's阈值分割
使用cv::threshold函数设置threshold参数为0,并且传递THRESH_BINARY + THRESH_OTSU标志。int thresholdValue = 0;
Mat dst;
threshold(src, dst, thresholdValue, 255, THRESH_BINARY + THRESH_OTSU);这里,thresholdValue设置为0是因为Otsu's算法会根据图像的直方图自动计算最佳阈值。255是超过阈值后的最大值,对于黑白二值化来说通常就是白色。步骤 4: 显示结果
显示原始图像和处理后的图像。
namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", src);namedWindow("Otsu's Binarization", WINDOW_NORMAL);
imshow("Otsu's Binarization", dst);waitKey(0);

完整示例代码1

以下是完整的示例代码:

#include <opencv2/opencv.hpp>
#include <iostream>int main(int argc, char** argv) {cv::Mat src = cv::imread("path_to_your_image.jpg", cv::IMREAD_GRAYSCALE);if (src.empty()) {std::cout << "Error opening image" << std::endl;return -1;}int thresholdValue = 0;cv::Mat dst;cv::threshold(src, dst, thresholdValue, 255, cv::THRESH_BINARY + cv::THRESH_OTSU);cv::namedWindow("Original Image", cv::WINDOW_NORMAL);cv::imshow("Original Image", src);cv::namedWindow("Otsu's Binarization", cv::WINDOW_NORMAL);cv::imshow("Otsu's Binarization", dst);cv::waitKey(0);return 0;
}

运行结果1

Otsu 阈值分割的实现步骤
1. 导入必要的头文件: 需要包含 OpenCV 的核心模块头文件。
#include <opencv2/opencv.hpp>
using namespace cv;2. 读取图像: 使用 imread 函数从磁盘读取图像,并将其转换为灰度图,因为 Otsu 阈值分割通常应用于灰度图像。Mat src = imread("path/to/image.jpg", IMREAD_GRAYSCALE);
if (src.empty()) {std::cout << "Error: Image not found or unable to read the image." << std::endl;return -1;
}3. 应用 Otsu 阈值分割: 使用 threshold 函数进行 Otsu 阈值分割。这里需要注意的是,需要将 THRESH_OTSU 标志添加到 threshold 函数中,以便启用 Otsu 方法。double thresholdValue;
// 选择一个初始阈值(这里设置为0),并让OpenCV计算最佳阈值
threshold(src, src, 0, 255, THRESH_BINARY + THRESH_OTSU, &thresholdValue);
THRESH_OTSU 标志告诉 threshold 函数使用 Otsu 的算法来计算最佳阈值。thresholdValue 是一个输出参数,它将返回计算出的最佳阈值。4. 显示结果: 可以通过 imshow 显示原始图像和处理后的图像,并等待用户按键退出。namedWindow("Original Image", WINDOW_NORMAL);
imshow("Original Image", src);namedWindow("Otsu Threshold Result", WINDOW_NORMAL);
imshow("Otsu Threshold Result", src);waitKey(0); // Wait for a keystroke in the window
5. 获取并打印阈值(可选): 如果需要查看计算出的最佳阈值,可以在程序中打印出来。
std::cout << "The optimal threshold value is: " << thresholdValue << std::endl;

完整的示例代码2

#include "pch.h"#include <opencv2/opencv.hpp>
#include <iostream>using namespace cv;
using namespace std;int main() {// 读取图像Mat src = imread("654.png", IMREAD_GRAYSCALE);if (src.empty()) {cout << "Error: Image not found or unable to read the image." << endl;return -1;}// 应用 Otsu 阈值分割double thresholdValue;Mat dst;thresholdValue=threshold(src, dst, 0, 255, THRESH_BINARY + THRESH_OTSU);// 显示结果namedWindow("Original Image", WINDOW_NORMAL);imshow("Original Image", src);namedWindow("Otsu Threshold Result", WINDOW_NORMAL);imshow("Otsu Threshold Result", dst);// 打印阈值cout << "The optimal threshold value is: " << thresholdValue << endl;waitKey(0); // Wait for a keystroke in the windowreturn 0;
}注意事项
•Otsu 阈值分割适用于双峰直方图的图像,即图像中前景和背景有明显的灰度差异。
•如果图像的直方图没有明显的双峰分布,Otsu 阈值分割可能不会得到满意的结果。
•对于光照不均匀或背景复杂的图像,可能需要结合其他预处理技术(如直方图均衡化)来改善分割效果。

运行结果2

示例代码3

下面是一个使用OpenCV C++ API进行Otsu阈值分割的示例代码:

#include <opencv2/opencv.hpp>  
#include <iostream>  using namespace cv;  
using namespace std;  int main() {  // 加载图像  Mat src = imread("path_to_image.jpg", IMREAD_GRAYSCALE);  if (src.empty()) {  cout << "Could not open or find the image!\n";  return -1;  }  // 创建输出图像  Mat dst;  // 应用Otsu阈值分割  // 注意:thresh被设置为0,因为Otsu会自动计算它  // maxval是超过阈值时要赋予的新像素值  // THRESH_BINARY | THRESH_OTSU表示使用Otsu算法进行二值化  double threshVal = threshold(src, dst, 0, 255, THRESH_BINARY | THRESH_OTSU);  // 输出计算得到的阈值  cout << "Calculated threshold value with Otsu's method: " << threshVal << endl;  // 显示结果  imshow("Original Image", src);  imshow("Otsu Thresholding", dst);  waitKey(0);  return 0;  
}

在这个示例中,我们加载了一个灰度图像,并使用Otsu算法对其进行了二值化处理。计算得到的阈值通过threshold函数的返回值获得,并打印到控制台上。然后,我们显示了原始图像和分割后的图像。

运行结果3

请注意,Otsu阈值分割适用于具有明显双峰直方图的图像,即图像的前景和背景在像素值上差异较大,且它们的分布相对独立。如果图像的直方图不满足这些条件,Otsu算法可能无法提供最佳结果。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 使用Django 搭建自动化平台
  • 项目实战 (15)--- 代码区块重构及相关技术落地
  • (k8s)kubernetes 部署Promehteus学习之路
  • [Redis][List]详细讲解
  • Elasticsearch 应用实战:从基础到高级实践
  • Radware 报告 Web DDoS 攻击活动
  • 图书管理系统小程序的设计
  • 【autoware】编译时候出现“没有那个文件或目录 20 | #include <pcl/point_types.h>“错误
  • ChatGPT 4o 使用指南 (9月更新)
  • WebServer:buffer
  • 某省公共资源交易电子平台爬虫逆向
  • Spring Mybatis PageHelper分页插件 总结
  • 【JVM原理】运行时数据区(内存结构)
  • Open3D 利用点云的曲率密度提取特征点【2024最新版】
  • Linux1-ls,cd,pwd
  • 9月CHINA-PUB-OPENDAY技术沙龙——IPHONE
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 2017前端实习生面试总结
  • Android框架之Volley
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • SQLServer之创建数据库快照
  • uni-app项目数字滚动
  • Vue 重置组件到初始状态
  • windows-nginx-https-本地配置
  • 小程序开发中的那些坑
  • 原生js练习题---第五课
  • mysql面试题分组并合并列
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • ​第20课 在Android Native开发中加入新的C++类
  • # Redis 入门到精通(七)-- redis 删除策略
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (20050108)又读《平凡的世界》
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (Git) gitignore基础使用
  • (javascript)再说document.body.scrollTop的使用问题
  • (二十五)admin-boot项目之集成消息队列Rabbitmq
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (十)T检验-第一部分
  • (十三)Flask之特殊装饰器详解
  • (万字长文)Spring的核心知识尽揽其中
  • (轉貼) UML中文FAQ (OO) (UML)
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • ***微信公众号支付+微信H5支付+微信扫码支付+小程序支付+APP微信支付解决方案总结...
  • ..回顾17,展望18
  • .JPG图片,各种压缩率下的文件尺寸
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net core 外观者设计模式 实现,多种支付选择
  • .Net Core 微服务之Consul(三)-KV存储分布式锁
  • //TODO 注释的作用
  • /bin/rm: 参数列表过长"的解决办法
  • [Algorithm][动态规划][两个数组的DP][正则表达式匹配][交错字符串][两个字符串的最小ASCII删除和][最长重复子数组]详细讲解
  • [C#]DataTable常用操作总结【转】
  • [C/C++]数据结构 栈和队列()
  • [C++][ProtoBuf][初识ProtoBuf]详细讲解