├── dataset
└── iamdataset
│ ├── form
│ └── a01-000u.png
│ ├── line
│ └── a01
│ │ └── a01-000u
│ │ └── a01-000u-00.png
│ ├── subject
│ ├── validationset1.txt
│ ├── validationset2.txt
│ └── testset.txt
│ └── xml
│ └── a01-000u.xml
├── utilities
├── expand_bounding_box.py
├── draw_text_on_image.py
├── draw_box_on_image.py
├── beam_search.py
├── word_to_line.py
├── handwriting_line_recognition.py
├── iam_dataset.py
└── word_and_line_segmentation.py
└── README.md
/dataset/iamdataset/form/a01-000u.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KevinGThomas/HandwrittenTextRecognition/HEAD/dataset/iamdataset/form/a01-000u.png
--------------------------------------------------------------------------------
/dataset/iamdataset/line/a01/a01-000u/a01-000u-00.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KevinGThomas/HandwrittenTextRecognition/HEAD/dataset/iamdataset/line/a01/a01-000u/a01-000u-00.png
--------------------------------------------------------------------------------
/utilities/expand_bounding_box.py:
--------------------------------------------------------------------------------
1 | def expand_bounding_box(bb, expand_bb_scale_x=0.05, expand_bb_scale_y=0.05):
2 | (x, y, w, h) = bb
3 | new_w = (1 + expand_bb_scale_x) * w
4 | new_h = (1 + expand_bb_scale_y) * h
5 |
6 | x = x - (new_w - w)/2
7 | y = y - (new_h - h)/2
8 | w = new_w
9 | h = new_h
10 | return (x, y, w, h)
11 |
--------------------------------------------------------------------------------
/utilities/draw_text_on_image.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import cv2
5 | import numpy as np
6 |
7 | def draw_text_on_image(images, text):
8 | output_image_shape = (images.shape[0], images.shape[1], images.shape[2] * 2, images.shape[3]) # Double the output_image_shape to print the text in the bottom
9 |
10 | output_images = np.zeros(shape=output_image_shape)
11 | for i in range(images.shape[0]):
12 | white_image_shape = (images.shape[2], images.shape[3])
13 | white_image = np.ones(shape=white_image_shape)*1.0
14 | text_image = cv2.putText(white_image, text[i], org=(5, 30), fontFace=cv2.FONT_HERSHEY_SIMPLEX, fontScale=1, color=0.0, thickness=1)
15 | output_images[i, :, :images.shape[2], :] = images[i]
16 | output_images[i, :, images.shape[2]:, :] = text_image
17 | return output_images
18 |
--------------------------------------------------------------------------------
/utilities/draw_box_on_image.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import numpy as np
5 | from skimage.draw import line_aa
6 | import matplotlib.pyplot as plt
7 |
8 | def draw_line(image, y1, x1, y2, x2, line_type):
9 | rr, cc, val = line_aa(y1, x1, y2, x2)
10 | if line_type == "dotted":
11 | rr = np.delete(rr, np.arange(0, rr.size, 5))
12 | cc = np.delete(cc, np.arange(0, cc.size, 5))
13 | image[rr, cc] = 0
14 | return image
15 |
16 | def draw_box(bounding_box, image, line_type, is_xywh=True):
17 | image_h, image_w = image.shape[-2:]
18 | if is_xywh:
19 | (x, y, w, h) = bounding_box
20 | (x1, y1, x2, y2) = (x, y, x + w, y + h)
21 | else:
22 | (x1, y1, x2, y2) = bounding_box
23 | (x1, y1, x2, y2) = (int(x1), int(y1), int(x2), int(y2))
24 | if y2 >= image_h:
25 | y2 = image_h - 1
26 | if x2 >= image_w:
27 | x2 = image_w - 1
28 | if y1 >= image_h:
29 | y1 = image_h - 1
30 | if x1 >= image_w:
31 | x1 = image_w - 1
32 | if y2 < 0:
33 | y2 = 0
34 | if x2 < 0:
35 | x2 =0
36 | if y1 < 0:
37 | y1 = 0
38 | if x1 < 0:
39 | x1 = 0
40 |
41 | image = draw_line(image, y1, x1, y2, x1, line_type)
42 | image = draw_line(image, y2, x1, y2, x2, line_type)
43 | image = draw_line(image, y2, x2, y1, x2, line_type)
44 | image = draw_line(image, y1, x2, y1, x1, line_type)
45 | return image
46 |
47 | def draw_boxes_on_image(pred, label, images):
48 | ''' Function to draw multiple bounding boxes on the images. Predicted bounding boxes will be
49 | presented with a dotted line and actual boxes are presented with a solid line.
50 |
51 | Parameters
52 | ----------
53 |
54 | pred: [n x [x, y, w, h]]
55 | The predicted bounding boxes in percentages.
56 | n is the number of bounding boxes predicted on an image
57 |
58 | label: [n x [x, y, w, h]]
59 | The actual bounding boxes in percentages
60 | n is the number of bounding boxes predicted on an image
61 |
62 | images: [[np.array]]
63 | The correponding images.
64 |
65 | Returns
66 | -------
67 |
68 | images: [[np.array]]
69 | Images with bounding boxes printed on them.
70 | '''
71 | image_h, image_w = images.shape[-2:]
72 | label[:, :, 0], label[:, :, 1] = label[:, :, 0] * image_w, label[:, :, 1] * image_h
73 | label[:, :, 2], label[:, :, 3] = label[:, :, 2] * image_w, label[:, :, 3] * image_h
74 | for i in range(len(pred)):
75 | pred_b = pred[i]
76 | pred_b[:, 0], pred_b[:, 1] = pred_b[:, 0] * image_w, pred_b[:, 1] * image_h
77 | pred_b[:, 2], pred_b[:, 3] = pred_b[:, 2] * image_w, pred_b[:, 3] * image_h
78 |
79 | image = images[i, 0]
80 | for j in range(pred_b.shape[0]):
81 | image = draw_box(pred_b[j, :], image, line_type="dotted")
82 |
83 | for k in range(label.shape[1]):
84 | image = draw_box(label[i, k, :], image, line_type="solid")
85 | images[i, 0, :, :] = image
86 | return images
87 |
88 | def draw_box_on_image(pred, label, images):
89 | ''' Function to draw bounding boxes on the images. Predicted bounding boxes will be
90 | presented with a dotted line and actual boxes are presented with a solid line.
91 |
92 | Parameters
93 | ----------
94 |
95 | pred: [[x, y, w, h]]
96 | The predicted bounding boxes in percentages
97 |
98 | label: [[x, y, w, h]]
99 | The actual bounding boxes in percentages
100 |
101 | images: [[np.array]]
102 | The correponding images.
103 |
104 | Returns
105 | -------
106 |
107 | images: [[np.array]]
108 | Images with bounding boxes printed on them.
109 | '''
110 |
111 | image_h, image_w = images.shape[-2:]
112 | pred[:, 0], pred[:, 1] = pred[:, 0] * image_w, pred[:, 1] * image_h
113 | pred[:, 2], pred[:, 3] = pred[:, 2] * image_w, pred[:, 3] * image_h
114 |
115 | label[:, 0], label[:, 1] = label[:, 0] * image_w, label[:, 1] * image_h
116 | label[:, 2], label[:, 3] = label[:, 2] * image_w, label[:, 3] * image_h
117 |
118 | for i in range(images.shape[0]):
119 | image = images[i, 0]
120 | image = draw_box(pred[i, :], image, line_type="dotted")
121 | image = draw_box(label[i, :], image, line_type="solid")
122 | images[i, 0, :, :] = image
123 | return images
124 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HandwrittenTextRecognition
2 | Recognizing Handwritten Text by segmenting the page into paragraphs and lines and then converting them to digital text.
3 |
4 | # Overview
5 | This is the full code for 'Handwritten Text Recognition'. This code helps to convert a handwritten page into digital text by identifying the paragraph present in the page, segmenting the lines and running handwriting recognition to accurately identify the text. The dataset used is the IAMDataset (http://www.fki.inf.unibe.ch/databases/iam-handwriting-database) containing about 6,000 labeled sentences and about 120,000 labeled words.
6 |
7 | # Dependency
8 | * mxnet
9 | * pandas
10 | * matplotlib
11 | * numpy
12 | * skimage
13 |
14 | # Methodology
15 | ## Paragraph Segmentation
16 |
17 |
18 |
19 | ### Pre-processing
20 | The pre-processing is a series of operations performed of scanned input image. It essentially enhances the image rendering for suitable segmentation. The role of pre-processing is to segment the interesting pattern from the background. Methods like data augmentation (a copy of the input image is made and slight alterations such as small rotation of the image are done and both of these images are sent to the model to increase it’s dataset examples), grey-scaling (images are turned to black and white for the model to accurately detect the presence of handwritten text).
21 |
22 | ### Feature Extraction
23 | The art of finding useful features in a machine learning problem can be tedious and heavily affected by human bias but by using Convolution Neural Networks, we are able to detect features by itself by comparing similar patterns in the images. To extract features from the DCNN model, first we need to train the CNN network with the last sigmoid/logistic dense layer (here dimension 4). The objective of the training network is to identify the correct weight for the network by multiple forward and backward iterations, which eventually try to minimise mean square error. We use MXNet in order to solve the problem for a given problem and set MSE (Mean Square Error) as the evaluation metric. We will optimize the model by attempting to reduce MSE value in each new epoch.
24 |
25 | ### Segmentation
26 | Here is the architecture of the DCNN model.
27 |
28 | The model gives 4 values as output in the end, (x,y,w,h). (x,y) are the coordinates of the starting of the paragraph that the model has recognized, w is the width of the paragraph and h is the height of the paragraph. Using this parameters, a bounding box can be formed around the paragraph to successfully segment the paragraph from the given image.
29 |
30 |
31 |
32 | ## Line Segmentation
33 | Similarly, line segmentation is done through pre-processing, feature extraction and segmentation. Line Segmentation is used to identify the lines present in the paragraph. This is important as many people have a tendency to not write in a straight line.
34 |
35 |
36 | Here is the architecture of the SSD network model.
37 |
38 | The model contains a list of bounding boxes each containing 4 values as output in the end, [n][(x,y,w,h)]. n is the number of words detected in the paragraph, (x,y) are the coordinates of the starting of the word that the model has recognized, w is the width of the word and h is the height of the word. Using this parameters, a bounding box can be formed around each word to successfully detect the words from the given image to segment to lines (checks if y coordinate of the bounding boxes overlap each other).
39 |
40 |
41 |
42 | ## Handwriting Recognition
43 | The final model is the handwriting recognition model which takes a line as input and converts the line into digital text. This model consits of a CNN-biLSTM architecture. The loss used is the CTC (Connectionist Temporal Classification) loss.
44 |
45 |
46 |
55 |
56 | ## Line Segmentation
57 |
58 |
59 | ## Handwriting Recognition
60 |
61 |
--------------------------------------------------------------------------------
/utilities/beam_search.py:
--------------------------------------------------------------------------------
1 | # From https://github.com/githubharald/CTCDecoder
2 | #
3 | #MIT License
4 |
5 | #Copyright (c) 2018 Harald Scheidl
6 |
7 | #Permission is hereby granted, free of charge, to any person obtaining a copy
8 | #of this software and associated documentation files (the "Software"), to deal
9 | #in the Software without restriction, including without limitation the rights
10 | #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | #copies of the Software, and to permit persons to whom the Software is
12 | #furnished to do so, subject to the following conditions:
13 |
14 | #The above copyright notice and this permission notice shall be included in all
15 | #copies or substantial portions of the Software.
16 |
17 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | #FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | #AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | #LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 | #SOFTWARE.
24 |
25 | from __future__ import division
26 | from __future__ import print_function
27 | import numpy as np
28 |
29 | class BeamEntry:
30 | "information about one single beam at specific time-step"
31 | def __init__(self):
32 | self.prTotal = 0 # blank and non-blank
33 | self.prNonBlank = 0 # non-blank
34 | self.prBlank = 0 # blank
35 | self.prText = 1 # LM score
36 | self.lmApplied = False # flag if LM was already applied to this beam
37 | self.labeling = () # beam-labeling
38 |
39 | class BeamState:
40 | "information about the beams at specific time-step"
41 | def __init__(self):
42 | self.entries = {}
43 |
44 | def norm(self):
45 | "length-normalise LM score"
46 | for (k, _) in self.entries.items():
47 | labelingLen = len(self.entries[k].labeling)
48 | self.entries[k].prText = self.entries[k].prText ** (1.0 / (labelingLen if labelingLen else 1.0))
49 |
50 | def sort(self):
51 | "return beam-labelings, sorted by probability"
52 | beams = [v for (_, v) in self.entries.items()]
53 | sortedBeams = sorted(beams, reverse=True, key=lambda x: x.prTotal*x.prText)
54 | return [x.labeling for x in sortedBeams]
55 |
56 | def applyLM(parentBeam, childBeam, classes, lm):
57 | "calculate LM score of child beam by taking score from parent beam and bigram probability of last two chars"
58 | if lm and not childBeam.lmApplied:
59 | c1 = classes[parentBeam.labeling[-1] if parentBeam.labeling else classes.index(' ')] # first char
60 | c2 = classes[childBeam.labeling[-1]] # second char
61 | lmFactor = 0.01 # influence of language model
62 | bigramProb = lm.getCharBigram(c1, c2) ** lmFactor # probability of seeing first and second char next to each other
63 | childBeam.prText = parentBeam.prText * bigramProb # probability of char sequence
64 | childBeam.lmApplied = True # only apply LM once per beam entry
65 |
66 | def addBeam(beamState, labeling):
67 | "add beam if it does not yet exist"
68 | if labeling not in beamState.entries:
69 | beamState.entries[labeling] = BeamEntry()
70 |
71 | def ctcBeamSearch(mat, classes, lm, beamWidth):
72 | "beam search as described by the paper of Hwang et al. and the paper of Graves et al."
73 |
74 | blankIdx = len(classes)
75 | maxT, maxC = mat.shape
76 |
77 | # initialise beam state
78 | last = BeamState()
79 | labeling = ()
80 | last.entries[labeling] = BeamEntry()
81 | last.entries[labeling].prBlank = 1
82 | last.entries[labeling].prTotal = 1
83 |
84 | # go over all time-steps
85 | for t in range(maxT):
86 | curr = BeamState()
87 |
88 | # get beam-labelings of best beams
89 | bestLabelings = last.sort()[0:beamWidth]
90 |
91 | # go over best beams
92 | for labeling in bestLabelings:
93 |
94 | # probability of paths ending with a non-blank
95 | prNonBlank = 0
96 | # in case of non-empty beam
97 | if labeling:
98 | # probability of paths with repeated last char at the end
99 | try:
100 | prNonBlank = last.entries[labeling].prNonBlank * mat[t, labeling[-1]]
101 | except FloatingPointError:
102 | prNonBlank = 0
103 |
104 | # probability of paths ending with a blank
105 | prBlank = (last.entries[labeling].prTotal) * mat[t, blankIdx]
106 |
107 | # add beam at current time-step if needed
108 | addBeam(curr, labeling)
109 |
110 | # fill in data
111 | curr.entries[labeling].labeling = labeling
112 | curr.entries[labeling].prNonBlank += prNonBlank
113 | curr.entries[labeling].prBlank += prBlank
114 | curr.entries[labeling].prTotal += prBlank + prNonBlank
115 | curr.entries[labeling].prText = last.entries[labeling].prText # beam-labeling not changed, therefore also LM score unchanged from
116 | curr.entries[labeling].lmApplied = True # LM already applied at previous time-step for this beam-labeling
117 |
118 | # extend current beam-labeling
119 | for c in range(maxC - 1):
120 | # add new char to current beam-labeling
121 | newLabeling = labeling + (c,)
122 |
123 | # if new labeling contains duplicate char at the end, only consider paths ending with a blank
124 | if labeling and labeling[-1] == c:
125 | prNonBlank = mat[t, c] * last.entries[labeling].prBlank
126 | else:
127 | prNonBlank = mat[t, c] * last.entries[labeling].prTotal
128 |
129 | # add beam at current time-step if needed
130 | addBeam(curr, newLabeling)
131 |
132 | # fill in data
133 | curr.entries[newLabeling].labeling = newLabeling
134 | curr.entries[newLabeling].prNonBlank += prNonBlank
135 | curr.entries[newLabeling].prTotal += prNonBlank
136 |
137 | # apply LM
138 | applyLM(curr.entries[labeling], curr.entries[newLabeling], classes, lm)
139 |
140 | # set new beam state
141 | last = curr
142 |
143 | # normalise LM scores according to beam-labeling-length
144 | last.norm()
145 |
146 | # sort by probability
147 | bestLabelings = last.sort()[:beamWidth] # get most probable labeling
148 |
149 | output = []
150 | for bestLabeling in bestLabelings:
151 | # map labels to chars
152 | res = ''
153 | for l in bestLabeling:
154 | res += classes[l]
155 | output.append(res)
156 | return output
157 |
158 | def testBeamSearch():
159 | "test decoder"
160 | classes = 'ab'
161 | mat = np.array([[0.4, 0, 0.6], [0.4, 0, 0.6]])
162 | print('Test beam search')
163 | expected = 'a'
164 | actual = ctcBeamSearch(mat, classes, None)
165 | print('Expected: "' + expected + '"')
166 | print('Actual: "' + actual + '"')
167 | print('OK' if expected == actual else 'ERROR')
168 |
169 | if __name__ == '__main__':
170 | testBeamSearch()
--------------------------------------------------------------------------------
/utilities/word_to_line.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import math
5 |
6 | import numpy as np
7 | from scipy.cluster.hierarchy import fcluster
8 |
9 | from .expand_bounding_box import expand_bounding_box
10 |
11 | def _clip_value(value, max_value):
12 | '''
13 | Helper function to make sure that "value" will not be greater than max_value
14 | or lower than 0.
15 | '''
16 | output = value
17 | if output < 0:
18 | output = 0
19 | if output > max_value:
20 | output = max_value
21 | return int(output)
22 |
23 | def _get_max_coord(bbs, x_or_y):
24 | '''
25 | Helper function to find the largest coordinate given a list of
26 | bounding boxes in the x or y direction.
27 | '''
28 | assert x_or_y in ["x", "y"], "x_or_y can only be x or y"
29 | max_value = 0.0
30 | for bb in bbs:
31 | if x_or_y == "x":
32 | value = bb[0] + bb[2]
33 | else:
34 | value = bb[1] + bb[3]
35 | if value > max_value:
36 | max_value = value
37 | return max_value
38 |
39 | def _get_min_coord(bbs, x_or_y):
40 | '''
41 | Helper function to find the largest coordinate given a list of
42 | bounding boxes in the x or y direction.
43 | '''
44 | assert x_or_y in ["x", "y"], "x_or_y can only be x or y"
45 | min_value = 100
46 | for bb in bbs:
47 | if x_or_y == "x":
48 | value = bb[0]
49 | else:
50 | value = bb[1]
51 | if value < min_value:
52 | min_value = value
53 | return min_value
54 |
55 | def _get_bounding_box_of_bb_list(bbs_in_a_line):
56 | '''
57 | Given a list of bounding boxes, find the maximum x, y and
58 | minimum x, y coordinates. This is the bounding box that
59 | emcompasses all the words. Return this bounding box in the form
60 | (x', y', w', h').
61 | '''
62 | max_x = _get_max_coord(bbs_in_a_line, x_or_y="x")
63 | min_x = _get_min_coord(bbs_in_a_line, x_or_y="x")
64 |
65 | max_y = _get_max_coord(bbs_in_a_line, x_or_y="y")
66 | min_y = _get_min_coord(bbs_in_a_line, x_or_y="y")
67 |
68 | line_bb = (min_x, min_y, max_x - min_x, max_y - min_y)
69 | return line_bb
70 |
71 | def _filter_bbs(bbs, min_size=0.005):
72 | '''
73 | Remove bounding boxes that are too small
74 | '''
75 | output_bbs = []
76 | for bb in bbs:
77 | if bb[2] * bb[3] > min_size:
78 | output_bbs.append(bb)
79 | return np.array(output_bbs)
80 |
81 | def _get_line_overlap_percentage(y1, h1, y2, h2):
82 | '''
83 | Calculates how much (percentage) y2->y2+h2 overlaps with y1->y1+h1.
84 | Algorithm assumes that y2 is larger than y1
85 | '''
86 | if y2 > y1 and (y1 + h1) > y2:
87 | # Is y2 enclosed in y1
88 | if (y1 + h1) > (y2 + h2):
89 | return 1.0
90 | else:
91 | return ((y1 + h1) - (y2))/h1
92 | else:
93 | return 0.0
94 |
95 | def _get_rect_overlap_percentage(x1, y1, w1, h1, x2, y2, w2, h2):
96 | '''
97 | Calculate how much (in percentage) that rect2 overlaps with rect1
98 | '''
99 | # Check if rect overlaps
100 | x_overlap = (x1 + w1 >= x2 and x2 >= x1) or (x2 + w2 >= x1 and x1 >= x2)
101 | y_overlap = (y1 + h1 >= y2 and y2 >= y1) or (y2 + h2 >= y1 and y1 >= y2)
102 | if x_overlap and y_overlap:
103 | intersect_size = max(0, min(x1 + w1, x2 + w2) - min(x1, x2)) * max(0, min(y1 + h1, y2 + h2) - max(y1, y2))
104 | s1 = w1 * h1
105 | return intersect_size / s1
106 | else:
107 | return 0
108 |
109 | def combine_bbs_into_lines(bbs, y_overlap=0.2):
110 | '''
111 | Algorithm to group word crops into lines.
112 | Iterates over every bb, if the overlap in the y direction
113 | between 2 boxes has less than y_overlap overlap, then group the previous words together.
114 | '''
115 | line_bbs = []
116 | bbs_in_a_line = []
117 | y_indexes = np.argsort(bbs[:, 1])
118 | # Iterate through the sorted bounding box.
119 | previous_y_coords = None
120 | for y_index in y_indexes:
121 | y_coords = (bbs[y_index, 1], bbs[y_index, 3]) # y and height
122 |
123 | # new line if the overlap is more than y_overlap
124 | if previous_y_coords is not None:
125 | line_overlap_percentage1 = _get_line_overlap_percentage(
126 | previous_y_coords[0], previous_y_coords[1],
127 | y_coords[0], y_coords[1])
128 | line_overlap_percentage2 = _get_line_overlap_percentage(
129 | y_coords[0], y_coords[1],
130 | previous_y_coords[0], previous_y_coords[1])
131 | line_overlap_percentage = max(line_overlap_percentage1, line_overlap_percentage2)
132 | if line_overlap_percentage < y_overlap:
133 | line_bb = _get_bounding_box_of_bb_list(bbs_in_a_line)
134 | line_bbs.append(line_bb)
135 | bbs_in_a_line = []
136 | bbs_in_a_line.append(bbs[y_index, :])
137 | previous_y_coords = y_coords
138 |
139 | # process the last line
140 | line_bb = _get_bounding_box_of_bb_list(bbs_in_a_line)
141 | line_bbs.append(line_bb)
142 | return line_bbs
143 |
144 | def sort_bbs_line_by_line(bbs, y_overlap=0.2):
145 | '''
146 | Function to combine word bbs into lines.
147 | '''
148 | line_bbs = _filter_bbs(bbs, min_size=0.0001) #Filter small word BBs
149 | line_bbs = combine_bbs_into_lines(line_bbs, y_overlap)
150 | line_bb_expanded = []
151 | for line_bb in line_bbs:
152 | line_bb_i = expand_bounding_box(line_bb, expand_bb_scale_x=0.1,
153 | expand_bb_scale_y=0.05)
154 | line_bb_expanded.append(line_bb_i)
155 | line_bbs = np.array(line_bb_expanded)
156 |
157 | # X start heuristics
158 | # Remove lines that start more than 150% away
159 | x_start_within_boundary = line_bbs[:, 0] < 0.5
160 | line_bbs = line_bbs[x_start_within_boundary]
161 |
162 | # Remove lines that start 20% away from the average
163 | x_start_line_bbs = line_bbs[:, 0]
164 | x_start_diff = np.abs(x_start_line_bbs - np.median(x_start_line_bbs))
165 | x_start_remove = x_start_diff < 0.2
166 | line_bbs = line_bbs[x_start_remove]
167 |
168 | # X length heuristics
169 | # Remove lines that are 50% shorter excluding the last element
170 | if len(line_bbs) > 1:
171 | x_length_line_bbs = line_bbs[:-1, 0] - line_bbs[:-1, 2]
172 | x_length_diff = np.abs(x_length_line_bbs - np.median(x_length_line_bbs))
173 | x_length_remove = x_length_diff < 0.5
174 | last_line = line_bbs[-1]
175 | line_bbs = line_bbs[:-1][x_length_remove]
176 | line_bbs = np.vstack([line_bbs, last_line])
177 |
178 | # Y height heuristics
179 | # Split lines that are more than 1.5 of the others
180 | y_height = line_bbs[:, 3]
181 | y_height_diff = np.abs(y_height/np.median(y_height))
182 | y_height_remove = y_height_diff > 1.65
183 |
184 | new_line_bbs = []
185 | for i in range(line_bbs.shape[0]):
186 | if y_height_remove[i]:
187 | # split line into 2
188 | new_line_top = np.copy(line_bbs[i])
189 | new_line_top[3] = new_line_top[3] / 2
190 |
191 | new_line_bottom = np.copy(line_bbs[i])
192 | new_line_bottom[1] = new_line_bottom[1] + new_line_bottom[3]/2
193 | new_line_bottom[3] = new_line_bottom[3] / 2
194 |
195 | new_line_bbs.append(new_line_top)
196 | new_line_bbs.append(new_line_bottom)
197 | else:
198 | new_line_bbs.append(line_bbs[i])
199 | line_bbs = np.vstack(new_line_bbs)
200 |
201 | # Y consistency heuristics
202 | # Remove lines that overlap by 40% with other lines
203 | line_total_overlap = []
204 | for i in range(line_bbs.shape[0]):
205 | overlap_i = 0.0
206 | for j in range(line_bbs.shape[0]):
207 | if i != j:
208 | line_i, line_j = line_bbs[i], line_bbs[j]
209 | overlap_i += _get_rect_overlap_percentage(line_i[0], line_i[1], line_i[2], line_i[3],
210 | line_j[0], line_j[1], line_j[2], line_j[3])
211 | line_total_overlap.append(overlap_i)
212 | overlap_remove = np.array(line_total_overlap) < 1
213 | line_bbs = line_bbs[overlap_remove]
214 | return line_bbs
215 |
216 | def crop_line_images(image, line_bbs):
217 | '''
218 | Given the input form image, crop the image given a list of bounding boxes.
219 | '''
220 | line_images = []
221 | for line_bb in line_bbs:
222 | (x, y, w, h) = line_bb
223 | image_h, image_w = image.shape[-2:]
224 | (x, y, w, h) = (x * image_w, y * image_h, w * image_w, h * image_h)
225 | x1 = _clip_value(x, max_value=image_w)
226 | x2 = _clip_value(x + w, max_value=image_w)
227 | y1 = _clip_value(y, max_value=image_h)
228 | y2 = _clip_value(y + h, max_value=image_h)
229 |
230 | line_image = image[y1:y2, x1:x2]
231 | if line_image.shape[0] > 0 and line_image.shape[1] > 0:
232 | line_images.append(line_image)
233 | return line_images
234 |
--------------------------------------------------------------------------------
/dataset/iamdataset/subject/validationset1.txt:
--------------------------------------------------------------------------------
1 | f04-032-00
2 | f04-032-01
3 | f04-032-02
4 | f04-032-03
5 | f04-032-04
6 | f04-032-05
7 | f04-032-06
8 | f04-032-07
9 | f04-032-08
10 | f04-035-00
11 | f04-035-01
12 | f04-035-02
13 | f04-035-03
14 | f04-035-04
15 | f04-039-00
16 | f04-039-01
17 | f04-039-02
18 | f04-039-03
19 | f04-039-04
20 | f04-039-05
21 | f04-039-06
22 | f04-039-07
23 | f04-043-00
24 | f04-043-01
25 | f04-043-02
26 | f04-043-03
27 | f04-043-04
28 | f04-043-05
29 | f04-043-06
30 | f04-043-07
31 | f04-046-00
32 | f04-046-01
33 | f04-046-02
34 | f04-046-03
35 | f04-046-04
36 | f04-046-05
37 | f04-049-00
38 | f04-049-01
39 | f04-049-02
40 | f04-049-03
41 | f04-049-04
42 | f04-049-05
43 | f04-049-06
44 | f04-053-00
45 | f04-053-01
46 | f04-053-02
47 | f04-053-03
48 | f04-053-04
49 | f04-053-05
50 | f04-053-06
51 | f04-057-00
52 | f04-057-01
53 | f04-057-02
54 | f04-057-03
55 | f04-057-04
56 | f04-057-05
57 | f04-057-06
58 | f04-057-07
59 | f04-057-08
60 | f04-061-00
61 | f04-061-01
62 | f04-061-02
63 | f04-061-03
64 | f04-061-04
65 | f04-061-05
66 | f04-061-06
67 | f04-061-07
68 | f04-064-00
69 | f04-064-01
70 | f04-064-02
71 | f04-064-03
72 | f04-064-04
73 | f04-064-05
74 | f04-064-06
75 | f04-064-07
76 | f04-068-00
77 | f04-068-01
78 | f04-068-02
79 | f04-068-03
80 | f04-068-04
81 | f04-068-05
82 | f04-068-06
83 | f04-071-00
84 | f04-071-01
85 | f04-071-02
86 | f04-071-03
87 | f04-071-04
88 | f04-071-05
89 | f04-071-06
90 | f04-071-07
91 | f04-071-08
92 | f04-071-09
93 | f04-074-00
94 | f04-074-01
95 | f04-074-02
96 | f04-074-03
97 | f04-074-04
98 | f04-074-05
99 | f04-074-06
100 | f04-074-07
101 | f04-074-08
102 | f04-074-09
103 | f04-074-10
104 | f04-074-11
105 | f04-079-00
106 | f04-079-01
107 | f04-079-02
108 | f04-079-03
109 | f04-079-04
110 | f04-079-05
111 | f04-079-06
112 | f04-079-07
113 | f04-079-08
114 | f04-079-09
115 | f04-083-00
116 | f04-083-01
117 | f04-083-02
118 | f04-083-03
119 | f04-083-04
120 | f04-083-05
121 | f04-083-06
122 | f04-083-07
123 | f04-083-08
124 | f04-083-09
125 | f04-087-00
126 | f04-087-01
127 | f04-087-02
128 | f04-087-03
129 | f04-087-04
130 | f07-000-00
131 | f07-000-01
132 | f07-000-02
133 | f07-000-03
134 | f07-000-04
135 | f07-000-05
136 | f07-000-06
137 | f07-000-07
138 | f07-039a-00
139 | f07-039a-01
140 | f07-039a-02
141 | f07-039a-03
142 | f07-039a-04
143 | f07-039a-05
144 | f07-039a-06
145 | f07-042a-00
146 | f07-042a-01
147 | f07-042a-02
148 | f07-042a-03
149 | f07-042a-04
150 | f07-042a-05
151 | f07-042a-06
152 | f07-042a-07
153 | f07-046a-00
154 | f07-046a-01
155 | f07-046a-02
156 | f07-046a-03
157 | f07-046a-04
158 | f07-046a-05
159 | f07-046a-06
160 | f07-046a-07
161 | f07-046a-08
162 | f07-046a-09
163 | g07-079a-00
164 | g07-079a-01
165 | g07-079a-02
166 | g07-079a-03
167 | g07-079a-04
168 | g07-079a-05
169 | g07-079a-06
170 | g07-079a-07
171 | g07-079a-08
172 | g07-079a-09
173 | g07-079a-10
174 | f07-000b-00
175 | f07-000b-01
176 | f07-000b-02
177 | f07-000b-03
178 | f07-000b-04
179 | f07-000b-05
180 | f07-000b-06
181 | f07-002-00
182 | f07-002-01
183 | f07-002-02
184 | f07-002-03
185 | f07-002-04
186 | f07-002-05
187 | f07-002-06
188 | f07-002-07
189 | f07-002-08
190 | f07-006-00
191 | f07-006-01
192 | f07-006-02
193 | f07-006-03
194 | f07-006-04
195 | f07-006-05
196 | f07-006-06
197 | f07-009-00
198 | f07-009-01
199 | f07-009-02
200 | f07-009-03
201 | f07-009-04
202 | f07-009-05
203 | f07-009-06
204 | f07-009-07
205 | f07-009-08
206 | f07-009-09
207 | f07-013-00
208 | f07-013-01
209 | f07-013-02
210 | f07-013-03
211 | f07-013-04
212 | f07-013-05
213 | f07-013-06
214 | f07-013-07
215 | f07-013-08
216 | f07-013-09
217 | f07-013-10
218 | f07-016-00
219 | f07-016-01
220 | f07-016-02
221 | f07-016-03
222 | f07-016-04
223 | f07-016-05
224 | f07-016-06
225 | f07-016-07
226 | f07-016-08
227 | f07-016-09
228 | f07-016-10
229 | f07-019b-00
230 | f07-019b-01
231 | f07-019b-02
232 | f07-019b-03
233 | f07-019b-04
234 | f07-019b-05
235 | f07-019b-06
236 | f07-019b-07
237 | f07-019b-08
238 | f07-019b-09
239 | f07-019b-10
240 | f07-021b-00
241 | f07-021b-01
242 | f07-021b-02
243 | f07-021b-03
244 | f07-021b-04
245 | f07-021b-05
246 | f07-021b-06
247 | f07-021b-07
248 | f07-021b-08
249 | f07-021b-09
250 | f07-024b-00
251 | f07-024b-01
252 | f07-024b-02
253 | f07-024b-03
254 | f07-024b-04
255 | f07-024b-05
256 | f07-024b-06
257 | f07-024b-07
258 | f07-024b-08
259 | f07-024b-09
260 | f07-019a-00
261 | f07-019a-01
262 | f07-019a-02
263 | f07-019a-03
264 | f07-019a-04
265 | f07-019a-05
266 | f07-019a-06
267 | f07-019a-07
268 | f07-021a-00
269 | f07-021a-01
270 | f07-021a-02
271 | f07-021a-03
272 | f07-021a-04
273 | f07-021a-05
274 | f07-021a-06
275 | f07-024a-00
276 | f07-024a-01
277 | f07-024a-02
278 | f07-024a-03
279 | f07-024a-04
280 | f07-024a-05
281 | f07-024a-06
282 | f07-024a-07
283 | f07-028a-00
284 | f07-028a-01
285 | f07-028a-02
286 | f07-028a-03
287 | f07-028a-04
288 | f07-028a-05
289 | f07-028a-06
290 | f07-028a-07
291 | f07-028a-08
292 | f07-032a-00
293 | f07-032a-01
294 | f07-032a-02
295 | f07-032a-03
296 | f07-032a-04
297 | f07-032a-05
298 | f07-032a-06
299 | f07-032a-07
300 | f07-032a-08
301 | f07-032a-09
302 | f07-028b-00
303 | f07-028b-01
304 | f07-028b-02
305 | f07-028b-03
306 | f07-028b-04
307 | f07-028b-05
308 | f07-028b-06
309 | f07-028b-07
310 | f07-028b-08
311 | f07-028b-09
312 | f07-028b-10
313 | f07-028b-11
314 | f07-032b-00
315 | f07-032b-01
316 | f07-032b-02
317 | f07-032b-03
318 | f07-032b-04
319 | f07-032b-05
320 | f07-032b-06
321 | f07-032b-07
322 | f07-032b-08
323 | f07-032b-09
324 | f07-032b-10
325 | f07-032b-11
326 | f07-036-00
327 | f07-036-01
328 | f07-036-02
329 | f07-036-03
330 | f07-036-04
331 | f07-036-05
332 | f07-036-06
333 | f07-036-07
334 | f07-039b-00
335 | f07-039b-01
336 | f07-039b-02
337 | f07-039b-03
338 | f07-039b-04
339 | f07-039b-05
340 | f07-039b-06
341 | f07-039b-07
342 | f07-039b-08
343 | f07-042b-00
344 | f07-042b-01
345 | f07-042b-02
346 | f07-042b-03
347 | f07-042b-04
348 | f07-042b-05
349 | f07-042b-06
350 | f07-042b-07
351 | f07-046b-00
352 | f07-046b-01
353 | f07-046b-02
354 | f07-046b-03
355 | f07-046b-04
356 | f07-046b-05
357 | f07-046b-06
358 | f07-046b-07
359 | f07-046b-08
360 | f07-069-00
361 | f07-069-01
362 | f07-069-02
363 | f07-069-03
364 | f07-069-04
365 | f07-069-05
366 | f07-069-06
367 | f07-069-07
368 | f07-069-08
369 | f07-069-09
370 | f07-073-00
371 | f07-073-01
372 | f07-073-02
373 | f07-073-03
374 | f07-073-04
375 | f07-073-05
376 | f07-073-06
377 | f07-073-07
378 | f07-073-08
379 | f07-073-09
380 | f07-081b-00
381 | f07-081b-01
382 | f07-081b-02
383 | f07-081b-03
384 | f07-081b-04
385 | f07-081b-05
386 | f07-081b-06
387 | f07-084b-00
388 | f07-084b-01
389 | f07-084b-02
390 | f07-084b-03
391 | f07-084b-04
392 | f07-084b-05
393 | f07-084b-06
394 | f07-084b-07
395 | f07-084b-08
396 | f07-076a-00
397 | f07-076a-01
398 | f07-076a-02
399 | f07-076a-03
400 | f07-076a-04
401 | f07-076a-05
402 | f07-076a-06
403 | f07-076a-07
404 | f07-076a-08
405 | f07-076a-09
406 | f07-076a-10
407 | f07-081a-00
408 | f07-081a-01
409 | f07-081a-02
410 | f07-081a-03
411 | f07-081a-04
412 | f07-081a-05
413 | f07-081a-06
414 | f07-081a-07
415 | f07-081a-08
416 | f07-081a-09
417 | f07-084a-00
418 | f07-084a-01
419 | f07-084a-02
420 | f07-084a-03
421 | f07-084a-04
422 | f07-084a-05
423 | f07-084a-06
424 | f07-084a-07
425 | f07-084a-08
426 | f07-084a-09
427 | f07-084a-10
428 | f07-088a-00
429 | f07-088a-01
430 | f07-088a-02
431 | f07-088a-03
432 | f07-088a-04
433 | f07-088a-05
434 | f07-088a-06
435 | f07-088a-07
436 | f07-088a-08
437 | f07-092a-00
438 | f07-092a-01
439 | f07-092a-02
440 | f07-092a-03
441 | f07-092a-04
442 | f07-092a-05
443 | f07-092a-06
444 | f07-092a-07
445 | f07-092a-08
446 | f07-088b-00
447 | f07-088b-01
448 | f07-088b-02
449 | f07-088b-03
450 | f07-088b-04
451 | f07-088b-05
452 | f07-092b-00
453 | f07-092b-01
454 | f07-092b-02
455 | f07-092b-03
456 | f07-092b-04
457 | f07-092b-05
458 | f07-096-00
459 | f07-096-01
460 | f07-096-02
461 | f07-096-03
462 | f07-096-04
463 | f07-096-05
464 | f07-101b-00
465 | f07-101b-01
466 | f07-101b-02
467 | f07-101b-03
468 | f07-101b-04
469 | g07-000b-00
470 | g07-000b-01
471 | g07-000b-02
472 | g07-000b-03
473 | g07-000b-04
474 | g07-000b-05
475 | g07-000b-06
476 | g07-000b-07
477 | g07-000b-08
478 | g01-004-00
479 | g01-004-01
480 | g01-004-02
481 | g01-004-03
482 | g01-004-04
483 | g01-004-05
484 | g01-008-00
485 | g01-008-01
486 | g01-008-02
487 | g01-008-03
488 | g01-008-04
489 | g01-008-05
490 | g01-008-06
491 | g01-008-07
492 | g01-008-08
493 | g01-012-00
494 | g01-012-01
495 | g01-012-02
496 | g01-012-03
497 | g01-012-04
498 | g01-012-05
499 | g01-016-00
500 | g01-016-01
501 | g01-016-02
502 | g01-016-03
503 | g01-016-04
504 | g01-016-05
505 | g01-016-06
506 | g01-016-07
507 | g01-019-00
508 | g01-019-01
509 | g01-019-02
510 | g01-019-03
511 | g01-019-04
512 | g01-019-05
513 | g01-019-06
514 | g01-019-07
515 | g01-019-08
516 | g01-019-09
517 | g01-025-00
518 | g01-025-01
519 | g01-025-02
520 | g01-025-03
521 | g01-025-04
522 | g01-025-05
523 | g01-025-06
524 | g01-025-07
525 | g01-025-08
526 | g01-025-09
527 | g01-027-00
528 | g01-027-01
529 | g01-027-02
530 | g01-027-03
531 | g01-027-04
532 | g01-027-05
533 | g01-027-06
534 | g01-027-07
535 | g01-027-08
536 | g01-027-09
537 | g01-031-00
538 | g01-031-01
539 | g01-031-02
540 | g01-031-03
541 | g01-031-04
542 | g01-031-05
543 | g01-031-06
544 | g01-031-07
545 | g01-031-08
546 | g01-031-09
547 | g01-031-10
548 | g01-034-00
549 | g01-034-01
550 | g01-034-02
551 | g01-034-03
552 | g01-034-04
553 | g01-034-05
554 | g01-034-06
555 | g01-034-07
556 | g01-034-08
557 | g01-037-00
558 | g01-037-01
559 | g01-037-02
560 | g01-037-03
561 | g01-037-04
562 | g01-037-05
563 | g01-037-06
564 | g01-037-07
565 | g01-037-08
566 | g01-037-09
567 | g01-039-00
568 | g01-039-01
569 | g01-039-02
570 | g01-039-03
571 | g01-039-04
572 | g01-039-05
573 | g01-039-06
574 | g01-039-07
575 | g01-039-08
576 | g01-039-09
577 | g01-043-00
578 | g01-043-01
579 | g01-043-02
580 | g01-043-03
581 | g01-043-04
582 | g01-043-05
583 | g01-043-06
584 | g01-043-07
585 | g01-043-08
586 | g01-043-09
587 | g01-045-00
588 | g01-045-01
589 | g01-045-02
590 | g01-045-03
591 | g01-045-04
592 | g01-045-05
593 | g01-045-06
594 | g01-045-07
595 | g01-045-08
596 | g01-045-09
597 | g01-067-00
598 | g01-067-01
599 | g01-067-02
600 | g01-067-03
601 | g01-067-04
602 | g01-067-05
603 | g01-067-06
604 | g01-067-07
605 | g01-067-08
606 | g01-067-09
607 | g01-070-00
608 | g01-070-01
609 | g01-070-02
610 | g01-070-03
611 | g01-070-04
612 | g01-070-05
613 | g01-070-06
614 | g01-070-07
615 | g01-070-08
616 | g01-070-09
617 | g01-074-00
618 | g01-074-01
619 | g01-074-02
620 | g01-074-03
621 | g01-074-04
622 | g01-074-05
623 | g01-074-06
624 | g01-074-07
625 | g01-074-08
626 | g01-074-09
627 | g01-083-00
628 | g01-083-01
629 | g01-083-02
630 | g01-083-03
631 | g01-083-04
632 | g01-083-05
633 | g01-083-06
634 | g01-083-07
635 | g01-083-08
636 | g01-083-09
637 | g01-083-10
638 | h01-004-00
639 | h01-004-01
640 | h01-004-02
641 | h01-004-03
642 | h01-004-04
643 | h01-004-05
644 | g01-088-00
645 | g01-088-01
646 | g01-088-02
647 | g01-088-03
648 | g01-088-04
649 | g01-088-05
650 | g01-088-06
651 | g01-088-07
652 | g01-088-08
653 | g01-088-09
654 | g02-059-00
655 | g02-059-01
656 | g02-059-02
657 | g02-059-03
658 | g02-059-04
659 | g02-059-05
660 | g02-059-06
661 | g02-059-07
662 | g02-062-00
663 | g02-062-01
664 | g02-062-02
665 | g02-062-03
666 | g02-062-04
667 | g02-062-05
668 | g02-062-06
669 | g02-062-07
670 | g02-062-08
671 | g02-065-00
672 | g02-065-01
673 | g02-065-02
674 | g02-065-03
675 | g02-065-04
676 | g02-065-05
677 | g02-065-06
678 | g02-065-07
679 | g02-065-08
680 | g02-065-09
681 | g02-073-00
682 | g02-073-01
683 | g02-073-02
684 | g02-073-03
685 | g02-073-04
686 | g02-073-05
687 | g03-000-01
688 | g03-000-02
689 | g03-000-03
690 | g03-000-04
691 | g03-000-05
692 | g03-000-06
693 | g03-000-07
694 | g03-000-08
695 | g03-004-00
696 | g03-004-01
697 | g03-004-02
698 | g03-004-03
699 | g03-004-04
700 | g03-004-05
701 | g03-016-00
702 | g03-016-01
703 | g03-016-02
704 | g03-016-03
705 | g03-016-04
706 | g03-016-05
707 | g03-016-06
708 | g03-016-07
709 | g03-032-00
710 | g03-032-01
711 | g03-032-02
712 | g03-032-03
713 | g03-032-04
714 | g03-032-05
715 | g03-032-06
716 | g03-032-07
717 | g03-040-00
718 | g03-040-01
719 | g03-040-02
720 | g03-040-03
721 | g03-040-04
722 | g03-040-05
723 | g03-040-06
724 | g03-043-00
725 | g03-043-01
726 | g03-043-02
727 | g03-043-03
728 | g03-043-04
729 | g03-043-05
730 | g03-043-06
731 | g03-043-07
732 | g03-043-08
733 | g03-043-09
734 | g03-043-10
735 | g03-049-00
736 | g03-049-01
737 | g03-049-02
738 | g03-049-03
739 | g03-049-04
740 | g03-049-05
741 | g03-049-06
742 | g03-049-07
743 | n02-104-00
744 | n02-104-01
745 | n02-104-02
746 | n02-104-03
747 | n02-104-04
748 | n02-104-05
749 | n02-104-06
750 | n02-109-00
751 | n02-109-01
752 | n02-109-02
753 | n02-109-03
754 | n02-109-04
755 | n02-109-05
756 | n02-109-06
757 | n02-109-07
758 | n02-114-00
759 | n02-114-01
760 | n02-114-02
761 | n02-114-03
762 | n02-114-04
763 | n02-114-05
764 | n02-114-06
765 | n02-114-07
766 | n02-114-08
767 | n02-120-00
768 | n02-120-01
769 | n02-120-02
770 | n02-120-03
771 | n02-120-04
772 | n02-120-05
773 | n02-120-06
774 | n02-127-00
775 | n02-127-01
776 | n02-127-02
777 | n02-127-03
778 | n02-127-04
779 | n02-127-05
780 | n02-127-06
781 | n02-127-07
782 | r03-053-00
783 | r03-053-01
784 | r03-053-02
785 | r03-053-03
786 | r03-053-04
787 | r03-053-05
788 | r03-053-06
789 | r03-053-07
790 | r03-053-08
791 | g03-052-00
792 | g03-052-01
793 | g03-052-02
794 | g03-052-03
795 | g03-052-04
796 | g03-052-05
797 | g03-052-06
798 | g03-052-07
799 | g03-052-08
800 | g03-052-09
801 | g03-052-10
802 | g03-058-00
803 | g03-058-01
804 | g03-058-02
805 | g03-058-03
806 | g03-058-04
807 | g03-058-05
808 | g03-058-06
809 | g03-064-00
810 | g03-064-01
811 | g03-064-02
812 | g03-064-03
813 | g03-064-04
814 | g03-064-05
815 | g03-064-06
816 | g03-064-07
817 | g04-022-00
818 | g04-022-01
819 | g04-022-02
820 | g04-022-03
821 | g04-022-04
822 | g04-022-05
823 | g04-022-06
824 | g04-036-00
825 | g04-036-01
826 | g04-036-02
827 | g04-036-03
828 | g04-036-04
829 | g04-036-05
830 | g04-036-06
831 | g04-039-00
832 | g04-039-01
833 | g04-039-02
834 | g04-039-03
835 | g04-039-04
836 | g04-039-05
837 | g04-039-06
838 | g04-043-00
839 | g04-043-01
840 | g04-043-02
841 | g04-043-03
842 | g04-043-04
843 | g04-043-05
844 | g04-043-06
845 | g04-043-07
846 | g04-048-00
847 | g04-048-01
848 | g04-048-02
849 | g04-048-03
850 | g04-048-04
851 | g04-048-05
852 | g04-048-06
853 | g04-052-00
854 | g04-052-01
855 | g04-052-02
856 | g04-052-03
857 | g04-052-04
858 | g04-052-05
859 | g04-055-00
860 | g04-055-01
861 | g04-055-02
862 | g04-055-03
863 | g04-055-04
864 | g04-055-05
865 | g04-055-06
866 | g04-055-07
867 | g04-055-08
868 | g04-060-00
869 | g04-060-01
870 | g04-060-02
871 | g04-060-03
872 | g04-060-04
873 | g04-060-05
874 | g04-063-00
875 | g04-063-01
876 | g04-063-02
877 | g04-063-03
878 | g04-063-04
879 | g04-063-05
880 | g04-063-06
881 | g04-063-07
882 | g04-063-08
883 | g04-068-00
884 | g04-068-01
885 | g04-068-02
886 | g04-068-03
887 | g04-068-04
888 | g04-068-05
889 | g04-068-06
890 | g04-068-07
891 | g04-068-08
892 | g04-068-09
893 | g04-072-00
894 | g04-072-01
895 | g04-072-02
896 | g04-072-03
897 | g04-072-04
898 | g04-072-05
899 | g04-072-06
900 | g04-072-07
901 |
--------------------------------------------------------------------------------
/dataset/iamdataset/subject/validationset2.txt:
--------------------------------------------------------------------------------
1 | c04-110-00
2 | c04-110-01
3 | c04-110-02
4 | c04-110-03
5 | c04-116-00
6 | c04-116-01
7 | c04-116-02
8 | c04-116-03
9 | c04-134-00
10 | c04-134-01
11 | c04-134-02
12 | c04-134-03
13 | c04-134-05
14 | c04-139-00
15 | c04-139-01
16 | c04-139-02
17 | c04-139-03
18 | c04-139-04
19 | c04-139-05
20 | c04-139-06
21 | c04-144-00
22 | c04-144-01
23 | c04-144-02
24 | c04-144-03
25 | c04-144-04
26 | c04-144-05
27 | c04-144-06
28 | c04-144-07
29 | c04-150-00
30 | c04-150-01
31 | c04-150-02
32 | c04-150-03
33 | c04-150-04
34 | c04-150-05
35 | c04-150-06
36 | c04-156-00
37 | c04-156-01
38 | c04-156-02
39 | c04-156-03
40 | c04-156-04
41 | c04-156-05
42 | c04-160-00
43 | c04-160-01
44 | c04-160-02
45 | c04-160-03
46 | c04-160-04
47 | c04-160-05
48 | c04-160-06
49 | c04-160-07
50 | c04-160-08
51 | c04-160-09
52 | c04-165-00
53 | c04-165-01
54 | c04-165-02
55 | c04-165-03
56 | c04-165-04
57 | c04-165-05
58 | c04-165-06
59 | c04-165-07
60 | c04-165-08
61 | c04-170-00
62 | c04-170-01
63 | c04-170-02
64 | c04-170-03
65 | c04-170-04
66 | c06-011-00
67 | c06-011-01
68 | c06-011-02
69 | c06-011-03
70 | c06-011-04
71 | c06-011-05
72 | c06-011-06
73 | c06-011-07
74 | c06-011-08
75 | d06-008-00
76 | d06-008-01
77 | d06-008-02
78 | d06-008-03
79 | d06-008-04
80 | d06-008-05
81 | d06-008-06
82 | d06-008-07
83 | d06-008-08
84 | d06-008-09
85 | d06-020-00
86 | d06-020-01
87 | d06-020-02
88 | d06-020-03
89 | d06-020-04
90 | d06-020-05
91 | d06-020-06
92 | d06-020-07
93 | d06-020-08
94 | d06-020-09
95 | d06-046-00
96 | d06-046-01
97 | d06-046-02
98 | d06-046-03
99 | d06-046-04
100 | d06-046-05
101 | d06-046-06
102 | d06-046-07
103 | d06-046-08
104 | d06-046-09
105 | d06-063-00
106 | d06-063-01
107 | d06-063-02
108 | d06-063-03
109 | d06-063-04
110 | d06-063-05
111 | d06-063-06
112 | d06-063-07
113 | d06-063-08
114 | d06-063-09
115 | d06-063-10
116 | c06-083-01
117 | c06-083-02
118 | c06-083-03
119 | c06-083-04
120 | c06-083-05
121 | c06-083-06
122 | c06-083-07
123 | d06-015-00
124 | d06-015-01
125 | d06-015-02
126 | d06-015-03
127 | d06-015-04
128 | d06-030-00
129 | d06-030-01
130 | d06-030-02
131 | d06-030-03
132 | d06-030-04
133 | d06-050-00
134 | d06-050-01
135 | d06-050-02
136 | d06-050-03
137 | d06-050-04
138 | d06-050-05
139 | d06-082-00
140 | d06-082-01
141 | d06-082-02
142 | d06-082-03
143 | d06-082-04
144 | d01-016-00
145 | d01-016-01
146 | d01-016-02
147 | d01-016-03
148 | d01-019-00
149 | d01-019-01
150 | d01-019-02
151 | d01-019-03
152 | d01-019-04
153 | d01-019-05
154 | d01-024-00
155 | d01-024-01
156 | d01-024-02
157 | d01-024-03
158 | d01-024-04
159 | d01-024-05
160 | d01-024-06
161 | d01-049-00
162 | d01-049-01
163 | d01-049-02
164 | d01-049-03
165 | d01-049-04
166 | d01-049-05
167 | d01-049-06
168 | d01-049-07
169 | d01-052-00
170 | d01-052-01
171 | d01-052-02
172 | d01-052-03
173 | d01-052-04
174 | d01-052-05
175 | d01-052-06
176 | d01-052-07
177 | d01-056-00
178 | d01-056-01
179 | d01-056-02
180 | d01-056-03
181 | d01-056-04
182 | d01-056-05
183 | d01-056-06
184 | d01-056-07
185 | d01-056-08
186 | d01-060-00
187 | d01-060-01
188 | d01-060-02
189 | d01-060-03
190 | d01-060-04
191 | d01-060-05
192 | d01-060-06
193 | d01-060-07
194 | d01-060-08
195 | d01-060-09
196 | d01-080-00
197 | d01-080-01
198 | d01-080-02
199 | d01-080-03
200 | d01-080-04
201 | d01-080-05
202 | d01-080-06
203 | d01-085-00
204 | d01-085-01
205 | d01-085-02
206 | d01-085-03
207 | d01-085-04
208 | d01-085-05
209 | d01-085-06
210 | d01-098-00
211 | d01-098-01
212 | d01-098-02
213 | d01-098-03
214 | d01-098-04
215 | d01-098-05
216 | d01-098-06
217 | d01-104-00
218 | d01-104-01
219 | d01-104-02
220 | d01-104-03
221 | d01-104-04
222 | d01-104-05
223 | d01-104-06
224 | d01-104-07
225 | d01-118-00
226 | d01-118-01
227 | d01-118-02
228 | d01-118-03
229 | d01-118-04
230 | d01-118-05
231 | d01-118-06
232 | d01-123-00
233 | d01-123-01
234 | d01-123-02
235 | d01-123-03
236 | d01-123-04
237 | d01-123-05
238 | d01-123-06
239 | d01-123-07
240 | e01-055-00
241 | e01-055-01
242 | e01-055-02
243 | e01-055-03
244 | e01-055-04
245 | e01-055-05
246 | e01-055-06
247 | e01-055-07
248 | e01-055-08
249 | e01-055-09
250 | d03-112-00
251 | d03-112-01
252 | d03-112-02
253 | d03-112-03
254 | d03-112-04
255 | d03-112-05
256 | d03-112-06
257 | d03-112-07
258 | d03-112-08
259 | d03-117-00
260 | d03-117-01
261 | d03-117-02
262 | d03-117-03
263 | d03-117-04
264 | d03-117-05
265 | d03-117-06
266 | d03-117-07
267 | d03-117-08
268 | d04-005-00
269 | d04-005-01
270 | d04-005-02
271 | d04-005-03
272 | d04-005-04
273 | d04-005-05
274 | d04-005-06
275 | d04-008-00
276 | d04-008-01
277 | d04-008-02
278 | d04-008-03
279 | d04-008-04
280 | d04-008-05
281 | d04-012-00
282 | d04-012-01
283 | d04-012-02
284 | d04-012-03
285 | d04-012-04
286 | d04-012-05
287 | d04-012-06
288 | d04-012-07
289 | d04-012-08
290 | d04-012-09
291 | d04-016-00
292 | d04-016-01
293 | d04-016-02
294 | d04-016-03
295 | d04-016-04
296 | d04-016-05
297 | d04-016-06
298 | d04-016-07
299 | d04-016-08
300 | d04-021-00
301 | d04-021-01
302 | d04-021-02
303 | d04-021-03
304 | d04-021-04
305 | d04-021-05
306 | d04-021-06
307 | d04-028-00
308 | d04-028-01
309 | d04-028-02
310 | d04-028-03
311 | d04-028-04
312 | d04-028-05
313 | d04-028-06
314 | d04-032-00
315 | d04-032-01
316 | d04-032-02
317 | d04-032-03
318 | d04-032-04
319 | d04-032-05
320 | d04-032-06
321 | d04-032-07
322 | d04-032-08
323 | d04-032-09
324 | d04-032-10
325 | d04-037-00
326 | d04-037-01
327 | d04-037-02
328 | d04-037-03
329 | d04-037-04
330 | d04-037-05
331 | d04-047-00
332 | d04-047-01
333 | d04-047-02
334 | d04-047-03
335 | d04-047-04
336 | d04-047-05
337 | d04-047-06
338 | d04-047-07
339 | d04-053-00
340 | d04-053-01
341 | d04-053-02
342 | d04-053-03
343 | d04-053-04
344 | d04-053-05
345 | d04-053-06
346 | d04-053-07
347 | d04-053-08
348 | d04-053-09
349 | d04-050-00
350 | d04-050-01
351 | d04-050-02
352 | d04-050-03
353 | d04-050-04
354 | d04-058-00
355 | d04-058-01
356 | d04-058-02
357 | d04-058-03
358 | d04-058-04
359 | d04-058-05
360 | d04-058-06
361 | d04-062-00
362 | d04-062-01
363 | d04-062-02
364 | d04-062-03
365 | d04-062-04
366 | d04-066-00
367 | d04-066-01
368 | d04-066-02
369 | d04-066-03
370 | d04-066-04
371 | d04-066-05
372 | d04-066-06
373 | d04-066-07
374 | d04-066-08
375 | d04-066-09
376 | d04-071-00
377 | d04-071-01
378 | d04-071-02
379 | d04-071-03
380 | d04-071-04
381 | d04-071-05
382 | d04-071-06
383 | d04-075-00
384 | d04-075-01
385 | d04-075-02
386 | d04-075-03
387 | d04-075-04
388 | d04-075-05
389 | d04-075-06
390 | d04-075-07
391 | d04-075-08
392 | d04-075-09
393 | d04-081-00
394 | d04-081-01
395 | d04-081-02
396 | d04-081-03
397 | d04-081-04
398 | d04-081-05
399 | d04-081-06
400 | d04-081-07
401 | d04-081-08
402 | f04-093-00
403 | f04-093-01
404 | f04-093-02
405 | f04-093-03
406 | f04-093-04
407 | f04-093-05
408 | f04-093-06
409 | f04-093-07
410 | f04-093-08
411 | f04-093-09
412 | f04-096-00
413 | f04-096-01
414 | f04-096-02
415 | f04-096-03
416 | f04-096-04
417 | f04-096-05
418 | f04-096-06
419 | f04-096-07
420 | f04-096-08
421 | f04-096-09
422 | f04-096-10
423 | f04-100-00
424 | f04-100-01
425 | f04-100-02
426 | f04-100-03
427 | f04-100-04
428 | f04-100-05
429 | f04-100-06
430 | f04-100-07
431 | f04-100-08
432 | f04-100-09
433 | f04-100-10
434 | d04-086-00
435 | d04-086-01
436 | d04-086-02
437 | d04-086-03
438 | d04-086-04
439 | d04-086-05
440 | d04-089-00
441 | d04-089-01
442 | d04-089-02
443 | d04-089-03
444 | d04-089-04
445 | d04-089-05
446 | d04-089-06
447 | d04-089-07
448 | d04-096-00
449 | d04-096-01
450 | d04-096-02
451 | d04-096-03
452 | d04-096-04
453 | d04-096-05
454 | d04-096-06
455 | d04-101-00
456 | d04-101-01
457 | d04-101-02
458 | d04-101-03
459 | d04-101-04
460 | d04-101-05
461 | d04-111-00
462 | d04-111-01
463 | d04-111-02
464 | d04-111-03
465 | d04-111-04
466 | d04-111-05
467 | d04-111-06
468 | d04-111-07
469 | d04-111-08
470 | d04-111-09
471 | d04-111-10
472 | d04-111-11
473 | d04-117-00
474 | d04-117-01
475 | d04-117-02
476 | d04-117-03
477 | d04-117-04
478 | d04-117-05
479 | d04-117-06
480 | d04-121-00
481 | d04-121-01
482 | d04-121-02
483 | d04-121-03
484 | d04-121-04
485 | d04-121-05
486 | d04-125-00
487 | d04-125-01
488 | d04-125-02
489 | d04-125-03
490 | d04-125-04
491 | d04-125-05
492 | d04-131-00
493 | d04-131-01
494 | d04-131-02
495 | d04-131-03
496 | d04-131-04
497 | d04-131-05
498 | d04-131-06
499 | d05-008-00
500 | d05-008-01
501 | d05-008-02
502 | d05-008-03
503 | d05-008-04
504 | d05-008-05
505 | d05-008-06
506 | d05-008-07
507 | d05-021-00
508 | d05-021-01
509 | d05-021-02
510 | d05-021-03
511 | d05-021-04
512 | d05-021-05
513 | d05-021-06
514 | d05-021-07
515 | d05-021-08
516 | d05-025-00
517 | d05-025-01
518 | d05-025-02
519 | d05-025-03
520 | d05-025-04
521 | d05-025-05
522 | d05-025-06
523 | d05-025-07
524 | d05-025-08
525 | d05-030-00
526 | d05-030-01
527 | d05-030-02
528 | d05-030-03
529 | d05-030-04
530 | d05-030-05
531 | d05-030-06
532 | d05-030-07
533 | d05-030-08
534 | d05-013-00
535 | d05-013-01
536 | d05-013-02
537 | d05-013-03
538 | d05-013-04
539 | d05-013-05
540 | d05-013-06
541 | d05-013-07
542 | d05-040-00
543 | d05-040-01
544 | d05-040-02
545 | d05-040-03
546 | d05-040-04
547 | d05-040-05
548 | d06-000-00
549 | d06-000-01
550 | d06-000-02
551 | d06-000-03
552 | d06-000-04
553 | d06-000-05
554 | d06-000-06
555 | d06-000-07
556 | d06-000-08
557 | d06-000-09
558 | d06-091-00
559 | d06-091-01
560 | d06-091-02
561 | d06-091-03
562 | d06-091-04
563 | d06-091-05
564 | d06-091-06
565 | d06-091-07
566 | d06-091-08
567 | d06-091-09
568 | d06-091-10
569 | e06-006-00
570 | e06-006-01
571 | e06-006-02
572 | e06-006-03
573 | e06-006-04
574 | e06-006-05
575 | e06-006-06
576 | e06-006-07
577 | e06-006-08
578 | e06-006-09
579 | e06-037-00
580 | e06-037-01
581 | e06-037-02
582 | e06-037-03
583 | e06-037-04
584 | e06-037-05
585 | e06-037-06
586 | e06-037-07
587 | e06-037-08
588 | e06-037-09
589 | e06-037-10
590 | e06-041-00
591 | e06-041-01
592 | e06-041-02
593 | e06-041-03
594 | e06-041-04
595 | e06-041-05
596 | e06-041-06
597 | e06-041-07
598 | e06-041-08
599 | e06-041-09
600 | d06-003-00
601 | d06-003-01
602 | d06-003-02
603 | d06-003-03
604 | d06-003-04
605 | d06-003-05
606 | d06-076-00
607 | d06-076-01
608 | d06-076-02
609 | d06-076-03
610 | d06-076-04
611 | d06-111-00
612 | d06-111-01
613 | d06-111-02
614 | d06-111-03
615 | d06-111-04
616 | d06-111-05
617 | e06-010-00
618 | e06-010-01
619 | e06-010-02
620 | e06-010-03
621 | e06-010-04
622 | e06-010-05
623 | e06-010-06
624 | e06-010-07
625 | e06-046-00
626 | e06-046-01
627 | e06-046-02
628 | e06-046-03
629 | e06-046-04
630 | e06-046-05
631 | d06-011-00
632 | d06-011-01
633 | d06-011-02
634 | d06-011-03
635 | d06-011-04
636 | d06-011-05
637 | d06-011-06
638 | d06-011-07
639 | d06-011-08
640 | d06-011-09
641 | d06-107-00
642 | d06-107-01
643 | d06-107-02
644 | d06-107-03
645 | d06-107-04
646 | d06-107-05
647 | d06-107-06
648 | d06-107-07
649 | d06-107-08
650 | d06-107-09
651 | d06-107-10
652 | e06-003-00
653 | e06-003-01
654 | e06-003-02
655 | e06-003-03
656 | e06-003-04
657 | e06-003-05
658 | e06-003-06
659 | e06-003-07
660 | e06-003-08
661 | e06-003-09
662 | e06-003-10
663 | e06-015-00
664 | e06-015-01
665 | e06-015-02
666 | e06-015-03
667 | e06-015-04
668 | e06-015-05
669 | e06-015-06
670 | e06-015-07
671 | e06-015-08
672 | e06-015-09
673 | e06-030-00
674 | e06-030-01
675 | e06-030-02
676 | e06-030-03
677 | e06-030-04
678 | e06-030-05
679 | e06-030-06
680 | e06-030-07
681 | e06-030-08
682 | e06-030-09
683 | e06-030-10
684 | d06-025-00
685 | d06-025-01
686 | d06-025-02
687 | d06-025-03
688 | d06-025-04
689 | d06-025-05
690 | d06-025-06
691 | d06-025-07
692 | d06-067-00
693 | d06-067-01
694 | d06-067-02
695 | d06-067-03
696 | d06-067-04
697 | d06-067-05
698 | d06-067-06
699 | d06-067-07
700 | d06-067-08
701 | d06-104-00
702 | d06-104-01
703 | d06-104-02
704 | d06-104-03
705 | d06-104-04
706 | d06-104-05
707 | d06-104-06
708 | d06-104-07
709 | d06-104-08
710 | d06-104-09
711 | e06-026-00
712 | e06-026-01
713 | e06-026-02
714 | e06-026-03
715 | e06-026-04
716 | e06-026-05
717 | e06-026-06
718 | e06-026-07
719 | e06-026-08
720 | e06-026-09
721 | e06-049-00
722 | e06-049-01
723 | e06-049-02
724 | e06-049-03
725 | e06-049-04
726 | e06-049-05
727 | e06-049-06
728 | e06-049-07
729 | e06-049-08
730 | e06-049-09
731 | d06-027-00
732 | d06-027-01
733 | d06-027-02
734 | d06-027-03
735 | d06-027-04
736 | d06-027-05
737 | d06-027-06
738 | d06-056-00
739 | d06-056-01
740 | d06-056-02
741 | d06-056-03
742 | d06-056-04
743 | d06-056-05
744 | d06-056-06
745 | d06-056-07
746 | d06-056-08
747 | d06-096-00
748 | d06-096-01
749 | d06-096-02
750 | d06-096-03
751 | d06-096-04
752 | d06-096-05
753 | d06-096-06
754 | d06-096-07
755 | d06-096-08
756 | e06-000-00
757 | e06-000-01
758 | e06-000-02
759 | e06-000-03
760 | e06-000-04
761 | e06-000-05
762 | e06-000-06
763 | e06-000-07
764 | e06-021-00
765 | e06-021-01
766 | e06-021-02
767 | e06-021-03
768 | e06-021-04
769 | e06-021-05
770 | e06-021-06
771 | e06-021-07
772 | e06-021-08
773 | e06-021-09
774 | e06-021-10
775 | d06-037-00
776 | d06-037-01
777 | d06-037-02
778 | d06-037-03
779 | d06-037-04
780 | d06-037-05
781 | d06-037-06
782 | d06-037-07
783 | d06-072-00
784 | d06-072-01
785 | d06-072-02
786 | d06-072-03
787 | d06-072-04
788 | d06-072-05
789 | d06-072-06
790 | d06-072-07
791 | d06-072-08
792 | d06-072-09
793 | d06-072-10
794 | d06-100-00
795 | d06-100-01
796 | d06-100-02
797 | d06-100-03
798 | d06-100-04
799 | d06-100-05
800 | d06-100-06
801 | e06-033-00
802 | e06-033-01
803 | e06-033-02
804 | e06-033-03
805 | e06-033-04
806 | e06-033-05
807 | e06-033-06
808 | e06-033-07
809 | e06-033-08
810 | e06-033-09
811 | e06-070-00
812 | e06-070-01
813 | e06-070-02
814 | e06-070-03
815 | e06-070-04
816 | e06-070-05
817 | e06-070-06
818 | e06-070-07
819 | e06-070-08
820 | e06-070-09
821 | d06-041-00
822 | d06-041-01
823 | d06-041-02
824 | d06-041-03
825 | d06-041-04
826 | d06-041-05
827 | d06-041-06
828 | d06-041-07
829 | d06-060-00
830 | d06-060-01
831 | d06-060-02
832 | d06-060-03
833 | d06-060-04
834 | d06-060-05
835 | d06-060-06
836 | d06-060-07
837 | d06-060-08
838 | d06-086-00
839 | d06-086-01
840 | d06-086-02
841 | d06-086-03
842 | d06-086-04
843 | d06-086-05
844 | d06-086-06
845 | d06-086-07
846 | d06-086-08
847 | d06-086-09
848 | d06-086-10
849 | d06-113-00
850 | d06-113-01
851 | d06-113-02
852 | d06-113-03
853 | e06-053-00
854 | e06-053-01
855 | e06-053-02
856 | e06-053-03
857 | e06-053-04
858 | e06-053-05
859 | e06-053-06
860 | e06-053-07
861 | e06-053-08
862 | d07-082-00
863 | d07-082-01
864 | d07-082-02
865 | d07-082-03
866 | d07-082-04
867 | d07-082-05
868 | d07-082-06
869 | d07-082-07
870 | d07-085-00
871 | d07-085-01
872 | d07-085-02
873 | d07-085-03
874 | d07-085-04
875 | d07-085-05
876 | d07-085-06
877 | d07-085-07
878 | d07-089-00
879 | d07-089-01
880 | d07-089-02
881 | d07-089-03
882 | d07-089-04
883 | d07-089-05
884 | d07-089-06
885 | d07-089-07
886 | d07-089-08
887 | d07-089-09
888 | d07-089-10
889 | d07-093-00
890 | d07-093-01
891 | d07-093-02
892 | d07-093-03
893 | d07-093-04
894 | d07-093-05
895 | d07-093-06
896 | d07-093-07
897 | d07-093-08
898 | d07-096-00
899 | d07-096-01
900 | d07-096-02
901 | d07-096-03
902 | d07-096-04
903 | d07-096-05
904 | d07-096-06
905 | d07-096-07
906 | d07-096-08
907 | d07-096-09
908 | d07-100-00
909 | d07-100-01
910 | d07-100-02
911 | d07-100-03
912 | d07-100-04
913 | d07-100-05
914 | d07-100-06
915 | d07-100-07
916 | d07-100-08
917 | d07-102-00
918 | d07-102-01
919 | d07-102-02
920 | d07-102-03
921 | d07-102-04
922 | d07-102-05
923 | d07-102-06
924 | d07-102-07
925 | e01-014-00
926 | e01-014-01
927 | e01-014-02
928 | e01-014-03
929 | e01-014-04
930 | e01-014-05
931 | e01-014-06
932 | e01-018-00
933 | e01-018-01
934 | e01-018-02
935 | e01-018-03
936 | e01-018-04
937 | e01-018-05
938 | e01-018-06
939 | e01-018-07
940 | e01-018-08
941 |
--------------------------------------------------------------------------------
/dataset/iamdataset/xml/a01-000u.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
319 |
320 |
--------------------------------------------------------------------------------
/utilities/handwriting_line_recognition.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import time
5 | import random
6 | import os
7 | import matplotlib.pyplot as plt
8 | import argparse
9 |
10 | import mxnet as mx
11 | import numpy as np
12 | from skimage import transform as skimage_tf
13 | from skimage import exposure
14 |
15 | from mxnet import nd, autograd, gluon
16 | from mxboard import SummaryWriter
17 | from mxnet.gluon.model_zoo.vision import resnet34_v1
18 | np.seterr(all='raise')
19 |
20 | import multiprocessing
21 | mx.random.seed(1)
22 |
23 | from utilities.iam_dataset import IAMDataset, resize_image
24 | from utilities.draw_text_on_image import draw_text_on_image
25 |
26 | print_every_n = 1
27 | send_image_every_n = 20
28 |
29 | # Best results:
30 | # python handwriting_line_recognition.py --epochs 251 -n handwriting_line.params -g 0 -l 0.0001 -x 0.1 -y 0.1 -j 0.15 -k 0.15 -p 0.75 -o 2 -a 128
31 |
32 | alphabet_encoding = r' !"#&\'()*+,-./0123456789:;?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
33 | alphabet_dict = {alphabet_encoding[i]:i for i in range(len(alphabet_encoding))}
34 |
35 | class EncoderLayer(gluon.HybridBlock):
36 | '''
37 | The encoder layer takes the image features from a CNN. The image features are transposed so that the LSTM
38 | slices of the image features can be sequentially fed into the LSTM from left to right (and back via the
39 | bidirectional LSTM).
40 | '''
41 | def __init__(self, hidden_states=200, rnn_layers=1, max_seq_len=100, **kwargs):
42 | self.max_seq_len = max_seq_len
43 | super(EncoderLayer, self).__init__(**kwargs)
44 | with self.name_scope():
45 | self.lstm = mx.gluon.rnn.LSTM(hidden_states, rnn_layers, bidirectional=True)
46 |
47 | def hybrid_forward(self, F, x):
48 | x = x.transpose((0, 3, 1, 2))
49 | x = x.flatten()
50 | x = x.split(num_outputs=self.max_seq_len, axis=1) # (SEQ_LEN, N, CHANNELS)
51 | x = F.concat(*[elem.expand_dims(axis=0) for elem in x], dim=0)
52 | x = self.lstm(x)
53 | x = x.transpose((1, 0, 2)) #(N, SEQ_LEN, HIDDEN_UNITS)
54 | return x
55 |
56 | class Network(gluon.HybridBlock):
57 | '''
58 | The CNN-biLSTM to recognise handwriting text given an image of handwriten text.
59 | Parameters
60 | ----------
61 | num_downsamples: int, default 2
62 | The number of times to downsample the image features. Each time the features are downsampled, a new LSTM
63 | is created.
64 | resnet_layer_id: int, default 4
65 | The layer ID to obtain features from the resnet34
66 | lstm_hidden_states: int, default 200
67 | The number of hidden states used in the LSTMs
68 | lstm_layers: int, default 1
69 | The number of layers of LSTMs to use
70 | '''
71 | FEATURE_EXTRACTOR_FILTER = 64
72 | def __init__(self, num_downsamples=2, resnet_layer_id=4, rnn_hidden_states=200, rnn_layers=1, max_seq_len=100, ctx=mx.gpu(0), **kwargs):
73 | super(Network, self).__init__(**kwargs)
74 | self.p_dropout = 0.5
75 | self.num_downsamples = num_downsamples
76 | self.max_seq_len = max_seq_len
77 | self.ctx = ctx
78 | with self.name_scope():
79 | self.body = self.get_body(resnet_layer_id=resnet_layer_id)
80 |
81 | self.encoders = gluon.nn.HybridSequential()
82 | with self.encoders.name_scope():
83 | for i in range(self.num_downsamples):
84 | encoder = self.get_encoder(rnn_hidden_states=rnn_hidden_states, rnn_layers=rnn_layers, max_seq_len=max_seq_len)
85 | self.encoders.add(encoder)
86 | self.decoder = self.get_decoder()
87 | self.downsampler = self.get_down_sampler(self.FEATURE_EXTRACTOR_FILTER)
88 |
89 | def get_down_sampler(self, num_filters):
90 | '''
91 | Creates a two-stacked Conv-BatchNorm-Relu and then a pooling layer to
92 | downsample the image features by half.
93 |
94 | Parameters
95 | ----------
96 | num_filters: int
97 | To select the number of filters in used the downsampling convolutional layer.
98 | Returns
99 | -------
100 | network: gluon.nn.HybridSequential
101 | The downsampler network that decreases the width and height of the image features by half.
102 |
103 | '''
104 | out = gluon.nn.HybridSequential()
105 | with out.name_scope():
106 | for _ in range(2):
107 | out.add(gluon.nn.Conv2D(num_filters, 3, strides=1, padding=1))
108 | out.add(gluon.nn.BatchNorm(in_channels=num_filters))
109 | out.add(gluon.nn.Activation('relu'))
110 | out.add(gluon.nn.MaxPool2D(2))
111 | out.collect_params().initialize(mx.init.Normal(), ctx=self.ctx)
112 | out.hybridize()
113 | return out
114 |
115 | def get_body(self, resnet_layer_id):
116 | '''
117 | Create the feature extraction network based on resnet34.
118 | The first layer of the res-net is converted into grayscale by averaging the weights of the 3 channels
119 | of the original resnet.
120 |
121 | Parameters
122 | ----------
123 | resnet_layer_id: int
124 | The resnet_layer_id specifies which layer to take from
125 | the bottom of the network.
126 | Returns
127 | -------
128 | network: gluon.nn.HybridSequential
129 | The body network for feature extraction based on resnet
130 | '''
131 |
132 | pretrained = resnet34_v1(pretrained=True, ctx=self.ctx)
133 | pretrained_2 = resnet34_v1(pretrained=True, ctx=mx.cpu(0))
134 | first_weights = pretrained_2.features[0].weight.data().mean(axis=1).expand_dims(axis=1)
135 | # First weights could be replaced with individual channels.
136 |
137 | body = gluon.nn.HybridSequential()
138 | with body.name_scope():
139 | first_layer = gluon.nn.Conv2D(channels=64, kernel_size=(7, 7), padding=(3, 3), strides=(2, 2), in_channels=1, use_bias=False)
140 | first_layer.initialize(mx.init.Xavier(), ctx=self.ctx)
141 | first_layer.weight.set_data(first_weights)
142 | body.add(first_layer)
143 | body.add(*pretrained.features[1:-resnet_layer_id])
144 | return body
145 |
146 | def get_encoder(self, rnn_hidden_states, rnn_layers, max_seq_len):
147 | '''
148 | Creates an LSTM to learn the sequential component of the image features.
149 |
150 | Parameters
151 | ----------
152 |
153 | rnn_hidden_states: int
154 | The number of hidden states in the RNN
155 |
156 | rnn_layers: int
157 | The number of layers to stack the RNN
158 | Returns
159 | -------
160 |
161 | network: gluon.nn.Sequential
162 | The encoder network to learn the sequential information of the image features
163 | '''
164 |
165 | encoder = gluon.nn.HybridSequential()
166 | with encoder.name_scope():
167 | encoder.add(EncoderLayer(hidden_states=rnn_hidden_states, rnn_layers=rnn_layers, max_seq_len=max_seq_len))
168 | encoder.add(gluon.nn.Dropout(self.p_dropout))
169 | encoder.collect_params().initialize(mx.init.Xavier(), ctx=self.ctx)
170 | return encoder
171 |
172 | def get_decoder(self):
173 | '''
174 | Creates a network to convert the output of the encoder into characters.
175 | '''
176 |
177 | alphabet_size = len(alphabet_encoding) + 1
178 | decoder = mx.gluon.nn.Dense(units=alphabet_size, flatten=False)
179 | decoder.collect_params().initialize(mx.init.Xavier(), ctx=self.ctx)
180 | return decoder
181 |
182 | def hybrid_forward(self, F, x):
183 | features = self.body(x)
184 | hidden_states = []
185 | hs = self.encoders[0](features)
186 | hidden_states.append(hs)
187 | for i, _ in enumerate(range(self.num_downsamples - 1)):
188 | features = self.downsampler(features)
189 | hs = self.encoders[i+1](features)
190 | hidden_states.append(hs)
191 | hs = F.concat(*hidden_states, dim=2)
192 | output = self.decoder(hs)
193 | return output
194 |
195 | def handwriting_recognition_transform(image, line_image_size):
196 | '''
197 | Resize and normalise the image to be fed into the network.
198 | '''
199 | image, _ = resize_image(image, line_image_size)
200 | image = mx.nd.array(image)/255.
201 | image = (image - 0.942532484060557) / 0.15926149044640417
202 | image = image.expand_dims(0).expand_dims(0)
203 | return image
204 |
205 | def transform(image, label):
206 | '''
207 | This function resizes the input image and converts so that it could be fed into the network.
208 | Furthermore, the label (text) is one-hot encoded.
209 | '''
210 | image = np.expand_dims(image, axis=0).astype(np.float32)
211 | if image[0, 0, 0] > 1:
212 | image = image/255.
213 | image = (image - 0.942532484060557) / 0.15926149044640417
214 | label_encoded = np.zeros(max_seq_len, dtype=np.float32)-1
215 | i = 0
216 | for word in label:
217 | word = word.replace(""", r'"')
218 | word = word.replace("&", r'&')
219 | word = word.replace('";', '\"')
220 | for letter in word:
221 | label_encoded[i] = alphabet_dict[letter]
222 | i += 1
223 | return image, label_encoded
224 |
225 | def augment_transform(image, label):
226 | '''
227 | This function randomly:
228 | - translates the input image by +-width_range and +-height_range (percentage).
229 | - scales the image by y_scaling and x_scaling (percentage)
230 | - shears the image by shearing_factor (radians)
231 | '''
232 |
233 | ty = random.uniform(-random_y_translation, random_y_translation)
234 | tx = random.uniform(-random_x_translation, random_x_translation)
235 |
236 | sx = random.uniform(1. - random_y_scaling, 1. + random_y_scaling)
237 | sy = random.uniform(1. - random_x_scaling, 1. + random_x_scaling)
238 |
239 | s = random.uniform(-random_shearing, random_shearing)
240 | gamma = random.uniform(0.001, random_gamma)
241 | image = exposure.adjust_gamma(image, gamma)
242 |
243 | st = skimage_tf.AffineTransform(scale=(sx, sy),
244 | shear=s,
245 | translation=(tx*image.shape[1], ty*image.shape[0]))
246 | augmented_image = skimage_tf.warp(image, st, cval=1.0)
247 | return transform(augmented_image*255., label)
248 |
249 |
250 | def decode(prediction):
251 | '''
252 | Returns the string given one-hot encoded vectors.
253 | '''
254 |
255 | results = []
256 | for word in prediction:
257 | result = []
258 | for i, index in enumerate(word):
259 | if i < len(word) - 1 and word[i] == word[i+1] and word[-1] != -1: #Hack to decode label as well
260 | continue
261 | if index == len(alphabet_dict) or index == -1:
262 | continue
263 | else:
264 | result.append(alphabet_encoding[int(index)])
265 | results.append(result)
266 | words = [''.join(word) for word in results]
267 | return words
268 |
269 | def run_epoch(e, network, dataloader, trainer, log_dir, print_name, is_train):
270 | '''
271 | Run one epoch to train or test the CNN-biLSTM network
272 |
273 | Parameters
274 | ----------
275 |
276 | e: int
277 | The epoch number
278 | network: nn.Gluon.HybridSequential
279 | The CNN-biLSTM network
280 | dataloader: gluon.data.DataLoader
281 | The train or testing dataloader that is wrapped around the iam_dataset
282 |
283 | log_dir: Str
284 | The directory to store the log files for mxboard
285 | print_name: Str
286 | Name to print for associating with the data. usually this will be "train" and "test"
287 |
288 | is_train: bool
289 | Boolean to indicate whether or not the network should be updated. is_train should only be set to true for the training data
290 | Returns
291 | -------
292 |
293 | epoch_loss: float
294 | The loss of the current epoch
295 | '''
296 |
297 | total_loss = [nd.zeros(1, ctx_) for ctx_ in ctx]
298 | for i, (x_, y_) in enumerate(dataloader):
299 | X = gluon.utils.split_and_load(x_, ctx)
300 | Y = gluon.utils.split_and_load(y_, ctx)
301 | with autograd.record(train_mode=is_train):
302 | output = [network(x) for x in X]
303 | loss_ctc = [ctc_loss(o, y) for o, y in zip(output, Y)]
304 |
305 | if is_train:
306 | [l.backward() for l in loss_ctc]
307 | trainer.step(x_.shape[0])
308 |
309 | if i == 0 and e % send_image_every_n == 0 and e > 0:
310 | predictions = output[0][:4].softmax().topk(axis=2).asnumpy()
311 | decoded_text = decode(predictions)
312 | image = X[0][:4].asnumpy()
313 | image = image * 0.15926149044640417 + 0.942532484060557
314 | output_image = draw_text_on_image(image, decoded_text)
315 | print("{} first decoded text = {}".format(print_name, decoded_text[0]))
316 | with SummaryWriter(logdir=log_dir, verbose=False, flush_secs=5) as sw:
317 | sw.add_image('bb_{}_image'.format(print_name), output_image, global_step=e)
318 |
319 | for i, l in enumerate(loss_ctc):
320 | total_loss[i] += l.mean()
321 |
322 | epoch_loss = float(sum([tl.asscalar() for tl in total_loss]))/(len(dataloader)*len(ctx))
323 |
324 | with SummaryWriter(logdir=log_dir, verbose=False, flush_secs=5) as sw:
325 | sw.add_scalar('loss', {print_name: epoch_loss}, global_step=e)
326 |
327 | return epoch_loss
328 |
329 | if __name__ == "__main__":
330 | parser = argparse.ArgumentParser()
331 | parser.add_argument("-g", "--gpu_id", default="0",
332 | help="IDs of the GPU to use, -1 for CPU")
333 |
334 | parser.add_argument("-t", "--line_or_word", default="line",
335 | help="to choose the handwriting to train on words or lines")
336 |
337 | parser.add_argument("-u", "--num_downsamples", default=2,
338 | help="Number of downsamples for the res net")
339 | parser.add_argument("-q", "--resnet_layer_id", default=4,
340 | help="layer ID to obtain features from the resnet34")
341 | parser.add_argument("-a", "--rnn_hidden_states", default=200,
342 | help="Number of hidden states for the RNN encoder")
343 | parser.add_argument("-o", "--rnn_layers", default=1,
344 | help="Number of layers for the RNN")
345 |
346 | parser.add_argument("-e", "--epochs", default=121,
347 | help="Number of epochs to run")
348 | parser.add_argument("-l", "--learning_rate", default=0.0001,
349 | help="Learning rate for training")
350 | parser.add_argument("-w", "--lr_scale", default=1,
351 | help="Amount the divide the learning rate")
352 | parser.add_argument("-r", "--lr_period", default=30,
353 | help="Divides the learning rate after period")
354 |
355 | parser.add_argument("-s", "--batch_size", default=64,
356 | help="Batch size")
357 |
358 | parser.add_argument("-x", "--random_x_translation", default=0.03,
359 | help="Randomly translation the image in the x direction (+ or -)")
360 | parser.add_argument("-y", "--random_y_translation", default=0.03,
361 | help="Randomly translation the image in the y direction (+ or -)")
362 | parser.add_argument("-j", "--random_x_scaling", default=0.10,
363 | help="Randomly scale the image in the x direction")
364 | parser.add_argument("-k", "--random_y_scaling", default=0.10,
365 | help="Randomly scale the image in the y direction")
366 | parser.add_argument("-p", "--random_shearing", default=0.5,
367 | help="Randomly shear the image in radians (+ or -)")
368 | parser.add_argument("-ga", "--random_gamma", default=1,
369 | help="Randomly update gamma of image (+ or -)")
370 |
371 | parser.add_argument("-d", "--log_dir", default="./logs",
372 | help="Directory to store the log files")
373 | parser.add_argument("-c", "--checkpoint_dir", default="model_checkpoint",
374 | help="Directory to store the checkpoints")
375 | parser.add_argument("-n", "--checkpoint_name", default="handwriting_line.params",
376 | help="Name to store the checkpoints")
377 | parser.add_argument("-m", "--load_model", default=None,
378 | help="Name of model to load")
379 | parser.add_argument("-sl", "--max-seq-len", default=None,
380 | help="Maximum sequence length")
381 | args = parser.parse_args()
382 |
383 | print(args)
384 |
385 | gpu_ids = [int(elem) for elem in args.gpu_id.split(",")]
386 |
387 | if gpu_ids == [-1]:
388 | ctx=[mx.cpu()]
389 | else:
390 | ctx=[mx.gpu(i) for i in gpu_ids]
391 |
392 | line_or_word = args.line_or_word
393 | assert line_or_word in ["line", "word"], "{} is not a value option in [\"line\", \"word\"]"
394 |
395 | num_downsamples = int(args.num_downsamples)
396 | resnet_layer_id = int(args.resnet_layer_id)
397 | rnn_hidden_states = int(args.rnn_hidden_states)
398 | rnn_layers = int(args.rnn_layers)
399 |
400 | epochs = int(args.epochs)
401 | learning_rate = float(args.learning_rate)
402 | lr_scale = float(args.lr_scale)
403 | lr_period = float(args.lr_period)
404 | batch_size = int(args.batch_size)
405 |
406 | random_y_translation, random_x_translation = float(args.random_x_translation), float(args.random_y_translation)
407 | random_y_scaling, random_x_scaling = float(args.random_y_scaling), float(args.random_x_scaling)
408 | random_shearing = float(args.random_shearing)
409 | random_gamma = float(args.random_gamma)
410 |
411 | log_dir = args.log_dir
412 | checkpoint_dir, checkpoint_name = args.checkpoint_dir, args.checkpoint_name
413 | load_model = args.load_model
414 | max_seq_len = args.max_seq_len
415 |
416 | if max_seq_len is not None:
417 | max_seq_len = int(max_seq_len)
418 | elif line_or_word == "line":
419 | max_seq_len = 100
420 | else:
421 | max_seq_len = 32
422 |
423 | net = Network(num_downsamples=num_downsamples, resnet_layer_id=resnet_layer_id , rnn_hidden_states=rnn_hidden_states, rnn_layers=rnn_layers,
424 | max_seq_len=max_seq_len, ctx=ctx)
425 |
426 | if load_model is not None and os.path.isfile(os.path.join(checkpoint_dir,load_model)):
427 | net.load_parameters(os.path.join(checkpoint_dir,load_model))
428 |
429 | train_ds = IAMDataset(line_or_word, output_data="text", train=True)
430 | print("Number of training samples: {}".format(len(train_ds)))
431 |
432 | test_ds = IAMDataset(line_or_word, output_data="text", train=False)
433 | print("Number of testing samples: {}".format(len(test_ds)))
434 |
435 | train_data = gluon.data.DataLoader(train_ds.transform(augment_transform), batch_size, shuffle=True, last_batch="rollover", num_workers=4*len(ctx))
436 | test_data = gluon.data.DataLoader(test_ds.transform(transform), batch_size, shuffle=True, last_batch="discard", num_workers=4*len(ctx))
437 |
438 | schedule = mx.lr_scheduler.FactorScheduler(step=lr_period*len(train_data), factor=lr_scale)
439 | schedule.base_lr = learning_rate
440 |
441 | trainer = gluon.Trainer(net.collect_params(), 'adam', {'learning_rate': learning_rate, "lr_scheduler": schedule, 'clip_gradient': 2})
442 |
443 | ctc_loss = gluon.loss.CTCLoss()
444 |
445 | best_test_loss = 10e10
446 | for e in range(epochs):
447 | train_loss = run_epoch(e, net, train_data, trainer, log_dir, print_name="train", is_train=True)
448 | test_loss = run_epoch(e, net, test_data, trainer, log_dir, print_name="test", is_train=False)
449 | if test_loss < best_test_loss:
450 | print("Saving network, previous best test loss {:.6f}, current test loss {:.6f}".format(best_test_loss, test_loss))
451 | net.save_parameters(os.path.join(checkpoint_dir, checkpoint_name))
452 | best_test_loss = test_loss
453 |
454 | if e % print_every_n == 0 and e > 0:
455 | print("Epoch {0}, train_loss {1:.6f}, test_loss {2:.6f}".format(e, train_loss, test_loss))
456 |
--------------------------------------------------------------------------------
/utilities/iam_dataset.py:
--------------------------------------------------------------------------------
1 | import os
2 | import urllib
3 | import sys
4 | import time
5 | import glob
6 | import pickle
7 | import xml.etree.ElementTree as ET
8 | import cv2
9 | import numpy as np
10 | import pandas as pd
11 | import matplotlib.pyplot as plt
12 | import logging
13 |
14 | from mxnet.gluon.data import dataset
15 |
16 | class IAMDataset(dataset.ArrayDataset):
17 |
18 | """
19 | Parameters
20 | ----------
21 | parse_method: str, Required
22 | To select the method of parsing the images of the passage
23 | Available options: [form, form_bb, line, word]
24 |
25 | root: str, default: dataset/iamdataset
26 | Location to save the database
27 |
28 | train: bool, default True
29 | Whether to load the training or testing set of writers.
30 |
31 | output_data_type: str, default text
32 | What type of data you want as an output: Text or bounding box.
33 | Available options are: [text, bb]
34 |
35 | output_parse_method: str, default None
36 | If the bounding box (bb) was selected as an output_data_type,
37 | this parameter can select which bb you want to obtain.
38 | Available options: [form, line, word]
39 |
40 | output_form_text_as_array: bool, default False
41 | When output_data is set to text and the parse method is set to form or form_original,
42 | if output_form_text_as_array is true, the output text will be a list of lines string
43 | """
44 |
45 | MAX_IMAGE_SIZE_FORM = (1120, 800)
46 | MAX_IMAGE_SIZE_LINE = (60, 800)
47 | MAX_IMAGE_SIZE_WORD = (30, 140)
48 | def __init__(self, parse_method,
49 | root=os.path.join(os.path.dirname(__file__), '..', 'dataset', 'iamdataset'),
50 | train=True, output_data="text",
51 | output_parse_method=None,
52 | output_form_text_as_array=False):
53 |
54 | _parse_methods = ["form", "form_original", "form_bb", "line", "word"]
55 | error_message = "{} is not a possible parsing method: {}".format(
56 | parse_method, _parse_methods)
57 | assert parse_method in _parse_methods, error_message
58 | self._parse_method = parse_method
59 |
60 |
61 | self._train = train
62 |
63 | _output_data_types = ["text", "bb"]
64 | error_message = "{} is not a possible output data: {}".format(
65 | output_data, _output_data_types)
66 | assert output_data in _output_data_types, error_message
67 | self._output_data = output_data
68 |
69 | if self._output_data == "bb":
70 | assert self._parse_method in ["form", "form_bb"], "Bounding box only works with form."
71 | _parse_methods = ["form", "line", "word"]
72 | error_message = "{} is not a possible output parsing method: {}".format(
73 | output_parse_method, _parse_methods)
74 | assert output_parse_method in _parse_methods, error_message
75 | self._output_parse_method = output_parse_method
76 |
77 | self.image_data_file_name = os.path.join(root, "image_data-{}-{}-{}*.plk".format(
78 | self._parse_method, self._output_data, self._output_parse_method))
79 | else:
80 | self.image_data_file_name = os.path.join(root, "image_data-{}-{}*.plk".format(self._parse_method, self._output_data))
81 |
82 | self._root = root
83 | #if not os.path.isdir(root):
84 | # os.makedirs(root)
85 | self._output_form_text_as_array = output_form_text_as_array
86 |
87 | data = self._get_data()
88 | super(IAMDataset, self).__init__(data)
89 |
90 | def _get_data(self):
91 |
92 | '''
93 | Function to get the data and to extract the data for training or testing
94 |
95 | Returns
96 | -------
97 | pd.DataFrame
98 | A dataframe (subject, image, and output) that contains only the training/testing data
99 |
100 | '''
101 |
102 | #print("Get data")
103 |
104 |
105 |
106 |
107 | if len(glob.glob(self.image_data_file_name)) > 0:
108 | logging.info("Loading data from pickle")
109 | images_data = self._load_dataframe_chunks(self.image_data_file_name)
110 | else:
111 | images_data = self._process_data()
112 |
113 |
114 | #images_data = self._process_data() #comment this line if using pickle
115 |
116 | # Extract train or test data out
117 | train_subjects, test_subjects = self._process_subjects()
118 | if self._train:
119 | data = images_data[np.in1d(self._convert_subject_list(images_data["subject"]),
120 | train_subjects)]
121 | else:
122 | data = images_data[np.in1d(self._convert_subject_list(images_data["subject"]),
123 | test_subjects)]
124 | return data
125 |
126 | def _process_data(self):
127 | '''
128 | Function that iterates through the downloaded xml file to gather the input images and the
129 | corresponding output.
130 |
131 | Returns
132 | -------
133 | pd.DataFrame
134 | A pandas dataframe that contains the subject, image and output requested.
135 | '''
136 | image_data = []
137 | xml_files = glob.glob(self._root + "/xml/*.xml")
138 | print("Processing data:")
139 | logging.info("Processing data")
140 | for i, xml_file in enumerate(xml_files):
141 | tree = ET.parse(xml_file)
142 | root = tree.getroot()
143 | height, width = int(root.attrib["height"]), int(root.attrib["width"])
144 | for item in root.iter(self._parse_method.split("_")[0]): #_parse_method=form_original
145 | # Split _ to account for only taking the base "form", "line", "word" that is available in the IAM dataset
146 | #print(self._parse_method.split("_")[1])
147 | if self._parse_method in ["form", "form_bb", "form_original"]:
148 | image_id = item.attrib["id"]
149 | else:
150 | tmp_id = item.attrib["id"]
151 | tmp_id_split = tmp_id.split("-")
152 | image_id = os.path.join(tmp_id_split[0], tmp_id_split[0] + "-" + tmp_id_split[1], tmp_id)
153 | image_filename = os.path.join(self._root, self._parse_method.split("_")[0], image_id + ".png")
154 | image_arr = self._pre_process_image(image_filename)
155 | if image_arr is None:
156 | continue
157 | output_data = self._get_output_data(item, height, width)
158 | if self._parse_method == "form_bb":
159 | image_arr, output_data = self._crop_and_resize_form_bb(item, image_arr, output_data, height, width)
160 | image_data.append([item.attrib["id"], image_arr, output_data])
161 | image_data = pd.DataFrame(image_data, columns=["subject", "image", "output"])
162 | self._save_dataframe_chunks(image_data, self.image_data_file_name) #don't comment line if using pickle
163 | return image_data
164 |
165 | def _pre_process_image(self, img_in):
166 | '''
167 | Function to read the image and convert it to array data
168 | It also resizes the image to standard size if it is of type ["form","form_bb","line","word"]
169 |
170 | Parameters
171 | ----------
172 | img_in: str, Required
173 | Contains the filename of the image
174 |
175 | Returns
176 | ----------
177 | img_arr
178 | An image converted to an array
179 | '''
180 | #print("Pre Processing Image")
181 | im = cv2.imread(img_in, cv2.IMREAD_GRAYSCALE)
182 | if np.size(im) == 1: # skip if the image data is corrupt.
183 | return None
184 | # reduce the size of form images so that it can fit in memory.
185 | if self._parse_method in ["form", "form_bb"]:
186 | im, _ = resize_image(im, self.MAX_IMAGE_SIZE_FORM) #resize function to be done soon
187 | if self._parse_method == "line":
188 | im, _ = resize_image(im, self.MAX_IMAGE_SIZE_LINE)
189 | if self._parse_method == "word":
190 | im, _ = resize_image(im, self.MAX_IMAGE_SIZE_WORD)
191 | img_arr = np.asarray(im)
192 | return img_arr
193 |
194 | def _get_output_data(self, item, height, width):
195 |
196 | '''
197 | Function to obtain the output data (both text and bounding boxes).
198 | Note that the bounding boxes are rescaled based on the rescale_ratio parameter.
199 |
200 | Parameter
201 | ---------
202 | item: xml.etree
203 | XML object for a word/line/form.
204 |
205 | height: int
206 | Height of the form to calculate percentages of bounding boxes
207 |
208 | width: int
209 | Width of the form to calculate percentages of bounding boxes
210 |
211 | Returns
212 | -------
213 |
214 | np.array
215 | A numpy array of the output requested (text or the bounding box)
216 | '''
217 |
218 | #print("Get output data")
219 | output_data = []
220 | if self._output_data == "text":
221 | if self._parse_method in ["form", "form_bb", "form_original"]:
222 | text = ""
223 | for line in item.iter('line'):
224 | text += line.attrib["text"] + "\n"
225 | output_data.append(text)
226 | else:
227 | output_data.append(item.attrib['text'])
228 | else:
229 | for item_output in item.iter(self._output_parse_method):
230 | bb = self._get_bb_of_item(item_output, height, width)
231 | if bb == None: # Account for words with no letters
232 | continue
233 | output_data.append(bb)
234 | output_data = np.array(output_data)
235 | return output_data
236 |
237 | def _process_subjects(self, train_subject_lists = ["trainset", "validationset1", "validationset2"],
238 | test_subject_lists = ["testset"]):
239 |
240 | '''
241 | Function to organise the list of subjects to training and testing.
242 | The IAM dataset provides 4 files: trainset, validationset1, validationset2, and testset each
243 | with a list of subjects.
244 |
245 | Parameters
246 | ----------
247 |
248 | train_subject_lists: [str], default ["trainset", "validationset1", "validationset2"]
249 | The filenames of the list of subjects to be used for training the model
250 |
251 | test_subject_lists: [str], default ["testset"]
252 | The filenames of the list of subjects to be used for testing the model
253 |
254 | Returns
255 | -------
256 |
257 | train_subjects: [str]
258 | A list of subjects used for training
259 |
260 | test_subjects: [str]
261 | A list of subjects used for testing
262 | '''
263 |
264 | #print("Processing subjects")
265 | train_subjects = []
266 | test_subjects = []
267 | for train_list in train_subject_lists:
268 | subject_list = pd.read_csv(os.path.join(self._root, "subject", train_list+".txt"))
269 | train_subjects.append(subject_list.values)
270 | for test_list in test_subject_lists:
271 | subject_list = pd.read_csv(os.path.join(self._root, "subject", test_list+".txt"))
272 | test_subjects.append(subject_list.values)
273 |
274 | train_subjects = np.concatenate(train_subjects)
275 | test_subjects = np.concatenate(test_subjects)
276 | if self._parse_method in ["form", "form_bb", "form_original"]:
277 | new_train_subjects = []
278 | for i in train_subjects:
279 | form_subject_number = i[0].split("-")[0] + "-" + i[0].split("-")[1]
280 | new_train_subjects.append(form_subject_number)
281 | new_test_subjects = []
282 | for i in test_subjects:
283 | form_subject_number = i[0].split("-")[0] + "-" + i[0].split("-")[1]
284 | new_test_subjects.append(form_subject_number)
285 | train_subjects, test_subjects = new_train_subjects, new_test_subjects
286 | return train_subjects, test_subjects
287 |
288 | def _convert_subject_list(self, subject_list):
289 |
290 | '''
291 | Function to convert the list of subjects for the "word" parse method
292 |
293 | Parameters
294 | ----------
295 |
296 | subject_lists: [str]
297 | A list of subjects
298 |
299 | Returns
300 | -------
301 |
302 | subject_lists: [str]
303 | A list of subjects that is compatible with the "word" parse method
304 |
305 | '''
306 |
307 | print("Convert subject list")
308 | if self._parse_method == "word":
309 | new_subject_list = []
310 | for sub in subject_list:
311 | new_subject_number = "-".join(sub.split("-")[:3])
312 | new_subject_list.append(new_subject_number)
313 | return new_subject_list
314 | else:
315 | return subject_list
316 |
317 | def _get_bb_of_item(self, item, height, width):
318 | ''' Helper function to find the bounding box (bb) of an item in the xml file.
319 | All the characters within the item are found and the left-most (min) and right-most (max + length)
320 | are found.
321 | The bounding box emcompasses the left and right most characters in the x and y direction.
322 |
323 | Parameter
324 | ---------
325 | item: xml.etree object for a word/line/form.
326 |
327 | height: int
328 | Height of the form to calculate percentages of bounding boxes
329 |
330 | width: int
331 | Width of the form to calculate percentages of bounding boxes
332 |
333 | Returns
334 | -------
335 | list
336 | The bounding box [x, y, w, h] in percentages that encompasses the item.
337 | '''
338 |
339 | character_list = [a for a in item.iter("cmp")]
340 | if len(character_list) == 0: # To account for some punctuations that have no words
341 | return None
342 | x1 = np.min([int(a.attrib['x']) for a in character_list])
343 | y1 = np.min([int(a.attrib['y']) for a in character_list])
344 | x2 = np.max([int(a.attrib['x']) + int(a.attrib['width']) for a in character_list])
345 | y2 = np.max([int(a.attrib['y']) + int(a.attrib['height'])for a in character_list])
346 |
347 | x1 = float(x1) / width
348 | x2 = float(x2) / width
349 | y1 = float(y1) / height
350 | y2 = float(y2) / height
351 | bb = [x1, y1, x2 - x1, y2 - y1]
352 | return bb
353 |
354 | def _crop_and_resize_form_bb(self, item, image_arr, output_data, height, width):
355 | bb = self._get_bb_of_item(item, height, width)
356 |
357 | # Expand the form bounding box by 5%
358 | expand_bb_scale = 0.05
359 | new_w = (1 + expand_bb_scale) * bb[2]
360 | new_h = (1 + expand_bb_scale) * bb[3]
361 |
362 | bb[0] = bb[0] - (new_w - bb[2])/2
363 | bb[1] = bb[1] - (new_h - bb[3])/2
364 | bb[2] = new_w
365 | bb[3] = new_h
366 |
367 | image_arr_bb = crop_image(image_arr, bb)
368 |
369 | if self._output_data == "bb":
370 | output_data = self._change_bb_reference(output_data, bb, image_arr.shape, image_arr.shape, image_arr_bb.shape, "minus")
371 |
372 | image_arr_bb_, bb = resize_image(image_arr_bb, desired_size=(700, 700))
373 |
374 | if self._output_data == "bb":
375 | output_data = self._change_bb_reference(output_data, bb, image_arr_bb.shape, image_arr_bb_.shape, image_arr_bb_.shape, "plus")
376 | image_arr = image_arr_bb_
377 | return image_arr, output_data
378 |
379 | def _change_bb_reference(self, bb, relative_bb, bb_reference_size, relative_bb_reference_size, output_size, operator):
380 | ''' Helper function to convert bounding boxes relative into another bounding bounding box.
381 | Parameter
382 | --------
383 | bb: [[int, int, int, int]]
384 | Bounding boxes (x, y, w, h) in percentages to be converted.
385 |
386 | relative_bb: [int, int, int, int]
387 | Reference bounding box (in percentages) to convert bb to
388 |
389 | bb_reference_size: (int, int)
390 | Size (h, w) in pixels of the image containing bb
391 |
392 | relative_bb_reference_size: (int, int)
393 | Size (h, w) in pixels of the image containing relative_bb
394 |
395 | output_size: (int, int)
396 | Size (h, w) in pixels of the output image
397 |
398 | operator: string
399 | Options ["plus", "minus"]. "plus" if relative_bb is within bb and "minus" if bb is within relative_bb
400 |
401 | Returns
402 | -------
403 | bb: [[int, int, int, int]]
404 | Bounding boxes (x, y, w, h) in percentages that are converted
405 |
406 | '''
407 | (x1, y1, x2, y2) = (bb[:, 0], bb[:, 1], bb[:, 0] + bb[:, 2], bb[:, 1] + bb[:, 3])
408 | (x1, y1, x2, y2) = (x1 * bb_reference_size[1], y1 * bb_reference_size[0],
409 | x2 * bb_reference_size[1], y2 * bb_reference_size[0])
410 |
411 | if operator == "plus":
412 | new_x1 = (x1 + relative_bb[0] * relative_bb_reference_size[1]) / output_size[1]
413 | new_y1 = (y1 + relative_bb[1] * relative_bb_reference_size[0]) / output_size[0]
414 | new_x2 = (x2 + relative_bb[0] * relative_bb_reference_size[1]) / output_size[1]
415 | new_y2 = (y2 + relative_bb[1] * relative_bb_reference_size[0]) / output_size[0]
416 | else:
417 | new_x1 = (x1 - relative_bb[0] * relative_bb_reference_size[1]) / output_size[1]
418 | new_y1 = (y1 - relative_bb[1] * relative_bb_reference_size[0]) / output_size[0]
419 | new_x2 = (x2 - relative_bb[0] * relative_bb_reference_size[1]) / output_size[1]
420 | new_y2 = (y2 - relative_bb[1] * relative_bb_reference_size[0]) / output_size[0]
421 |
422 | new_bbs = np.zeros(shape=bb.shape)
423 | new_bbs[:, 0] = new_x1
424 | new_bbs[:, 1] = new_y1
425 | new_bbs[:, 2] = new_x2 - new_x1
426 | new_bbs[:, 3] = new_y2 - new_y1
427 | return new_bbs
428 |
429 |
430 |
431 | def _save_dataframe_chunks(self, df, name):
432 | for i, df_split in enumerate(np.array_split(df, 4)):
433 | filename = name[:-5] + str(i) + ".plk" # remove *.plk in the filename
434 | df_split.to_pickle(filename, protocol=2)
435 |
436 | def _load_dataframe_chunks(self, name):
437 | image_data_chunks = []
438 | for fn in sorted(glob.glob(name)):
439 | df = pickle.load(open(fn, 'rb'))
440 | image_data_chunks.append(df)
441 | image_data = pd.concat(image_data_chunks)
442 | return image_data
443 |
444 |
445 |
446 | def __getitem__(self, idx):
447 | return (self._data[0].iloc[idx].image, self._data[0].iloc[idx].output)
448 |
449 | def crop_image(image, bb):
450 | ''' Helper function to crop the image by the bounding box (in percentages)
451 | '''
452 | (x, y, w, h) = bb
453 | x = x * image.shape[1]
454 | y = y * image.shape[0]
455 | w = w * image.shape[1]
456 | h = h * image.shape[0]
457 | (x1, y1, x2, y2) = (x, y, x + w, y + h)
458 | (x1, y1, x2, y2) = (int(x1), int(y1), int(x2), int(y2))
459 | return image[y1:y2, x1:x2]
460 |
461 | def resize_image(image, desired_size):
462 | ''' Helper function to resize an image while keeping the aspect ratio.
463 | Parameter
464 | ---------
465 |
466 | image: np.array
467 | The image to be resized.
468 |
469 | desired_size: (int, int)
470 | The (height, width) of the resized image
471 |
472 | Return
473 | ------
474 |
475 | image: np.array
476 | The image of size = desired_size
477 |
478 | bounding box: (int, int, int, int)
479 | (x, y, w, h) in percentages of the resized image of the original
480 | '''
481 | size = image.shape[:2]
482 | if size[0] > desired_size[0] or size[1] > desired_size[1]:
483 | ratio_w = float(desired_size[0])/size[0]
484 | ratio_h = float(desired_size[1])/size[1]
485 | ratio = min(ratio_w, ratio_h)
486 | new_size = tuple([int(x*ratio) for x in size])
487 | image = cv2.resize(image, (new_size[1], new_size[0]))
488 | size = image.shape
489 |
490 | delta_w = max(0, desired_size[1] - size[1])
491 | delta_h = max(0, desired_size[0] - size[0])
492 | top, bottom = delta_h//2, delta_h-(delta_h//2)
493 | left, right = delta_w//2, delta_w-(delta_w//2)
494 |
495 | color = image[0][0]
496 | if color < 230:
497 | color = 230
498 | image = cv2.copyMakeBorder(image, top, bottom, left, right, cv2.BORDER_CONSTANT, value=float(color))
499 | crop_bb = (left/image.shape[1], top/image.shape[0], (image.shape[1] - right - left)/image.shape[1],
500 | (image.shape[0] - bottom - top)/image.shape[0])
501 | image[image > 230] = 255
502 | return image, crop_bb
503 |
504 | def crop_handwriting_page(image, bb, image_size):
505 | '''
506 | Given an image and bounding box (bb) crop the input image based on the bounding box.
507 | The final output image was scaled based on the image size.
508 |
509 | Parameters
510 | ----------
511 | image: np.array
512 | Input form image
513 |
514 | bb: (x, y, w, h)
515 | The bounding box in percentages to crop
516 |
517 | image_size: (h, w)
518 | Image size to scale the output image to.
519 |
520 | Returns
521 | -------
522 | output_image: np.array
523 | cropped image of size image_size.
524 | '''
525 | image = crop_image(image, bb)
526 |
527 | image, _ = resize_image(image, desired_size=image_size)
528 | return image
529 |
--------------------------------------------------------------------------------
/utilities/word_and_line_segmentation.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2 | # SPDX-License-Identifier: Apache-2.0
3 |
4 | import time
5 | import random
6 | import os
7 | import cv2
8 | import matplotlib.pyplot as plt
9 | import matplotlib.patches as patches
10 | import argparse
11 |
12 | import mxnet as mx
13 | from mxnet.contrib.ndarray import MultiBoxPrior, MultiBoxTarget, MultiBoxDetection, box_nms
14 | import numpy as np
15 | from skimage.draw import line_aa
16 | from skimage import transform as skimage_tf
17 |
18 | from mxnet import nd, autograd, gluon
19 | from mxnet.image import resize_short
20 | from mxboard import SummaryWriter
21 | from mxnet.gluon.model_zoo.vision import resnet34_v1
22 | np.seterr(all='raise')
23 |
24 | import multiprocessing
25 | mx.random.seed(1)
26 |
27 | from utilities.iam_dataset import IAMDataset
28 | from utilities.draw_box_on_image import draw_boxes_on_image
29 |
30 | print_every_n = 5
31 | send_image_every_n = 20
32 | save_every_n = 50
33 |
34 | # To run:
35 | # python word_segmentation.py --min_c 0.01 --overlap_thres 0.10 --topk 150 --epoch 401 --checkpoint_name ssd_400.params
36 | # For fine_tuning:
37 | # python word_segmentation.py -p ssd_550.params
38 |
39 | # python word_segmentation.py --min_c 0.05 --overlap_thres 0.001 --topk 400 --epoch 401 --checkpoint_name word_seg.params
40 |
41 | class SSD(gluon.Block):
42 | def __init__(self, num_classes, ctx, **kwargs):
43 | super(SSD, self).__init__(**kwargs)
44 |
45 | # Seven sets of anchor boxes are defined. For each set, n=2 sizes and m=3 ratios are defined.
46 | # Four anchor boxes (n + m - 1) are generated: 2 square anchor boxes based on the n=2 sizes and 2 rectanges based on
47 | # the sizes and the ratios. See https://discuss.mxnet.io/t/question-regarding-ssd-algorithm/1307 for more information.
48 |
49 | #self.anchor_sizes = [[.1, .2], [.2, .3], [.2, .4], [.4, .6], [.5, .7], [.6, .8], [.7, .9]]
50 | #self.anchor_ratios = [[1, 3, 5], [1, 3, 5], [1, 6, 8], [1, 5, 7], [1, 6, 8], [1, 7, 9], [1, 7, 10]]
51 |
52 | self.anchor_sizes = [[.1, .2], [.2, .3], [.2, .4], [.3, .4], [.3, .5], [.4, .6]]
53 | self.anchor_ratios = [[1, 3, 5], [1, 3, 5], [1, 6, 8], [1, 4, 7], [1, 6, 8], [1, 5, 7]]
54 |
55 | self.num_anchors = len(self.anchor_sizes)
56 | self.num_classes = num_classes
57 | self.ctx = ctx
58 | with self.name_scope():
59 | self.body, self.downsamples, self.class_preds, self.box_preds = self.get_ssd_model()
60 | self.downsamples.initialize(mx.init.Normal(), ctx=self.ctx)
61 | self.class_preds.initialize(mx.init.Normal(), ctx=self.ctx)
62 | self.box_preds.initialize(mx.init.Normal(), ctx=self.ctx)
63 |
64 | def get_body(self):
65 | '''
66 | Create the feature extraction network of the SSD based on resnet34.
67 | The first layer of the res-net is converted into grayscale by averaging the weights of the 3 channels
68 | of the original resnet.
69 |
70 | Returns
71 | -------
72 | network: gluon.nn.HybridSequential
73 | The body network for feature extraction based on resnet
74 |
75 | '''
76 | pretrained = resnet34_v1(pretrained=True, ctx=self.ctx)
77 | pretrained_2 = resnet34_v1(pretrained=True, ctx=mx.cpu(0))
78 | first_weights = pretrained_2.features[0].weight.data().mean(axis=1).expand_dims(axis=1)
79 | # First weights could be replaced with individual channels.
80 |
81 | body = gluon.nn.HybridSequential()
82 | with body.name_scope():
83 | first_layer = gluon.nn.Conv2D(channels=64, kernel_size=(7, 7), padding=(3, 3), strides=(2, 2), in_channels=1, use_bias=False)
84 | first_layer.initialize(mx.init.Normal(), ctx=self.ctx)
85 | first_layer.weight.set_data(first_weights)
86 | body.add(first_layer)
87 | body.add(*pretrained.features[1:-3])
88 | return body
89 |
90 | def get_class_predictor(self, num_anchors_predicted):
91 | '''
92 | Creates the category prediction network (takes input from each downsampled feature)
93 |
94 | Parameters
95 | ----------
96 |
97 | num_anchors_predicted: int
98 | Given n sizes and m ratios, the number of boxes predicted is n+m-1.
99 | e.g., sizes=[.1, .2], ratios=[1, 3, 5] the number of anchors predicted is 4.
100 |
101 | Returns
102 | -------
103 |
104 | network: gluon.nn.HybridSequential
105 | The class predictor network
106 | '''
107 | return gluon.nn.Conv2D(num_anchors_predicted*(self.num_classes + 1), kernel_size=3, padding=1)
108 |
109 | def get_box_predictor(self, num_anchors_predicted):
110 | '''
111 | Creates the bounding box prediction network (takes input from each downsampled feature)
112 |
113 | Parameters
114 | ----------
115 |
116 | num_anchors_predicted: int
117 | Given n sizes and m ratios, the number of boxes predicted is n+m-1.
118 | e.g., sizes=[.1, .2], ratios=[1, 3, 5] the number of anchors predicted is 4.
119 |
120 | Returns
121 | -------
122 |
123 | pred: gluon.nn.HybridSequential
124 | The box predictor network
125 | '''
126 | pred = gluon.nn.HybridSequential()
127 | with pred.name_scope():
128 | pred.add(gluon.nn.Conv2D(channels=num_anchors_predicted*4, kernel_size=3, padding=1))
129 | return pred
130 |
131 | def get_down_sampler(self, num_filters):
132 | '''
133 | Creates a two-stacked Conv-BatchNorm-Relu and then a pooling layer to
134 | downsample the image features by half.
135 | '''
136 | out = gluon.nn.HybridSequential()
137 | for _ in range(2):
138 | out.add(gluon.nn.Conv2D(num_filters, 3, strides=1, padding=1))
139 | out.add(gluon.nn.BatchNorm(in_channels=num_filters))
140 | out.add(gluon.nn.Activation('relu'))
141 | out.add(gluon.nn.MaxPool2D(2))
142 | out.hybridize()
143 | return out
144 |
145 | def get_ssd_model(self):
146 | '''
147 | Creates the SSD model that includes the image feature, downsample, category
148 | and bounding boxes prediction networks.
149 | '''
150 | body = self.get_body()
151 | downsamples = gluon.nn.HybridSequential()
152 | class_preds = gluon.nn.HybridSequential()
153 | box_preds = gluon.nn.HybridSequential()
154 |
155 | downsamples.add(self.get_down_sampler(32))
156 | downsamples.add(self.get_down_sampler(32))
157 | downsamples.add(self.get_down_sampler(32))
158 |
159 | for scale in range(self.num_anchors):
160 | num_anchors_predicted = len(self.anchor_sizes[0]) + len(self.anchor_ratios[0]) - 1
161 | class_preds.add(self.get_class_predictor(num_anchors_predicted))
162 | box_preds.add(self.get_box_predictor(num_anchors_predicted))
163 |
164 | return body, downsamples, class_preds, box_preds
165 |
166 | def ssd_forward(self, x):
167 | '''
168 | Helper function of the forward pass of the sdd
169 | '''
170 | x = self.body(x)
171 |
172 | default_anchors = []
173 | predicted_boxes = []
174 | predicted_classes = []
175 |
176 | for i in range(self.num_anchors):
177 | default_anchors.append(MultiBoxPrior(x, sizes=self.anchor_sizes[i], ratios=self.anchor_ratios[i]))
178 | predicted_boxes.append(self._flatten_prediction(self.box_preds[i](x)))
179 | predicted_classes.append(self._flatten_prediction(self.class_preds[i](x)))
180 | if i < len(self.downsamples):
181 | x = self.downsamples[i](x)
182 | elif i == 3:
183 | x = nd.Pooling(x, global_pool=True, pool_type='max', kernel=(4, 4))
184 | return default_anchors, predicted_classes, predicted_boxes
185 |
186 | def forward(self, x):
187 | default_anchors, predicted_classes, predicted_boxes = self.ssd_forward(x)
188 | # we want to concatenate anchors, class predictions, box predictions from different layers
189 | anchors = nd.concat(*default_anchors, dim=1)
190 | box_preds = nd.concat(*predicted_boxes, dim=1)
191 | class_preds = nd.concat(*predicted_classes, dim=1)
192 | class_preds = nd.reshape(class_preds, shape=(0, -1, self.num_classes + 1))
193 | return anchors, class_preds, box_preds
194 |
195 | def _flatten_prediction(self, pred):
196 | '''
197 | Helper function to flatten the predicted bounding boxes and categories
198 | '''
199 | return nd.flatten(nd.transpose(pred, axes=(0, 2, 3, 1)))
200 |
201 | def training_targets(self, default_anchors, class_predicts, labels):
202 | '''
203 | Helper function to obtain the bounding boxes from the anchors.
204 | '''
205 | class_predicts = nd.transpose(class_predicts, axes=(0, 2, 1))
206 | box_target, box_mask, cls_target = MultiBoxTarget(default_anchors, labels, class_predicts)
207 | return box_target, box_mask, cls_target
208 |
209 | class SmoothL1Loss(gluon.loss.Loss):
210 | '''
211 | A SmoothL1loss function defined in https://gluon.mxnet.io/chapter08_computer-vision/object-detection.html
212 | '''
213 | def __init__(self, batch_axis=0, **kwargs):
214 | super(SmoothL1Loss, self).__init__(None, batch_axis, **kwargs)
215 |
216 | def hybrid_forward(self, F, output, label, mask):
217 | loss = F.smooth_l1((output - label) * mask, scalar=1.0)
218 | return F.mean(loss, self._batch_axis, exclude=True)
219 |
220 | def augment_transform(image, label):
221 | '''
222 | 1) Function that randomly translates the input image by +-width_range and +-height_range.
223 | The labels (bounding boxes) are also translated by the same amount.
224 | 2) Each line can also be randomly removed for augmentation. Labels are also reduced to correspond to this
225 | data and label are converted into tensors by calling the "transform" function.
226 | '''
227 | ty = random.uniform(-random_y_translation, random_y_translation)
228 | tx = random.uniform(-random_x_translation, random_x_translation)
229 |
230 | st = skimage_tf.SimilarityTransform(translation=(tx*image.shape[1], ty*image.shape[0]))
231 | image = skimage_tf.warp(image, st, cval=1.0)
232 |
233 | label[:, 0] = label[:, 0] - tx/2 #NOTE: Check why it has to be halfed (found experimentally)
234 | label[:, 1] = label[:, 1] - ty/2
235 |
236 | index = np.random.uniform(0, 1.0, size=label.shape[0]) > random_remove_box
237 | for i, should_output_bb in enumerate(index):
238 | if should_output_bb == False:
239 | (x, y, w, h) = label[i]
240 | (x1, y1, x2, y2) = (x, y, x + w, y + h)
241 | (x1, y1, x2, y2) = (x1 * image.shape[1], y1 * image.shape[0],
242 | x2 * image.shape[1], y2 * image.shape[0])
243 | (x1, y1, x2, y2) = (int(x1), int(y1), int(x2), int(y2))
244 | x1 = 0 if x1 < 0 else x1
245 | y1 = 0 if y1 < 0 else y1
246 | x2 = 0 if x2 < 0 else x2
247 | y2 = 0 if y2 < 0 else y2
248 | image_h, image_w = image.shape
249 | x1 = image_w-1 if x1 >= image_w else x1
250 | y1 = image_h-1 if y1 >= image_h else y1
251 | x2 = image_w-1 if x2 >= image_w else x2
252 | y2 = image_h-1 if y2 >= image_h else y2
253 | image[y1:y2, x1:x2] = image[y1, x1]
254 |
255 | augmented_labels = label[index, :]
256 | return transform(image*255., augmented_labels)
257 |
258 | def transform(image, label):
259 | '''
260 | Function that converts resizes image into the input image tensor for a CNN.
261 | The labels (bounding boxes) are expanded, converted into (x, y, x+w, y+h), and
262 | zero padded to the maximum number of labels. Finally, it is converted into a float
263 | tensor.
264 | '''
265 | max_label_n = 128 if detection_box == "word" else 13
266 |
267 | # Resize the image
268 | image = np.expand_dims(image, axis=2)
269 | image = mx.nd.array(image)
270 | image = resize_short(image, image_size)
271 | image = image.transpose([2, 0, 1])/255.
272 |
273 | # Expand the bounding box by expand_bb_scale
274 | bb = label.copy()
275 | new_w = (1 + expand_bb_scale) * bb[:, 2]
276 | new_h = (1 + expand_bb_scale) * bb[:, 3]
277 |
278 | bb[:, 0] = bb[:, 0] - (new_w - bb[:, 2])/2
279 | bb[:, 1] = bb[:, 1] - (new_h - bb[:, 3])/2
280 | bb[:, 2] = new_w
281 | bb[:, 3] = new_h
282 | label = bb
283 |
284 | # Convert the predicted bounding box from (x, y, w, h to (x, y, x + w, y + h)
285 | label = label.astype(np.float32)
286 | label[:, 2] = label[:, 0] + label[:, 2]
287 | label[:, 3] = label[:, 1] + label[:, 3]
288 |
289 | # Zero pad the data
290 | label_n = label.shape[0]
291 | label_padded = np.zeros(shape=(max_label_n, 5))
292 | label_padded[:label_n, 1:] = label
293 | label_padded[:label_n, 0] = np.ones(shape=(1, label_n))
294 | label_padded = mx.nd.array(label_padded)
295 | return image, label_padded
296 |
297 |
298 | def generate_output_image(box_predictions, default_anchors, cls_probs, box_target, box_mask, cls_target, x, y):
299 | '''
300 | Generate the image with the predicted and actual bounding boxes.
301 | Parameters
302 | ----------
303 | box_predictions: nd.array
304 | Bounding box predictions relative to the anchor boxes, output of the network
305 |
306 | default_anchors: nd.array
307 | Anchors used, output of the network
308 |
309 | cls_probs: nd.array
310 | Output of nd.SoftmaxActivation(nd.transpose(class_predictions, (0, 2, 1)), mode='channel')
311 | where class_predictions is the output of the network.
312 |
313 | box_target: nd.array
314 | Output classification probabilities from network.training_targets(default_anchors, class_predictions, y)
315 |
316 | box_mask: nd.array
317 | Output bounding box predictions from network.training_targets(default_anchors, class_predictions, y)
318 |
319 | cls_target: nd.array
320 | Output targets from network.training_targets(default_anchors, class_predictions, y)
321 |
322 | x: nd.array
323 | The input images
324 |
325 | y: nd.array
326 | The actual labels
327 |
328 | Returns
329 | -------
330 | output_image: np.array
331 | The images with the predicted and actual bounding boxes drawn on
332 |
333 | number_of_bbs: int
334 | The number of predicting bounding boxes
335 | '''
336 | output = MultiBoxDetection(*[cls_probs, box_predictions, default_anchors], force_suppress=True, clip=False)
337 | output = box_nms(output, overlap_thresh=overlap_thres, valid_thresh=min_c, topk=topk)
338 | output = output.asnumpy()
339 |
340 | number_of_bbs = 0
341 | predicted_bb = []
342 | for b in range(output.shape[0]):
343 | predicted_bb_ = output[b, output[b, :, 0] != -1]
344 | predicted_bb_ = predicted_bb_[:, 2:]
345 | number_of_bbs += predicted_bb_.shape[0]
346 | predicted_bb_[:, 2] = predicted_bb_[:, 2] - predicted_bb_[:, 0]
347 | predicted_bb_[:, 3] = predicted_bb_[:, 3] - predicted_bb_[:, 1]
348 | predicted_bb.append(predicted_bb_)
349 |
350 | labels = y[:, :, 1:].asnumpy()
351 | labels[:, :, 2] = labels[:, :, 2] - labels[:, :, 0]
352 | labels[:, :, 3] = labels[:, :, 3] - labels[:, :, 1]
353 |
354 | output_image = draw_boxes_on_image(predicted_bb, labels, x.asnumpy())
355 | output_image[output_image<0] = 0
356 | output_image[output_image>1] = 1
357 |
358 | return output_image, number_of_bbs
359 |
360 | def predict_bounding_boxes(net, image, min_c, overlap_thres, topk, ctx=mx.gpu()):
361 | '''
362 | Given the outputs of the dataset (image and bounding box) and the network,
363 | the predicted bounding boxes are provided.
364 |
365 | Parameters
366 | ----------
367 | net: SSD
368 | The trained SSD network.
369 |
370 | image: np.array
371 | A grayscale image of the handwriting passages.
372 |
373 | Returns
374 | -------
375 | predicted_bb: [(x, y, w, h)]
376 | The predicted bounding boxes.
377 | '''
378 | image = mx.nd.array(image).expand_dims(axis=2)
379 | image = mx.image.resize_short(image, 350)
380 | image = image.transpose([2, 0, 1])/255.
381 |
382 | image = image.as_in_context(ctx)
383 | image = image.expand_dims(0)
384 |
385 | bb = np.zeros(shape=(13, 5))
386 | bb = mx.nd.array(bb)
387 | bb = bb.as_in_context(ctx)
388 | bb = bb.expand_dims(axis=0)
389 |
390 | default_anchors, class_predictions, box_predictions = net(image)
391 |
392 | box_target, box_mask, cls_target = net.training_targets(default_anchors,
393 | class_predictions, bb)
394 |
395 | cls_probs = mx.nd.SoftmaxActivation(mx.nd.transpose(class_predictions, (0, 2, 1)), mode='channel')
396 |
397 | predicted_bb = MultiBoxDetection(*[cls_probs, box_predictions, default_anchors], force_suppress=True, clip=False)
398 | predicted_bb = box_nms(predicted_bb, overlap_thresh=overlap_thres, valid_thresh=min_c, topk=topk)
399 | predicted_bb = predicted_bb.asnumpy()
400 | predicted_bb = predicted_bb[0, predicted_bb[0, :, 0] != -1]
401 | predicted_bb = predicted_bb[:, 2:]
402 | predicted_bb[:, 2] = predicted_bb[:, 2] - predicted_bb[:, 0]
403 | predicted_bb[:, 3] = predicted_bb[:, 3] - predicted_bb[:, 1]
404 |
405 | return predicted_bb
406 |
407 |
408 | def run_epoch(e, network, dataloader, trainer, log_dir, print_name, is_train, update_metric):
409 | '''
410 | Run one epoch to train or test the SSD network
411 |
412 | Parameters
413 | ----------
414 |
415 | e: int
416 | The epoch number
417 |
418 | network: nn.Gluon.HybridSequential
419 | The SSD network
420 |
421 | dataloader: gluon.data.DataLoader
422 | The train or testing dataloader that is wrapped around the iam_dataset
423 |
424 | log_dir: Str
425 | The directory to store the log files for mxboard
426 |
427 | print_name: Str
428 | Name to print for associating with the data. usually this will be "train" and "test"
429 |
430 | is_train: bool
431 | Boolean to indicate whether or not the CNN should be updated. is_train should only be set to true for the training data
432 |
433 | Returns
434 | -------
435 |
436 | network: gluon.nn.HybridSequential
437 | The class predictor network
438 | '''
439 |
440 | total_losses = [0 for ctx_i in ctx]
441 | for i, (X, Y) in enumerate(dataloader):
442 | X = gluon.utils.split_and_load(X, ctx)
443 | Y = gluon.utils.split_and_load(Y, ctx)
444 |
445 | with autograd.record(train_mode=is_train):
446 | losses = []
447 | for x, y in zip(X, Y):
448 | default_anchors, class_predictions, box_predictions = network(x)
449 | box_target, box_mask, cls_target = network.training_targets(default_anchors, class_predictions, y)
450 | # losses
451 | loss_class = cls_loss(class_predictions, cls_target)
452 | loss_box = box_loss(box_predictions, box_target, box_mask)
453 | # sum all losses
454 | loss = loss_class + loss_box
455 | losses.append(loss)
456 |
457 | if is_train:
458 | for loss in losses:
459 | loss.backward()
460 | step_size = 0
461 | for x in X:
462 | step_size += x.shape[0]
463 | trainer.step(step_size)
464 |
465 | for index, loss in enumerate(losses):
466 | total_losses[index] += loss.mean().asscalar()
467 |
468 | if update_metric:
469 | cls_metric.update([cls_target], [nd.transpose(class_predictions, (0, 2, 1))])
470 | box_metric.update([box_target], [box_predictions * box_mask])
471 |
472 | if i == 0 and e % send_image_every_n == 0 and e > 0:
473 | cls_probs = nd.SoftmaxActivation(nd.transpose(class_predictions, (0, 2, 1)), mode='channel')
474 | output_image, number_of_bbs = generate_output_image(box_predictions, default_anchors,
475 | cls_probs, box_target, box_mask,
476 | cls_target, x, y)
477 | print("Number of predicted {} BBs = {}".format(print_name, number_of_bbs))
478 | with SummaryWriter(logdir=log_dir, verbose=False, flush_secs=5) as sw:
479 | sw.add_image('bb_{}_image'.format(print_name), output_image, global_step=e)
480 |
481 |
482 | total_loss = 0
483 | for loss in total_losses:
484 | total_loss += loss / (len(dataloader)*len(total_losses))
485 |
486 | with SummaryWriter(logdir=log_dir, verbose=False, flush_secs=5) as sw:
487 | if update_metric:
488 | name1, val1 = cls_metric.get()
489 | name2, val2 = box_metric.get()
490 | sw.add_scalar(name1, {"test": val1}, global_step=e)
491 | sw.add_scalar(name2, {"test": val2}, global_step=e)
492 | sw.add_scalar('loss', {print_name: total_loss}, global_step=e)
493 |
494 | return total_loss
495 |
496 | if __name__ == "__main__":
497 | parser = argparse.ArgumentParser()
498 | parser.add_argument("-g", "--gpu_count", default=4,
499 | help="Number of GPUs to use")
500 |
501 | parser.add_argument("-b", "--expand_bb_scale", default=0.05,
502 | help="Scale to expand the bounding box")
503 | parser.add_argument("-m", "--min_c", default=0.01,
504 | help="Minimum probability to be considered a bounding box (used in box_nms)")
505 | parser.add_argument("-o", "--overlap_thres", default=0.1,
506 | help="Maximum overlap between bounding boxes")
507 | parser.add_argument("-t", "--topk", default=150,
508 | help="Maximum number of bounding boxes on one slide")
509 |
510 | parser.add_argument("-e", "--epochs", default=351,
511 | help="Number of epochs to run")
512 | parser.add_argument("-l", "--learning_rate", default=0.0001,
513 | help="Learning rate for training")
514 | parser.add_argument("-s", "--batch_size", default=32,
515 | help="Batch size")
516 | parser.add_argument("-w", "--image_size", default=350,
517 | help="Size of the input image (w and h), the value must be less than 700 pixels ")
518 |
519 | parser.add_argument("-x", "--random_x_translation", default=0.03,
520 | help="Randomly translation the image in the x direction (+ or -)")
521 | parser.add_argument("-y", "--random_y_translation", default=0.03,
522 | help="Randomly translation the image in the y direction (+ or -)")
523 | parser.add_argument("-r", "--random_remove_box", default=0.15,
524 | help="Randomly remove bounding boxes and texts with a probability of r")
525 |
526 | parser.add_argument("-d", "--log_dir", default="./logs",
527 | help="Directory to store the log files")
528 | parser.add_argument("-c", "--checkpoint_dir", default="model_checkpoint",
529 | help="Directory to store the checkpoints")
530 | parser.add_argument("-n", "--checkpoint_name", default="ssd.params",
531 | help="Name to store the checkpoints")
532 | parser.add_argument("-db", "--detection_box", default="word",
533 | help="word or line")
534 | parser.add_argument("-p", "--load_model", default=None,
535 | help="Model to load from")
536 |
537 | args = parser.parse_args()
538 |
539 | print(args)
540 |
541 | gpu_count = int(args.gpu_count)
542 |
543 | ctx = [mx.gpu(i) for i in range(gpu_count)]
544 |
545 | expand_bb_scale = float(args.expand_bb_scale)
546 | min_c = float(args.min_c)
547 | overlap_thres = float(args.overlap_thres)
548 | topk = int(args.topk)
549 |
550 | epochs = int(args.epochs)
551 | learning_rate = float(args.learning_rate)
552 | batch_size = int(args.batch_size) * len(ctx)
553 | image_size = int(args.image_size)
554 |
555 | random_y_translation, random_x_translation = float(args.random_x_translation), float(args.random_y_translation)
556 | random_remove_box = float(args.random_remove_box)
557 |
558 | log_dir = args.log_dir
559 | load_model = args.load_model
560 | detection_box = args.detection_box
561 | checkpoint_dir, checkpoint_name = args.checkpoint_dir, detection_box+"_"+args.checkpoint_name
562 |
563 | train_ds = IAMDataset("form_bb", output_data="bb", output_parse_method=detection_box, train=True)
564 | print("Number of training samples: {}".format(len(train_ds)))
565 |
566 | test_ds = IAMDataset("form_bb", output_data="bb", output_parse_method=detection_box, train=False)
567 | print("Number of testing samples: {}".format(len(test_ds)))
568 |
569 | train_data = gluon.data.DataLoader(train_ds.transform(augment_transform), batch_size, shuffle=True, last_batch="rollover", num_workers=multiprocessing.cpu_count()-4)
570 | test_data = gluon.data.DataLoader(test_ds.transform(transform), batch_size, shuffle=False, last_batch="keep", num_workers=multiprocessing.cpu_count()-4)
571 |
572 | net = SSD(2, ctx=ctx)
573 | net.hybridize()
574 | if load_model is not None:
575 | net.load_parameters(os.path.join(checkpoint_dir, load_model))
576 |
577 | trainer = gluon.Trainer(net.collect_params(), 'adam', {'learning_rate': learning_rate, })
578 |
579 | cls_loss = gluon.loss.SoftmaxCrossEntropyLoss()
580 |
581 | box_loss = SmoothL1Loss()
582 |
583 | best_test_loss = 10e5
584 | for e in range(epochs):
585 | cls_metric = mx.metric.Accuracy()
586 | box_metric = mx.metric.MAE()
587 | train_loss = run_epoch(e, net, train_data, trainer, log_dir, print_name="train", is_train=True, update_metric=False)
588 | test_loss = run_epoch(e, net, test_data, trainer, log_dir, print_name="test", is_train=False, update_metric=True)
589 | if test_loss < best_test_loss:
590 | print("Saving network, previous best test loss {:.6f}, current test loss {:.6f}".format(best_test_loss, test_loss))
591 | net.save_parameters(os.path.join(checkpoint_dir, checkpoint_name))
592 | best_test_loss = test_loss
593 |
594 | if e % print_every_n == 0:
595 | name1, val1 = cls_metric.get()
596 | name2, val2 = box_metric.get()
597 | print("Epoch {0}, train_loss {1:.6f}, test_loss {2:.6f}, test {3}={4:.6f}, {5}={6:.6f}".format(e, train_loss, test_loss, name1, val1, name2, val2))
598 |
--------------------------------------------------------------------------------
/dataset/iamdataset/subject/testset.txt:
--------------------------------------------------------------------------------
1 | m01-049-00
2 | m01-049-01
3 | m01-049-02
4 | m01-049-03
5 | m01-049-04
6 | m01-049-05
7 | m01-049-06
8 | m01-049-07
9 | m01-049-08
10 | m01-049-09
11 | m01-049-10
12 | m01-049-11
13 | m01-060-00
14 | m01-060-01
15 | m01-060-02
16 | m01-060-03
17 | m01-060-04
18 | m01-060-05
19 | m01-060-06
20 | m01-079-00
21 | m01-079-01
22 | m01-079-02
23 | m01-079-03
24 | m01-079-04
25 | m01-079-05
26 | m01-084-00
27 | m01-084-01
28 | m01-084-02
29 | m01-084-03
30 | m01-084-04
31 | m01-084-05
32 | m01-084-06
33 | m01-084-07
34 | m01-090-00
35 | m01-090-01
36 | m01-090-02
37 | m01-090-03
38 | m01-090-04
39 | m01-090-05
40 | m01-090-06
41 | m01-090-07
42 | m01-095-00
43 | m01-095-01
44 | m01-095-02
45 | m01-095-03
46 | m01-095-04
47 | m01-095-05
48 | m01-095-06
49 | m01-095-07
50 | m01-104-00
51 | m01-104-01
52 | m01-104-02
53 | m01-104-03
54 | m01-104-04
55 | m01-104-05
56 | m01-104-06
57 | m01-104-07
58 | m01-121-00
59 | m01-121-01
60 | m01-121-02
61 | m01-121-03
62 | m01-121-04
63 | m01-121-05
64 | m01-121-06
65 | m01-121-07
66 | m01-110-00
67 | m01-110-01
68 | m01-110-02
69 | m01-110-03
70 | m01-110-04
71 | m01-110-05
72 | m01-110-06
73 | m01-110-07
74 | m01-110-08
75 | m01-110-09
76 | m01-110-10
77 | m01-110-11
78 | m01-131-00
79 | m01-131-01
80 | m01-131-02
81 | m01-131-03
82 | m01-131-04
83 | m01-131-05
84 | m01-115-00
85 | m01-115-01
86 | m01-115-02
87 | m01-115-03
88 | m01-115-04
89 | m01-115-05
90 | m01-115-06
91 | m01-115-07
92 | m01-125-00
93 | m01-125-01
94 | m01-125-02
95 | m01-125-03
96 | m01-125-04
97 | m01-125-05
98 | m01-125-06
99 | m01-125-07
100 | m01-125-08
101 | m01-125-09
102 | m01-125-10
103 | m01-136-00
104 | m01-136-01
105 | m01-136-02
106 | m01-136-03
107 | m01-136-04
108 | m01-136-05
109 | m01-136-06
110 | m01-136-07
111 | m01-136-08
112 | m01-136-09
113 | m01-136-10
114 | m01-149-00
115 | m01-149-01
116 | m01-149-02
117 | m01-149-03
118 | m01-149-04
119 | m01-149-05
120 | m01-149-06
121 | m01-149-07
122 | m01-160-00
123 | m01-160-01
124 | m01-160-02
125 | m01-160-03
126 | m01-160-04
127 | m01-160-05
128 | m01-160-06
129 | m02-048-00
130 | m02-048-01
131 | m02-048-02
132 | m02-048-03
133 | m02-048-04
134 | m02-048-05
135 | m02-048-06
136 | m02-048-07
137 | m02-048-08
138 | m02-048-09
139 | m02-048-10
140 | m02-052-00
141 | m02-052-01
142 | m02-052-02
143 | m02-052-03
144 | m02-052-04
145 | m02-052-05
146 | m02-052-06
147 | m02-055-00
148 | m02-055-01
149 | m02-055-02
150 | m02-055-03
151 | m02-055-04
152 | m02-055-05
153 | m02-055-06
154 | m02-055-07
155 | m02-055-08
156 | m02-059-00
157 | m02-059-01
158 | m02-059-02
159 | m02-059-03
160 | m02-059-04
161 | m02-059-05
162 | m02-066-00
163 | m02-066-01
164 | m02-066-02
165 | m02-066-03
166 | m02-066-04
167 | m02-066-05
168 | m02-069-00
169 | m02-069-01
170 | m02-069-02
171 | m02-069-03
172 | m02-069-04
173 | m02-069-05
174 | m02-069-06
175 | m02-069-07
176 | m02-069-08
177 | m02-072-00
178 | m02-072-01
179 | m02-072-02
180 | m02-072-03
181 | m02-072-04
182 | m02-072-05
183 | m02-072-06
184 | m02-075-00
185 | m02-075-01
186 | m02-075-02
187 | m02-075-03
188 | m02-075-04
189 | m02-075-05
190 | m02-075-06
191 | m02-106-00
192 | m02-106-01
193 | m02-106-02
194 | m02-106-03
195 | m02-106-04
196 | m02-106-05
197 | m02-106-06
198 | m02-106-07
199 | m02-106-08
200 | m02-106-09
201 | m02-080-01
202 | m02-080-02
203 | m02-080-03
204 | m02-080-04
205 | m02-080-05
206 | m02-080-06
207 | m02-080-07
208 | m02-080-08
209 | m02-083-00
210 | m02-083-01
211 | m02-083-02
212 | m02-083-03
213 | m02-083-04
214 | m02-083-05
215 | m02-083-06
216 | m02-083-07
217 | m02-083-08
218 | m02-083-09
219 | m02-083-10
220 | m02-083-11
221 | m02-087-00
222 | m02-087-01
223 | m02-087-02
224 | m02-087-03
225 | m02-087-04
226 | m02-087-05
227 | m02-087-06
228 | m02-090-00
229 | m02-090-01
230 | m02-090-02
231 | m02-090-03
232 | m02-090-04
233 | m02-090-05
234 | m02-090-06
235 | m02-090-07
236 | m02-090-08
237 | m02-090-09
238 | m02-090-10
239 | m02-095-00
240 | m02-095-01
241 | m02-095-02
242 | m02-095-03
243 | m02-095-04
244 | m02-095-05
245 | m02-095-06
246 | m02-095-07
247 | m02-095-08
248 | m02-102-00
249 | m02-102-01
250 | m02-102-02
251 | m02-102-03
252 | m02-102-04
253 | m02-102-05
254 | m02-102-06
255 | m02-102-07
256 | m02-102-08
257 | m02-102-09
258 | m02-109-00
259 | m02-109-01
260 | m02-109-02
261 | m02-109-03
262 | m02-109-04
263 | m02-109-05
264 | m02-109-06
265 | m02-109-07
266 | m02-112-00
267 | m02-112-01
268 | m02-112-02
269 | m02-112-03
270 | m02-112-04
271 | m02-112-05
272 | m03-006-00
273 | m03-006-01
274 | m03-006-02
275 | m03-006-03
276 | m03-006-04
277 | m03-006-05
278 | m03-006-06
279 | m03-006-07
280 | m03-006-08
281 | m03-006-09
282 | m03-013-00
283 | m03-013-01
284 | m03-013-02
285 | m03-013-03
286 | m03-013-04
287 | m03-013-05
288 | m03-020-00
289 | m03-020-01
290 | m03-020-02
291 | m03-020-03
292 | m03-020-04
293 | m03-020-05
294 | m03-033-00
295 | m03-033-01
296 | m03-033-02
297 | m03-033-03
298 | m03-033-04
299 | m03-033-05
300 | m03-033-06
301 | m03-062-00
302 | m03-062-01
303 | m03-062-02
304 | m03-062-03
305 | m03-062-04
306 | m03-062-05
307 | m03-062-06
308 | m03-062-07
309 | m03-062-08
310 | m03-095-00
311 | m03-095-01
312 | m03-095-02
313 | m03-095-03
314 | m03-095-04
315 | m03-095-05
316 | m03-095-06
317 | m03-095-07
318 | m03-095-08
319 | m03-110-00
320 | m03-110-01
321 | m03-110-02
322 | m03-110-03
323 | m03-110-04
324 | m03-110-05
325 | m03-110-06
326 | m03-110-07
327 | m03-110-08
328 | m03-110-09
329 | m03-114-00
330 | m03-114-01
331 | m03-114-02
332 | m03-114-03
333 | m03-114-04
334 | m03-114-05
335 | m03-114-06
336 | m03-114-07
337 | m03-114-08
338 | m03-114-09
339 | m03-118-00
340 | m03-118-01
341 | m03-118-02
342 | m03-118-03
343 | m03-118-04
344 | m03-118-05
345 | m04-000-00
346 | m04-000-01
347 | m04-000-02
348 | m04-000-03
349 | m04-000-04
350 | m04-000-05
351 | m04-000-06
352 | m04-000-07
353 | m04-007-00
354 | m04-007-01
355 | m04-007-02
356 | m04-007-03
357 | m04-007-04
358 | m04-007-05
359 | m04-007-06
360 | m04-007-07
361 | m04-007-08
362 | m04-012-00
363 | m04-012-01
364 | m04-012-02
365 | m04-012-03
366 | m04-012-04
367 | m04-012-05
368 | m04-012-06
369 | m04-012-07
370 | m04-012-08
371 | m04-012-09
372 | m04-019-00
373 | m04-019-01
374 | m04-019-02
375 | m04-019-03
376 | m04-019-04
377 | m04-019-05
378 | m04-019-06
379 | m04-019-07
380 | m04-024-00
381 | m04-024-01
382 | m04-024-02
383 | m04-024-03
384 | m04-024-04
385 | m04-024-05
386 | m04-024-06
387 | m04-024-07
388 | m04-030-00
389 | m04-030-01
390 | m04-030-02
391 | m04-030-03
392 | m04-030-04
393 | m04-038-00
394 | m04-038-01
395 | m04-038-02
396 | m04-038-03
397 | m04-038-04
398 | m04-043-00
399 | m04-043-01
400 | m04-043-02
401 | m04-043-03
402 | m04-043-04
403 | m04-061-00
404 | m04-061-01
405 | m04-061-02
406 | m04-061-03
407 | m04-061-04
408 | m04-072-00
409 | m04-072-01
410 | m04-072-02
411 | m04-072-03
412 | m04-072-04
413 | m04-072-05
414 | m04-072-06
415 | m04-072-07
416 | m04-072-08
417 | m04-072-09
418 | m04-078-00
419 | m04-078-01
420 | m04-078-02
421 | m04-078-03
422 | m04-078-04
423 | m04-078-05
424 | m04-078-06
425 | m04-078-07
426 | m04-081-00
427 | m04-081-01
428 | m04-081-02
429 | m04-081-03
430 | m04-081-04
431 | m04-081-05
432 | m04-081-06
433 | m04-081-07
434 | m04-081-08
435 | m04-081-09
436 | m04-081-10
437 | m04-093-00
438 | m04-093-01
439 | m04-093-02
440 | m04-093-03
441 | m04-093-04
442 | m04-093-05
443 | m04-093-06
444 | m04-093-07
445 | m04-093-08
446 | m04-093-09
447 | m04-100-00
448 | m04-100-01
449 | m04-100-02
450 | m04-100-03
451 | m04-100-04
452 | m04-100-05
453 | m04-100-06
454 | m04-100-07
455 | m04-107-00
456 | m04-107-01
457 | m04-107-02
458 | m04-107-03
459 | m04-107-04
460 | m04-107-05
461 | m04-107-06
462 | m04-107-07
463 | m04-107-08
464 | m04-107-09
465 | m04-113-00
466 | m04-113-01
467 | m04-113-02
468 | m04-113-03
469 | m04-113-04
470 | m04-113-05
471 | m04-113-06
472 | m04-113-07
473 | m04-113-08
474 | m04-113-09
475 | m04-113-10
476 | m04-123-00
477 | m04-123-01
478 | m04-123-02
479 | m04-123-03
480 | m04-123-04
481 | m04-123-05
482 | m04-123-06
483 | m04-123-07
484 | m04-123-08
485 | m04-123-09
486 | m04-123-10
487 | m04-131-00
488 | m04-131-01
489 | m04-131-02
490 | m04-131-03
491 | m04-131-04
492 | m04-131-05
493 | m04-131-06
494 | m04-131-07
495 | m04-131-08
496 | m04-138-00
497 | m04-138-01
498 | m04-138-02
499 | m04-138-03
500 | m04-138-04
501 | m04-138-05
502 | m04-138-06
503 | m04-138-07
504 | m04-138-08
505 | m04-138-09
506 | m04-145-00
507 | m04-145-01
508 | m04-145-02
509 | m04-145-03
510 | m04-145-04
511 | m04-145-05
512 | m04-145-06
513 | m04-152-00
514 | m04-152-01
515 | m04-152-02
516 | m04-152-03
517 | m04-152-04
518 | m04-152-05
519 | m04-152-06
520 | m04-152-07
521 | m04-164-00
522 | m04-164-01
523 | m04-164-02
524 | m04-164-03
525 | m04-164-04
526 | m04-164-05
527 | m04-164-06
528 | m04-180-00
529 | m04-180-01
530 | m04-180-02
531 | m04-180-03
532 | m04-180-04
533 | m04-180-05
534 | m04-180-06
535 | m04-251-00
536 | m04-251-01
537 | m04-190-00
538 | m04-190-01
539 | m04-190-02
540 | m04-190-03
541 | m04-190-04
542 | m04-190-05
543 | m04-190-06
544 | m04-190-07
545 | m04-190-08
546 | m04-190-09
547 | m04-200-00
548 | m04-200-01
549 | m04-200-02
550 | m04-200-03
551 | m04-200-04
552 | m04-200-05
553 | m04-200-06
554 | m04-209-00
555 | m04-209-01
556 | m04-209-02
557 | m04-209-03
558 | m04-209-04
559 | m04-209-05
560 | m04-216-00
561 | m04-216-01
562 | m04-216-02
563 | m04-216-03
564 | m04-216-04
565 | m04-216-05
566 | m04-222-00
567 | m04-222-01
568 | m04-222-02
569 | m04-222-03
570 | m04-222-04
571 | m04-222-05
572 | m04-222-06
573 | m04-231-00
574 | m04-231-01
575 | m04-231-02
576 | m04-231-03
577 | m04-231-04
578 | m04-231-05
579 | m04-238-00
580 | m04-238-01
581 | m04-238-02
582 | m04-238-03
583 | m04-238-04
584 | m04-238-05
585 | m04-246-00
586 | m04-246-01
587 | m04-246-02
588 | m04-246-03
589 | m04-246-04
590 | m04-246-05
591 | m04-246-06
592 | n04-000-00
593 | n04-000-01
594 | n04-000-02
595 | n04-000-03
596 | n04-000-04
597 | n04-000-05
598 | n04-009-00
599 | n04-009-01
600 | n04-009-02
601 | n04-009-03
602 | n04-009-04
603 | n04-009-05
604 | n04-009-06
605 | m06-019-00
606 | m06-019-01
607 | m06-019-02
608 | m06-019-03
609 | m06-019-04
610 | m06-019-05
611 | m06-019-06
612 | n06-148-00
613 | n06-148-01
614 | n06-148-02
615 | n06-148-03
616 | n06-148-04
617 | n06-148-05
618 | n06-148-06
619 | n06-148-07
620 | n06-148-08
621 | n06-156-00
622 | n06-156-01
623 | n06-156-02
624 | n06-156-03
625 | n06-156-04
626 | n06-156-05
627 | n06-156-06
628 | n06-156-07
629 | n06-163-00
630 | n06-163-01
631 | n06-163-02
632 | n06-163-03
633 | n06-163-04
634 | n06-163-05
635 | n06-163-06
636 | n06-163-07
637 | n06-163-08
638 | n06-163-09
639 | n06-169-00
640 | n06-169-01
641 | n06-169-02
642 | n06-169-03
643 | n06-169-04
644 | n06-169-05
645 | n06-169-06
646 | n06-169-07
647 | n06-175-00
648 | n06-175-01
649 | n06-175-02
650 | n06-175-03
651 | n06-175-04
652 | n06-175-05
653 | n06-175-06
654 | n06-175-07
655 | n06-175-08
656 | n06-182-00
657 | n06-182-01
658 | n06-182-02
659 | n06-182-03
660 | n06-182-04
661 | n06-182-05
662 | n06-182-06
663 | n06-182-07
664 | n06-186-00
665 | n06-186-01
666 | n06-186-02
667 | n06-186-03
668 | n06-186-04
669 | n06-186-05
670 | n06-186-06
671 | n06-186-07
672 | n06-194-00
673 | n06-194-01
674 | n06-194-02
675 | n06-194-03
676 | n06-194-04
677 | n06-194-05
678 | n06-194-06
679 | n06-194-07
680 | n06-201-00
681 | n06-201-01
682 | n06-201-02
683 | n06-201-03
684 | n06-201-04
685 | n06-201-05
686 | n06-201-06
687 | m06-031-00
688 | m06-031-01
689 | m06-031-02
690 | m06-031-03
691 | m06-031-04
692 | m06-031-05
693 | m06-031-06
694 | m06-042-00
695 | m06-042-01
696 | m06-042-02
697 | m06-042-03
698 | m06-042-04
699 | m06-048-00
700 | m06-048-01
701 | m06-048-02
702 | m06-048-03
703 | m06-048-04
704 | m06-048-05
705 | m06-048-06
706 | m06-048-07
707 | m06-056-00
708 | m06-056-01
709 | m06-056-02
710 | m06-056-03
711 | m06-056-04
712 | m06-056-05
713 | m06-067-00
714 | m06-067-01
715 | m06-067-02
716 | m06-067-03
717 | m06-067-04
718 | m06-067-05
719 | m06-067-06
720 | m06-076-00
721 | m06-076-01
722 | m06-076-02
723 | m06-076-03
724 | m06-076-04
725 | m06-076-05
726 | m06-083-00
727 | m06-083-01
728 | m06-083-02
729 | m06-083-03
730 | m06-083-04
731 | m06-083-05
732 | m06-083-06
733 | m06-091-00
734 | m06-091-01
735 | m06-091-02
736 | m06-091-03
737 | m06-091-04
738 | m06-091-05
739 | m06-091-06
740 | m06-098-00
741 | m06-098-01
742 | m06-098-02
743 | m06-098-03
744 | m06-098-04
745 | m06-098-05
746 | m06-106-00
747 | m06-106-01
748 | m06-106-02
749 | m06-106-03
750 | m06-106-04
751 | m06-106-05
752 | m06-106-06
753 | m06-106-07
754 | m06-106-08
755 | n01-000-00
756 | n01-000-01
757 | n01-000-02
758 | n01-000-03
759 | n01-000-04
760 | n01-000-05
761 | n01-000-06
762 | n01-000-07
763 | n01-009-00
764 | n01-009-01
765 | n01-009-02
766 | n01-009-03
767 | n01-009-04
768 | n01-009-05
769 | n01-009-06
770 | n01-009-07
771 | n01-004-00
772 | n01-004-01
773 | n01-004-02
774 | n01-004-03
775 | n01-004-04
776 | n01-004-05
777 | n01-004-06
778 | n01-020-00
779 | n01-020-01
780 | n01-020-02
781 | n01-020-03
782 | n01-020-04
783 | n01-020-05
784 | n01-020-06
785 | n01-020-07
786 | n01-020-08
787 | n01-031-00
788 | n01-031-01
789 | n01-031-02
790 | n01-031-03
791 | n01-031-04
792 | n01-031-05
793 | n01-031-06
794 | n01-031-07
795 | n01-031-08
796 | n01-045-00
797 | n01-045-01
798 | n01-045-02
799 | n01-045-03
800 | n01-045-04
801 | n01-045-05
802 | n01-045-06
803 | n01-045-07
804 | n01-045-08
805 | n01-045-09
806 | n01-036-00
807 | n01-036-01
808 | n01-036-02
809 | n01-036-03
810 | n01-036-04
811 | n01-036-05
812 | n01-052-00
813 | n01-052-01
814 | n01-052-02
815 | n01-052-03
816 | n01-052-04
817 | n01-052-05
818 | n01-052-06
819 | n01-052-07
820 | n01-052-08
821 | n01-052-09
822 | n01-052-10
823 | n01-052-11
824 | n01-052-12
825 | n01-057-00
826 | n01-057-01
827 | n01-057-02
828 | n01-057-03
829 | n01-057-04
830 | n01-057-05
831 | n01-057-06
832 | n01-057-07
833 | n01-057-08
834 | n02-000-00
835 | n02-000-01
836 | n02-000-02
837 | n02-000-03
838 | n02-000-04
839 | n02-000-05
840 | n02-000-06
841 | n02-016-00
842 | n02-016-01
843 | n02-016-02
844 | n02-016-03
845 | n02-016-04
846 | n02-016-05
847 | n02-016-06
848 | n02-016-07
849 | n02-004-00
850 | n02-004-01
851 | n02-004-02
852 | n02-004-03
853 | n02-004-04
854 | n02-004-05
855 | n02-004-06
856 | n02-004-07
857 | n02-004-08
858 | n02-009-00
859 | n02-009-01
860 | n02-009-02
861 | n02-009-03
862 | n02-009-04
863 | n02-009-05
864 | n02-009-06
865 | n02-028-00
866 | n02-028-01
867 | n02-028-02
868 | n02-028-03
869 | n02-028-04
870 | n02-028-05
871 | n02-028-06
872 | n02-028-07
873 | n02-028-08
874 | n02-049-00
875 | n02-049-01
876 | n02-049-02
877 | n02-049-03
878 | n02-049-04
879 | n02-033-00
880 | n02-033-01
881 | n02-033-02
882 | n02-033-03
883 | n02-033-04
884 | n02-033-05
885 | n02-033-06
886 | n02-033-07
887 | n02-033-08
888 | n02-037-00
889 | n02-037-01
890 | n02-037-02
891 | n02-037-03
892 | n02-037-04
893 | n02-037-05
894 | n02-037-06
895 | n02-037-07
896 | n02-037-08
897 | n02-040-00
898 | n02-040-01
899 | n02-040-02
900 | n02-040-03
901 | n02-040-04
902 | n02-040-05
903 | n02-040-06
904 | n02-040-07
905 | n02-045-00
906 | n02-045-01
907 | n02-045-02
908 | n02-045-03
909 | n02-045-04
910 | n02-045-05
911 | n02-045-06
912 | n02-045-07
913 | n02-054-00
914 | n02-054-01
915 | n02-054-02
916 | n02-054-03
917 | n02-054-04
918 | n02-054-05
919 | n02-054-06
920 | n02-054-07
921 | n02-054-08
922 | n02-054-09
923 | n02-062-00
924 | n02-062-01
925 | n02-062-02
926 | n02-062-03
927 | n02-062-04
928 | n02-062-05
929 | n02-062-06
930 | n02-062-07
931 | n02-082a-00
932 | n02-082a-01
933 | n02-082a-02
934 | n02-082a-03
935 | n02-082a-04
936 | n02-082a-05
937 | n02-082a-06
938 | n02-098-00
939 | n02-098-01
940 | n02-098-02
941 | n02-098-03
942 | n02-098-04
943 | n02-098-05
944 | n02-098-06
945 | n02-098-07
946 | p03-057-00
947 | p03-057-01
948 | p03-057-02
949 | p03-057-03
950 | p03-057-04
951 | p03-057-05
952 | p03-057-06
953 | p03-057-07
954 | p03-057-08
955 | p03-087-00
956 | p03-087-01
957 | p03-087-02
958 | p03-087-03
959 | p03-087-04
960 | p03-087-05
961 | p03-087-06
962 | p03-087-07
963 | p03-087-08
964 | p03-087-09
965 | p03-087-10
966 | p03-096-00
967 | p03-096-01
968 | p03-096-02
969 | p03-096-03
970 | p03-096-04
971 | p03-096-05
972 | p03-096-06
973 | p03-096-07
974 | p03-096-08
975 | p03-103-00
976 | p03-103-01
977 | p03-103-02
978 | p03-103-03
979 | p03-103-04
980 | p03-103-05
981 | p03-103-06
982 | p03-103-07
983 | p03-112-00
984 | p03-112-01
985 | p03-112-02
986 | p03-112-03
987 | p03-112-04
988 | p03-112-05
989 | p03-112-06
990 | p03-112-07
991 | p03-112-08
992 | p03-112-09
993 | n02-151-00
994 | n02-151-01
995 | n02-151-02
996 | n02-151-03
997 | n02-151-04
998 | n02-151-05
999 | n02-151-06
1000 | n02-151-07
1001 | n02-151-08
1002 | n02-151-09
1003 | n02-151-10
1004 | n02-154-00
1005 | n02-154-01
1006 | n02-154-02
1007 | n02-154-03
1008 | n02-154-04
1009 | n02-154-05
1010 | n02-157-00
1011 | n02-157-01
1012 | n02-157-02
1013 | n02-157-03
1014 | n02-157-04
1015 | n02-157-05
1016 | n02-157-06
1017 | n02-157-07
1018 | n02-157-08
1019 | n03-038-00
1020 | n03-038-01
1021 | n03-038-02
1022 | n03-038-03
1023 | n03-038-04
1024 | n03-038-05
1025 | n03-064-00
1026 | n03-064-01
1027 | n03-064-02
1028 | n03-064-03
1029 | n03-064-04
1030 | n03-064-05
1031 | n03-066-00
1032 | n03-066-01
1033 | n03-066-02
1034 | n03-066-03
1035 | n03-066-04
1036 | n03-066-05
1037 | n03-066-06
1038 | n03-066-07
1039 | n03-079-00
1040 | n03-079-01
1041 | n03-079-02
1042 | n03-079-03
1043 | n03-079-04
1044 | n03-079-05
1045 | n03-082-00
1046 | n03-082-01
1047 | n03-082-02
1048 | n03-082-03
1049 | n03-082-04
1050 | n03-082-05
1051 | n03-082-06
1052 | n03-091-00
1053 | n03-091-01
1054 | n03-091-02
1055 | n03-091-03
1056 | n03-091-04
1057 | n03-091-05
1058 | n03-091-06
1059 | n03-091-07
1060 | n03-097-00
1061 | n03-097-01
1062 | n03-097-02
1063 | n03-097-03
1064 | n03-097-04
1065 | n03-097-05
1066 | n03-097-06
1067 | n03-097-07
1068 | n03-103-00
1069 | n03-103-01
1070 | n03-103-02
1071 | n03-103-03
1072 | n03-103-04
1073 | n03-103-05
1074 | n03-103-06
1075 | n03-103-07
1076 | n03-103-08
1077 | n03-103-09
1078 | n03-106-00
1079 | n03-106-01
1080 | n03-106-02
1081 | n03-106-03
1082 | n03-106-04
1083 | n03-106-05
1084 | n03-106-06
1085 | n03-106-07
1086 | n03-106-08
1087 | n03-106-09
1088 | n03-106-10
1089 | n03-106-11
1090 | n03-113-00
1091 | n03-113-01
1092 | n03-113-02
1093 | n03-113-03
1094 | n03-113-04
1095 | n03-113-05
1096 | n03-113-06
1097 | n03-113-07
1098 | n03-113-08
1099 | n03-113-09
1100 | n03-120-00
1101 | n03-120-01
1102 | n03-120-02
1103 | n03-120-03
1104 | n03-120-04
1105 | n03-120-05
1106 | n03-120-06
1107 | n03-120-07
1108 | n03-120-08
1109 | n03-126-00
1110 | n03-126-01
1111 | n03-126-02
1112 | n03-126-03
1113 | n03-126-04
1114 | n04-015-00
1115 | n04-015-01
1116 | n04-015-02
1117 | n04-015-03
1118 | n04-015-04
1119 | n04-015-05
1120 | n04-015-06
1121 | n04-022-00
1122 | n04-022-01
1123 | n04-022-02
1124 | n04-022-03
1125 | n04-022-04
1126 | n04-022-05
1127 | n04-022-06
1128 | n04-022-07
1129 | n04-031-00
1130 | n04-031-01
1131 | n04-031-02
1132 | n04-031-03
1133 | n04-031-04
1134 | n04-031-05
1135 | n04-031-06
1136 | n04-039-00
1137 | n04-039-01
1138 | n04-039-02
1139 | n04-039-03
1140 | n04-039-04
1141 | n04-039-05
1142 | n04-044-00
1143 | n04-044-01
1144 | n04-044-02
1145 | n04-044-03
1146 | n04-044-04
1147 | n04-044-05
1148 | n04-044-06
1149 | n04-044-07
1150 | n04-044-08
1151 | n04-044-09
1152 | n04-048-00
1153 | n04-048-01
1154 | n04-048-02
1155 | n04-048-03
1156 | n04-048-04
1157 | n04-048-05
1158 | n04-048-06
1159 | n04-048-08
1160 | n04-052-00
1161 | n04-052-01
1162 | n04-052-02
1163 | n04-052-03
1164 | n04-052-04
1165 | n04-052-05
1166 | n04-052-06
1167 | n04-052-07
1168 | n04-052-08
1169 | n04-060-00
1170 | n04-060-01
1171 | n04-060-02
1172 | n04-060-03
1173 | n04-060-04
1174 | n04-060-05
1175 | n04-060-06
1176 | n04-068-00
1177 | n04-068-01
1178 | n04-068-02
1179 | n04-068-03
1180 | n04-068-04
1181 | n04-068-05
1182 | n04-068-06
1183 | n04-068-07
1184 | n04-075-00
1185 | n04-075-01
1186 | n04-075-02
1187 | n04-075-03
1188 | n04-075-04
1189 | n04-075-05
1190 | n04-075-06
1191 | n04-084-00
1192 | n04-084-01
1193 | n04-084-02
1194 | n04-084-03
1195 | n04-084-04
1196 | n04-084-05
1197 | n04-084-06
1198 | n04-092-00
1199 | n04-092-01
1200 | n04-092-02
1201 | n04-092-03
1202 | n04-092-04
1203 | n04-092-05
1204 | n04-092-06
1205 | n04-092-07
1206 | n04-100-00
1207 | n04-100-01
1208 | n04-100-02
1209 | n04-100-03
1210 | n04-100-04
1211 | n04-100-05
1212 | n04-100-06
1213 | n04-107-00
1214 | n04-107-01
1215 | n04-107-02
1216 | n04-107-03
1217 | n04-107-04
1218 | n04-107-05
1219 | n04-107-06
1220 | n04-107-07
1221 | n04-114-00
1222 | n04-114-01
1223 | n04-114-02
1224 | n04-114-03
1225 | n04-114-04
1226 | n04-114-05
1227 | n04-114-06
1228 | n04-114-07
1229 | n04-130-00
1230 | n04-130-01
1231 | n04-130-02
1232 | n04-130-03
1233 | n04-130-04
1234 | n04-130-05
1235 | n04-139-00
1236 | n04-139-01
1237 | n04-139-02
1238 | n04-139-03
1239 | n04-139-04
1240 | n04-139-05
1241 | n04-139-06
1242 | n04-139-07
1243 | n04-149-00
1244 | n04-149-01
1245 | n04-149-02
1246 | n04-149-03
1247 | n04-149-04
1248 | n04-149-05
1249 | n04-149-06
1250 | n04-156-00
1251 | n04-156-01
1252 | n04-156-02
1253 | n04-156-03
1254 | n04-156-04
1255 | n04-156-05
1256 | n04-156-06
1257 | n04-156-07
1258 | n04-163-00
1259 | n04-163-01
1260 | n04-163-02
1261 | n04-163-03
1262 | n04-163-04
1263 | n04-163-05
1264 | n04-163-06
1265 | n04-163-07
1266 | n04-171-00
1267 | n04-171-01
1268 | n04-171-02
1269 | n04-171-03
1270 | n04-171-04
1271 | n04-171-05
1272 | n04-171-06
1273 | n04-183-00
1274 | n04-183-01
1275 | n04-183-02
1276 | n04-183-03
1277 | n04-183-04
1278 | n04-183-05
1279 | n04-183-06
1280 | n04-190-00
1281 | n04-190-01
1282 | n04-190-02
1283 | n04-190-03
1284 | n04-190-04
1285 | n04-190-05
1286 | n04-195-00
1287 | n04-195-01
1288 | n04-195-02
1289 | n04-195-03
1290 | n04-195-04
1291 | n04-195-05
1292 | n04-202-00
1293 | n04-202-01
1294 | n04-202-02
1295 | n04-202-03
1296 | n04-202-04
1297 | n04-202-05
1298 | n04-202-06
1299 | n04-202-07
1300 | n04-202-08
1301 | n04-209-00
1302 | n04-209-01
1303 | n04-209-02
1304 | n04-209-03
1305 | n04-209-04
1306 | n04-209-05
1307 | n04-209-06
1308 | n04-213-00
1309 | n04-213-01
1310 | n04-213-02
1311 | n04-213-03
1312 | n04-213-04
1313 | n04-213-05
1314 | n04-213-06
1315 | n04-218-00
1316 | n04-218-01
1317 | n04-218-02
1318 | n04-218-03
1319 | n04-218-04
1320 | n04-218-05
1321 | n04-218-06
1322 | n04-218-07
1323 | n04-218-08
1324 | n06-074-00
1325 | n06-074-01
1326 | n06-074-02
1327 | n06-074-03
1328 | n06-074-04
1329 | n06-074-05
1330 | n06-074-06
1331 | n06-082-00
1332 | n06-082-01
1333 | n06-082-02
1334 | n06-082-03
1335 | n06-082-04
1336 | n06-082-05
1337 | n06-082-06
1338 | n06-092-00
1339 | n06-092-01
1340 | n06-092-02
1341 | n06-092-03
1342 | n06-092-04
1343 | n06-092-05
1344 | n06-092-06
1345 | n06-092-07
1346 | n06-100-00
1347 | n06-100-01
1348 | n06-100-02
1349 | n06-100-03
1350 | n06-100-04
1351 | n06-100-05
1352 | n06-100-06
1353 | n06-100-07
1354 | n06-100-08
1355 | n06-111-00
1356 | n06-111-01
1357 | n06-111-02
1358 | n06-111-03
1359 | n06-111-04
1360 | n06-111-05
1361 | n06-111-06
1362 | n06-111-07
1363 | n06-119-00
1364 | n06-119-01
1365 | n06-119-02
1366 | n06-119-03
1367 | n06-119-04
1368 | n06-119-05
1369 | n06-123-00
1370 | n06-123-01
1371 | n06-123-02
1372 | n06-123-03
1373 | n06-123-04
1374 | n06-123-05
1375 | n06-123-06
1376 | n06-123-07
1377 | n06-123-08
1378 | n06-123-09
1379 | n06-128-00
1380 | n06-128-01
1381 | n06-128-02
1382 | n06-128-03
1383 | n06-128-04
1384 | n06-128-05
1385 | n06-128-06
1386 | n06-128-07
1387 | n06-133-00
1388 | n06-133-01
1389 | n06-133-02
1390 | n06-133-03
1391 | n06-133-04
1392 | n06-133-05
1393 | n06-133-06
1394 | n06-133-07
1395 | n06-133-08
1396 | n06-140-00
1397 | n06-140-01
1398 | n06-140-02
1399 | n06-140-03
1400 | n06-140-04
1401 | n06-140-05
1402 | n06-140-06
1403 | p01-147-00
1404 | p01-147-01
1405 | p01-147-02
1406 | p01-147-03
1407 | p01-147-04
1408 | p01-147-05
1409 | p01-147-06
1410 | p01-147-07
1411 | p01-147-08
1412 | p01-147-09
1413 | p01-147-10
1414 | p01-155-00
1415 | p01-155-01
1416 | p01-155-02
1417 | p01-155-03
1418 | p01-155-04
1419 | p01-155-05
1420 | p01-155-06
1421 | p01-155-07
1422 | p01-155-08
1423 | p01-155-09
1424 | p01-168-00
1425 | p01-168-01
1426 | p01-168-02
1427 | p01-168-03
1428 | p01-168-04
1429 | p01-168-05
1430 | p01-168-06
1431 | p01-174-00
1432 | p01-174-01
1433 | p01-174-02
1434 | p01-174-03
1435 | p01-174-04
1436 | p01-174-05
1437 | p01-174-06
1438 | p01-174-07
1439 | p01-174-08
1440 | p02-000-00
1441 | p02-000-01
1442 | p02-000-02
1443 | p02-000-03
1444 | p02-000-04
1445 | p02-000-05
1446 | p02-008-00
1447 | p02-008-01
1448 | p02-008-02
1449 | p02-008-03
1450 | p02-008-04
1451 | p02-008-05
1452 | p02-008-06
1453 | p02-008-07
1454 | p02-008-08
1455 | p02-008-09
1456 | p02-008-10
1457 | p02-017-00
1458 | p02-017-01
1459 | p02-017-02
1460 | p02-017-03
1461 | p02-017-04
1462 | p02-017-05
1463 | p02-017-06
1464 | p02-022-00
1465 | p02-022-01
1466 | p02-022-02
1467 | p02-022-03
1468 | p02-022-04
1469 | p02-022-05
1470 | p02-022-06
1471 | p02-022-07
1472 | p02-022-08
1473 | p02-027-00
1474 | p02-027-01
1475 | p02-027-02
1476 | p02-027-03
1477 | p02-027-04
1478 | p02-069-00
1479 | p02-069-01
1480 | p02-069-02
1481 | p02-069-03
1482 | p02-069-04
1483 | p02-069-05
1484 | p02-069-06
1485 | p02-069-08
1486 | p02-069-09
1487 | p02-090-00
1488 | p02-090-01
1489 | p02-090-02
1490 | p02-090-03
1491 | p02-090-04
1492 | p02-090-05
1493 | p02-090-06
1494 | p02-090-07
1495 | p02-090-08
1496 | p02-076-00
1497 | p02-076-01
1498 | p02-076-02
1499 | p02-076-03
1500 | p02-076-04
1501 | p02-076-05
1502 | p02-076-06
1503 | p02-076-07
1504 | p02-076-08
1505 | p02-076-09
1506 | p02-076-10
1507 | p02-081-00
1508 | p02-081-01
1509 | p02-081-02
1510 | p02-081-03
1511 | p02-081-04
1512 | p02-081-05
1513 | p02-081-06
1514 | p02-081-07
1515 | p02-081-08
1516 | p02-081-09
1517 | p02-101-00
1518 | p02-101-01
1519 | p02-101-02
1520 | p02-101-03
1521 | p02-101-04
1522 | p02-101-05
1523 | p02-101-06
1524 | p02-105-00
1525 | p02-105-01
1526 | p02-105-02
1527 | p02-105-03
1528 | p02-105-04
1529 | p02-105-05
1530 | p02-105-06
1531 | p02-105-07
1532 | p02-109-00
1533 | p02-109-02
1534 | p02-109-03
1535 | p02-109-04
1536 | p02-109-05
1537 | p02-109-06
1538 | p02-109-07
1539 | p02-109-08
1540 | p02-115-00
1541 | p02-115-01
1542 | p02-115-02
1543 | p02-115-03
1544 | p02-115-04
1545 | p02-115-05
1546 | p02-115-06
1547 | p02-115-07
1548 | p02-115-08
1549 | p02-121-00
1550 | p02-121-01
1551 | p02-121-02
1552 | p02-121-03
1553 | p02-121-04
1554 | p02-121-05
1555 | p02-127-00
1556 | p02-127-01
1557 | p02-127-02
1558 | p02-127-03
1559 | p02-127-04
1560 | p02-127-05
1561 | p02-131-00
1562 | p02-131-01
1563 | p02-131-02
1564 | p02-131-03
1565 | p02-131-04
1566 | p02-131-05
1567 | p02-131-06
1568 | p02-131-07
1569 | p02-135-00
1570 | p02-135-01
1571 | p02-135-02
1572 | p02-135-03
1573 | p02-135-04
1574 | p02-135-05
1575 | p02-135-06
1576 | p02-135-07
1577 | p02-135-08
1578 | p02-139-00
1579 | p02-139-01
1580 | p02-139-02
1581 | p02-139-03
1582 | p02-139-04
1583 | p02-144-00
1584 | p02-144-01
1585 | p02-144-02
1586 | p02-144-03
1587 | p02-144-04
1588 | p02-144-05
1589 | p02-144-06
1590 | p02-144-07
1591 | p02-144-08
1592 | p02-144-09
1593 | p02-144-10
1594 | p02-150-00
1595 | p02-150-01
1596 | p02-150-02
1597 | p02-150-03
1598 | p02-150-04
1599 | p02-150-05
1600 | p02-150-06
1601 | p02-150-07
1602 | p02-155-00
1603 | p03-004-00
1604 | p03-004-01
1605 | p03-004-02
1606 | p03-004-03
1607 | p03-004-04
1608 | p03-004-05
1609 | p03-004-06
1610 | p03-004-07
1611 | p03-004-08
1612 | p03-004-09
1613 | p03-004-10
1614 | p03-009-00
1615 | p03-009-01
1616 | p03-009-02
1617 | p03-009-03
1618 | p03-009-04
1619 | p03-009-05
1620 | p03-009-06
1621 | p03-012-00
1622 | p03-012-01
1623 | p03-012-02
1624 | p03-012-03
1625 | p03-012-04
1626 | p03-012-05
1627 | p03-012-06
1628 | p03-012-07
1629 | p03-012-08
1630 | p03-023-00
1631 | p03-023-01
1632 | p03-023-02
1633 | p03-023-03
1634 | p03-023-04
1635 | p03-027-00
1636 | p03-027-01
1637 | p03-027-02
1638 | p03-027-03
1639 | p03-027-04
1640 | p03-027-05
1641 | p03-027-06
1642 | p03-029-00
1643 | p03-029-01
1644 | p03-029-02
1645 | p03-029-03
1646 | p03-029-04
1647 | p03-029-05
1648 | p03-029-06
1649 | p03-029-07
1650 | p03-029-08
1651 | p03-029-09
1652 | p03-033-00
1653 | p03-033-01
1654 | p03-033-02
1655 | p03-033-03
1656 | p03-033-04
1657 | p03-040-00
1658 | p03-040-01
1659 | p03-040-02
1660 | p03-040-03
1661 | p03-040-04
1662 | p03-040-05
1663 | p03-040-06
1664 | p03-040-07
1665 | p03-047-00
1666 | p03-047-01
1667 | p03-047-02
1668 | p03-047-03
1669 | p03-047-04
1670 | p03-047-05
1671 | p03-047-06
1672 | p03-047-07
1673 | p03-047-08
1674 | p03-047-09
1675 | p03-069-00
1676 | p03-069-01
1677 | p03-069-02
1678 | p03-069-03
1679 | p03-069-04
1680 | p03-069-05
1681 | p03-069-06
1682 | p03-072-00
1683 | p03-072-01
1684 | p03-072-02
1685 | p03-072-03
1686 | p03-072-04
1687 | p03-072-05
1688 | p03-072-06
1689 | p03-080-00
1690 | p03-080-01
1691 | p03-080-02
1692 | p03-080-03
1693 | p03-080-04
1694 | p03-080-05
1695 | p03-080-06
1696 | p03-121-00
1697 | p03-121-01
1698 | p03-121-02
1699 | p03-121-03
1700 | p03-121-04
1701 | p03-121-05
1702 | p03-121-06
1703 | p03-135-00
1704 | p03-135-01
1705 | p03-135-02
1706 | p03-135-03
1707 | p03-135-04
1708 | p03-135-05
1709 | p03-142-00
1710 | p03-142-01
1711 | p03-142-02
1712 | p03-142-03
1713 | p03-142-04
1714 | p03-142-05
1715 | p03-142-06
1716 | p03-151-00
1717 | p03-151-01
1718 | p03-151-02
1719 | p03-151-03
1720 | p03-151-04
1721 | p03-151-05
1722 | p03-151-06
1723 | p03-151-07
1724 | p03-158-00
1725 | p03-158-01
1726 | p03-158-02
1727 | p03-158-03
1728 | p03-158-04
1729 | p03-158-05
1730 | p03-158-06
1731 | p03-163-00
1732 | p03-163-01
1733 | p03-163-02
1734 | p03-163-03
1735 | p03-163-04
1736 | p03-163-05
1737 | p03-163-06
1738 | p03-163-07
1739 | p03-173-00
1740 | p03-173-01
1741 | p03-173-02
1742 | p03-173-03
1743 | p03-173-04
1744 | p03-173-05
1745 | p03-173-06
1746 | p03-173-07
1747 | p03-173-08
1748 | p03-181-00
1749 | p03-181-01
1750 | p03-181-02
1751 | p03-181-03
1752 | p03-181-04
1753 | p03-181-05
1754 | p03-181-06
1755 | p03-181-07
1756 | p03-181-08
1757 | p03-181-09
1758 | p03-185-00
1759 | p03-185-01
1760 | p03-185-02
1761 | p03-185-03
1762 | p03-185-04
1763 | p03-185-05
1764 | p03-185-06
1765 | p03-185-07
1766 | p03-189-00
1767 | p03-189-01
1768 | p03-189-02
1769 | p03-189-03
1770 | p06-030-00
1771 | p06-030-01
1772 | p06-030-02
1773 | p06-030-03
1774 | p06-030-04
1775 | p06-030-05
1776 | p06-030-06
1777 | p06-030-07
1778 | p06-030-08
1779 | p06-042-00
1780 | p06-042-01
1781 | p06-042-02
1782 | p06-042-03
1783 | p06-042-04
1784 | p06-042-05
1785 | p06-042-06
1786 | p06-042-07
1787 | p06-042-08
1788 | p06-042-09
1789 | p06-042-10
1790 | p06-047-00
1791 | p06-047-01
1792 | p06-047-02
1793 | p06-047-03
1794 | p06-047-04
1795 | p06-047-05
1796 | p06-047-06
1797 | p06-047-07
1798 | p06-047-08
1799 | p06-047-09
1800 | p06-047-10
1801 | p06-052-00
1802 | p06-052-01
1803 | p06-052-02
1804 | p06-052-03
1805 | p06-052-04
1806 | p06-052-05
1807 | p06-052-06
1808 | p06-052-07
1809 | p06-052-08
1810 | p06-058-00
1811 | p06-058-01
1812 | p06-058-02
1813 | p06-058-03
1814 | p06-058-04
1815 | p06-058-05
1816 | p06-058-06
1817 | p06-058-07
1818 | p06-058-08
1819 | p06-058-09
1820 | p06-058-10
1821 | p06-069-00
1822 | p06-069-01
1823 | p06-069-02
1824 | p06-069-03
1825 | p06-069-04
1826 | p06-069-05
1827 | p06-069-06
1828 | p06-069-07
1829 | p06-069-08
1830 | p06-069-09
1831 | p06-088-00
1832 | p06-088-01
1833 | p06-088-02
1834 | p06-088-03
1835 | p06-088-04
1836 | p06-088-05
1837 | p06-088-06
1838 | p06-088-07
1839 | p06-088-08
1840 | p06-088-09
1841 | p06-096-00
1842 | p06-096-01
1843 | p06-096-02
1844 | p06-096-03
1845 | p06-096-04
1846 | p06-096-05
1847 | p06-096-06
1848 | p06-096-07
1849 | p06-096-08
1850 | p06-096-09
1851 | p06-096-10
1852 | p06-104-00
1853 | p06-104-01
1854 | p06-104-02
1855 | p06-104-03
1856 | p06-104-04
1857 | p06-104-05
1858 | p06-104-06
1859 | p06-104-07
1860 | p06-104-08
1861 | p06-104-09
1862 |
--------------------------------------------------------------------------------