对于七段数码数字模型进行改进:一个关键的数字1的问题

网友投稿 507 2022-05-30

简 介:

对于训练集合进行扩增,需要根据图片本身在应用中可能遇到的变化进行。对于图片中的数码管数字识别,一个最重要的问题是字符的平移,特别是对于字符1来说,遇到的可能性最大。比如在一些三位半,四位半的数字表中,最前面的数字可能只有1,0两个数字,所以分割过程中,1的位置有可能位于图片的最左。针对这种情况,对于训练数据集合进行平移扩充,通过测试结果可以看出,模型的精度得到了提高。

关键词:

数码管,LENET,CNN,数据增强

数字1的问题

文章目录

问题来源

如何解决?

重新训练

准备数据集合

训练LeNet

检验数字问题

数字平移

数据准备

训练LCDNet

测试网络

总 结

资源下载

模型应用

数字1的问题

文章目录

问题来源

如何解决?

重新训练

准备数据集合

训练LeNet

检验数字问题

数字平移

数据准备

训练LCDNet

测试网络

总 结

资源下载

模型应用

1.1 问题来源

在 一个中等规模的七段数码数据库以及利用它训练的识别网络 中,利用了近200张网络数码图片训练出LeNet网络,可以达到了很好的数字(LCD,LED七段数字)识别的效果,网络的适应性比较强。但是在 测试LCDNet对于万用表读数识别效果 测试中,对于如下的图片识别的结果出现了问题:

下面的图片被识别成“07729”

问题出现在对于字符分割的问题上,明显,对于最左侧的“1”,实际上它的左侧部分被切割出去了。因此,将上述图片按照5等分,所获得到的图片如下。如果注视到这个分割结果,对于第一个字符应该说,还是分割的不错的。主要原因是“1”所在的位置偏向中心。

为了验证这个问题,对原来图片左侧进行填补背景颜色,对应的图片如下。

然后再进行五等分,对应的图片为:

在这种情况下,所获得的识别结果就正确了。

这说明在原来训练模型中,对于“1”这个字符,更多的样本对应“1”它是在图片的左侧,而不是在中间或者右边。

1.2 如何解决?

上面的这种情况对于数字“1”比较特殊,一种简单的解决方案,就是直接对于样本中所有的“1”的样本,都进行左右平移的扩充,使得模型对于“1”的左右位置不敏感。

plt.figure(figsize=(10, 5)) n = inp[0][0] x = list(range(0, 24, 4)) print(type(n), shape(n), x) for id,xx in enumerate(x): mm = roll(n, xx) plt.subplot(1, len(x), id+1) plt.imshow(mm)

1

2

3

4

5

6

7

8

9

2.1 准备数据集合

2.1.1 数据集合进行合并

现在已经有了四个7段数字图片集合,将它们合并在一起。

输入数字目录:7seg, testlcd, testled, testseg7

输出数字目录:seg7all

最终获得数字图片:303个

from headm import * # = import shutil inputdir = ['7Seg', 'testlcd', 'testled', 'testseg7'] outdir = '/home/aistudio/work/7seg/seg7all' count = 0 for d in inputdir: dstr = '/home/aistudio/work/7seg/' + d fdir = os.listdir(dstr) for f in fdir: ext = f.split('.')[-1].upper() if ext.find('JPG') < 0 and ext.find('BMP') < 0: continue numstr = f.split('.')[0].split('-')[-1] outfn = '%03d-%s.%s'%(count, numstr, ext) outfn = os.path.join(outdir, outfn) count += 1 shutil.copyfile(os.path.join(dstr, f), outfn) printt(count)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

2.1.2 分解图片中的数字

对前面准备好的数字图片分割相应的数字。

