yoniyoni12 commited on
Commit
c882487
·
verified ·
1 Parent(s): 619eda3

Upload CRNN.py

Browse files
Files changed (1) hide show
  1. CRNN.py +147 -0
CRNN.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torch.nn as nn
3
+ import numpy as np
4
+ import os
5
+ import shutil
6
+ import cv2
7
+
8
+ CRNN_loc = 'best_crnn.pth'
9
+
10
+ class CRNN(nn.Module):
11
+ def __init__(self, imgH, nc, nclass, nh):
12
+ super(CRNN, self).__init__()
13
+ self.cnn = nn.Sequential(
14
+ nn.Conv2d(nc,64,3,1,1), nn.ReLU(True), nn.MaxPool2d(2,2),
15
+ nn.Conv2d(64,128,3,1,1), nn.ReLU(True), nn.MaxPool2d(2,2),
16
+ nn.Conv2d(128,256,3,1,1), nn.ReLU(True),
17
+ nn.Conv2d(256,256,3,1,1), nn.ReLU(True), nn.MaxPool2d((2,2),(2,1),(0,1)),
18
+ nn.Conv2d(256,512,3,1,1), nn.BatchNorm2d(512), nn.ReLU(True),
19
+ nn.Conv2d(512,512,3,1,1), nn.BatchNorm2d(512), nn.ReLU(True), nn.MaxPool2d((2,2),(2,1),(0,1)),
20
+ nn.Conv2d(512,512,2,1,0), nn.ReLU(True)
21
+ )
22
+ self.rnn1 = nn.LSTM(512, nh, bidirectional=True, dropout=0.3)
23
+ self.rnn2 = nn.LSTM(nh*2, nh, bidirectional=True, dropout=0.3)
24
+ self.fc = nn.Linear(nh*2, nclass)
25
+
26
+ def forward(self, x):
27
+ conv = self.cnn(x)
28
+ b, c, h, w = conv.size()
29
+ conv = conv.squeeze(2).permute(2, 0, 1)
30
+ recurrent, _ = self.rnn1(conv)
31
+ recurrent, _ = self.rnn2(recurrent)
32
+ output = self.fc(recurrent)
33
+ return output.permute(1, 0, 2)
34
+
35
+ # Device
36
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
37
+
38
+ # Recreate model with same hyperparameters
39
+ CRNN_model = CRNN(imgH=32, nc=1, nclass= 303, nh=256).to(DEVICE)
40
+
41
+ # Load weights
42
+ checkpoint = torch.load(CRNN_loc, map_location=DEVICE)
43
+ CRNN_model.load_state_dict(checkpoint)
44
+
45
+ CRNN_model.eval()
46
+ print("Model loaded and ready!")
47
+
48
+ def preprocess_image(img_path):
49
+ img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
50
+ print(img.shape)
51
+ h, w= img.shape
52
+ new_w = max(int(32 * (w / h)), 32)
53
+ img = cv2.resize(img, (new_w, 32))
54
+ img = (img / 255.0).astype(np.float32)
55
+ img = (img - 0.5) / 0.5 # normalize
56
+ img = torch.from_numpy(img).unsqueeze(0).unsqueeze(0) # [B,C,H,W]
57
+ return img.to(DEVICE)
58
+
59
+ BLANK = 302
60
+ def ctc_greedy_decoder(output, idx_to_char, blank=BLANK):
61
+ # output: [B, T, nclass]
62
+ preds = output.softmax(2).argmax(2) # [B, T]
63
+ preds = preds[0].cpu().numpy().tolist()
64
+
65
+ decoded = []
66
+ prev = -1
67
+ for p in preds:
68
+ if p != prev and p != blank: # collapse repeats, ignore blanks
69
+ decoded.append(idx_to_char.get(p, "�"))
70
+ prev = p
71
+ return "".join(decoded)
72
+
73
+ amharic_mapping = {
74
+ # Basic consonants + vowels
75
+ 0: 'ሀ', 1: 'ሁ', 2: 'ሂ', 3: 'ሃ', 4: 'ሄ', 5: 'ህ', 6: 'ሆ',
76
+ 7: 'ለ', 8: 'ሉ', 9: 'ሊ', 10: 'ላ', 11: 'ሌ', 12: 'ል', 13: 'ሎ', 14: 'ሏ',
77
+ 15: 'ሐ', 16: 'ሑ', 17: 'ሒ', 18: 'ሓ', 19: 'ሔ', 20: 'ሕ', 21: 'ሖ', 22: 'ሗ',
78
+ 23: 'መ', 24: 'ሙ', 25: 'ሚ', 26: 'ማ', 27: 'ሜ', 28: 'ም', 29: 'ሞ', 30: 'ሟ',
79
+ 31: 'ሠ', 32: 'ሡ', 33: 'ሢ', 34: 'ሣ', 35: 'ሤ', 36: 'ሥ', 37: 'ሦ', 38: 'ሧ',
80
+ 39: 'ረ', 40: 'ሩ', 41: 'ሪ', 42: 'ራ', 43: 'ሬ', 44: 'ር', 45: 'ሮ', 46: 'ሯ',
81
+ 47: 'ሰ', 48: 'ሱ', 49: 'ሲ', 50: 'ሳ', 51: 'ሴ', 52: 'ስ', 53: 'ሶ', 54: 'ሷ',
82
+ 55: 'ሸ', 56: 'ሹ', 57: 'ሺ', 58: 'ሻ', 59: 'ሼ', 60: 'ሽ', 61: 'ሾ', 62: 'ሿ',
83
+ 63: 'ቀ', 64: 'ቁ', 65: 'ቂ', 66: 'ቃ', 67: 'ቄ', 68: 'ቅ', 69: 'ቆ', 70: 'ቋ',
84
+ 71: 'በ', 72: 'ቡ', 73: 'ቢ', 74: 'ባ', 75: 'ቤ', 76: 'ብ', 77: 'ቦ', 78: 'ቧ',
85
+ 79: 'ቨ', 80: 'ቩ', 81: 'ቪ', 82: 'ቫ', 83: 'ቬ', 84: 'ቭ', 85: 'ቮ', 86: 'ቯ',
86
+ 87: 'ተ', 88: 'ቱ', 89: 'ቲ', 90: 'ታ', 91: 'ቴ', 92: 'ት', 93: 'ቶ', 94: 'ቷ',
87
+ 95: 'ቸ', 96: 'ቹ', 97: 'ቺ', 98: 'ቻ', 99: 'ቼ', 100: 'ች', 101: 'ቾ', 102: 'ቿ',
88
+ 103: 'ኀ', 104: 'ኁ', 105: 'ኂ', 106: 'ኃ', 107: 'ኄ', 108: 'ኅ', 109: 'ኆ',
89
+ 110: 'ነ', 111: 'ኑ', 112: 'ኒ', 113: 'ና', 114: 'ኔ', 115: 'ን', 116: 'ኖ', 117: 'ኗ',
90
+ 118: 'ኘ', 119: 'ኙ', 120: 'ኚ', 121: 'ኛ', 122: 'ኜ', 123: 'ኝ', 124: 'ኞ', 125: 'ኟ',
91
+ 126: 'አ', 127: 'ኡ', 128: 'ኢ', 129: 'ኣ', 130: 'ኤ', 131: 'እ', 132: 'ኦ', 133: 'ኧ',
92
+ 134: 'ከ', 135: 'ኩ', 136: 'ኪ', 137: 'ካ', 138: 'ኬ', 139: 'ክ', 140: 'ኮ', 141: 'ኯ',
93
+ 142: 'ኸ', 143: 'ኹ', 144: 'ኺ', 145: 'ኻ', 146: 'ኼ', 147: 'ኽ', 148: 'ኾ', 149: 'ዀ', 150: 'ዃ',
94
+ 151: 'ወ', 152: 'ዉ', 153: 'ዊ', 154: 'ዋ', 155: 'ዌ', 156: 'ው', 157: 'ዎ', 158: 'ዏ',
95
+ 159: 'ዐ', 160: 'ዑ', 161: 'ዒ', 162: 'ዓ', 163: 'ዔ', 164: 'ዕ', 165: 'ዖ',
96
+ 166: 'ዘ', 167: 'ዙ', 168: 'ዚ', 169: 'ዛ', 170: 'ዜ', 171: 'ዝ', 172: 'ዞ', 173: 'ዟ',
97
+ 174: 'ዠ', 175: 'ዡ', 176: 'ዢ', 177: 'ዣ', 178: 'ዤ', 179: 'ዥ', 180: 'ዦ', 181: 'ዧ',
98
+ 182: 'የ', 183: 'ዩ', 184: 'ዪ', 185: 'ያ', 186: 'ዬ', 187: 'ይ', 188: 'ዮ',
99
+ 189: 'ደ', 190: 'ዱ', 191: 'ዲ', 192: 'ዳ', 193: 'ዴ', 194: 'ድ', 195: 'ዶ', 196: 'ዷ',
100
+ 197: 'ጀ', 198: 'ጁ', 199: 'ጂ', 200: 'ጃ', 201: 'ጄ', 202: 'ጅ', 203: 'ጆ', 204: 'ጇ',
101
+ 205: 'ገ', 206: 'ጉ', 207: 'ጊ', 208: 'ጋ', 209: 'ጌ', 210: 'ግ', 211: 'ጎ', 212: 'ጏ',
102
+ 213: 'ጠ', 214: 'ጡ', 215: 'ጢ', 216: 'ጣ', 217: 'ጤ', 218: 'ጥ', 219: 'ጦ', 220: 'ጧ',
103
+ 221: 'ጨ', 222: 'ጩ', 223: 'ጪ', 224: 'ጫ', 225: 'ጬ', 226: 'ጭ', 227: 'ጮ', 228: 'ጯ',
104
+ 229: 'ጰ', 230: 'ጱ', 231: 'ጲ', 232: 'ጳ', 233: 'ጴ', 234: 'ጵ', 235: 'ጶ', 236: 'ጷ',
105
+ 237: 'ጸ', 238: 'ጹ', 239: 'ጺ', 240: 'ጻ', 241: 'ጼ', 242: 'ጽ', 243: 'ጾ', 244: 'ጿ',
106
+ 245: 'ፀ', 246: 'ፁ', 247: 'ፂ', 248: 'ፃ', 249: 'ፄ', 250: 'ፅ', 251: 'ፆ', 252: 'ፇ',
107
+ 253: 'ፈ', 254: 'ፉ', 255: 'ፊ', 256: 'ፋ', 257: 'ፌ', 258: 'ፍ', 259: 'ፎ', 260: 'ፏ',
108
+ 261: 'ፐ', 262: 'ፑ', 263: 'ፒ', 264: 'ፓ', 265: 'ፔ', 266: 'ፕ', 267: 'ፖ', 268: 'ፗ',
109
+
110
+ # Special characters / punctuation / numbers
111
+ 269: "!", 270: ":-", 271: "<", 272: "(", 273: "«", 274: "፥", 275: "%", 276: "»", 277: ")",
112
+ 278: ">", 279: ".", 280: "+", 281: "፣", 282: "-", 283: "።", 284: "/",
113
+ 285: "0", 286: "1", 287: "2", 288: "3", 289: "4", 290: "5", 291: "6", 292: "7", 293: "8", 294: "9",
114
+ 295: "፡", 296: "፤", 297: "...", 298: "*", 299: "#", 300: "?"
115
+ }
116
+
117
+ def CNNR_Interface(img_path):
118
+ img = preprocess_image(img_path)
119
+ with torch.no_grad():
120
+ output = CRNN_model(img) # [B, T, nclass]
121
+
122
+ predicted_text = ctc_greedy_decoder(output, amharic_mapping, blank=BLANK)
123
+ print("Predicted:", predicted_text)
124
+ return predicted_text
125
+
126
+ def clear_folder(folder_path):
127
+ # Create folder if it does not exist
128
+ if not os.path.exists(folder_path):
129
+ os.makedirs(folder_path)
130
+ print(f"📁 Created folder '{folder_path}'")
131
+ return
132
+
133
+ # Clear existing contents
134
+ for filename in os.listdir(folder_path):
135
+ file_path = os.path.join(folder_path, filename)
136
+ try:
137
+ if os.path.isfile(file_path) or os.path.islink(file_path):
138
+ os.remove(file_path) # Remove file or symlink
139
+ elif os.path.isdir(file_path):
140
+ shutil.rmtree(file_path) # Remove subdirectory
141
+ except Exception as e:
142
+ print(f"⚠️ Failed to delete {file_path}. Reason: {e}")
143
+ print(f"✅ Cleared all contents in '{folder_path}'")
144
+
145
+ if __name__ == "__main__":
146
+ path = 'row6_word5.jpg'
147
+ print(CNNR_Interface(path))