naivecv的设计与实现(2): 读写gray和rgb图像

图像读写并不是图像处理的核心,仅仅作为调试工具, 是一种手段而非目的。

图像文件格式的选择

正因如此,对gray和rgb图像的读写,存在多种方法。 最常见的三种图像文件格式:

  • bmp
  • png
  • jpg

实际上有更简单的方式:pgm(存储gray图像),ppm(存储gray图像)。
选择 pgm 和 ppm 图像文件格式, 纯粹是因为编解码更为简单, 实现起来更容易。

获取 .ppm 和 .pgm 样例图像文件

https://graphics.stanford.edu/~jowens/223b/examples.html

提供了 lena.ppm, lena.pgm 等图像。

读写 .ppm 和 .pgm 图像文件

代码源自网络,稍加整理。放在 test.cpp 里。

/// @brief Save GRAY image to .pgm file
static void savePGM(const char* filename, int width, int height, uint8_t* image)
{FILE* fout = fopen(filename, "wb");fprintf(fout, "P5\n%d %d\n255\n", width, height);fwrite(image, width * height, 1, fout);fclose(fout);
}/// @brief Load GRAY image from .pgm file
/// The caller should release the memory
static uint8_t* loadPGM(const char* filename, int* out_width, int* out_height)
{FILE* fin = fopen(filename, "rb");char magic[3];int width, height;int nscan = fscanf(fin, "%2s\n%d %d\n255\n", magic, &width, &height);*out_width = width;*out_height = height;uint8_t* image = nullptr;if (nscan == 3 && magic[0] == 'P' && magic[1] == '5'){image = (uint8_t*) malloc(width * height);fread(image, width * height, 1, fin);}fclose(fin);return image;
}/// @brief Save RGB image to .ppm file
static void savePPM(const char* filename, int width, int height, unsigned char* data)
{FILE* fp;char header[20];fp = fopen(filename, "wb");// 写图片格式、宽高、最大像素值fprintf(fp,"P6\n%d %d\n255\n", width, height);// 写RGB数据fwrite(data, width*height*3, 1, fp);fclose(fp);
}/// @brief Load RGB image from .ppm file
/// The caller should release the memory
static uint8_t* loadPPM(const char* filename, int* out_width, int* out_height)
{char header[1024];FILE* fp = NULL;int line = 0;fp = fopen(filename, "rb");// 读取图片格式(例如:"P6")// 高宽在第二行非注释数据while(line < 2){    fgets(header, 1024, fp);if(header[0] != '#'){++line;}}int width, height;sscanf(header,"%d %d\n", &width, &height);*out_width = width;*out_height = height;// 获取最大像素值fgets(header, 20, fp);size_t buf_size = height * width * 3;uint8_t* data = (uint8_t*) malloc(buf_size);// get rgb datafread(data, buf_size, 1, fp);fclose(fp);return data;
}

投入使用

调试是一种手段。 上述 ppm/pgm 图像的读写, 是用于 naivecv 第一个图像处理函数:rgb 转 gray。

NCV_Status ncvConvertColorRGBtoGRAY(const NCV_Image* srcImg, NCV_Image* dstImg);

api 设计

enum {NCV_STATUS_OK = 0,NCV_STATUS_INVALID_PARAM = 1
};
typedef int NCV_Status;typedef enum NCV_PixelFormat {NCV_PIXFMT_GRAY,NCV_PIXFMT_RGB,
} NCV_PixelFormat;typedef struct NCV_Image {NCV_PixelFormat format;int width;int height;uint8_t* plane[4];int pitch[4];
} NCV_Image;

具体实现

具体实现是细节, 这里忽略。

测试

这里贴出测试代码:

int main()
{const char* filename = "/Users/zz/data/lena.ppm";int width, height;uint8_t* ppm_data = loadPPM(filename, &width, &height);// 使用读取到的图像数据进行后续处理NCV_Image rgbImg;rgbImg.format = NCV_PIXFMT_RGB;rgbImg.height = height;rgbImg.width = width;rgbImg.pitch[0] = width * 3;rgbImg.plane[0] = ppm_data;NCV_Image grayImg;grayImg.format = NCV_PIXFMT_GRAY;grayImg.height = height;grayImg.width = width;grayImg.pitch[0] = width;grayImg.plane[0] = (uint8_t*) malloc(height * width);ncvConvertColorRGBtoGRAY(&rgbImg, &grayImg);savePGM("lena.pgm", width, height, grayImg.plane[0]);savePPM("lena.ppm", width, height, rgbImg.plane[0]);// free memoryfree(ppm_data);free(grayImg.plane[0]);return 0;
}

