Read MNIST image information

This is a sample program that reads MNIST image information in Perl. MNIST is a sample image that can be used in deep learning.

This is a sample to read THE MNIST DATABASE of handwritten digits.

use strict;
use warnings;
use FindBin;

# MNIST Read image information
my $mnist_image_file = "$FindBin::Bin / data / train-images-idx3-ubyte";

open my $mnist_image_fh,'<', $mnist_image_file
  or die "Can't open file $mnist_image_file: $!";

#Magic number
my $image_buffer;
read($mnist_image_fh, $image_buffer, 4);
my $magic_number = unpack('N1', $image_buffer);
if ($magic_number! = 0x00000803) {
  die "Invalid magic number expected". 0x00000803. "actual $magic_number";
}

#Number of images
read($mnist_image_fh, $image_buffer, 4);
my $items_count = unpack('N1', $image_buffer);

# Image row pixel count
read($mnist_image_fh, $image_buffer, 4);
my $rows_count = unpack('N1', $image_buffer);

#Image column pixel count
read($mnist_image_fh, $image_buffer, 4);
my $columns_count = unpack('N1', $image_buffer);

#Load image
my $image_data;
my $all_images_length = $items_count * $rows_count * $columns_count;
my $read_length = read $mnist_image_fh, $image_data, $all_images_length;
unless ($read_length == $all_images_length) {
  die "Can't read all images";
}

#Image information
my $image_info = {};
$image_info->{items_count} = $items_count;
$image_info->{rows_count} = $rows_count;
$image_info->{columns_count} = $columns_count;
$image_info->{data} = $image_data;

A brief explanation of the program that reads MNIST image information

Place "train-images-idx3-ubyte" under "data".

Open the file and read it with the read function.

Check the magic number. Since it is a big endian 32-bit integer, specify "N1" for unpack.

Get the number of images. Since it is a big endian 32-bit integer, specify "N1" for unpack.

Gets the number of rows of pixels in the image. Since it is a big endian 32-bit integer, specify "N1" for unpack.

Gets the number of column pixels in the image. Since it is a big endian 32-bit integer, specify "N1" for unpack.

In MNIST image information, the number of row pixels and the number of column pixels are the same for all image data.

Load all images.

The image information for training "train-images-idx3-ubyte" is read, but the image information for verification "t10k-images-idx3-ubyte" can also be read in the same way.

How to output MNIST image information

I read the MNIST image information in memory, but I will explain how to check this. You can check the contents by outputting it as a bitmap image.

Use the module Imager. It's a CPAN module, so install it with cpanm or cpan.

Below is a sample that outputs the first 5 images as bitmap images.

use strict;
use warnings;
use FindBin;
use Imager;

# MNIST Read image information
my $mnist_image_file = "$FindBin::Bin / data / train-images-idx3-ubyte";

open my $mnist_image_fh,'<', $mnist_image_file
  or die "Can't open file $mnist_image_file: $!";

#Magic number
my $image_buffer;
read($mnist_image_fh, $image_buffer, 4);
my $magic_number = unpack('N1', $image_buffer);
if ($magic_number! = 0x00000803) {
  die "Invalid magic number expected". 0x00000803. "actual $magic_number";
}

#Number of images
read($mnist_image_fh, $image_buffer, 4);
my $items_count = unpack('N1', $image_buffer);

# Image row pixel count
read($mnist_image_fh, $image_buffer, 4);
my $rows_count = unpack('N1', $image_buffer);

#Image column pixel count
read($mnist_image_fh, $image_buffer, 4);
my $columns_count = unpack('N1', $image_buffer);

#Load image
my $image_data;
my $all_images_length = $items_count * $rows_count * $columns_count;
my $read_length = read $mnist_image_fh, $image_data, $all_images_length;
unless ($read_length == $all_images_length) {
  die "Can't read all images";
}

#Image information
my $image_info = {};
$image_info->{items_count} = $items_count;
$image_info->{rows_count} = $rows_count;
$image_info->{columns_count} = $columns_count;
$image_info->{data} = $image_data;

#Image information output
for (my $i = 0; $i <5; $i ++) {

  #Image offset
  my $offset = $i * $rows_count * $columns_count;

  #Canvas (monochrome)
  my $img = Imager->new(xsize => $rows_count, ysize => $columns_count, channels => 1);
  
  # Output image information in order
  for (my $row = 0; $row <$rows_count; $row ++) {
    for (my $column = 0; $column <$columns_count; $column ++) {
      
      #Color (Inverted because black and white is the opposite of RGB)
      my $pos = $offset + ($column * $rows_count) + $row;
      my $color_bin = substr($image_data, $pos, 1);
      my $color_value = unpack('C1', $color_bin);
      my $color_value_neg = $color_value ^ 0xFF;
      my $color = Imager::Color->new($color_value_neg, $color_value_neg, $color_value_neg);
      
      # Pixel drawing
      $img->setpixel(x => $row, y => $column, color => $color);
    }
  }
  #Save as PNG for web viewing
  my $bitmap_file = "$FindBin::Bin / tmp_images / number $i.png";
  $img->write(file => $bitmap_file);
}

This is the output image.

A brief explanation of the program that outputs MNIST image information

Create an Imager object with width, height and number of channels. Since it is monochrome, 1 is specified.

I will read the image information. The color depths are arranged in the order of the matrix, so get it. Since the data is stored as an unsigned 8-bit integer, "C1" is specified for unpack.

The color depth of MNIST is the opposite of RGB, so it is inverted.

I am creating an Imager::Color object.

Draw on pixels.

Finally, it is saved as png so that it can be displayed on the Web. It is automatically determined from the extension.

You may need the C language libpng library installed on your OS and Imager::File::PNG.

Associated Information