При работе с машинным обучением и обработкой изображений, часто возникает необходимость преобразования датасетов в удобные для использования форматы. Один из самых известных датасетов для задачи распознавания рукописных цифр — MNIST. Этот датасет содержит изображения цифр и их метки. В данной статье мы рассмотрим, как устроены форматы данных и подписей в MNIST, и как их можно конвертировать в более удобный графический формат, например, PPM P6.
Форматы данных и подписей в MNIST
Формат данных
MNIST состоит из двух файлов: один для изображений и другой для меток. Формат файлов следующий:
- Файл изображений (
train-images-idx3-ubyte
):
- Первые 4 байта: магическое число (0x00000803)
- Следующие 4 байта: количество изображений
- Следующие 4 байта: количество строк в изображении (28)
- Следующие 4 байта: количество столбцов в изображении (28)
- Далее идут байты с изображениями, каждое изображение представлено в виде последовательности 28×28 байт (0–255).
- Файл меток (
train-labels-idx1-ubyte
):
- Первые 4 байта: магическое число (0x00000801)
- Следующие 4 байта: количество меток
- Далее идут байты с метками, каждая метка представлена одним байтом (0–9).
Конвертация в формат PPM P6
Формат PPM P6
PPM (Portable Pixmap) — это простой формат хранения изображений. Формат PPM P6 поддерживает цветные изображения и хранит данные в бинарном виде. Структура PPM P6 файла:
- Заголовок:
P6
(идентификатор формата)- Ширина изображения
- Высота изображения
- Максимальное значение цвета (обычно 255)
- Данные изображения: последовательность байтов для всех пикселей (R, G, B).
Пример скрипта на D для конверсии
import std.stdio;
import std.file;
import std.zlib;
import std.conv;
import std.array;
void convertMNISTtoPPM(string imageFilePath, string labelFilePath, string outputDir) {
// Скачиваем и распаковываем файлы MNIST (предполагаем, что файлы уже скачаны и находятся в imageFilePath и labelFilePath)
ubyte[] imageData = cast(ubyte[]) read(imageFilePath);
ubyte[] labelData = cast(ubyte[]) read(labelFilePath);
// Парсим заголовки файлов
size_t numImages = to!size_t(imageData[4..8].reverse);
size_t numRows = to!size_t(imageData[8..12].reverse);
size_t numCols = to!size_t(imageData[12..16].reverse);
assert(numRows == 28 && numCols == 28);
// Создаем выходную директорию, если она не существует
if (!exists(outputDir)) {
mkdir(outputDir);
}
// Конвертируем каждое изображение в PPM
size_t imageSize = numRows * numCols;
foreach (i; 0 .. numImages) {
// Извлекаем изображение
ubyte[] image = imageData[16 + i * imageSize .. 16 + (i + 1) * imageSize];
// Извлекаем метку
ubyte label = labelData[8 + i];
// Генерируем имя файла
string outputFileName = format("%s/%02d_%05d.ppm", outputDir, label, i);
File outputFile = File(outputFileName, "wb");
// Пишем заголовок PPM
outputFile.write("P6\n%d %d\n255\n".format(numCols, numRows));
// Пишем данные изображения, преобразуем в формат RGB (серые значения)
foreach (pixel; image) {
outputFile.rawWrite([pixel, pixel, pixel]);
}
outputFile.close();
}
}
void main() {
string imageFilePath = "train-images-idx3-ubyte";
string labelFilePath = "train-labels-idx1-ubyte";
string outputDir = "output";
convertMNISTtoPPM(imageFilePath, labelFilePath, outputDir);
}
Пояснение работы скрипта
- Загрузка данных:
- Скрипт предполагает, что файлы MNIST уже скачаны и находятся в директориях, указанных в
imageFilePath
иlabelFilePath
. - Файлы читаются целиком в массивы
imageData
иlabelData
.
- Парсинг заголовков:
- Из массива данных извлекаются заголовки, чтобы получить количество изображений, количество строк и столбцов.
- Конвертация изображений:
- Для каждого изображения извлекается его часть из массива данных.
- Метка изображения используется для генерации имени файла.
- Создается файл PPM и записывается его заголовок.
- Данные изображения записываются в формате RGB (серые значения повторяются трижды для каждого пикселя).
- Создание выходной директории:
- Проверяется наличие директории для выходных файлов, при отсутствии — создается.
- Вывод файлов:
- Каждый файл сохраняется в директорию с именем, включающим метку и индекс изображения.
Особенности и ограничения
- Для работы требуется наличие библиотек для работы с файлами и бинарными данными.
- Скрипт использует методы
read
,write
,mkdir
и другие функции стандартной библиотеки языка D для работы с файловой системой и бинарными данными.
Конвертация датасетов в более удобные форматы позволяет значительно облегчить их использование в задачах машинного обучения и анализа данных. Приведенный пример скрипта на языке D демонстрирует процесс конверсии изображений из формата MNIST в формат PPM P6, что делает данные более доступными для последующей обработки и визуализации.
Автор статьи:
Обновлено:
Добавить комментарий