查看 lena.pgm, 符合预期

在这里插入图片描述

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

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

相关文章

设计壁纸时,色彩选择是至关重要的一步

在设计壁纸时&#xff0c;色彩选择是至关重要的一步&#xff0c;它直接影响到壁纸的整体视觉效果和情感传达。以下是一些色彩选择的技巧&#xff0c;帮助你在设计中更好地运用色彩&#xff1a; 一、了解色彩理论 色彩轮&#xff1a; 基本颜色&#xff1a;红、黄、蓝是三原色&am…

二次封装的方法

二次封装 我们开发中经常需要封装一些第三方组件&#xff0c;那么父组件应该怎么传值&#xff0c;怎么调用封装好的组件原有的属性、插槽、方法&#xff0c;一个个调用虽然可行&#xff0c;但十分麻烦&#xff0c;我们一起来看更简便的方法。 二次封装组件&#xff0c;属性怎…

c++多态

1.多态的概念 通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同 的状态。 2.多态的定义及实现 2.1多态的构成条件 多态是在不同继承关系的类对象&#xff0c;去调用同一函数&#xff0c;产生了不同的行为…

docker安装Redis:docker离线安装Redis、docker在线安装Redis、Redis镜像下载、Redis配置、Redis命令

一、镜像下载 1、在线下载 在一台能连外网的linux上执行docker镜像拉取命令 docker pull redis:7.4.0 2、离线包下载 两种方式&#xff1a; 方式一&#xff1a; -&#xff09;在一台能连外网的linux上安装docker执行第一步的命令下载镜像 -&#xff09;导出 # 导出镜像…

【unity游戏开发之InputSystem——07】InputSystem+UGUI配合使用(基于unity6开发介绍)

文章目录 一、InputSystem+UGUI配合使用1、官方文档参考2、切换到新的输入模块二、UGUI中的新输入系统输入模块参数相关1、Send Pointer Hover To Parent2、Move Repeat Delay3、Move Repeat Rate4、XR Tracking Origin5、Deselect On Background CLick6、Pointer Behavior7、S…

国内优秀的FPGA设计公司主要分布在哪些城市?

近年来&#xff0c;国内FPGA行业发展迅速&#xff0c;随着5G通信、人工智能、大数据等新兴技术的崛起&#xff0c;FPGA设计企业的需求也迎来了爆发式增长。很多技术人才在求职时都会考虑城市的行业分布和发展潜力。因此&#xff0c;国内优秀的FPGA设计公司主要分布在哪些城市&a…

汇编基础语法及其示例

1.汇编指令 1.1汇编指令的基本格式 <opcode>{<cond>}{s} <Rd> , <Rn> , <shifter_operand> <功能码>{<条件码>}{cpsr影响位} <目标寄存器> , <第一操作寄存器> , <第二操作数> 注&#xff1a;第一操作寄存器…

Direct2D 极速教程(1) —— 画图形

极速导航 Direct2D 简介创建新项目&#xff1a;001-DrawGraphics弄一个白窗口在窗口上画图 Direct2D 简介 大家在学 WINAPI 的时候的时候有没有想过&#xff0c;怎么在一副窗口上画图呢&#xff1f;大家知道 Windows 系统是 GUI 图形用户界面 系统&#xff0c;以 Graphics 图形…

Linux之详谈——权限管理

目录 小 峰 编 程 ​编辑 一、权限概述 1、什么是权限 2、为什么要设置权限 3、Linux中的权限类别- 4、Linux中文件所有者 1&#xff09;所有者分类&#xff08;谁&#xff09; 2&#xff09;所有者的表示方法 ① u(the user who owns it)&#xff08;属主权限&…

基于金融新闻的大型语言模型强化学习在投资组合管理中的应用

