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

智能汽车竞赛摄像头处理(3)——动态阈值二值化(大津法)

前言

(1)在上一节中,我们学习了对图像的固定二值化处理,可以将原始图像处理成二值化的黑白图像,这里面的本质就是将原来的二维数组进行了处理,处理后的二维数组里的元素都是0和255两个值。

(2)固定阈值二值化的使用是比赛过程中,每一处地方的二值化阈值都是同一个值,而赛道的不同地方以同一个阈值二值化出来的图像可能不合适,甚至不能正常循迹。

(3)为了适应赛道上的不同环境,很多同学会采用动态二值化,即对于采集到的不同图像,通过算法计算出合适的阈值来进行二值化处理,最后的二值化效果可能会比固定阈值化好一些(因为也有不少同学在比赛中采用固定阈值二值化处理,最后拿到了国奖,所以哪个方法更好,还真不好说,主要根据实际情况看自己的作品)。

(4)毋庸置疑,大津法会增加算法处理,处理时间肯定比固定阈值二值化长。

概念

对于图像处理入门,建议大家可以去看这篇文章

详解-OTUS(大津法-最大类间方差)原理及C语言代码实现-CSDN博客

但是,你不想看也没关系,请继续看我后面的内容,你只需要理解到一个点:大津法就是一个对二维数组处理后会得到一个值的算法,而这个值就是我们二值化要的阈值。想要搞清楚大津法原理,请移步上面的文章进行学习,我这里只进行简要介绍。

大津法

        大津法阈值采用最大类间方差的原理,适合于图像灰度分布整体呈现“双峰”的情况。大津法会自动找出一个阈值,使得分割后的两部分类间方差最大。

        最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出,是一种确定图像二值化分割阈值的算法。算法假设图像像素能够根据全局阈值,被分成背景[background]和目标[objects]两部分。然后,计算该最佳阈值来区分这两类像素,使得两类像素区分度最大。

大津法阈值采用最大类间方差的原理,适合于图像灰度分布整体呈现“双峰”的情况。大津法会自动找出一个阈值,使得分割后的两部分类间方差最大。

特性:

  1. 大津法对噪音十分敏感,在处理之前应对图片进行去噪处理。如果图像有存在局部噪声,则会影响大津法的判断
  2. 当目标与背景的面积比例悬殊的时候,类间方差函数可能呈现双峰或者多峰,这个时候 大津法的效果不好

(1)双峰图像,目标和背景面积差距不大,可以很好的判断,如下:

(2)当图像中的目标与背景的面积相差很大时,灰度直方图没有明显的双峰,或者两个峰的大小相差很大,分割效果不佳:

代码实现

一般大津法代码如下:

(你只需要将我的代码复制粘贴到images.c文件中,把这个函数在cpu1.c中调用即可)

images.c

