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

news/2024/11/18 0:21:48/

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 文件。

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);
}

http://www.ppmy.cn/news/438165.html

相关文章

星界边境联机服务器未响应,星界边境Starbound联机注意事项

好吧,这里其实给大家分享一些比较逗比的《星界边境Starbound》联机时应该注意的一些建议,不过如果玩家们有不会联机的也可以参考文中中关于联机的方法教程! 【1】爱人爱己,别安装MOD,飞船MOD啥的别人都上不了你飞船。 …

基于 QT 开发的联机五子棋

🌸 前言 个人博客:小北北北北的秘密小窝 本文链接:https://www.seny.xyz/archives/gobang Github:https://github.com/senyucci/Gobang 最近闲来无事优化了一下上学期的 C 课程设计,在原来的本地五子棋对战的基础上结合…

计算机桌面联机,如何设置电脑联机共享(详细图解)

在需要传文件,但又没有U盘的情况下怎么办呢?这时候就需要用到电脑联机共享文件了,下面好易学小编将为大家介绍一下怎么设置电脑联机共享。 怎么设置电脑联机共享 1在桌面找到“我的电脑”图标,双击鼠标进入。 2找到左下角的“网络…

hamachi联机_hamachi怎么进行联机_hamachi联机流程详解

hamachi怎么进行联机_hamachi联机流程详解 时间:2020-08-05 12:05:20 责任编辑:李尬尬 许多玩友们想联机玩游戏,不知道怎么进行联机,那么今天小编就讲解hamachi怎么联机的操作步骤哦,希望能够帮助到大家呢。 下载并安装hamachi: 记得安装的时候选择“简体中文版”哦~ 如果…

php联机代码,噬血代码无法联机解决办法

下面给大家带来噬血代码无法联机解决办法,有些玩家遇到了噬血代码联机失败的问题,那么应该怎么解决呢 ? 一起来看看吧。 联机失败解决方法介绍 多人连线不稳定的问题许多人由上一次更新后就开始发生,大多人遇到的是连结或是接收时偶有失败的…

rust 局域网联机_腐蚀rust搭建Rust服务器及联机教程

Steam游戏后台服务器管理程序下载 但凡是Steam上的游戏,想要搭建游戏服务器都必须要有一个SteamCMD命令行的执行程序包,该程序的目的是快速下载和更新本地的游戏服务器程序。 下载地址:https://steamcdn-a.akamaihd.net/client/installer/steamcmd.zip 下载完成后将该压缩包…

HTML多人联机游戏,前端实现双人联机版俄罗斯方块小游戏2(实现双人联机)

基于websocket实现双人联机俄罗斯方块游戏,逻辑思路整理如下 思路整理 1.游戏开始,双方都收到start消息,同时调用start方法 2.start方法中,调用game.init方法,同时发送init消息给server,server收到后会转发给另一个游戏玩家 3.另一个游戏玩家在remote.js中接收init,会驱动…

hamachi联机_hamachi怎么联机 蛤蟆吃联机教程

类型:编程辅助大小:8.0M语言:中文 评分:10.0 标签: 立即下载 hamachi也即蛤蟆吃是一款虚拟局域网软件,您可以使用蛤蟆吃与外网的机友进行联机玩游戏的哦,这样您可以很方便您和其他不在同一个局域…