“Financial News-Driven LLM Reinforcement Learning for Portfolio Management” 论文地址&#xff1a;https://arxiv.org/pdf/2411.11059 摘要 本研究探索了如何通过将大语言模型&#xff08;LLM&#xff09;支持的情感分析融入强化学习&#xff08;RL&#xff09;中&#…

K8s运维管理平台 - KubeSphere 3.x 和4.x 使用分析:功能较强,UI美观

目录标题 Lic使用感受优点&#xff1a;优化点&#xff1a; 实操首页项目 | 应用负载 | 配置 | 定制资源定义存储监控告警集群设置 **KubeSphere 3.x** 和 **4.x**1. **架构变化**&#xff1a;2. **多集群管理**&#xff1a;3. **增强的 DevOps 功能**&#xff1a;4. **监控与日…

当AI学会“顿悟”:DeepSeek-R1如何用强化学习突破推理边界?

开篇&#xff1a;一场AI的“青春期叛逆” 你有没有想过&#xff0c;AI模型在学会“推理”之前&#xff0c;可能也经历过一段“中二时期”&#xff1f;比如&#xff0c;解题时乱写一通、语言混搭、答案藏在火星文里……最近&#xff0c;一支名为DeepSeek-AI的团队&#xff0c;就…

Ollama+DeepSeek本地大模型部署

1、Ollama 官网&#xff1a;https://ollama.com/ Ollama可以干什么&#xff1f; 可以快速在本地部署和管理各种大语言模型&#xff0c;操作命令和dokcer类似。 mac安装ollama&#xff1a; # 安装ollama brew install ollama# 启动ollama服务&#xff08;默认11434端口&#xf…

论文笔记(六十三)Understanding Diffusion Models: A Unified Perspective(三)

Understanding Diffusion Models: A Unified Perspective&#xff08;三&#xff09; 文章概括 文章概括 引用&#xff1a; article{luo2022understanding,title{Understanding diffusion models: A unified perspective},author{Luo, Calvin},journal{arXiv preprint arXiv:…

mybatis(104/134)

动态sql标签&#xff0c;用于选择查询 if标签 where标签 &#xff1a;自动生成where&#xff0c;取决于后面有没有条件&#xff0c;会自动去除条件前面的and和or&#xff0c;不会去除语句后面的 trim标签&#xff1a;自动生成where&#xff0c;在语句后自动去除后缀and和or for…

【数据结构】动态内存管理函数

动态内存管理 为什么存在动态内存管理动态内存函数的介绍&#x1f38a;malloc补充&#xff1a;perror函数&#x1f38a;free&#x1f38a;calloc&#x1f38a;realloc 常见动态内存错误对空指针的解引用操作对动态开辟空间的越界访问对非动态开辟内存使用free释放使用free释放一…

文档智能扫描,提升无纸化办公效率

随着无纸化办公的推广和移动设备的普及&#xff0c;用户迫切需要将纸质文档快速、准确地转换成电子格式&#xff0c;以提高工作效率和信息管理的便捷性。同时&#xff0c;用户将文档扫描成电子版后&#xff0c;可以自行通过加密和访问控制提高电子文档的安全性&#xff0c;以满…

汇编的使用总结

一、汇编的组成 1、汇编指令&#xff08;指令集&#xff09; 数据处理指令: 数据搬移指令 数据移位指令 位运算指令 算术运算指令 比较指令 跳转指令 内存读写指令 状态寄存器传送指令 异常产生指令等 2、伪指令 不是汇编指令&#xff0c;但是可以起到指令的作用&#xff0c;伪…

python实现dbscan

python实现dbscan 原理 DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一个比较有代表性的基于密度的聚类算法。它将簇定义为密度相连的点的最大集合&#xff0c;能够把具有足够高密度的区域划分为簇&#xff0c;并可在噪声的空间数据库中发现任意形…

gesp(C++六级)(4)洛谷:B3874:[GESP202309 六级] 小杨的握手问题

gesp(C六级)&#xff08;4&#xff09;洛谷&#xff1a;B3874&#xff1a;[GESP202309 六级] 小杨的握手问题 题目描述 小杨的班级里共有 N N N 名同学&#xff0c;学号从 0 0 0 至 N − 1 N-1 N−1。 某节课上&#xff0c;老师安排全班同学进行一次握手游戏&#xff0c;具…