使用VC++设计程序对一幅256级灰度图像进行全局固定阈值分割、自适应阈值分割

图像分割–全局固定阈值分割、自适应阈值分割

获取源工程可访问gitee可在此工程的基础上进行学习。
该工程的其他文章:
01- 一元熵值、二维熵值
02- 图像平移变换,图像缩放、图像裁剪、图像对角线镜像以及图像的旋转
03-邻域平均平滑算法、中值滤波算法、K近邻均值滤波器
04-分段线性变换,直方图均衡化、锐化处理
05-基于拉普拉斯算子、Canny的边缘检测功能、实现Otsu分割方法
06-最近邻插值,双线性插值,立方卷积插值

文章目录

  • 图像分割--全局固定阈值分割、自适应阈值分割
    • 实验内容
    • 一、全局固定阈值分割
      • 全局固定阈值分割的原理
      • 全局固定阈值分割的实验代码
      • 全局固定阈值分割的实验现象
    • 二、自适应阈值分割
      • 自适应阈值分割的实验原理
      • 自适应阈值分割的实验代码
      • 自适应阈值分割的实验现象

实验内容

实验目的:
(1)掌握图像分割的原理与相关方法。
(2)能使用VC++开发一些图像分割方法。
实验要求:
A部分:
(1)使用VC++设计程序:对一幅256级灰度图像,进行全局固定阈值分割。
(2)使用VC++设计程序:对一幅256级灰度图像,进行自适应阈值分割。

一、全局固定阈值分割

全局固定阈值分割的原理

全局固定阈值分割是图像处理中一种简单而常用的图像分割方法,主要用于将图像中的目标与背景分开。该方法假设图像的目标和背景在灰度上有较大的差异,因此通过设定一个固定的阈值来将图像分割成两个部分。

具体步骤如下:

  1. 灰度图像转换: 如果图像不是灰度图像,首先将其转换为灰度图像。

  2. 选择阈值: 选择一个适当的阈值,该阈值将图像的灰度级别划分为两个部分,一部分属于目标,另一部分属于背景。阈值的选择通常基于图像的直方图分布以及应用场景。

  3. 分割图像: 将图像中每个像素的灰度值与选定的阈值进行比较,将灰度值大于阈值的像素归为一类,灰度值小于等于阈值的像素归为另一类。这样就得到了分割后的图像。

  4. 可选的后处理: 分割后的图像可能包含一些噪声或不连续的区域,因此可能需要进行一些后处理步骤,如去噪、连通性分析等。

  5. 应用领域: 全局固定阈值分割常用于具有清晰目标和背景对比度的图像,例如二值化处理、物体检测等。

虽然全局固定阈值分割简单易用,但对于光照不均匀、目标与背景差异不大的图像,效果可能不佳。在这种情况下,可能需要采用自适应阈值分割方法或其他更复杂的图像分割技术。

全局固定阈值分割的实验代码

/*************************************************************************
 *
 * \函数名称:
 *   RegionSegFixThreshold()
 *
 * \输入参数:
 *   CDib * pDib     - 指向CDib类的指针,含有原始图象信息
 *   int nThreshold     - 区域分割的阈值
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   1(逻辑)表示对应象素为前景区域,0表示背景
 *   阈值分割的关键问题在于阈值的选取。阈值的选取一般应该视实际的应用而
 *   灵活设定。
 *
 *************************************************************************
 */
void RegionSegFixThreshold(CDib * pDib, int nThreshold)
{
 //遍历图象的纵坐标
 int y;

 //遍历图象的横坐标
 int x;

 //图象的长宽大小
 CSize sizeImage  = pDib->GetDimensions();
 int nWidth   = sizeImage.cx  ;
 int nHeight   = sizeImage.cy  ;

 //图像在计算机在存储中的实际大小
 CSize sizeImageSave = pDib->GetDibSaveDim();

 //图像在内存中每一行象素占用的实际空间
 int nSaveWidth = sizeImageSave.cx;

 
 //图像数据的指针
 LPBYTE  pImageData = pDib->m_lpImage;

 for(y=0; y<nHeight ; y++ )
  for(x=0; x<nWidth ; x++ )
  {
   if( *(pImageData+y*nSaveWidth+x) < nThreshold)
    *(pImageData+y*nSaveWidth+x) = 0;
   else
    *(pImageData+y*nSaveWidth+x) = 255;
  }
}

