IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 大津法的C语言实现 -> 正文阅读

[数据结构与算法]大津法的C语言实现

大津法

大津法又叫最大类间方差法,由日本学者大津展之在1979年提出的对图像二值化高效算法.

对于一帧灰度图像,一个像素由八位0~255表示,单片机是很难实时处理这么大的数据的,我们需要通过一个阈值将其二值化,小于这个阈值的像素判定黑色,大于的判定白色.

摄像头视野内,最主要的颜色就是赛道白色和蓝布蓝色,对于总钻风获取的灰度图也可以通过灰度直方图来区分,下图是photoshop提取的灰度直方图,可以非常明显地看到两个峰,我们需要找到一个值(一般在两峰之间),使这个值两边间类方差最大.
智能车赛道灰度直方图

原理

将直方图在一阈值分割为两组,使这两组之间方差最大.

对一张图像

  • m m m: 灰度值为 1 ~ m 1\sim m 1m
  • n i n_i ni?: 灰度值 i i i的像素数量
  • N N N: 像素总数 N = ∑ i = 0 n x i N=\sum_{i=0}^n x_i N=i=0n?xi?
  • p i p_i pi?: 各级灰度概率 p i = n i N p_i=\frac{n_i}{N} pi?=Nni??

用一个灰度阈值 k k k将像素分为前景 C 0 = ∣ 1 ~ k ∣ C_0=|1 \sim k| C0?=1k和背景 C 1 = ∣ k + 1 ~ m ∣ C_1=|k+1\sim m| C1?=k+1m两组,得到

  • ω 0 \omega_0 ω0?: 前景 C 0 C_0 C0?组像素出现的概率 ω 0 = ω ( k ) = ∑ i = 1 k p i \omega_0=\omega(k)=\sum_{i=1}^kp_i ω0?=ω(k)=i=1k?pi?
  • μ 0 \mu_0 μ0?: 前景 C 0 C_0 C0?组灰度平均值 μ 0 = μ ( k ) = μ ( k ) ω ( k ) = ∑ i = 1 k i ? p i ω 0 \mu_0=\mu(k)=\frac{\mu(k)}{\omega(k)}=\sum_{i=1}^k\frac{i\cdot p_i}{\omega_0} μ0?=μ(k)=ω(k)μ(k)?=i=1k?ω0?i?pi??
  • ω 1 \omega_1 ω1?: 背景 C 1 C_1 C1?组像素出现的概率 ω 1 = 1 ? ω 0 = ∑ i = k + 1 m p i \omega_1=1-\omega_0=\sum_{i=k+1}^m p_i ω1?=1?ω0?=i=k+1m?pi?
  • μ 1 \mu_1 μ1?: 背景 C 1 C_1 C1?组灰度平均值 μ 1 = μ ? μ ( k ) 1 ? ω ( k ) = ∑ i = k + 1 m i ? p i ω 1 \mu_1=\frac{\mu-\mu(k)}{1-\omega(k)}=\sum_{i=k+1}^m\frac{i\cdot p_i}{\omega_1} μ1?=1?ω(k)μ?μ(k)?=i=k+1m?ω1?i?pi??
  • μ \mu μ: 整个图像灰度平均值 μ = ω 0 μ 0 + ω 1 μ 1 \mu=\omega_0\mu_0+\omega_1\mu_1 μ=ω0?μ0?+ω1?μ1?
  • δ 2 \delta^2 δ2: 两组间方差 δ 2 = ω 0 ( μ 0 ? μ ) 2 + ω 1 ( μ 1 ? μ ) 2 = ω 0 ω 1 ( μ 1 ? μ 0 ) 2 \delta^2=\omega_0(\mu_0-\mu)^2+\omega_1(\mu_1-\mu)^2=\omega_0\omega_1(\mu_1-\mu_0)^2 δ2=ω0?(μ0??μ)2+ω1?(μ1??μ)2=ω0?ω1?(μ1??μ0?)2

我们需要做的是求出一个 k k k值,使得两组间方差 δ 2 \delta^2 δ2最大,这就是图像进行二值分割的阈值,可以得到最理想的效果.

实现

定义灰度直方图数组grayhist,灰度有16级,32级,64级三种级次,而灰度图一个像素用8位数据(0~255)表示,64级灰度即把256分为64级,故用嵌套for循环遍历整个图像,读取其值再除以4得到灰度值(右移2位),同时求总灰度值和像素数量,这里步长为形参step并传入10可节省计算量.

for~for~
temp_this_pixel = img[n] >> 2;
if (temp_this_pixel < 64)
    grayhist[temp_this_pixel]++;
gray_sum_all += temp_this_pixel;
px_sum_all++;

接下来用迭代法求取令两组间方差fCal_var最大的k

for
    w0 = px_sum / px_sum_all;
    w1 = 1 - w0;
    u0 = gray_sum / px_sum;
    u1 = (gray_sum_all - gray_sum) / (px_sum_all - px_sum);
    fCal_var = w0 * w1 * (u0 - u1) * (u0 - u1);
// 找到使方差最大的k值
if (fCal_var > fTemp_maxvar)
    fTemp_maxvar = fCal_var;
    temp_best_th = k;

这样求得的 k k k值是64灰度级次下的k,需要返回256灰度下的阈值return k*4.

这样得到的阈值可以用if和else来进行二值化了

if(temp >= threshold)
    bitmap = 1;
else
    bitmap = 0;

代码

int img_otsu(uint8_t *img, uint8_t img_v, uint8_t img_h)
{
    uint8_t grayhist[64] = {0}; //灰度直方图
    uint16_t px_sum_all = 0;             //像素点总数
    uint32_t gray_sum_all = 0;           //总灰度积分
    uint16_t px_sum = 0;                 //像素点数量
    uint32_t gray_sum = 0;               //灰度积分
	float fCal_var;

    //生成:1. 灰度直方图 2. 像素点总数 3. 总灰度积分
    for (int i = 0; i < img_v; i += 10)
    {
        for (int j = 0; j < img_h; j += 10)
        {
            temp_this_pixel = img[i * img_h + j] /4;
            grayhist[temp_this_pixel]++;
            gray_sum_all += temp_this_pixel;
            px_sum_all++;
        }
    }
    //迭代求得最大类间方差的阈值
    float fTemp_maxvar = 0;
    uint8_t temp_best_th = 0;
    uint8_t temp_this_pixel = 0;
    float u0, u1, w0, w1;
    for (uint8_t k = 0; k < 64; k++)
    {
        px_sum += grayhist[k];       //该灰度及以下的像素点数量
        gray_sum += k * grayhist[k]; //该灰度及以下的像素点的灰度和
        w0 = 1.0 * px_sum / px_sum_all;
        w1 = 1.0 - w0;
        u0 = 1.0 * gray_sum / px_sum;
        u1 = 1.0 * (gray_sum_all - gray_sum) / (px_sum_all - px_sum);
        fCal_var = w0 * w1 * (u0 - u1) * (u0 - u1);
        if (fCal_var > fTemp_maxvar)
        {
            fTemp_maxvar = fCal_var;
            temp_best_th = k;
        }
    }
    return temp_best_th  * 4;
}

请添加图片描述

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:24:47  更:2022-04-15 00:29:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:38:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码