В настоящее время во многих колледжах и школах книги выдаются студентам вручную с помощью сканеров штрихкодов и электронных таблиц. Все книги и студенческие читательские билеты имеют штрихкоды. Чтобы получить книгу, студент должен передать её библиотекарю вместе со своим читательским билетом, и библиотекарь выдаёт книгу, сканируя штрихкод на книге и читательском билете. Данную систему можно улучшить с помощью решений представленных в настоящей статье.

В рамках этого проекта студенты могут легко выдавать/возвращать книги: им достаточно провести рукой по правой/левой стороне устройства (с ИК-датчиками), приложить книгу и читательский билет, после чего книга будет выдана/возвращена. Каждая книга и читательский билет снабжены штрихкодом. Вместо считывателя штрихкодов в этом проекте я использую камеру и OpenCV для определения значения штрихкода. Данные о книгах и читательских билетах хранятся в удаленной базе данных MySQL. Я также создал приложение и веб-сайт на Python-Flask и разместил их онлайн на Heroku бесплатно. Студенты могут просмотреть свои данные на веб-сайте, введя свой университетский регистрационный номер или номер штрихкода читательского билета. Преимущество веб-сайта в худшем случае, если оборудование по какой-либо причине выйдет из строя, заключается в том, что преподаватель может вручную выдать/вернуть книгу студенту. Приложение создано с помощью MIT App Inventor, и доступ к нему имеет только сотрудник библиотеки в целях безопасности, чтобы никто не мог украсть книгу из библиотеки. Подробнее об этом расскажу ниже.
Что вам следует знать о проекте:
- Каждую книгу можно выдать студентам на 14 дней. Если студент пропустит срок возврата, с него будет взиматься определенная плата каждый день (это значение можно изменить в коде).
- Студенту могут выдать только 5 книг. Если попытаться выдать больше 5 книг, система отобразит сообщение «Вы не можете выдать более 5 книг». Мы можем увеличить количество выдаваемых книг, но это сделает код слишком длинным, поскольку я создал код с простой логикой, которая более эффективна и менее подвержена ошибкам.
- Студенты могут вернуть/переоформить бронирование только через 7 дней, до этого момента сделать это невозможно.
Поскольку это прототип, я сделал его из картона, но в практическом мире можно изготовить коробку, напечатанную на 3D-принтере, или коробку из листового металла.
Если вы новичок в OpenCV, вы можете ознакомиться с нашим руководством «Начало работы с OpenCV».
Необходимые компоненты для проекта

