scratch lenet(1): 读写 pgm 图像文件

文章目录

  • scratch lenet(1): 读写 pgm 图像文件
    • 1. 目的
    • 2. pgm 格式介绍
      • 2.1 概要
      • 2.2 meta 信息
      • 2.3 像素内容
    • 3. 创建 .pgm 文件
    • 4. 使用C语言读取 .pgm 灰度图文件
      • 4.1 实现
      • 4.2 解释
    • 5. 使用C语言保存 .pgm 灰度图文件

1. 目的

最近在 github 上关注了 LLM 的流行库 llama.cpp 和 whisper.cpp 的作者 Georgi Gerganov, 简称 gg 哥。 通过 gg哥关注到了 deepdream 算法作者开源的 deepdream_c 代码。完全用 C89 写成的 deepdream, 编译只需要1秒钟, Windows 和 Linux 都能运行。完全不依赖 PyTorch 和 OpenCV 等框架, 连 C++ 都没使用,非常克制, 可移植性非常高。这个风格和 gg 哥的风格有点像的: 喜欢单一的 .vimrc 文件, 写 ggml 主要放在一个16000行的文件中。打算按照这种风格, 用 C99 标准,不借助外部库, 实现 lenet。

实现过程中难免遇到不熟悉的内容, 因为这是一种“全都自己造”的风格; 没关系, 我会尝试逐一弄懂, 以博客形式分享出来。

这是这系列的第一篇, 分享的是 pgm 图像的读写。用 pgm 格式的原因是, 项目规模非常小的时候, BMP 的编解码都显得过于复杂, 目前只需要灰度图的前提下, pgm 足够使用, 而 Linux KDE 下的默认图像查看器, 完全可以查看 pgm 格式。

2. pgm 格式介绍

2.1 概要

pgm 里的 g 表示 gray, 是灰度图, 数据范围通常是 0 到 255。

pgm 文件,以二进制格式进行存储, 不过它的内容其实是 文本 + 二进制混合的:meta 信息是文本, 图像像素内容是二进制。

2.2 meta 信息

第一行是 P5 两个字符。
第二行是空格分隔的两个整数, 分别表示图像宽度,高度。
第三行是一个整数, 表示像素最大取值, 通常是255。

这些信息都是文本格式写入, 也就是用 fprintf 写入, fscanf 读取。也可以用记事本查看 .pgm 文件。

2.3 像素内容

用二进制形式存储, row-major。
也就是说, 用 fread 读取, 用 fwrite 写入。

3. 创建 .pgm 文件

我的开发环境是 Ubuntu 22.04, KDE 桌面, 也可以叫做 “KUbuntu”. 不过我认为 KUbuntu 的叫法很奇怪,Ubuntu 并不限制你用什么桌面, 安装了 KDE 之后也可以安装 Cinamon, XFCE 等桌面, 如果安装的不是 Ubuntu 而是 OpenSude, Manjaro 等 Linux 发行版, 也可以安装 KDE。

我使用 KDE 里的 KolourPaint 这个绘图软件,制作一张手写数字“3”的图像:

保存图像, 选择 .pgm 格式:

4. 使用C语言读取 .pgm 灰度图文件

4.1 实现

简单起见, 我们直接读取刚刚用 KolourPaint 生成的 3.pgm 文件。你也可以直接下载:
3.pgm:一张绘图图,格式为pgm

uchar g_image[784];
void read_pgm_image()
{FILE* fin = fopen("3.pgm", "rb");char magic[3];int width, height;int nscan = fscanf(fin, "%2s\n%d %d\n255\n", magic, &width, &height);if (nscan == 3 && magic[0] == 'P' && magic[1] == '5'){fread(g_image, 784, 1, fin);}fclose(fin);
}

如果打算读取其他 .pgm 文件, 可以自行重构, 其中 784 等于 28 * 28, 是图像大小。

4.2 解释

FILE* fin = fopen("3.pgm", "rb"); 是以二进制格式打开文件 3.pgm.

读取第一行的 P5 两个字符时, 使用了

char magic[3];

而不是

char magic[2];

原因是避免内存越界, 具体分析见 Cracking C++(13): 读取不超过n个字符。

int nscan = fscanf(fin, "%2s\n%d %d\n255\n", magic, &width, &height); 是读取 meta 信息,是以文本方式读取。

fread(g_image, 784, 1, fin); 是读取像素内容, 是按二进制格式读取。

5. 使用C语言保存 .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);
}