#include "zf_common_headfile.h"uint8  mt9v03x_image_BandW[MT9V03X_H][MT9V03X_W];/*begin  大津法比赛   begin*/
//快速大津法二值化 pixelSum = width * height/4;
//-------------------------------------------------------------------------------------------------------------------
//  @brief      快速大津
//  @return     uint8
//  @since      v1.1
//  Sample usage:   OTSU_Threshold = otsuThreshold(mt9v03x_image_dvp[0]);//大津法阈值
//-------------------------------------------------------------------------------------------------------------------
uint8 otsuThreshold_fast(uint8 *image)   //注意计算阈值的一定要是原图像
{
#define GrayScale 256int Pixel_Max=0;int Pixel_Min=255;uint16 width = MT9V03X_W;   //宽100uint16 height = MT9V03X_H;  //高80int pixelCount[GrayScale];  //各像素GrayScale的个数pixelCount 一维数组float pixelPro[GrayScale];  //各像素GrayScale所占百分比pixelPro 一维数组int i, j, pixelSum = width * height/4;  //pixelSum是获取总的图像像素个数的1/4,相应下面轮询时高和宽都是以2为单位自增uint8 threshold = 0;
//    uint8 last_threshold = 0;uint8* data = image;  //指向像素数据的指针//清零for (i = 0; i < GrayScale; i++){pixelCount[i] = 0;pixelPro[i] = 0;}uint32 gray_sum=0;  //每次执行到这会将gray_sum清零//统计灰度级中每个像素在整幅图像中的个数for (i = 0; i < height; i+=2)   //高{for (j = 0; j < width; j+=2)    //宽{pixelCount[(int)data[i * width + j]]++;  //将当前的点的像素值作为计数数组的下标gray_sum+=(int)data[i * width + j];       //灰度值总和if(data[i * width + j]>Pixel_Max)   Pixel_Max=data[i * width + j];if(data[i * width + j]<Pixel_Min)   Pixel_Min=data[i * width + j];}}//计算每个像素值的点在整幅图像中的比例for (i = Pixel_Min; i < Pixel_Max; i++){pixelPro[i] = (float)pixelCount[i] / pixelSum;}//遍历灰度级[0,255]float w0, w1, u0tmp, u1tmp, u0, u1, u, deltaTmp, deltaMax = 0;w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;for (j = Pixel_Min; j < Pixel_Max; j++){w0 += pixelPro[j];  //背景部分每个灰度值的像素点所占比例之和   即背景部分的比例u0tmp += j * pixelPro[j];  //背景部分 每个灰度值的点的比例 *灰度值w1=1-w0;u1tmp=gray_sum/pixelSum-u0tmp;u0 = u0tmp / w0;              //背景平均灰度u1 = u1tmp / w1;              //前景平均灰度u = u0tmp + u1tmp;            //全局平均灰度deltaTmp = (float)(w0 *w1* (u0 - u1)* (u0 - u1)) ;if (deltaTmp > deltaMax){deltaMax = deltaTmp;threshold = (uint8)j;}if (deltaTmp < deltaMax){break;}}return threshold;
}
/*end  大津法比赛   end*//*begin  大津法学习   begin*/
//------------------摄像头参数--------------//
uint8 image_threshold = 46;  //图像阈值 0~255
uint8 dis_image[60][80];uint8 otsuThreshold(uint8 *image, uint16 width, uint16 height)
{#define GrayScale 256int pixelCount[GrayScale] = {0};//每个灰度值所占像素个数float pixelPro[GrayScale] = {0};//每个灰度值所占总像素比例int i,j;int Sumpix = width * height;   //总像素点uint8 threshold = 0;uint8* data = image;  //指向像素数据的指针//统计灰度级中每个像素在整幅图像中的个数for (i = 0; i < height; i++){for (j = 0; j < width; j++){pixelCount[(int)data[i * width + j]]++;  //将像素值作为计数数组的下标//   pixelCount[(int)image[i][j]]++;    若不用指针用这个}}float u = 0;for (i = 0; i < GrayScale; i++){pixelPro[i] = (float)pixelCount[i] / Sumpix;   //计算每个像素在整幅图像中的比例u += i * pixelPro[i];  //总平均灰度}float maxVariance=0.0;  //最大类间方差float w0 = 0, avgValue  = 0;  //w0 前景比例 ,avgValue 前景平均灰度for(i = 0; i < 256; i++)     //每一次循环都是一次完整类间方差计算 (两个for叠加为1个){w0 += pixelPro[i];  //假设当前灰度i为阈值, 0~i 灰度像素所占整幅图像的比例即前景比例avgValue  += i * pixelPro[i];float variance = pow((avgValue/w0 - u), 2) * w0 /(1 - w0);    //类间方差if(variance > maxVariance){maxVariance = variance;threshold = (uint8)i;}}return threshold;
}/*end  大津法学习   end*///图像二值化
//0 - 255
//黑 - 白
void Set_image_towvalues(uint8 value)
{uint8 temp_valude;//暂存灰度值for(uint8 i = 0;i < MT9V03X_H;i++)//高{for(uint8 j = 0;j < MT9V03X_W;j++)//宽{temp_valude = mt9v03x_image[i][j];if(temp_valude < value){mt9v03x_image_BandW[i][j] = 0;//黑}else{mt9v03x_image_BandW[i][j] = 255;//白}}}
}

images.h

#ifndef CODE_IMAGES_H_
#define CODE_IMAGES_H_extern uint8  mt9v03x_image_BandW[MT9V03X_H][MT9V03X_W];void Set_image_towvalues(uint8 value);
uint8 otsuThreshold(uint8 *image, uint16 width, uint16 height);
uint8 otsuThreshold_fast(uint8 *image);
#endif /* CODE_IMAGES_H_ */

但是不优化大津法的代码,图像处理时间较长,所以大家又将“大津法”优化成了“快速大津法”,代码也在上面公布了,照我如下调用即可。

cpu1.c

