Imgui(3) | 基于 imgui-SFML 的 mnist 数据集查看器

news2025/1/4 15:52:56

Imgui(3) | 基于 imgui-SFML 的 mnist 数据集查看器

文章目录

  • Imgui(3) | 基于 imgui-SFML 的 mnist 数据集查看器
    • 0. 介绍
    • 1. 处理 mnist 数据集
    • 2. 显示单张图像和label
      • 2.1 显示单张图像
      • 2.2 点选列表后更新显示的图像
      • 2.3 显示 label
      • 2.4 使用完整的列表
    • 总结

0. 介绍

把mnist数据集保存为多张.png图像、 train-label.txt 后, 编写一个 GUI 程序,查看图像和对应的标签。

这是一个简陋的demo,可以扩展它来支持其他数据集的显示。

规划:

  • 处理 mnist 数据集
  • 显示单张图像和label
  • 图像文件名列表的显示
  • 点选列表item后切换显示的图像和label

1. 处理 mnist 数据集

from mnist import MNIST
import matplotlib.pyplot as plt
import numpy as np  # 导入numpy
import os

def save_images_and_labels(images, labels, directory, label_filename):
    """
    将图像和标签保存到指定目录。
    """
    if not os.path.exists(directory):
        os.makedirs(directory)

    label_file_path = os.path.join(directory, label_filename)
    with open(label_file_path, 'w') as label_file:
        for i, (image, label) in enumerate(zip(images, labels), start=1):
            image_filename = f"{i}.png"
            image_path = os.path.join(directory, image_filename)
            # 将图像数据转换为NumPy数组并重塑
            image_array = np.array(image, dtype=np.uint8).reshape(28, 28)
            # 保存图像
            plt.imsave(image_path, image_array, cmap='gray')
            # 写入标签
            label_file.write(f"{image_filename} {label}\n")

def main():
    # 加载MNIST数据集
    mndata = MNIST('mnist_data')
    train_images, train_labels = mndata.load_training()
    test_images, test_labels = mndata.load_testing()

    # 保存训练数据集
    save_images_and_labels(train_images, train_labels, 'train', 'train-label.txt')
    # 保存测试数据集
    save_images_and_labels(test_images, test_labels, 'test', 'test-label.txt')

if __name__ == "__main__":
    main()

目录结构:

train
    |-- 1.png
    |-- 2.png
    ...
    |-- train-label.txt

2. 显示单张图像和label

2.1 显示单张图像

简单起见, 直接使用 imgui-SFML 进行窗口创建, 方便后续直接添加 imgui 的 GUI widget. CMakeLists.txt 的写法,查看之前的博客内容。

加载了 train/1.png 图像文件到 sf::Texture 对象,通过 sf::Sprite 装载。 sprite 的好处是可以设定位置,还可以缩放。 我放大了20倍。关键代码:

    sf::Texture texture;
    if (!texture.loadFromFile("../train/1.png"))
    {
        std::cerr << "Error loading image" << std::endl;
        return -1;
    }
    sf::Sprite sprite;
    sprite.setTexture(texture);
    sprite.setScale(20, 20);
    sprite.setPosition(20, 20);

完整代码:

#include "imgui.h"
#include "imgui-SFML.h"

#include <SFML/Graphics.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>

#include <iostream>

int main()
{
    constexpr int win_width = 960;
    constexpr int win_height = 640;
    sf::RenderWindow window(sf::VideoMode(win_width, win_height), "mnist viewer");
    window.setFramerateLimit(60);
    bool ret = ImGui::SFML::Init(window); // [imgui-SFML]
    if (!ret)
        return -1;

    sf::CircleShape shape(100.f);
    shape.setFillColor(sf::Color::Green);

    sf::Texture texture;
    if (!texture.loadFromFile("../train/1.png"))
    {
        std::cerr << "Error loading image" << std::endl;
        return -1;
    }
    sf::Sprite sprite;
    sprite.setTexture(texture);
    sprite.setScale(10, 10); // 水平和垂直方向都放大20倍
    sprite.setPosition(20, 20);

    sf::Clock deltaClock;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            ImGui::SFML::ProcessEvent(window, event); // [imgui-SFML]

            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        ImGui::SFML::Update(window, deltaClock.restart()); // [imgui-SFML]

        window.clear();
        window.draw(sprite);
        ImGui::SFML::Render(window); // [imgui-SFML]
        window.display();
    }

    ImGui::SFML::Shutdown(); // [imgui-SFML]

    return 0;
}