from headm import * # = import cv2 from tqdm import tqdm picdir = '/home/aistudio/work/7seg/seg7all' filedim = [s for s in os.listdir(picdir) if s.upper().find('BMP') > 0 or s.upper().find('JPG') > 0] filedim = sorted(filedim) outdir = '/home/aistudio/work/7seg/pic48' totalpic = 0 OUT_SIZE = 48 for f in tqdm(filedim): fn = os.path.join(picdir, f) img = cv2.imread(fn) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) imgwidth = gray.shape[1] imgheight = gray.shape[0] numstr = f.split('.')[0].split('-')[1] numnum = len(numstr) for i in range(numnum): left = imgwidth * i // numnum right = imgwidth * (i + 1) // numnum data = gray[0:imgheight, left:right] dataout = cv2.resize(data, (OUT_SIZE, OUT_SIZE)) outfn = os.path.join(outdir, '%04d_%s.BMP'%(totalpic, numstr[i])) totalpic += 1 cv2.imwrite(outfn, dataout) newheight = int(imgheight * 0.85) newwidth = int((right-left)*0.85) deltaheight = (imgheight- newheight)//2 deltawidth = (right-left-newwidth)//2 data = gray[deltaheight:imgheight-deltaheight, left:right] dataout = cv2.resize(data, (OUT_SIZE, OUT_SIZE)) outfn = os.path.join(outdir, '%04d_%s.BMP'%(totalpic, numstr[i])) totalpic += 1 cv2.imwrite(outfn, dataout) data = gray[0:imgheight, left+deltawidth:right-deltawidth] dataout = cv2.resize(data, (OUT_SIZE, OUT_SIZE)) outfn = os.path.join(outdir, '%04d_%s.BMP'%(totalpic, numstr[i])) totalpic += 1 cv2.imwrite(outfn, dataout) data = gray[deltaheight:imgheight-deltaheight, left+deltawidth:right-deltawidth] dataout = cv2.resize(data, (OUT_SIZE, OUT_SIZE)) outfn = os.path.join(outdir, '%04d_%s.BMP'%(totalpic, numstr[i])) totalpic += 1 cv2.imwrite(outfn, dataout) printt(totalpic:)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

分割完毕之后,每个数字对应四个数字,分别是原来数字,上下左右膨胀1.17倍的图片。图片总数为: 5340。

2.1.3 数字清洗与1平移

下面对于分割出的数字进行清洗,其中包含有“N”背景颜色的数字。另外,对于所有为“1”的数字往右平移倍增。

if num == 1: img = cv2.imread(infn) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray1 = roll(gray, -12) gray2 = roll(gray, -24) gray3 = roll(gray, -36)

1

2

3

4

5

6

可以看到实际上,只需要平移12,24两个即可。

处理完之后,总共的数字个数: 6548,各个数字的分布如下,可以看到其中数字1已经倍增了3倍。

from headm import * # = import shutil import cv2 digitdir = '/home/aistudio/work/7seg/pic48' outdir = '/home/aistudio/work/7seg/pic48_1' filedim = sorted(os.listdir(digitdir)) printt(len(filedim)) label = [] count = 0 for f in filedim: infn = os.path.join(digitdir, f) nstr = f.split('.')[0].split('_')[-1] if not nstr.isdigit(): continue extstr = f.split('.')[-1] num = int(nstr) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 label.append(num) shutil.copyfile(infn, outfn) if num == 1: img = cv2.imread(infn) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray1 = roll(gray, -12) gray2 = roll(gray, -24) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray1) label.append(num) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray2) label.append(num) printt(count) plt.figure(figsize=(10,6)) plt.hist(label, 10) plt.xlabel("N") plt.ylabel("Frequency") plt.grid(True) plt.tight_layout() plt.show()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

2.1.4 图片数据归一化

将生成的图片目录中的数据转换成归一化的图片数据。

from headm import * # = import paddle import paddle.fluid as fluid import paddle.nn.functional as F from paddle import to_tensor as TT import cv2 outdir = '/home/aistudio/work/7seg/pic48_1' filedim = sorted([s for s in os.listdir(outdir) if s.find('BMP') > 0 or s.find('JPG') > 0]) printt(len(filedim)) picarray = [] labeldim = [] for f in filedim: fn = os.path.join(outdir, f) img = cv2.imread(fn) gray = img[:,:,0] gray = gray - mean(gray) stdd = std(gray) gray1 = gray / stdd gray2 = gray * (-1.0) ff = f.split('.')[0].split('_')[-1] if ff.isdigit(): ff = int(ff) picarray.append(gray1) picarray.append(gray2) labeldim.append(ff) labeldim.append(ff) printt(shape(picarray)) printt(labeldim) outfile = '/home/aistudio/work/7seg/seg7_48_4_1.npz' savez(outfile, pic=picarray, label=labeldim)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

