scratch lenet(2): C语言实现图像直方图的计算

news2024/9/27 21:22:50

scratch lenet(2): C语言实现图像直方图的计算

1. 目的

用 C 语言实现 uint8 类型图像(单通道)的直方图计算。不涉及直方图均衡化。

2. 什么是图像直方图

2.1 统计得到图像直方图

通常是对于单通道的灰度图而言的。像素范围是 [0, 255], 统计每个像素出现的次数, 存放到一个 256 元素的一维数组 hist 中。换言之, hist 是一个统计结果。

void calculate_histogram(uchar* image, int width, int height, int hist[256])
{
    memset(hist, 0, 256 * sizeof(int));
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int idx = i * width + j;
            uchar v = image[idx];
            hist[v]++;
        }
    }

    printf("[DEBUG] print histogram:\n");
    for (int i = 0; i < 256; i++)
    {
        if (hist[i] > 0)
        {
            printf("gray value=%d, occurance cnt=%d\n", i, hist[i]);
        }
    }
}

2.2 可视化:直方图转为图像表示

所谓可视化直方图, 是说把原本是1维的、256 元素的数组 hist[256], 转为2维图像。 图像宽度是256, 高度是 max(hist[i]).

在计算机视觉中, 白色对应到255,黑色对应到0.

在计算机视觉的C/C++实现中,图像坐标原点是左上角, 而数学中的绘制图像曲线,左下角才是原点。

于是, 需要在获取图像坐标点 P(i, j) 时, 执行坐标变换,得到以左下角为原点时的坐标 P'(inv_i, j)

P' 的取值为 0 或 255: 如果比 hist[j] 要大(坐标点更高),则为255; 否则为0.

typedef struct GrayImage
{
    int width;
    int height;
    uchar* data;
} GrayImage;

GrayImage create_gray_image_from_histogram(int hist[256])
{
    // draw histogram as image
    int max_hist = 0;
    for (int i = 0; i < 256; i++)
    {
        if (hist[i] > max_hist)
        {
            max_hist = hist[i];
        }
    }
    int hist_height = max_hist;
    int hist_width = 256;
    uchar* image = (uchar*)malloc(hist_height * hist_width);
    for (int i = 0; i < hist_height; i++)
    {
        int inv_i = hist_height - 1 - i;
        for (int j = 0; j < hist_width; j++)
        {
            int idx = i * hist_width + j;
            if (inv_i > hist[j])
            {
                image[idx] = 255;
            }
            else
            {
                image[idx] = 0;
            }
        }
    }

    GrayImage hist_image;
    hist_image.width = hist_width;
    hist_image.height = hist_height;
    hist_image.data = image;
    return hist_image;
}

2.3 可视化:保存结果图

使用 .pgm 格式。使用 scratch lenet(1): 读写 pgm 图像文件 中实现的 .pgm 图像读写函数。

void write_pgm_image(uchar* image, int width, int height, const char* filename)
{
    FILE* fout = fopen(filename, "wb");
    fprintf(fout, "P5\n%d %d\n255\n", width, height);
    fwrite(image, width * height, 1, fout);
    fclose(fout);
}

3. 完整代码和结果

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char uchar;

void write_pgm_image(uchar* image, int width, int height, const char* filename)
{
    FILE* fout = fopen(filename, "wb");
    fprintf(fout, "P5\n%d %d\n255\n", width, height);
    fwrite(image, width * height, 1, fout);
    fclose(fout);
}

void* memset(void* s, int c, size_t n)
{
    char x = c & 0xff;
    char* p = (char*)s;
    for (int i = 0; i < n; i++)
    {
        p[i] = n;
    }
    return s;
}

void calculate_histogram(uchar* image, int width, int height, int hist[256])
{
    memset(hist, 0, 256 * sizeof(int));
    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            int idx = i * width + j;
            uchar v = image[idx];
            hist[v]++;
        }
    }

    printf("[DEBUG] print histogram:\n");
    for (int i = 0; i < 256; i++)
    {
        if (hist[i] > 0)
        {
            printf("gray value=%d, occurance cnt=%d\n", i, hist[i]);
        }
    }
}

typedef struct GrayImage
{
    int width;
    int height;
    uchar* data;
} GrayImage;

GrayImage create_gray_image_from_histogram(int hist[256])
{
    // draw histogram as image
    int max_hist = 0;
    for (int i = 0; i < 256; i++)
    {
        if (hist[i] > max_hist)
        {
            max_hist = hist[i];
        }
    }
    int hist_height = max_hist;
    int hist_width = 256;
    uchar* image = (uchar*)malloc(hist_height * hist_width);
    for (int i = 0; i < hist_height; i++)
    {
        int inv_i = hist_height - 1 - i;
        for (int j = 0; j < hist_width; j++)
        {
            int idx = i * hist_width + j;
            if (inv_i > hist[j])
            {
                image[idx] = 255;
            }
            else
            {
                image[idx] = 0;
            }
        }
    }

    GrayImage hist_image;
    hist_image.width = hist_width;
    hist_image.height = hist_height;
    hist_image.data = image;
    return hist_image;
}