scratch lenet(1): 读写 pgm 图像文件相关推荐

  1. scratch lenet(9): C语言实现tanh的计算

    文章目录 1. 目的 2. tanh ⁡ ( x ) \tanh(x) tanh(x) 的 naive 实现 2.1 数学公式 2.2 naive 实现 3. tanh ⁡ ( x ) \tanh(x ...

  2. scratch lenet(4): 开根号的C语言实现

    文章目录 1. 目的 2 二分法求开根号 2.1 数学原理:单调函数 2.2 代码实现:注意事项 2.3 代码实现: 完整代码 2.4 验证结果 3. 牛顿法 3.1 数学原理:迭代求解 3.2 代码 ...

  3. C++读写BMP图像文件

    bmp格式图像分为四个部分: 1.位图文件头(Bitmap File Header) ,大小:14字节 主要包括位图文件大小和位图文件类型信息. 2.位图信息头(Bitmap Info Header) ...

  4. java import imageio_java数字图像处理基础使用imageio写图像文件示例

    一个BufferedImage的像素数据储存在Raster中,ColorModel里面储存颜色空间,类型等信息,当前Java只支持一下三种图像格式- JPG,PNG,GIF,如何向让Java支持其它格 ...

  5. Java数字图像处理基础知识 - 必读

    转载自:http://blog.csdn.net/jia20003/article/details/7279667 写了很多篇关于图像处理的文章,没有一篇介绍Java 2D的图像处理API,文章讨论和 ...

  6. 完全手册-MATLAB使用详解:基础、开发及工程应用

    [书名]完全手册-MATLAB使用详解:基础.开发及工程应用 [作者]董霖 编著 [ISBN]978-7-121-07397-7 [出版社]电子工业出版社 [出版日期]2009年1月 [内容简介] M ...

  7. OpenCV读写图像文件解析

    OpenCV读写图像文件解析 imdecode 从内存中的缓冲区读取图像. C++: Mat imdecode(InputArray buf, int flags) C++: Mat imdecode ...

  8. pbmplus-图像文件格式转换包与PBM/PGM/PPM 格式图像文件

    pbmplus-图像文件格式转换包 PBMPLUS 是一个用于多种图像类型和可移植格式(portble formats)之间来回转换的工具包.官方网站主页介绍,和下载地址在这里.该工具的想法是如果你想 ...

  9. 图像文件的读写和转换——BMP转YUV

    文章目录 数据压缩实验(二) 一.BMP文件格式分析 二.YUV文件格式分析 1.概述 2.YUV采样 Planar平面格式 RGB转YUV 三.实验过程 1.实验思路 2.实验代码 四.实验结果 数 ...

最新文章

  1. 【css】如何实现响应式布局
  2. Redis操作Set类型
  3. AngularJS+Jersey下载excel
  4. 使用 PSD Validator 在线校验 PSD 文件的质量
  5. 华为P30/P30 Pro细节再曝光:3.5mm耳机插孔和红外遥控各占其一
  6. react 轮播组件
  7. linux处理除零异常,linux – 如何在x86程序集中使用中断来触发被零除错误异常?...
  8. 腾讯想拿到Big Data资源,8h删抓紧时间!!
  9. matlab练习程序(倾斜校正,透视变换)
  10. 数据库事务的特性(ACID)
  11. c语言三位数倒序,C语言求助!一个三位数的逆序数,总是编不对
  12. hdu 5745 la vie en rose
  13. 2021 年 15 款适用于 PC 和 Mac 的最佳 Android 模拟器
  14. android网络诊断服务(ping网络的实现,判断网络是否可用)
  15. 当前 .NET SDK 不支持将 .NET Core 2.2 设置为目标。请将 .NET Core 2.1 或更低版本设置。
  16. IWAM账号密码不一致引起IIS无法处理ASP文件
  17. 基于Java--获取城市天气与给手机发送验证码--HTTP协议实践
  18. 数据分析师成长路径-第二阶段
  19. 华为鸿蒙电视配置,华为旗下荣耀智慧屏PRO55英寸AI摄像头鸿蒙系统4K超清电视机...
  20. Python 简易版小工具 | 计算天数

热门文章

  1. MySQL-比较两个表不同的数据
  2. 获晨晖资本领投的1.5亿元A轮融资,犀思云想为企业用户提供NAAS服务
  3. 支撑腾讯直播百亿请求的 Redis 集群是如何工作的
  4. 考研英语 - word-list-42
  5. 【机器学习】Reinforcement Learning-强化学习学习笔记
  6. 2 监督学习与非监督学习
  7. ROS---进行建图或者move_base路径规划时出现打滑现象(雷达匹配不上地图)的解决方法 附gmapping建图配置参数
  8. HTTP请求流程(超级详细)
  9. 银行票据业务如何实现BI赋能
  10. 用户即将一分钟后关闭计算机,win10即将注销您的登陆怎么办_win10将在一分钟后注销的解决方法...