Использованное оборудование для проекта
- модель платы Raspberry Pi 3 B+,
- ИК-датчики,
- TFT-дисплей для Raspberry Pi.
- USB веб-камера,
- USB звуковая карта,
- трансформатор,
- конденсатор,
- диод,
- резистор,
- выпрямитель напряжения 7805,
- светодиод, адаптер питания,
- перемычка,
- печатная плата,
- коробка,
- USB-динамик.
В проекте использовалось программное обеспечение:
- Python,
- Open-cv,
- библиотека Pyzbar,
- библиотека gtts,
- Python-Flask,
- MySQL,
- MIT App Inventor (приложение),
- PHP,
- pysimplegui.
Выбор аппаратного и программного обеспечения для проекта
В этом проекте я использовал Raspberry Pi 3 B+ с процессором 1,4 ГГц, встроенным Wi-Fi и Bluetooth. Я выбрал Raspberry Pi из-за необходимости высокой вычислительной мощности, а также потому, что он проще в использовании, дешевле и поддерживает USB-веб-камеру. Raspberry Pi также предоставляет контакты GPIO, благодаря чему я смог легко подключить ИК-датчик. Для создания графического интерфейса пользователя (GUI) я использовал библиотеку pysimplegui, с помощью которой смог отображать текст (инструкции) на TFT-дисплее. Вместо обычного ЖК-дисплея я использовал TFT-дисплей (3,5 дюйма), чтобы сделать проект более удобным для пользователя. Источник питания — я создал преобразователь переменного тока в постоянный с полным мостовым выпрямителем, который выдает 12 В и 5 В. Это обеспечивает питание как ИК-датчика, так и светодиода (12 В). Для питания Raspberry Pi я использовал адаптер 5 В, 3 А, а для динамика — ещё один USB-адаптер. Всё питание подключил к одному кабелю.
Для считывания (обнаружения) штрихкодов книг или студенческих удостоверений есть два варианта: обычный USB-считыватель штрихкодов или USB-веб-камера. Здесь я использовал USB-веб-камеру для обнаружения штрихкодов вместо обычного считывателя, потому что это дешевле. Веб-сайт, который вы видите здесь (https://librarybookmanager.herokuapp.com/), создан с использованием Python-Flask, поскольку с его помощью я смог использовать библиотеку MySQL Connector, которая позволяет мне подключаться к моей базе данных, а также вручную выдавать/возвращать/повторно выдавать книги или вносить изменения в базу данных. Приложение будет играть важную роль, предотвращая кражу книг. Поскольку система автоматизирована, есть вероятность, что некоторые студенты попытаются забрать книги без проблем. Чтобы предотвратить это, сотрудник библиотеки будет сидеть у выхода из библиотеки с мобильным приложением и, сканируя студентов, сможет увидеть все данные о студентах, например, сколько книг им выдано, какие именно книги им выданы и какова общая сумма штрафа.
Схема проекта
Схема автоматизированной системы управления библиотечными книгами на основе платы Raspberry Pi показана на следующем рисунке.

В аппаратной части установлены два ИК-датчика, подключенных к GPIO Raspberry Pi. Выходной контакт правого датчика подключен к контакту 20 GPIO Raspberry Pi, а выходной контакт левого датчика — к контакту 21 GPIO Raspberry Pi. VCC обоих датчиков подключен к выходу 5 В источника питания, а земля — к земле источника питания. Контакт GND Raspberry Pi также подключен к земле источника питания. Я подал на Raspberry Pi отдельное питание с помощью адаптера 5 В 3 А, а динамик подключен к отдельному USB-адаптеру, но все входы питания подключены к одному кабелю (вилке). Динамики подключены к Raspberry Pi через звуковую карту, чтобы мы могли слышать громкие звуки — это позволяет увеличить громкость динамиков. USB-веб-камера подключена к USB-порту Raspberry Pi. Светодиодная подсветка используется для лучшего освещения USB-веб-камеры, чтобы камера могла четко видеть штрихкод. Положительная сторона светодиода подключается к выходу 12 В источника питания, а заземление — к заземлению источника питания.
Исходный код проекта
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
#!/usr/bin/python3 import time import datetime import mysql.connector as c import cv2 from pyzbar.pyzbar import decode import RPi.GPIO as GPIO from gtts import gTTS from mpyg321.mpyg321 import MPyg321Player import PySimpleGUI as sg sg.LOOK_AND_FEEL_TABLE['MyCreatedTheme'] = {'BACKGROUND': '#34495E', 'TEXT': '#FFCC66', 'INPUT': '#339966', 'TEXT_INPUT': '#000000', 'SCROLL': '#99CC99', 'BUTTON': ('#003333', '#FFCC66'), 'PROGRESS': ('#D1826B', '#CC8019'), 'BORDER': 1, 'SLIDER_DEPTH': 0, 'PROGRESS_DEPTH': 0, } sg.theme('MyCreatedTheme') layout1 = [[sg.Text('Welcome to Library book manager',justification='center',size=(80,4),font=("Helvetica", 20))], [sg.Text(size=(100,3),justification='center',key='-OUTPUT-',font=("Helvetica", 15))], [sg.Text(justification='center',size=(100,4),key='-LEFT-',font=("Helvetica", 13))]] window = sg.Window(title="Library book manager",layout=layout1,size=(600,700),resizable=True,use_custom_titlebar=True, alpha_channel=.5,right_click_menu = None, grab_anywhere=False,no_titlebar=True).finalize() window.Maximize() sensor1 = 20 sensor2 = 21 language = 'en' #welcometext = 'Welcome to Automatic Library book management system!' #myobj = gTTS(text=welcometext, lang=language, slow=False) #myobj.save("welcome.mp3") ##placebooktext = 'Please Place Book which you want to issue or re issue!' #myobj1 = gTTS(text=placebooktext, lang=language, slow=False) #myobj1.save("placebook.mp3") #placereturnbooktext = 'Please Place Book which you want to Return!' #myobj1 = gTTS(text=placereturnbooktext, lang=language, slow=False) #myobj1.save("placereturnbook.mp3") #placecardtext = 'Please Place Your LIBRARY ID CARD!' #myobj2 = gTTS(text=placecardtext, lang=language, slow=False) #myobj2.save("placecard.mp3") #bookissuetext = 'Book has been issued to you!' #myobj3 = gTTS(text=bookissuetext, lang=language, slow=False) #myobj3.save("bookissue.mp3") #bookreissuetext = 'Book has been re issued to you!' #myobj4 = gTTS(text=bookreissuetext, lang=language, slow=False) #myobj4.save("bookreissue.mp3") #bookreturntext = 'Book has been succesfully Returned!' #myobj5 = gTTS(text=bookreturntext, lang=language, slow=False) #myobj5.save("bookreturn.mp3") #morebooktext = 'YOU CANNOT ISSUE BOOKS MORE THAN 5' #myobj6 = gTTS(text=morebooktext, lang=language, slow=False) #myobj6.save("morebook.mp3") #nobooktext = 'Book Not Registered in Database' #myobj7 = gTTS(text=nobooktext, lang=language, slow=False) #myobj7.save("nobook.mp3") #nousertext = 'Book Not Registered in Database' #myobj8 = gTTS(text=nousertext, lang=language, slow=False) #myobj8.save("nouser.mp3") #errortext = 'You can only Return book after 7 Days' #myobj9 = gTTS(text=errortext, lang=language, slow=False) #myobj9.save("error.mp3") #error2text = 'Book is not isued to you or something went wrong' #myobj10 = gTTS(text=error2text, lang=language, slow=False) #myobj10.save("error2.mp3") player = MPyg321Player() player.play_song("welcome.mp3") GPIO.setmode(GPIO.BCM) GPIO.setup(sensor1,GPIO.IN) GPIO.setup(sensor2,GPIO.IN) cap = cv2.VideoCapture(0) cap.set(3, 320) cap.set(4, 240) flag1 = True flag2 = False flag3 = True flag4 = False con = c.connect(host="hostname", user="username", passwd="password", database="database name", port=3306 ) def mohit(frame): global flag1 global flag2 global bookname global bookuid global bookissuedto global cursor con.commit() if flag1 == True: for code in decode(frame): print(code.type) print(code.data.decode('utf-8')) id = code.data.decode('utf-8') cursor.execute("Select uid, bookname , available , issuedto FROM bookdatabase WHERE uid="+str(id)) result = cursor.fetchone() #print(result[2]) if result is not(None): if result[2] == 1: bookname = result[1] bookuid = result[0] bookissuedto = result[3] #cv2.destroyAllWindows() flag2= True function2(result[2]) flag1= False elif result is None: flag1=False print("Book not Registered!!") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Is Not Registered !!") window.finalize() player.play_song("nobook.mp3") def function2(res): if res == 1: print("Place Your LIBRARY ID CARD!!") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Place Your LIBRARY ID CARD !!") window.finalize() player.play_song("placecard.mp3") count = 0 maurya(count) def maurya(count): global flag1 global flag2 time.sleep(10) count_f_stop = 0 while count <= 100: if count_f_stop == 0: while count_f_stop <= 10: success, frame1 = cap.read() count_f_stop = count_f_stop + 1 count = count + 1 success, frame1 = cap.read() read(frame1) #cv2.imshow('test', frame) #cv2.waitKey(1) flag1 = True main() def read(frame1): global flag1 global flag2 global bookname global bookuid global intissuefine global cursor con.commit() if flag2 == True: for code1 in decode(frame1): print(code1.type) print(code1.data.decode('utf-8')) uid = code1.data.decode('utf-8') if uid == bookissuedto or bookissuedto == str(0): cursor.execute("Select lid, name , issued,fine FROM usersdatabase WHERE lid="+str(uid)) result1 = cursor.fetchone() if result1 is not(None): flag2 = False usedlid = result1[0] username = result1[1] userissued = result1[2] issuefine1 = result1[3] intissuefine = int(issuefine1) if userissued == 0: tday = datetime.date.today() tdelta = datetime.timedelta(days=14) returndate = tday + tdelta newuserissued = userissued + 1 query = """ UPDATE usersdatabase SET b1name = %s,b1uid = %s,b1issuedate=%s,b1returndate=%s,issued=%s WHERE lid = %s """ data = (bookname,bookuid,tday,returndate,newuserissued,uid) cursor.execute(query, data) con.commit() bquery = """ UPDATE bookdatabase SET issuedto=%s WHERE uid = %s """ bdata = (uid,bookuid) cursor.execute(bquery,bdata) con.commit() print("Book Has been issued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been issued to "+str(username)+"\nReturn Date : "+str(returndate)) window.finalize() player.play_song("bookissue.mp3") if userissued == 1: tday = datetime.date.today() tdelta = datetime.timedelta(days=14) returndate = tday + tdelta cursor.execute("Select lid, name ,b1returndate,b1issuedate,issued FROM usersdatabase WHERE b1uid="+str(bookuid)) result2 = cursor.fetchone() if result2 is not(None): m1 = result2[2] ynew1 = m1[0:4] yint1 = int(ynew1) mnew1 = m1[5:7] mint1 = int(mnew1) dnew1 = m1[8:10] dint1 = int(dnew1) previousreturndate1 = datetime.date(yint1,mint1,dint1) tday = datetime.date.today() remainderdate=previousreturndate1 - tday remainderday = remainderdate.days #print(remainderday) if remainderday < 7 and remainderday >= 0: reissuequery1 = """ UPDATE usersdatabase SET b1name = %s,b1uid = %s,b1issuedate=%s,b1returndate=%s WHERE b1uid = %s """ newreturndate = returndate + remainderdate data1 = (bookname,bookuid,tday,newreturndate,bookuid) cursor.execute(reissuequery1,data1) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date :"+str(newreturndate)) window.finalize() player.play_song("bookreissue.mp3") elif remainderday < 0 : absremainderday = abs(remainderday) fine = intissuefine + 2 * absremainderday reissuequery2 = """ UPDATE usersdatabase SET b1name = %s,b1uid = %s,b1issuedate=%s,b1returndate=%s,fine=%s WHERE b1uid = %s """ newreturndate = returndate + remainderdate data2 = (bookname,bookuid,tday,returndate,fine,bookuid) cursor.execute(reissuequery2,data2) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date : "+str(newreturndate)+"\nTotal Fine: "+str(fine)) window.finalize() player.play_song("bookreissue.mp3") cursor.execute("Select lid, name ,b2returndate,b2issuedate,issued FROM usersdatabase WHERE b2uid="+str(bookuid)) result17 = cursor.fetchone() if (result17 is not(None)) and (result2 is None): m1 = result17[2] ynew1 = m1[0:4] yint1 = int(ynew1) mnew1 = m1[5:7] mint1 = int(mnew1) dnew1 = m1[8:10] dint1 = int(dnew1) previousreturndate1 = datetime.date(yint1,mint1,dint1) tday = datetime.date.today() remainderdate=previousreturndate1 - tday remainderday = remainderdate.days if remainderday < 7 and remainderday >= 0: reissuequery3 = """ UPDATE usersdatabase SET b2name = %s,b2uid = %s,b2issuedate=%s,b2returndate=%s WHERE b2uid = %s """ newreturndate = returndate + remainderdate data3 = (bookname,bookuid,tday,newreturndate,bookuid) cursor.execute(reissuequery3,data3) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date :"+str(newreturndate)) window.finalize() player.play_song("bookreissue.mp3") elif remainderday < 0 : absremainderday = abs(remainderday) fine = intissuefine + 2 * absremainderday reissuequery4 = """ UPDATE usersdatabase SET b2name = %s,b2uid = %s,b2issuedate=%s,b2returndate=%s,fine=%s WHERE b2uid = %s """ newreturndate = returndate + remainderdate data4 = (bookname,bookuid,tday,returndate,fine,bookuid) cursor.execute(reissuequery4,data4) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date : "+str(newreturndate)+"\nTotal Fine: "+str(fine)) window.finalize() player.play_song("bookreissue.mp3") cursor.execute("Select lid, name ,b3returndate,b3issuedate,issued FROM usersdatabase WHERE b3uid="+str(bookuid)) result18 = cursor.fetchone() if (result18 is not(None)) and (result17 is None) and (result2 is None): m1 = result18[2] ynew1 = m1[0:4] yint1 = int(ynew1) mnew1 = m1[5:7] mint1 = int(mnew1) dnew1 = m1[8:10] dint1 = int(dnew1) previousreturndate1 = datetime.date(yint1,mint1,dint1) tday = datetime.date.today() remainderdate=previousreturndate1 - tday remainderday = remainderdate.days if remainderday < 7 and remainderday >= 0: reissuequery5 = """ UPDATE usersdatabase SET b3name = %s,b3uid = %s,b3issuedate=%s,b3returndate=%s WHERE b3uid = %s """ newreturndate = returndate + remainderdate data5 = (bookname,bookuid,tday,newreturndate,bookuid) cursor.execute(reissuequery5,data5) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date :"+str(newreturndate)) window.finalize() player.play_song("bookreissue.mp3") elif remainderday < 0 : absremainderday = abs(remainderday) fine = intissuefine + 2 * absremainderday reissuequery6 = """ UPDATE usersdatabase SET b3name = %s,b3uid = %s,b3issuedate=%s,b3returndate=%s,fine=%s WHERE b3uid = %s """ newreturndate = returndate + remainderdate data6 = (bookname,bookuid,tday,returndate,fine,bookuid) cursor.execute(reissuequery6,data6) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date : "+str(newreturndate)+"\nTotal Fine: "+str(fine)) window.finalize() player.play_song("bookreissue.mp3") cursor.execute("Select lid, name ,b4returndate,b4issuedate,issued FROM usersdatabase WHERE b4uid="+str(bookuid)) result19 = cursor.fetchone() if (result19 is not(None)) and (result2 is None) and (result17 is None) and (result18 is None): m1 = result19[2] ynew1 = m1[0:4] yint1 = int(ynew1) mnew1 = m1[5:7] mint1 = int(mnew1) dnew1 = m1[8:10] dint1 = int(dnew1) previousreturndate1 = datetime.date(yint1,mint1,dint1) tday = datetime.date.today() remainderdate=previousreturndate1 - tday remainderday = remainderdate.days if remainderday < 7 and remainderday >= 0: reissuequery7 = """ UPDATE usersdatabase SET b4name = %s,b4uid = %s,b4issuedate=%s,b4returndate=%s WHERE b4uid = %s """ newreturndate = returndate + remainderdate data7 = (bookname,bookuid,tday,newreturndate,bookuid) cursor.execute(reissuequery7,data7) con.commit() print("Book Has been reissued to you") window['-LEFT-'].update(value="") window.finalize() window['-OUTPUT-'].update(value="Book Has been reissued to "+str(username)+"\nReturn Date :"+str(newreturndate)) window.finalize() player.play_song("bookreissue.mp3") elif remainderday < 0 : absremainderday = abs(remainderday) fine = intissuefine + 2 * absremainderday reissuequery8 = """ UPDATE usersdatabase SET b4name = %s,b4uid = %s,b4issuedate=%s,b4returndate=%s,fine=%s WHERE b4uid = %s """ newreturndate = returndate + remainderdate data8 = (bookname,bookuid,tday,returndate,fine,bookuid) cursor.execute(reissuequery8,data8) |