全局固定阈值分割的实验现象

在这里插入图片描述

二、自适应阈值分割

自适应阈值分割的实验原理

自适应阈值分割是一种根据图像局部特性确定阈值的方法,通常用于解决图像中灰度变化较大的情况。自适应阈值分割方法考虑图像中不同区域的灰度分布差异,根据局部信息确定每个像素的阈值。

以下是一些常见的自适应阈值分割方法:

  1. 局部均值法(Local Mean Method):

    • 对于每个像素,使用其邻域的平均灰度值作为阈值。这样可以适应图像中灰度变化较慢的区域。
  2. 局部中值法(Local Median Method):

    • 对于每个像素,使用其邻域的中值作为阈值。对于一些包含噪声的图像,中值法相对于均值法更具鲁棒性。
  3. 局部方差法(Local Variance Method):

    • 使用每个像素邻域的灰度方差作为阈值。适用于图像中包含有纹理或细节的区域。
  4. Sauvola’s Method:

    • Sauvola提出的方法考虑了局部均值和局部方差,通过权衡这两个因素来确定阈值。适用于具有不同光照条件的图像。
  5. Niblack’s Method:

    • 类似于Sauvola的方法,Niblack提出的方法使用局部均值和标准差来确定阈值。适用于具有强烈光照变化的图像。
  6. Bernsen’s Method:

    • Bernsen的方法使用局部最大值和最小值之间的差异来确定阈值。对于具有大范围灰度变化的图像比较有效。

在实际应用中,选择合适的自适应阈值分割方法取决于图像的特性以及分割任务的要求。这些方法的性能会受到图像噪声、光照条件和目标特性等因素的影响。因此,需要根据具体情况进行调整和选择。

自适应阈值分割的实验代码

/*************************************************************************
 *
 * \函数名称:
 *   RegionSegAdaptive()
 *
 * \输入参数:
 *   CDib * pDib     - 指向CDib类的指针,含有原始图象信息
 *
 * \返回值:
 *   无
 *
 * \说明:
 *   1(逻辑)表示对应象素为前景区域,0表示背景
 *   阈值分割的关键问题在于阈值的选取。阈值的选取一般应该视实际的应用而
 *   灵活设定。本函数中,阈值不是固定的,而是根据图象象素的实际性质而设定的。
 *   这个函数把图像分成四个子图象,然后计算每个子图象的均值,根据均值设置阈值
 *   阈值只是应用在对应的子图象
 *
 *************************************************************************
 */