处理完之后,数据个数:

2.2 训练LeNet

利用与 一个中等规模的七段数码数据库以及利用它训练的识别网络 相同的网络,对于刚刚生成的数据库进行训练。

训练环境: AI Studio,智尊版本。

训练存储模型:seg7model4_1.pdparams

2.2.1 训练代码

from headm import * # = import paddle import paddle.fluid as fluid from paddle import to_tensor as TT from paddle.nn.functional import square_error_cost as SQRC datafile = '/home/aistudio/work/7seg/seg7_48_4_1.npz' data = load(datafile) lcd = data['pic'] llabel = data['label'] printt(lcd.shape, llabel.shape) dl = [(d,l) for d,l in zip(lcd, llabel)] random.shuffle(dl) printt(shape(dl)) train_ratio = 0.8 train_num = int(len(llabel) * train_ratio) train_lcd = [a[0] for a in dl[:train_num]] train_label = [a[1] for a in dl[:train_num]] test_lcd = array([a[0] for a in dl[train_num:]]) test_label = array([a[1] for a in dl[train_num:]]) class Dataset(paddle.io.Dataset): def __init__(self, num_samples): super(Dataset, self).__init__() self.num_samples = num_samples def __getitem__(self, index): data = train_lcd[index][newaxis,:,:] label = train_label[index] return paddle.to_tensor(data,dtype='float32'), paddle.to_tensor(label,dtype='int64') def __len__(self): return self.num_samples _dataset = Dataset(len(train_label)) train_loader = paddle.io.DataLoader(_dataset, batch_size=1000, shuffle=True) test_d = paddle.to_tensor([a[newaxis,:,:] for a in test_lcd], dtype='float32') test_l = paddle.to_tensor(test_label[:, newaxis], dtype='int64') printt(shape(test_d):, shape(test_l):) imgwidth = 48 imgheight = 48 inputchannel = 1 kernelsize = 5 targetsize = 10 ftwidth = ((imgwidth-kernelsize+1)//2-kernelsize+1)//2 ftheight = ((imgheight-kernelsize+1)//2-kernelsize+1)//2 class lenet(paddle.nn.Layer): def __init__(self, ): super(lenet, self).__init__() self.conv1 = paddle.nn.Conv2D(in_channels=inputchannel, out_channels=6, kernel_size=kernelsize, stride=1, padding=0) self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=kernelsize, stride=1, padding=0) self.mp1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.mp2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.L1 = paddle.nn.Linear(in_features=ftwidth*ftheight*16, out_features=120) self.L2 = paddle.nn.Linear(in_features=120, out_features=86) self.L3 = paddle.nn.Linear(in_features=86, out_features=targetsize) def forward(self, x): x = self.conv1(x) x = paddle.nn.functional.relu(x) x = self.mp1(x) x = self.conv2(x) x = paddle.nn.functional.relu(x) x = self.mp2(x) x = paddle.flatten(x, start_axis=1, stop_axis=-1) x = self.L1(x) x = paddle.nn.functional.relu(x) x = self.L2(x) x = paddle.nn.functional.relu(x) x = self.L3(x) return x model = lenet() optimizer = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters()) def train(model): model.train() epochs = 200 for epoch in range(epochs): for batch, data in enumerate(train_loader()): out = model(data[0]) loss = paddle.nn.functional.cross_entropy(out, data[1]) acc = paddle.metric.accuracy(out, data[1]).numpy() preout = model(test_d) test_acc = paddle.metric.accuracy(preout, test_l).numpy() loss.backward() optimizer.step() optimizer.clear_grad() printt('Epoch:{}, Accuracys:{}, Test:{}'.format(epoch, acc, test_acc)) train(model) paddle.save(model.state_dict(), './work/seg7model4_1.pdparams') filename = '/home/aistudio/stdout.txt' accdim = [] testdim = [] with open(filename, 'r') as f: for l in f.readlines(): ll = l.split(':[') if len(ll) < 3: continue lacc = ll[-2].split(']') if len(lacc) < 2: continue accdim.append(float(lacc[0])) tacc = ll[-1].split(']') if len(tacc) < 2: continue testdim.append(float(tacc[0])) plt.figure(figsize=(12, 8)) plt.plot(accdim, label='Train ACC') plt.plot(testdim, label='Test ACC') plt.xlabel("Step") plt.ylabel("Acc") plt.grid(True) plt.legend(loc='upper right') plt.tight_layout() plt.show()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