void core1_main(void)
{disable_Watchdog();                     // 关闭看门狗interrupt_global_enable(0);             // 打开全局中断// 此处编写用户代码 例如外设初始化代码等mt9v03x_init();//初始化摄像头// 此处编写用户代码 例如外设初始化代码等cpu_wait_event_ready();                 // 等待所有核心初始化完毕while (TRUE){// 此处编写需要循环执行的代码TFT180_SHOW();if(mt9v03x_finish_flag)     //一幅图像完全采集完毕后,再进行图像的显示判断和显示{//Set_image_towvalues(150); //固定阈值二值化BandW_threshold = otsuThreshold_fast(mt9v03x_image[0]);//大津法得到动态阈值BandW_thresholdSet_image_towvalues(BandW_threshold); //动态阈值二值化得到二维数组mt9v03x_image_BandWtft180_displayimage03x(mt9v03x_image_BandW[0],MT9V03X_W,MT9V03X_H);//显示二值化后的图像mt9v03x_finish_flag = 0;//图像显示完成后才对标志位清零}// 此处编写需要循环执行的代码}
}

通过调用大津法处理函数,将原始图像进行动态阈值二值化处理,也是会在显示屏上得到黑白图像,固定阈值二值化和动态阈值二值化处理哪个效果好,还得看实际情况。

相关文章:

智能汽车竞赛摄像头处理(3)——动态阈值二值化(大津法)

前言 &#xff08;1&#xff09;在上一节中&#xff0c;我们学习了对图像的固定二值化处理&#xff0c;可以将原始图像处理成二值化的黑白图像&#xff0c;这里面的本质就是将原来的二维数组进行了处理&#xff0c;处理后的二维数组里的元素都是0和255两个值。 &#xff08;2…...

BGP协议

1.BGP相关概念 1.1 BGP的起源 不同自治系统&#xff08;路由域&#xff09;间路由交换与管理的需求推动了EGP的发展&#xff0c;但是EGP的算法简单&#xff0c;无法选路&#xff0c;从而被BGP取代。 自治系统&#xff1a;&#xff08;AS&#xff09; IGP&#xff1a;自治系统…...

一个完整工作流管理系统的组成部分

一个完整工作流管理系统的组成部分 一个完整的工作流管理系统通常由工作流引擎、工作流设计器、流程操作、工作流客户端程序、流程监控、表单设计器、与表单的集成以及与应用程序的集成八个部分组成。 一、工作流组成 1. 工作流引擎 工作流引擎作为工作流管理系统的核心部分&…...

鱼和熊掌如何兼得?一文解析RDS数据库存储架构升级

在2023年云栖大会上&#xff0c;阿里云数据库产品事业部负责人李飞飞在主题演讲中提到&#xff0c;瑶池数据库推出“DB存储”一体化能力&#xff0c;结合人工智能、机器学习、存储等方法和创新能力&#xff0c;实现Buffer Pool Extension能力和智能冷温热数据分层能力。在大会的…...

中科大计网学习记录笔记(五):协议层次和服务模型

前言&#xff1a; 学习视频&#xff1a;中科大郑烇、杨坚全套《计算机网络&#xff08;自顶向下方法 第7版&#xff0c;James F.Kurose&#xff0c;Keith W.Ross&#xff09;》课程 该视频是B站非常著名的计网学习视频&#xff0c;但相信很多朋友和我一样在听完前面的部分发现信…...

同构异机迁移方案2_目标服务器仅安装数据库软件scp物理文件

源端和目标端的数据库版本需要保持一致&#xff0c;补丁版本可以不一致&#xff0c;目标端磁盘空间不能小于源端空间&#xff0c;目标端只需要安装 Oracle 软件即可。 特别说明&#xff1a;本文档案例Oracle的安装路径不同&#xff0c;数据目录一致&#xff0c;采用scp的方式实…...

华为机考入门python3--(6)牛客6-质数因子

分类&#xff1a;质数、素数 知识点&#xff1a; 取余符号% 5%3 2 取整符号// 5//3 1 list中int元素转str map(str, list) 题目来自【牛客】 def prime_factors(n): """ 输入一个正整数n&#xff0c;输出它的所有质因子&#xff08;重复的也…...

11月最新版付费进群源码自动定位+开源

Nginx 1.22.1 php5.6 mysql5.6 数据库配置&#xff1a;/config/database.php 配置后台域名&#xff1a;config/extra/ip.php 设置伪静态thinkphp 后台账号88886666 密码12345 代码结构 关键代码剖析 <?php // ----------------------------------------------------…...

Python算法题集_旋转图像

Python算法题集_旋转图像 题目48&#xff1a;旋转图像1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【矩阵复本】2) 改进版一【矩阵转置矩阵反转】3) 改进版二【四值旋转】 4. 最优算法 题目48&#xff1a;旋转图像 本文为Python算法题集之一…...

