概述
深度学习界的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。
运行效果

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

被折叠的 条评论
为什么被折叠?