2.3 检验数字问题

利用训练后所得到的模型,重新建议前面数字1所碰到的问题。

最终的识别结果,无论是原来的图片,还是之后左边补充背景颜色的图片,识别结构都正常了。

这说明通过平移1图片对于模型性能的提高是起到很重要的作用的。

据前面的结果,下面对所有的数字都进行平移扩增,只是对“1”是往左平移12,24,对于其它的数字往左右各平移6,形成倍增后的数字。

3.1 数据准备

3.1.1 平移数字

from headm import * # = import shutil import cv2 digitdir = '/home/aistudio/work/7seg/pic48' outdir = '/home/aistudio/work/7seg/pic48_1' filedim = sorted(os.listdir(digitdir)) printt(len(filedim)) label = [] count = 0 for f in filedim: infn = os.path.join(digitdir, f) nstr = f.split('.')[0].split('_')[-1] if not nstr.isdigit(): continue extstr = f.split('.')[-1] num = int(nstr) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 label.append(num) shutil.copyfile(infn, outfn) if num == 1: img = cv2.imread(infn) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray1 = roll(gray, -12) gray2 = roll(gray, -24) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray1) label.append(num) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray2) label.append(num) else: img = cv2.imread(infn) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray1 = roll(gray, 6) gray2 = roll(gray, -6) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray1) label.append(num) outfn = os.path.join(outdir, '%05d_%d.%s'%(count, num, extstr)) count += 1 cv2.imwrite(outfn, gray2) label.append(num) printt(count) plt.figure(figsize=(10,6)) plt.hist(label, 10) plt.xlabel("N") plt.ylabel("Frequency") plt.grid(True) plt.tight_layout() plt.show()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

对于七段数码数字模型进行改进:一个关键的数字1的问题

55

56

57

58

59

60

61

62

63

64

65

66

67

评议结果:个数:15948.

3.1.2 数据归一化

数据个数:43384

数据尺寸:48×48

数据文件:seg7_48_4_1_all.npz

3.2 训练LCDNet

训练参数与前面相同,训练后模型存入:

/work/seg7model4_1_all.pdparams

BatchSize:1000

Lr:0.001

Epoch:200

训练数据量:43384

训练/测试占比:0.8:0.2

最终的训练精度:

Train Accuarcy: 1.0

Test Accuarcy: 0.991

3.3 测试网络

利用该模型,对于303个七段数码管数字识别,进行测试。

总共有两个图片识别存在错误:

于训练集合进行扩增,需要根据图片本身在应用中可能遇到的变化进行。对于图片中的数码管数字识别,一个最重要的问题是字符的平移,特别是对于字符1来说,遇到的可能性最大。比如在一些三位半,四位半的数字表中,最前面的数字可能只有1,0两个数字,所以分割过程中,1的位置有可能位于图片的最左。

针对这种情况,对于训练数据集合进行平移扩充,通过测试结果可以看出,模型的精度得到了提高。

4.1 资源下载

AI Studio数据集合:扩增后的数据集合

CSDN上下载链接:七段数码管测试数据集合,LENET训练好的模型

4.2 模型应用