int main()
{
    uchar image[8 * 8] = {
        52, 55, 61, 66, 70, 61, 64, 73,
        63, 59, 55, 90, 109, 85, 69, 72,
        62, 59, 68, 113, 144, 104, 66, 73,
        63, 58, 71, 122, 154, 106, 70, 69,
        67, 61, 68, 104, 126, 88, 68, 70,
        79, 65, 60, 70, 77, 68, 58, 75,
        85, 71, 64, 59, 55, 61, 65, 83,
        87, 79, 69, 68, 65, 76, 78, 94
    };
    int width = 8;
    int height = 8;
    int hist[256] = { 0 };

    calculate_histogram(image, width, height, hist);
    GrayImage hist_image = create_gray_image_from_histogram(hist);
    write_pgm_image(hist_image.data, hist_image.width, hist_image.height, "histogram.pgm");
    free(hist_image.data);
}

运行结果

在这里插入图片描述

4. References

  1. 直方图均衡化(HE)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

提高错误日志处理效率!使用Python和钉钉机器人实现自动告警聚合

1、背景 日志是非常重要的信息资源。它们记录了应用程序的运行状态、错误和异常情况&#xff0c;帮助我们了解系统的健康状况以及发现潜在的问题。为了高效地管理和分析日志数据&#xff0c;许多组织采用了Elasticsearch、Logstash和Kibana&#xff08;ELK&#xff09;堆栈作为…

Eclipse Krazo(Jakarta MVC)的使用

文章目录 背景Jakarta MVC规范Eclipse Krazo使用前的思考全局配置Controller示例返回View的三种写法View中用到的Model如何设值&#xff1f;View中如何获取Model中的值&#xff1f; 参数校验防止CSRFKrazo是如何实现的呢&#xff1f;如何生成csrf的token&#xff1f;如何校验cs…

开源赋能,决胜未来 — 参加原子全球开源峰会有感

目录 文章目录 目录前言开源决胜未来&#xff1a;闭源摧毁 UNIX&#xff0c;开源成就 Linux开源创新&#xff1a;软硬件协同&#xff0c;共建开源生态 前言 开源原子基金会作为国内首家开源基金会组织&#xff0c;由其主办的首届 “开放原子全球开源峰会” 也是第一次被冠以 “…

干货文:Mac 中 .bash_profile 和 .zshrc 的区别

如果你想在 Mac OS 中配置 MySQL 的环境变量&#xff0c;在 .zshrc 文件中添加如下内容&#xff1a; # 设置 mysql 的路径 export MYSQL_HOME/usr/local/mysql/bin# 将 MYSQL_HOME 添加到 PATH 中 export PATH$HOME/bin:/usr/local/bin:$MYSQL_HOME:$PATH# 解决需要 source 才…

硬件【9】详解二极管钳位电路

文章目录 1 概述1.1 正向钳位电路1.2 偏置正向钳位电路 1 概述 在之前的 二极管限幅电路 一文中&#xff0c;我们学习了二极管限幅电路&#xff0c;该电路可以削掉一部分信号&#xff0c;但不会影响剩余信号。今天&#xff0c;我们将学习另一种基于二极管的电路&#xff0c;该…

搭建环境【2】windows主机和ubuntu互传文件的4种方法

我的ubuntu系统是安装在 VMware 虚拟机中的&#xff0c;两者之间经常要互传文件&#xff0c;下面介绍4种常用的互传文件方法。 1. 共享文件夹方式互传 在虚拟机中需要开启共享文件夹的功能。首先虚拟机中的ubuntu要求是已经开机了的状态&#xff0c;然后进行设置&#xff1a;…

Vue2封装一个全局通知组件并发布到NPM

✍&#x1f3fc;作者&#xff1a;周棋洛&#xff0c;计算机学生 ♉星座&#xff1a;金牛座 &#x1f3e0;主页&#xff1a;点击查看更多 &#x1f310;关键&#xff1a;vue2 组件封装 npm发包 文章目录 1. 前言 &#x1f343;2. 我为什么要封装通知插件 ❓3. 初始化vue空项目 &…

B047-cms02-高级查询 删除 添加 修改

目录 高级查询页面准备下拉框显示文章类型ArticleController用jstl和el表达式取值展示 高级查询参数ArticleQuery 高级查询页面发送请求导入jquery.jdirk.js在jquery下引用绑定按钮发送请求高级查询sql 绑定删除事件绑定事件拿到标签id值准备模态框来自xmind弹出删除模态框绑定…