在这里插入图片描述

2.2 点选列表后更新显示的图像

sprite 对象就是一个容器, 或者说带有位置的放大镜, 你随时可以换一个新的 texture 丢给它。 现在我们通过 imgui 显示一个 list, 任意个一个 list item 被选中的时候,就加载对应的图像文件,获取 texture 后装到 sprite 里头,界面上就看到更新的图像了:

在这里插入图片描述

关键代码:

        // 使用ImGui创建一个简单的列表
        ImGui::Begin("Image List");

        // 假设文件名为1.png到10.png
        for (int i = 1; i <= 10; ++i) {
            std::string fileName = std::to_string(i) + ".png";

            // 如果列表项被点击
            if (ImGui::Selectable(fileName.c_str(), currentFile == fileName)) {
                currentFile = fileName; // 更新当前选中的文件名

                // 加载对应的纹理
                if (!texture.loadFromFile(currentFile)) {
                    std::cerr << "Failed to load " << currentFile << std::endl;
                } else {
                    sprite.setTexture(texture);
                }
            }
        }

        ImGui::End();

2.3 显示 label

train-label.txt 每一行是 <image_name> <image_label> 的形式, 例如:

1.png 0

使用哈希表存储这一映射关系, 然后每当通过GUI交互选择了新的文件名字时, 从字典里查询出对应的 label。

在 imgui 里显示当前图像的 label 很简单, 只需要添加 ImGui::Text, 并用 ImGui::Begin() 和 End() 包裹即可:

    int currentLabel = label_map[currentFile];
    ImGui::Begin("Label Info");
    ImGui::Text("Current Image: %s", currentFile.c_str());
    ImGui::Text("Label: %d", currentLabel);
    ImGui::End();

增大显示的字体

label 是我们关注的重要信息, 要用大字体显示 label, 需要先加载字体,并执行build和刷新, 否则程序运行阶段会遇到 imgui 的检查失败。

关键代码:

    // 加载字体
    const std::string asset_dir = "../../games/Resources";
    const std::string font_path = asset_dir + "/Arial.ttf";

    // 在这里添加字体
    ImFont* bigFont = ImGui::GetIO().Fonts->AddFontFromFileTTF(font_path.c_str(), 24.0f);
    if (!bigFont) {
        std::cerr << "Failed to load font." << std::endl;
    }

    // 构建字体图集
    ImGui::GetIO().Fonts->Build();
    // 更新SFML中的字体纹理
    ret = ImGui::SFML::UpdateFontTexture();
    if (!ret)
        return -2;

    while()
    {
        while()
        {
            // 显示当前图像的标签
            if (!currentFile.empty()) {
                int currentLabel = label_map[currentFile];
                ImGui::Begin("Label Info", nullptr, ImGuiWindowFlags_AlwaysAutoResize);
                ImGui::PushFont(bigFont); // 使用更大的字体
                ImGui::Text("Label: %d", currentLabel);
                ImGui::PopFont(); // 恢复默认字体
                ImGui::End();
            }
        }
    }

如果不这样设定, 会遇到这些报错:

Assertion failed: (g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()"), function ErrorCheckNewFrameSanityChecks, file imgui.cpp, line 9579.

Assertion failed: (io.Fonts->TexID != (ImTextureID) nullptr), function RenderDrawLists, file imgui-SFML.cpp, line 876.

效果:

在这里插入图片描述

2.4 使用完整的列表

读取文件名字的时候,原来是硬编码10张图,现在改为从 unordered_map 里读取。 注意, 由于这个数据量不大, 因此没有另外开启线程。

        for (int i = 1; i <= 10; ++i) {
            std::string fileName = std::to_string(i) + ".png";
            ...
        }
        for (const auto& kv : label_map)
        {
            const std::string fileName = kv.first;
            ...
        }

最终效果:
在这里插入图片描述

总结

通过使用 SFML, 加载并显示了了图像(texture->sprite->window)。 通过使用 imgui, 显示了图像文件列表、 label, 并且列表被选中元素和图像、 label 是联动的。

在设置 label 字体的时候, 需要额外调用 imgui 的构建字体和 imgui-SFML 的刷新, 来避免运行时候的检查报错。

是一个很简陋的图像数据集查看工具,可以进一步完善。

源码放在: https://github.com/zchrissirhcz/imgui-sfml-examples/tree/main/mnist-viewer

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

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

相关文章

零基础学编程怎么入手,中文编程工具构件箱之多页面板构件用法教程,系统化的编程视频教程上线

零基础学编程怎么入手&#xff0c;中文编程工具构件箱之多页面板构件用法教程&#xff0c;系统化的编程视频教程上线 一、前言 今天给大家分享的中文编程开发语言工具资料如下&#xff1a; 编程入门视频教程链接 http://​ https://edu.csdn.net/course/detail/39036 ​ …

SpringCloud-Hystrix:服务熔断与服务降级

8. Hystrix&#xff1a;服务熔断 分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系&#xff0c;每个依赖关系在某些时候将不可避免失败&#xff01; 8.1 服务雪崩 多个微服务之间调用的时候&#xff0c;假设微服务A调用微服务B和微服务C&#xff0c;微服…

洛谷_P1116 车厢重组_python写法

这道题看起来很高级其实就是冒泡排序执行的次数。 那对于python而言的话&#xff0c;这道题最大的难点在于如何实现数据输入既可以是以空格隔开的数据又可以是换行隔开的数据&#xff0c;那代码里面有了十分详细的解释。 n int(input()) l [] while len(l) < n: # 如果没…

CSS之画常见的图形

1.三角形 .shape {width: 0;height: 0;border-top: 100px solid rgba(0, 0, 0, 0);border-right: 100px solid rgba(0, 0, 0, 0);border-bottom: 100px solid blue;border-left: 100px solid rgba(0, 0, 0, 0);}使用border属性实现。宽高设置为0&#xff0c;border里其中一个方…

lv15 平台总线驱动开发——ID匹配 3

一、ID匹配之框架代码 id匹配&#xff08;可想象成八字匹配&#xff09;&#xff1a;一个驱动可以对应多个设备 ------优先级次低&#xff08;上一章名称匹配只能1对1&#xff09; 注意事项&#xff1a; device模块中&#xff0c;id的name成员必须与struct platform_device中…

从零开始学howtoheap:解题西湖论剑Storm_note

how2heap是由shellphish团队制作的堆利用教程&#xff0c;介绍了多种堆利用技术&#xff0c;后续系列实验我们就通过这个教程来学习。环境可参见从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;从零开始配置pwn环境&#xff1a;优化pwn虚拟机配置支持libc等指…

统一功能处理----拦截器

拦截器 拦截器是Spring框架提供的核心功能之一&#xff0c;主要用来拦截用户的请求&#xff0c;在指定方法前后&#xff0c;根据业务需要执行预先设定的代码。 拦截器就像小区门口的保安一样&#xff0c;当有人&#xff08;外部请求&#xff09;想要进入小区&#xff0c;保安…

HTML5 Canvas与JavaScript携手绘制动态星空背景

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>星空背景</title> </head> <body style"overflow-x:hidden;"><canvas …

Rust 数据结构与算法:5栈:用栈实现前缀、中缀、后缀表达式

3、前缀、中缀和后缀表达式 计算机是从左到右处理数据的,类似(A + (B * C))这样的完全括号表达式,计算机如何跳到内部括号计算乘法,然后跳到外部括号计算加法呢? 一种直观的方法是将运算符移到操作数外,分离运算符和操作数。计算时先取运算符再取操作数,计算结果则作为…

软件实例分享,超市便利店进销存管理系统收银软件教程

软件实例分享&#xff0c;超市便利店进销存管理系统收银软件教程 一、前言 以下软件教程以 佳易王超市进销存管理软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 软件程序导航&#xff0c;系统设置&#xff1a;有管理员账号设置其他账…

本地部署 Stable Cascade

本地部署 Stable Cascade 0. 引言1. 事前准备2. 本地部署 Stable Cascade3. 使用 Stable Cascade 生成图片4. Stable Cascade Github 地址 0. 引言 Stable Cascade 模型建立在 Wrstchen 架构之上&#xff0c;它与 Stable Diffusion 等其他模型的主要区别在于它的工作潜在空间要…

搜索专项---最小步数模型

文章目录 魔板 一、魔板OJ链接 本题思路:最小步数模型: 将整个“图”视为一个状态也即一个节点. 状态的转移视为权值为1的边. BFS求解, 注意几点: 状态的存储: 一般用字符串存储状态, 用哈希表存储初始状态到每个状态的距离. 方案记录: 记忆数组存储. 本题中需要存储上一个状…

mac IDEA基础配置和激活+maven配置+scala插件导入+scala文件打包

文章目录 下载IDEA通过插件激活下载Maven在IDEA上配置Maven在IDEA上加载Scala插件在IDEA中创建Maven项目在IDEA上通过Maven打包scala文件 下载IDEA通过插件激活 IDEA从这里下载&#xff0c;下载首次登陆需要创建一个IntelliJ账号&#xff0c;登陆后点击start trail开启一个月的…

机器学习、深度学习、强化学习、迁移学习的关联与区别

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要了解并初步探究机器学习、深度学习、强化学习、迁移学习的关系与区别&#xff0c;通过清晰直观的关系图展现出四种“学习”之间的关系。虽然这四种“学习”方法在理论和应用上存在着一定的区别&#xff0c;但它们之间也…

【教程】MySQL数据库学习笔记(三)——数据定义语言DDL(持续更新)

写在前面&#xff1a; 如果文章对你有帮助&#xff0c;记得点赞关注加收藏一波&#xff0c;利于以后需要的时候复习&#xff0c;多谢支持&#xff01; 【MySQL数据库学习】系列文章 第一章 《认识与环境搭建》 第二章 《数据类型》 第三章 《数据定义语言DDL》 文章目录 【MyS…

AJAX——HTTP协议

1 HTTP协议-请求报文 HTTP协议&#xff1a;规定了浏览器发送及服务器返回内容的格式 请求报文&#xff1a;浏览器按照HTTP协议要求的格式&#xff0c;发送给服务器的内容 1.1 请求报文的格式 请求报文的组成部分有&#xff1a; 请求行&#xff1a;请求方法&#xff0c;URL…

【AI视野·今日Robot 机器人论文速览 第七十九期】Thu, 18 Jan 2024

AI视野今日CS.Robotics 机器人学论文速览 Thu, 18 Jan 2024 Totally 43 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Robotics Papers CognitiveDog: Large Multimodal Model Based System to Translate Vision and Language into Action of Quadruped Robot Aut…

Selenium图表自动化开篇

目录 前言&#xff1a; 使用 Canvas 或者 SVG 渲染 选择哪种渲染器 代码触发 ECharts 中组件的行为 前言&#xff1a; 图表自动化一直以来是自动化测试中的痛点&#xff0c;也是难点&#xff0c;痛点在于目前越来越多公司开始构建自己的BI报表平台但是没有合适的自动化测试…

【C语言】解析刘谦春晚魔术《守岁共此时》

今年的春晚上刘谦表演了魔术《守岁共此时》&#xff0c;台上台下积极互动&#xff08;尤其是小尼&#xff09;&#xff0c;十分的有趣。刘谦老师的魔术不仅仅是他的高超手法&#xff0c;还有这背后的严谨逻辑&#xff0c;下面我们来用C语言来解析魔术吧。 源代码 #define _CRT…

MySQL学习记录——구 复合查询

文章目录 1、基本查询2、多表查询3、自连接4、子查询1、多行子查询2、多列子查询3、from句中的子查询 5、合并查询 1、基本查询 看一些例子&#xff0c;不关心具体内容&#xff0c;只看写法 //查询工资高于500或岗位为MANAGER的雇员, 同时还要满足他们的姓名首字母为大写的J …