go读取MNIST数据集显示图片(1)

该博客介绍了如何使用Go语言读取MNIST手写数字数据集的训练图像文件,解析其二进制格式,包括魔数、图片数量、宽度和高度信息,并将第一张图片数据转换为灰度PNG图片。代码详细展示了从二进制文件读取到生成图片的整个过程。
Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

概述

深度学习界的Hello Word程序,MNIST手写数字体识别。

MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分:

train-images-idx3-ubyte.gz: training set images (9912422 bytes),训练图像数据
train-labels-idx1-ubyte.gz: training set labels (28881 bytes),训练图像标签
t10k-images-idx3-ubyte.gz: test set images (1648877 bytes),测试图像数据
t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes),测试图像标签

train-images-idx3-ubyte.gz需要解压为train-images.idx3-ubyte,用winhex打开此文件,如下图所示,00000803是固定,0000EA60表示有6万张图片,0000001C表示图片的宽度为28,接着0000001C表示图片的高度为28。

目标

本次目的,使用go语言把文件train-images.idx3-ubyte读取,并生成一张图片。

代码如下:

import (
	"encoding/binary"
	"fmt"
	"image"
	"image/color"
	"image/png"
	"io"
	"log"
	"os"
)

type RawImage []byte


// 输入文件句柄
// 输出所有图片切片数组
func readImageFile(r io.Reader) ([]RawImage, error)  {

	var magic int32

	if err := binary.Read(r, binary.BigEndian, &magic); nil != err{
		return nil , err
	}

	if 0x0803 != magic{
		return nil, os.ErrInvalid
	}

 	var picNum int32
	if err := binary.Read(r, binary.BigEndian, &picNum); nil != err{
		return nil, err
	}

	var width, heigth int32

	if err := binary.Read(r, binary.BigEndian, &width); nil != err{
		return nil, err
	}


	if err := binary.Read(r, binary.BigEndian, &heigth); nil != err{
		return nil, err
	}

	imags := make([]RawImage, picNum)

	for i := 0; i < int(picNum); i++ {

		imags[i] = make(RawImage, width * heigth)

		fLen, err := io.ReadFull(r, imags[i])

		if nil != err{
			return nil, err
		}

		if fLen != int(width * heigth) {
			return nil, os.ErrInvalid
		}

	}

	return imags, nil


}



func main()  {

	fp, _ := os.Open("train-images.idx3-ubyte")

	imgs, err := readImageFile(fp)

	if nil != err{
		log.Fatal(err)
	}

	fmt.Println(len(imgs))

	// 使用GO生成图片


	imCols := 28
	imRows := 28

	rect := image.Rect(0, 0, imCols, imRows)

	rgba := image.NewNRGBA(rect)

	//
	for dy := 0; dy < imCols; dy++{
		for dx := 0; dx < imRows; dx++{
			rgba.Set(dy, dx, color.Gray{imgs[0][dy + dx * imRows]})
		}
	}

	fIm, err := os.Create("aaa.png")

	if nil != err{
		log.Fatal(err)
	}

	err = png.Encode(fIm, rgba)

	if nil != err{
		log.Fatal(err)
	}


}

代码说明

	fp, _ := os.Open("train-images.idx3-ubyte")

	imgs, err := readImageFile(fp)

	if nil != err{
		log.Fatal(err)
	}

	fmt.Println(len(imgs))

函数readImageFile,用于读取文件train-images.idx3-ubyte,输入是文件句柄,输出是6万张图片的图片数据切片。

	var magic int32

	if err := binary.Read(r, binary.BigEndian, &magic); nil != err{
		return nil , err
	}

	if 0x0803 != magic{
		return nil, os.ErrInvalid
	}

函数readImageFile的实现,此处通过binary库读取二进制文件,并且按照大端读取,读取四个字节,读取魔数,并且判断是否为00000803。

 	var picNum int32
	if err := binary.Read(r, binary.BigEndian, &picNum); nil != err{
		return nil, err
	}

接着继续通过binary库读取二进制文件,接着读取图片的数量0000EA60,即60000张。

	var width, heigth int32

	if err := binary.Read(r, binary.BigEndian, &width); nil != err{
		return nil, err
	}


	if err := binary.Read(r, binary.BigEndian, &heigth); nil != err{
		return nil, err
	}

 继续读取图片的宽度和高度,都为0000001C,即28。

	imags := make([]RawImage, picNum)

	for i := 0; i < int(picNum); i++ {

		imags[i] = make(RawImage, width * heigth)

		fLen, err := io.ReadFull(r, imags[i])

		if nil != err{
			return nil, err
		}

		if fLen != int(width * heigth) {
			return nil, os.ErrInvalid
		}

	}

	return imags, nil

分配imags的60000张RawImage,其中RawImage也是切片[]byte。然后循环读取60000张,分别对每个imags切片,再次分配图片的大小width * heigth,再通过io.ReadFull接口读二进制文件内容。

至此函数readImageFile完成了读取每张图片的功能,并输出到imags的切片。

	// 使用GO生成图片


	imCols := 28
	imRows := 28

	rect := image.Rect(0, 0, imCols, imRows)

	rgba := image.NewNRGBA(rect)

	//
	for dy := 0; dy < imCols; dy++{
		for dx := 0; dx < imRows; dx++{
			//fmt.Printf("dx = [%d], dy = [%d]\r\n", dx, dy)
			rgba.Set(dy, dx, color.Gray{imgs[0][dy + dx * imRows]})
		}
	}

	fIm, err := os.Create("aaa.png")

	if nil != err{
		log.Fatal(err)
	}

	err = png.Encode(fIm, rgba)

	if nil != err{
		log.Fatal(err)
	}

此代码,是把imags的切片的第一张图片数据,生成灰图PNG格式图片。下面遂段分解说明:

rect := image.Rect(0, 0, imCols, imRows)

创建28 * 28大小矩形框。

rgba := image.NewNRGBA(rect)

创建28 * 28大小矩形框的画板,用于显示图片。

	for dy := 0; dy < imCols; dy++{
		for dx := 0; dx < imRows; dx++{
			rgba.Set(dy, dx, color.Gray{imgs[0][dy + dx * imRows]})
		}
	}

rgba.Set是用于在画板上画点,而颜色来源于color.Gray来设置8bit灰度。

	fIm, err := os.Create("aaa.png")

	if nil != err{
		log.Fatal(err)
	}

	err = png.Encode(fIm, rgba)

	if nil != err{
		log.Fatal(err)
	}

png.Encode的功能把画板上的图画,生成图片aaa.png。

运行效果

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值