使用VC++设计程序,进行全局固定阈值分割、自适应阈值分割

news/2024/7/7 20:09:11

图像分割

获取源工程可访问gitee可在此工程的基础上进行学习。

文章目录

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

实验内容

实验目的:
(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] ;
  }
 }
}

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

在这里插入图片描述


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

相关文章

C++20并发编程之线程闩(std::latch)和线程卡(std::barrier)

std::latch std::latch类是一种基于std::ptrdiff_t类型的倒计数器&#xff0c;可用于同步线程。计数器的值在创建时进行初始化。线程可以在 latch 上阻塞&#xff0c;直到计数器减少到零为止。无法增加或重置计数器&#xff0c;这使得 latch 成为一次性的屏障。 std::latch的成…

产品经理必备技能:如何快速锁定种子用户群体?

大家好&#xff0c;我是小米&#xff0c;一名热爱技术、热衷分享的90后小青年。今天我们要探讨的话题是一个在产品经理面试中经常被问到的问题&#xff1a;“产品上线后的种子用户该如何获取&#xff1f;”作为一个热爱挑战、乐于探讨的小伙伴&#xff0c;我将和大家分享一些我…

2023NOIP游寄

停课停了一个月&#xff0c;考炸了就真的寄了。 DAY -2 模拟赛出人意外的简单&#xff0c;信心赛吗&#xff1f; 开局30s切了T1。总共做出三题&#xff0c;但挂了 150pts。难绷。 直接没有信心了。 DAY -1 晚上直接跑路回家&#xff0c;表示&#xff1a;休息一天。 DAY …

Java项目实战《苍穹外卖》 二、项目搭建

当我痛苦地站在你的面前 你不能说我一无所有 你不能说我两手空空 系列文章目录 苍穹外卖是黑马程序员2023年的Java实战项目&#xff0c;作为业余练手用&#xff0c;需要源码或者课程的可以找我&#xff0c;无偿分享 Java项目实战《苍穹外卖》 一、项目概述Java项目实战《苍穹外…

从零开始写一个APM监控程序(一)协议

APM&#xff08;Application Performance Monitoring&#xff09;是一种用于监控和管理应用程序性能的解决方案。它通过收集、分析和报告应用程序的性能数据&#xff0c;帮助开发人员和系统管理员更好地了解应用程序的运行状况&#xff0c;识别潜在的性能问题&#xff0c;并进行…

Qt给状态栏添加一个按钮

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);QPushButton* btn new QPushButton(this);btn->setText("click");this->statusBar()->addWidget(btn); }

C/C++ 运用WMI接口查询系统信息

Windows Management Instrumentation&#xff08;WMI&#xff09;是一种用于管理和监视Windows操作系统的框架。它为开发人员、系统管理员和自动化工具提供了一种标准的接口&#xff0c;通过这个接口&#xff0c;可以获取有关计算机系统硬件、操作系统和应用程序的信息&#xf…

无需API开发,伯俊科技实现电商与客服系统的无缝集成

伯俊科技的无代码开发实现系统连接 自1999年成立以来&#xff0c;伯俊科技一直致力于为企业提供全渠道一盘货的服务。凭借其24年的深耕零售行业的经验&#xff0c;伯俊科技推出了一种无需API开发的方法&#xff0c;实现电商系统和客服系统的连接与集成。这种无代码开发的方式不…