void RegionSegAdaptive(CDib * pDib)
{
 //遍历图象的纵坐标
 int y;

 //遍历图象的横坐标
 int x;

 //图象的长宽大小
 CSize sizeImage  = pDib->GetDimensions();
 int nWidth   = sizeImage.cx  ;
 int nHeight   = sizeImage.cy  ;

 //图像在计算机在存储中的实际大小
 CSize sizeImageSave = pDib->GetDibSaveDim();

 //图像在内存中每一行象素占用的实际空间
 int nSaveWidth = sizeImageSave.cx;

 //图像数据的指针
 LPBYTE  lpImage = pDib->m_lpImage;
 // 局部阈值
 int nThd[2][2] ;
 // 子图象的平均值
 int nLocAvg ;
 // 对左上图像逐点扫描:
 nLocAvg = 0 ;
 // y方向
 for(y=0; y<nHeight/2 ; y++ )
 {
  // x方向
  for(x=0; x<nWidth/2 ; x++ )
  {
   nLocAvg += lpImage[y*nSaveWidth + x];
  }
 }
 // 计算均值
 nLocAvg /= ( (nHeight/2) * (nWidth/2) ) ;
 // 设置阈值为子图象的平均值
 nThd[0][0] = nLocAvg ;

 // 对左上图像逐点扫描进行分割:
 // y方向
 for(y=0; y<nHeight/2 ; y++ )
 {
  // x方向
  for(x=0; x<nWidth/2 ; x++ )
  {
   if(lpImage[y*nSaveWidth + x]<nThd[0][0])
    lpImage[y*nSaveWidth + x] = 255 ;
   else
   {
    lpImage[y*nSaveWidth + x] = 0 ;
   }
   
  }
 }
 // =============================================
 // 对左下图像逐点扫描:
 nLocAvg = 0 ;
 // y方向
 for(y=nHeight/2; y<nHeight ; y++ )
 {
  // x方向
  for(x=0; x<nWidth/2 ; x++ )
  {
   nLocAvg += lpImage[y*nSaveWidth + x];
  }
 }
 // 计算均值
 nLocAvg /= ( (nHeight - nHeight/2) * (nWidth/2) ) ;

 // 设置阈值为子图象的平均值
 nThd[1][0] = nLocAvg ;

 // 对左下图像逐点扫描进行分割:
 // y方向
 for(y=nHeight/2; y<nHeight ; y++ )
 {
  // x方向
  for(x=0; x<nWidth/2 ; x++ )
  {
   if(lpImage[y*nSaveWidth + x]<nThd[1][0])
    lpImage[y*nSaveWidth + x] = 255 ;
   else
   {
    lpImage[y*nSaveWidth + x] = 0 ;
   }
   
  }
 }
 // =============================================
 // 对右上图像逐点扫描:
 nLocAvg = 0 ;
 // y方向
 for(y=0; y<nHeight/2 ; y++ )
 {
  // x方向
  for(x=nWidth/2; x<nWidth ; x++ )
  {
   nLocAvg += lpImage[y*nSaveWidth + x];
  }
 }
 // 计算均值
 nLocAvg /= ( (nHeight/2) * (nWidth - nWidth/2) ) ;
 
 // 设置阈值为子图象的平均值
 nThd[0][1] = nLocAvg ;

 // 对右上图像逐点扫描进行分割:
 // y方向
 for(y=0; y<nHeight/2 ; y++ )
 {
  // x方向
  for(x=nWidth/2; x<nWidth ; x++ )
  {
   if(lpImage[y*nSaveWidth + x]<nThd[0][1])
    lpImage[y*nSaveWidth + x] = 255 ;
   else
   {
    lpImage[y*nSaveWidth + x] = 0 ;
   }
   
  }
 }
 // =============================================
 // 对右下图像逐点扫描:
 nLocAvg = 0 ;
 // y方向
 for(y=nHeight/2; y<nHeight ; y++ )
 {
  // x方向
  for(x=nWidth/2; x<nWidth ; x++ )
  {
   nLocAvg += lpImage[y*nSaveWidth + x];
  }
 }
 // 计算均值
 nLocAvg /= ( (nHeight - nHeight/2) * (nWidth - nWidth/2) ) ;

 // 设置阈值为子图象的平均值
 nThd[1][1] = nLocAvg ;

 // 对右下图像逐点扫描进行分割:
 // y方向
 for(y=nHeight/2; y<nHeight ; y++ )
 {
  // x方向
  for(x=nWidth/2; x<nWidth ; x++ )
  {
   if(lpImage[y*nSaveWidth + x]<nThd[1][1])
    lpImage[y*nSaveWidth + x] = 255 ;
   else
   {
    lpImage[y*nSaveWidth + x] = 0 ;
   }
  }
 }
 
 // 为了显示方便显示,逻辑1用黑色显示,逻辑0用白色显示
 for(y=0; y<nHeight ; y++ )
 {
  // x方向
  for(x=0; x<nWidth ; x++ )
  {
   lpImage[y*nSaveWidth + x] = 255 - lpImage[y*nSaveWidth + x] ;
  }
 }
}