from headm import * # = import paddle import paddle.fluid as fluid import cv2 imgwidth = 48 imgheight = 48 inputchannel = 1 kernelsize = 5 targetsize = 10 ftwidth = ((imgwidth-kernelsize+1)//2-kernelsize+1)//2 ftheight = ((imgheight-kernelsize+1)//2-kernelsize+1)//2 class lenet(paddle.nn.Layer): def __init__(self, ): super(lenet, self).__init__() self.conv1 = paddle.nn.Conv2D(in_channels=inputchannel, out_channels=6, kernel_size=kernelsize, stride=1, padding=0) self.conv2 = paddle.nn.Conv2D(in_channels=6, out_channels=16, kernel_size=kernelsize, stride=1, padding=0) self.mp1 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.mp2 = paddle.nn.MaxPool2D(kernel_size=2, stride=2) self.L1 = paddle.nn.Linear(in_features=ftwidth*ftheight*16, out_features=120) self.L2 = paddle.nn.Linear(in_features=120, out_features=86) self.L3 = paddle.nn.Linear(in_features=86, out_features=targetsize) def forward(self, x): x = self.conv1(x) x = paddle.nn.functional.relu(x) x = self.mp1(x) x = self.conv2(x) x = paddle.nn.functional.relu(x) x = self.mp2(x) x = paddle.flatten(x, start_axis=1, stop_axis=-1) x = self.L1(x) x = paddle.nn.functional.relu(x) x = self.L2(x) x = paddle.nn.functional.relu(x) x = self.L3(x) return x model = lenet() model.set_state_dict(paddle.load('./work/seg7model4_1_all.pdparams')) OUT_SIZE = 48 def pic2netinput(imgfile): img = cv2.imread(imgfile) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) imgwidth = gray.shape[1] imgheight = gray.shape[0] f = os.path.basename(imgfile) numstr = f.split('.')[0].split('-')[1] numnum = len(numstr) imgarray = [] labeldim = [] for i in range(numnum): left = imgwidth * i // numnum right = imgwidth * (i + 1) // numnum data = gray[0:imgheight, left:right] dataout = cv2.resize(data, (OUT_SIZE, OUT_SIZE)) dataout = dataout - mean(dataout) stdd = std(dataout) dataout = dataout / stdd if numstr[i].isdigit(): imgarray.append(dataout[newaxis,:,:]) labeldim.append(int(numstr[i])) test_i = paddle.to_tensor(imgarray, dtype='float32') test_label = array(labeldim) test_l = paddle.to_tensor(test_label[:, newaxis], dtype='int64') return test_i, test_l picdir = '/home/aistudio/work/7seg/seg7all' filedim = [s for s in os.listdir(picdir) if s.upper().find('BMP') > 0 or s.upper().find('JPG') > 0] filedim = sorted(filedim) def checkimglabel(imgfile): inp, label = pic2netinput(imgfile) preout = model(inp) preid = paddle.argmax(preout, axis=1).numpy().flatten() label = label.numpy().flatten() error = where(label != preid)[0] printt(preid:, label:) ''' inp = inp.numpy() plt.figure(figsize=(10, 5)) n = inp[0][0] x = list(range(0, 24, 4)) printt(type(n), shape(n), x) for id,xx in enumerate(x): mm = roll(n, xx) plt.subplot(1, len(x), id+1) plt.imshow(mm) ''' return error, preid ''' imgfile = os.path.join(picdir, filedim[-1]) error,id = checkimglabel(imgfile) printt(error:, id:) ''' for f in filedim: imgfile = os.path.join(picdir, f) error,id = checkimglabel(imgfile) if len(error) > 0: printt(error, f, id) img = cv2.imread(imgfile)[:,:,::-1] plt.clf() plt.figure(figsize=(8,8)) plt.axis("off") plt.imshow(img) plt.show()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

■ 相关文献链接:

一个中等规模的七段数码数据库以及利用它训练的识别网络

测试LCDNet对于万用表读数识别效果

AI Studio数据集合:扩增后的数据集合

七段数码管测试数据集合,LENET训练好的模型-深度学习文档类资源-CSDN文库

● 相关图表链接:

图1.1 图片内容被识别成07729

图1.1.2 图片分为5等分对应的图片

图1.1.3 对原来图片左侧进行填补背景之后的图片

图1.1.4 补充分割之后的图片

图1.2.1 将1图片左右平移

图2.1.1 十个数字的不同频次分布

图2.1.2 往右分别平移 12,24,36

图2.1.3 处理完之后的数字分布

图2.2.1 训练曲线:训练精度和测试精度

图3.2.1 训练过程的精度变化曲线

图A3.3.1 测试训练样本

图3.3.1 识别为:1824

图3.3.2 识别为:1466

机器学习 电商家电数码

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于STM32+SIM800C+华为云IoT设计的森林火灾预警系统(联动控制)
下一篇:excel表格里消除虚线的方法步骤(excel表格怎么消除虚线)
相关文章