[ChatGPT们】ChatGPT 如何辅助编程初探

主页&#xff1a;元存储的博客 全文 9000 字&#xff0c; 原创请勿转载。 我没有写过诗&#xff0c;但有人说我的代码像诗一样优雅 -- 雷军 图片来源&#xff1a;https://www.bilibili.com/video/BV1zL411X7oS/ 1. 引言 作为一个程序员&#xff0c;我们不仅要熟悉各种编程语…...

深入Spring MVC的工作流程

深入Spring MVC的工作流程 在Spring MVC的面试问题中&#xff0c;常常被询问到的一个问题。Spring MVC的程序中&#xff0c;HTTP请求是如何从开始到结束被处理的。为了研究这个问题&#xff0c;我们将需要深入学习一下Spring MVC框架的核心过程和工作流程。 1. 启动请求生命周…...

我的数据结构c(给自己用的)

目录 顺序表&#xff1a; 链表&#xff1a; 栈&#xff1a; 队列&#xff1a; 我想在之后的大学数据结构课上需要自己写来做题&#xff0c;但每次都自己写&#xff0c;那太麻烦了&#xff0c;所以我就将这个博客来把所有的C语言的数据结构弄上去&#xff0c; 问我为什么不…...

使用Arcgis对欧洲雷达高分辨率降水数据重投影

当前需要使用欧洲高分辨雷达降水数据&#xff0c;但是这个数据的投影问题非常头疼。实际的投影应该长这样&#xff08;https://gist.github.com/kmuehlbauer/645e42a53b30752230c08c20a9c964f9?permalink_comment_id2954366https://gist.github.com/kmuehlbauer/645e42a53b307…...

[Python] scikit-learn中数据集模块介绍和使用案例

sklearn.datasets模块介绍 在scikit-learn中&#xff0c;可以使用sklearn.datasets模块中的函数来构建数据集。这个模块提供了用于加载和生成数据集的函数。 API Reference — scikit-learn 1.4.0 documentation 以下是一些常用的sklearn.datasets模块中的函数 load_iris() …...

Qt-互斥量-临界区-QMutex-QMutexLocker-QReadWriteLock

文章目录 1.QMutex2.QMutexLocker3.QReadWriteLock 在Qt中&#xff0c;互斥量&#xff08;Mutex&#xff09;是用于同步多线程访问共享资源的一种机制。临界区&#xff08;Critical Section&#xff09;是指一段必须由单个线程执行的代码区域&#xff0c;防止多个线程同时执行这…...

《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述(6)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第4章 PCIe总线概述&#xff08;5&#xff09; 4.1 PCIe总线的基础知识 与PCI总线不同&#xff0c;PCIe总线使用端到端的连接方式&#xff0c;在一条PCIe链路的两端只能各连接一个设备&#xff0c;这两个…...

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台&#xff08;https://lbs.amap.com/&#xff09;**创建应用并申请Key   登录 高德开放平台&#xff0c;进入“控制台”&#xff0c;如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…...

2024年最新幻兽帕鲁服务器搭建教程

玩转幻兽帕鲁服务器&#xff0c;阿里云推出新手0基础一键部署幻兽帕鲁服务器教程&#xff0c;傻瓜式一键部署&#xff0c;3分钟即可成功创建一台Palworld专属服务器&#xff0c;成本仅需26元&#xff0c;阿里云服务器网aliyunfuwuqi.com分享2024年新版基于阿里云搭建幻兽帕鲁服…...

重新配置vue项目时出现的:连接已断开问题

在新机器上配置完node.js、vue-cli&#xff0c;配置了node_modules后&#xff0c;命令行运行vue ui后&#xff0c;出现了如下报错&#xff1a; C:\Users\LEN>vue ui &#x1f680; Starting GUI... &#x1f320; Ready on http://localhost:8000 node:events:496throw e…...

四、Redis之配置文件

redis配置文件的名称 redis.conf 通过命令 find / -name redis.confvim redis.conf通过 : set nu 设置行号: set nonu 取消行号/关键字 搜索关键字: set noh 取消高亮选择4.1 Units 配置大小单位&#xff0c;开头定义了一些基本的度量单位&#xff0c;只支持 bytes&#…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

【java面试】微服务篇

【java面试】微服务篇 一、总体框架二、Springcloud&#xff08;一&#xff09;Springcloud五大组件&#xff08;二&#xff09;服务注册和发现1、Eureka2、Nacos &#xff08;三&#xff09;负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...

[10-1]I2C通信协议 江协科技学习笔记(17个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17...