自适应阈值分割的实验现象

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux python安装 虚拟环境 virtualenv,以及 git clone的 文件数据, 以及 下资源配置

根目录创建 venvs 文件夹 sudo mkdir /venvs 进入 /venvs 目录 cd /venvsp 创建虚拟环境&#xff0c;前提要按照 python3 安装 的 命令 sudo apt install python3 sudo python3 -m venv 虚拟环境名 激活虚拟环境 source /venvs/zen-venv/bin/activate 安装flask pip install fl…

Java + openCV更换证件照背景色

最近在小红书上看到很多更换证件照背景色的需求&#xff0c;联想到以前自己也更换过证件照背景色而且还是付费的&#xff0c;碰巧最近在看一本书《JavaOpenCV高效入门》&#xff0c;于是查找资料&#xff0c;找到了通过技术解决这个需求的办法。 先看效果图&#xff08;图片来自…

每日一题2023.11.26——个位数统计【PTA】

题目要求&#xff1a; 输入格式&#xff1a; 每个输入包含 1 个测试用例&#xff0c;即一个不超过 1000 位的正整数 N。 输出格式&#xff1a; 对 N 中每一种不同的个位数字&#xff0c;以 D:M 的格式在一行中输出该位数字 D 及其在 N 中出现的次数 M。要求按 D 的升序输出。…

设备树是什么?

设备树&#xff1a; 设备树DTS(Device Tree Source) 描述设备信息的独立的文件。 为什么要引入设备树&#xff1f; 随着芯片的发展&#xff0c;Linux内核中就包含着越来越多这些描述设备的代码&#xff0c;导致Linux内核代码会很臃肿。因此引入了设备树文件&#xff0c;从…

Runloop解析

RunLoop 前言 ​ 本文介绍RunLoop的概念&#xff0c;并使用swift和Objective-C来描述RunLoop机制。 简介 ​ RunLoop——运行循环&#xff08;死循环&#xff09;&#xff0c;它提供了一个事件循环机制在程序运行过程中处理各种事件&#xff0c;例如用户交互、网络请求、定…

前端review

关于实时预览vs code中的颜色代码需要安装的插件&#xff0c;包括html文件格式中的颜色代码安装Flutter Color插件 VSCode 前端常用插件集合 1.Auto Close Tag自动闭合HTML/XML标签 2.Auto Rename Tag自动完成另一侧标签的同步修改 3.Beautify格式化代码&#xff0c;值得注…

Python武器库开发-前端篇之html概述(二十八)

前端篇之html概述(二十八) html概述 HTML5是构建Web内容的一种语言描述方式。HTML5是互联网的下一代标准&#xff0c;是构建以及呈现互联网内容的一种语言方式&#xff0e;被认为是互联网的核心技术之一。HTML产生于1990年&#xff0c;1997年HTML4成为互联网标准&#xff0c;…

斐讯K2结合Padavan实现锐捷认证破解方法

前言 众所周知&#xff0c;校园网在传统模式下是不能直接插路由使用的&#xff0c;但苦于校园网只能连接一台设备的烦恼&#xff0c;不得不“另辟蹊径”来寻求新的解决路径&#xff0c;这不&#xff0c;它来了&#xff0c;它来了&#xff0c;它带着希望走来了。 本文基于斐讯…

基于Haclon的图形镜像案例

项目要求&#xff1a; 图为HALCON的例图“green-dot”&#xff0c;请将其中的圆形图案按水平和垂直两个方向分别进行镜像。 项目知识&#xff1a; 首先要用BLOB分析的方法&#xff0c;得到圆形图案的目标区域&#xff0c;再对其进行镜像。 在HALCON中与镜像相关的算子为mirr…

Android平台GB28181设备接入模块开发填坑指南

技术背景 为什么要开发Android平台GB28181设备接入模块&#xff1f;这个问题不再赘述&#xff0c;在做Android平台GB28181客户端的时候&#xff0c;媒体数据这块&#xff0c;我们已经有了很好的积累&#xff0c;因为在此之前&#xff0c;我们就开发了非常成熟的RTMP推送、轻量…