matlab不显示子图刻度并调整子图间距

matlab中在使用subplot函数画图时&#xff0c;尤其是做emd分解查看IMF时&#xff0c; 正常画图的代码及结果如下&#xff1a; figure for i 1:size(imf_norm,1)subplot(7,1,i)plot(imf_norm(i,:))ylabel(IMFstring(i)) end其中imf_norm为分解得到的imfs 效果图&#xff1a; …

python里apply用法_Python apply函数的用法

Python编程语言Python 是一种面向对象、解释型计算机程序设计语言&#xff0c;由Guido van Rossum于1989年底发明&#xff0c;第一个公开发行版发行于1991年。Python语法简洁而清晰&#xff0c;具有丰富和强大的类库。它常被昵称为胶水语言&#xff0c;它能够把用其他语言制作的…

HDL抽象等级 仿真模型 网表 delay speicfy与sdf

1.HDL 硬件描述语言 抽象分级 HDL这里主要说verilog 在描述硬件电路时分为三个抽象级别 行为级模型&#xff1a;主要用于test bench&#xff0c;着重系统行为和算法&#xff0c;不在于电路实现&#xff0c;不可综合&#xff08;常用描述有initial&#xff0c;fork/join&#…

【MYSQL】MYSQL应用环境,系统特征,储存引擎,应用框架和索引功能的详细讲解

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

DINO-DETR匈牙利匹配与加噪过程学习记录

今天再来回顾一下DINO中匈牙利匹配与损失函数部分&#xff0c;该部分大致与DETR相似&#xff0c;却又略有不同。 为了查看数据方便&#xff0c;博主将num_query改为20&#xff0c;max_select值也为20。 匈牙利匹配过程 首先是数据送入匈牙利匹配中进行标签匹配过程了。 获取…

qt.qpa.plugin: Could not load the Qt platform plugin “xcb“ in

兄弟们看看是不是这个错&#xff1a; QObject::moveToThread: Current thread (0xe5205f0) is not the objects thread (0xa14d0f0). Cannot move to target thread (0xe5205f0)qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/xxx/python3.…

Esp32+Blynk实现云端控制LED开灭

目录 环境配置依赖库安装blynk 基础设置 GPIO 点灯实验 环境配置 依赖库安装 参考 blynk 官方快速上手文档 如果要使用 blynk 提供的环境&#xff0c;我们就必须安装对应的库 选择基于 blynk 且适用于 ESP32 的库并安装到 arduino 上&#xff1a; blynk 基础设置 进入官网并且…

Question1:harbor登录成功,推送镜像失败

denied: requested access to the resource is denied 解决方案 查看用户的权限 Harbor 用户角色权限速查 系统级角色&#xff1a; Harbor 系统管理员&#xff1a;“Harbor 系统管理员”拥有最多的权限。除了上述权限外&#xff0c;“Harbor 系统管理员”还可以列出所有项目、…

一种令人拍案叫绝的 ChatGPT 攻击手段!

公众号关注 “GitHubDaily” 设为 “星标”&#xff0c;每天带你逛 GitHub&#xff01; 最近看到一个非常巧妙的 ChatGPT 攻击手段&#xff0c;跟大家分享一下&#xff0c;也算是做个提醒。 不论你是否懂技术&#xff0c;我都建议你了解一下这种攻击手段&#xff0c;有备无患。…

Golang的trace性能分析

文章目录 一、trace概述二、trace的使用方式代码中trace采集通过pprof采集 三、trace分析细节trace的web界面trace中需要关注的关注GC的频率关注goroutine调度情况关注goroutine的数量理想情况 四、GC分析当前服务GC情况设置GOGC设置GOMEMLIMITGC阈值的讨论GC的特点 五、gorout…

【每日挠头算法题(8)】最后一个单词的长度|重新排列字符串

文章目录 一、最后一个单词的长度思路1&#xff1a;从后往前遍历具体代码如下&#xff1a; 思路2&#xff1a;具体代码如下&#xff1a; 二、重新排列字符串思路具体代码如下&#xff1a; 一、最后一个单词的长度 点我直达~ 思路1&#xff1a;从后往前遍历 从后往前遍历&…

Stable DiffusionAI绘画一键启动整合包

点击"仙网攻城狮”关注我们哦~ 不当想研发的渗透人不是好运维 让我们每天进步一点点 简介 搞了个Stable DiffusionAI绘画整合包&#xff0c;里面有二次元风格、3D风格、真人模型&#xff0c;需要的后台回复“AI绘画”即可获取下载链接,放几个用SD生成的图。 实战 1.下载好…