当前位置:   article > 正文

go读取MNIST数据集显示图片(1)_train-images-idx3-ubyte.gz

train-images-idx3-ubyte.gz

概述

深度学习界的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读取,并生成一张图片。

代码如下:

  1. import (
  2. "encoding/binary"
  3. "fmt"
  4. "image"
  5. "image/color"
  6. "image/png"
  7. "io"
  8. "log"
  9. "os"
  10. )
  11. type RawImage []byte
  12. // 输入文件句柄
  13. // 输出所有图片切片数组
  14. func readImageFile(r io.Reader) ([]RawImage, error) {
  15. var magic int32
  16. if err := binary.Read(r, binary.BigEndian, &magic); nil != err{
  17. return nil , err
  18. }
  19. if 0x0803 != magic{
  20. return nil, os.ErrInvalid
  21. }
  22. var picNum int32
  23. if err := binary.Read(r, binary.BigEndian, &picNum); nil != err{
  24. return nil, err
  25. }
  26. var width, heigth int32
  27. if err := binary.Read(r, binary.BigEndian, &width); nil != err{
  28. return nil, err
  29. }
  30. if err := binary.Read(r, binary.BigEndian, &heigth); nil != err{
  31. return nil, err
  32. }
  33. imags := make([]RawImage, picNum)
  34. for i := 0; i < int(picNum); i++ {
  35. imags[i] = make(RawImage, width * heigth)
  36. fLen, err := io.ReadFull(r, imags[i])
  37. if nil != err{
  38. return nil, err
  39. }
  40. if fLen != int(width * heigth) {
  41. return nil, os.ErrInvalid
  42. }
  43. }
  44. return imags, nil
  45. }
  46. func main() {
  47. fp, _ := os.Open("train-images.idx3-ubyte")
  48. imgs, err := readImageFile(fp)
  49. if nil != err{
  50. log.Fatal(err)
  51. }
  52. fmt.Println(len(imgs))
  53. // 使用GO生成图片
  54. imCols := 28
  55. imRows := 28
  56. rect := image.Rect(0, 0, imCols, imRows)
  57. rgba := image.NewNRGBA(rect)
  58. //
  59. for dy := 0; dy < imCols; dy++{
  60. for dx := 0; dx < imRows; dx++{
  61. rgba.Set(dy, dx, color.Gray{imgs[0][dy + dx * imRows]})
  62. }
  63. }
  64. fIm, err := os.Create("aaa.png")
  65. if nil != err{
  66. log.Fatal(err)
  67. }
  68. err = png.Encode(fIm, rgba)
  69. if nil != err{
  70. log.Fatal(err)
  71. }
  72. }

代码说明

  1. fp, _ := os.Open("train-images.idx3-ubyte")
  2. imgs, err := readImageFile(fp)
  3. if nil != err{
  4. log.Fatal(err)
  5. }
  6. fmt.Println(len(imgs))

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

  1. var magic int32
  2. if err := binary.Read(r, binary.BigEndian, &magic); nil != err{
  3. return nil , err
  4. }
  5. if 0x0803 != magic{
  6. return nil, os.ErrInvalid
  7. }

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

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

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

  1. var width, heigth int32
  2. if err := binary.Read(r, binary.BigEndian, &width); nil != err{
  3. return nil, err
  4. }
  5. if err := binary.Read(r, binary.BigEndian, &heigth); nil != err{
  6. return nil, err
  7. }

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

  1. imags := make([]RawImage, picNum)
  2. for i := 0; i < int(picNum); i++ {
  3. imags[i] = make(RawImage, width * heigth)
  4. fLen, err := io.ReadFull(r, imags[i])
  5. if nil != err{
  6. return nil, err
  7. }
  8. if fLen != int(width * heigth) {
  9. return nil, os.ErrInvalid
  10. }
  11. }
  12. return imags, nil

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

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

  1. // 使用GO生成图片
  2. imCols := 28
  3. imRows := 28
  4. rect := image.Rect(0, 0, imCols, imRows)
  5. rgba := image.NewNRGBA(rect)
  6. //
  7. for dy := 0; dy < imCols; dy++{
  8. for dx := 0; dx < imRows; dx++{
  9. //fmt.Printf("dx = [%d], dy = [%d]\r\n", dx, dy)
  10. rgba.Set(dy, dx, color.Gray{imgs[0][dy + dx * imRows]})
  11. }
  12. }
  13. fIm, err := os.Create("aaa.png")
  14. if nil != err{
  15. log.Fatal(err)
  16. }
  17. err = png.Encode(fIm, rgba)
  18. if nil != err{
  19. log.Fatal(err)
  20. }

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

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

创建28 * 28大小矩形框。

rgba := image.NewNRGBA(rect)

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

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

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

  1. fIm, err := os.Create("aaa.png")
  2. if nil != err{
  3. log.Fatal(err)
  4. }
  5. err = png.Encode(fIm, rgba)
  6. if nil != err{
  7. log.Fatal(err)
  8. }

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

运行效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/358460
推荐阅读
相关标签
  

闽ICP备14008679号