Deepin使用记录-deepin系统下安装RabbitMq

目录 0、引言 1、由于RabbitMq是erlang语言开发的&#xff0c;所有需要先安装erlang 2、更新源并安装RabbitMq 3、安装完成之后&#xff0c;服务是启动的&#xff0c;可以通过以下语句查看状态 4、这样安装完成之后&#xff0c;是看不到web页面的&#xff0c;需要再安装一…

PTA NeuDs_数据库题目

二.单选题 1.数据库应用程序的编写是基于数据库三级模式中的。 A.模式 B.外模式 C.内模式 D.逻辑模式 用户应用程序根据外模式进行数据操作&#xff0c;通过外模式一模式映射&#xff0c;定义和建立某个外模式与模式间的对应关系 2.对创建数据库模式一类的数据库对象的授权…

【开源项目】C#.NET 扩展库 -- Com.Gitusme.Net.Extensiones.Core

目录 1、项目介绍 2、集成方式 方法一&#xff1a;项目中通过Nuget包管理器安装导入 方法二&#xff1a;手动从Nuget官网下载&#xff0c;下载地址&#xff1a; 3、代码中导入命名空间 4、版本变更说明 1.0.7 版本 1.0.6 版本 1.0.5 版本 1.0.4 版本 5、演示示例 示…

Unity SRP 管线【第三讲:URP 光照】

3.2.3 以前属于Shader部分&#xff0c;Shader部分不进行讲解。 这里只涉及Unity内部管线的设置问题。 文章目录 3.2.3 向GPU发送灯光数据设置光源数据设置主光源设置额外点光源 Shader中的数据 3.2.3 向GPU发送灯光数据 在UniversalRenderPipeline.cs > RenderSingleCamera…

叠加原理(superposition principle)

叠加原理&#xff08;superposition principle&#xff09;指对线性系统而言&#xff0c;两个或多个输入产生的输出&#xff0c;等于这几个输入单独引起的输出的和&#xff0c;即输入的叠加等于各输入单独引起的输出的叠加。 例如&#xff0c;如果输入产生的输出是&#xff0c;…

如何使用nginx部署静态资源

Nginx可以作为静态web服务器来部署静态资源&#xff0c;这个静态资源是指在服务端真实存在&#xff0c;并且能够直接展示的一些文件数据&#xff0c;比如常见的静态资源有html页面、css文件、js文件、图片、视频、音频等资源相对于Tomcat服务器来说&#xff0c;Nginx处理静态资…

大数据面试大厂真题【附答案详细解析】

1.Java基础篇&#xff08;阿里、蚂蚁、字节、携程、快手、杭州银行等&#xff09; 问题&#xff1a;HashMap的底层实现原理 答案&#xff1a; 在jdk1.8之前&#xff0c;hashmap由 数组-链表数据结构组成&#xff0c;在jdk1.8之后hashmap由 数组-链表-红黑树数据结构组成&…

②⑩② 【读写分离】Sharding - JDBC 实现 MySQL读写分离[SpringBoot框架]

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ Sharding-JDBC Sharding-JDBC介绍使用 Shardin…

DistilBERT模型训练实战

LLM似乎正在接管世界&#xff0c;但许多人仍然不真正理解他们是如何运作的。 我从事机器学习工作已有几年&#xff0c;并且对自然语言处理和最近的进展非常着迷。 尽管我阅读了大部分随附的论文&#xff0c;但训练这些模型对我来说仍然是一个谜&#xff0c;这就是为什么我决定…

Java(七)(Lambda表达式,正则表达式,集合(Collection,Collection的遍历方式))

目录 Lambda表达式 省略写法(要看懂) 正则表达式 语法 案例 正则表达式的搜索替换和分割内容 集合进阶 集合体系结构 Collection Collection的遍历方式 迭代器 增强for循环 Lambda表达式遍历Collection List集合 ArrayList LinkedList 哈希值 HashSet底层原理 …