Guest User

Untitled

a guest
Nov 4th, 2018
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.49 KB | None | 0 0
  1. # Copyright (c) 2018 gps.az LLC
  2. #
  3. # @author: Tural Mahmudov <prodoccenter@gmail.com>
  4. # https://github.com/NimaBavari
  5. #
  6. # @date: 11.01.2018
  7. #
  8. # @description: Creates the desktop GUI application as one of our front-end
  9. # points
  10. import json
  11. import os
  12. import sys
  13.  
  14. import cv2
  15. import face_recognition
  16. from PIL import Image
  17. from PyQt5.QtCore import pyqtSlot, Qt
  18. from PyQt5.QtGui import QIcon, QStandardItemModel
  19. from PyQt5.QtWidgets import (QApplication, QDialog, QDialogButtonBox,
  20. QFileDialog, QFormLayout, QGridLayout, QGroupBox,
  21. QHBoxLayout, QLabel, QLineEdit, QMainWindow,
  22. QMessageBox, QPushButton, QTreeView, QVBoxLayout,
  23. QWidget)
  24.  
  25. import config
  26. from helpers import (add_to_json, add_user_to_db, add_user_to_model,
  27. edit_user_in_db, edit_user_in_model, get_stranger_faces,
  28. populate_model, remove_from_json, remove_user_in_db,
  29. remove_user_in_model)
  30.  
  31.  
  32. class AddDialog(QDialog):
  33.  
  34. def __init__(self, title, parent, **dial_attr):
  35. super(AddDialog, self).__init__()
  36. self.title = title
  37. self.parent = parent
  38. self.dial_attr = dial_attr
  39. self.img_to_upload = None
  40. self.create_form_group_box()
  41.  
  42. self.buttonBox = QDialogButtonBox(
  43. QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
  44. self.buttonBox.button(QDialogButtonBox.Ok).setText('Add')
  45. self.buttonBox.accepted.connect(self.submit_add)
  46. self.buttonBox.rejected.connect(self.reject)
  47.  
  48. main_layout = QVBoxLayout()
  49. main_layout.addWidget(self.formGroupBox)
  50. main_layout.addWidget(self.buttonBox)
  51. self.setLayout(main_layout)
  52.  
  53. self.setWindowTitle(self.title)
  54. self.setWindowIcon(self.dial_attr['favicon'])
  55.  
  56. def create_form_group_box(self):
  57. self.formGroupBox = QGroupBox('Add New Member')
  58. layout = QFormLayout()
  59. self.f_name_box = QLineEdit()
  60. layout.addRow(QLabel('First name:'), self.f_name_box)
  61. self.l_name_box = QLineEdit()
  62. layout.addRow(QLabel('Last name:'), self.l_name_box)
  63. self.img_url_btn = QPushButton('Upload image')
  64. layout.addRow(QLabel('Upload image:'), self.img_url_btn)
  65. self.img_url_btn.clicked.connect(self.img_upload_dialog)
  66. self.formGroupBox.setLayout(layout)
  67.  
  68. @pyqtSlot()
  69. def img_upload_dialog(self):
  70. options = QFileDialog.Options()
  71. options |= QFileDialog.DontUseNativeDialog
  72. self.img_to_upload, _ = QFileDialog.getOpenFileName(
  73. self,
  74. 'Upload an image',
  75. os.path.expanduser('~'),
  76. 'All Files (*);;Image Files (*.jpg *.jpeg *.png *.jfif)',
  77. options=options
  78. )
  79.  
  80. @pyqtSlot()
  81. def submit_add(self):
  82. first_name = self.f_name_box.text()
  83. last_name = self.l_name_box.text()
  84. if first_name and last_name and self.img_to_upload:
  85. full_name = '%s %s' % (first_name, last_name)
  86. temp_img = face_recognition.load_image_file(self.img_to_upload)
  87. if face_recognition.face_encodings(temp_img):
  88. _, ext = os.path.splitext(self.img_to_upload)
  89. img_name = '%s_%s%s' % (
  90. first_name.lower(), last_name.lower(), ext)
  91. img_path = os.path.join(config.member_dir, img_name)
  92. img = Image.open(self.img_to_upload)
  93. img.save(img_path)
  94. add_user_to_db(first_name, last_name, img_path)
  95. QMessageBox.about(
  96. self,
  97. 'Success',
  98. '%s successfully added as a new customer.' % full_name
  99. )
  100. face = face_recognition.face_encodings(temp_img)[0]
  101. capture_times_in_db, face_encs_in_db = get_stranger_faces()
  102. res = face_recognition.compare_faces(face_encs_in_db, face)
  103. capture_times = [capture_times_in_db[idx].isoformat()
  104. for idx, truth in enumerate(res) if truth]
  105. seen_at = None
  106. if capture_times:
  107. face_data = {
  108. 'full_name': full_name,
  109. 'capture_times': capture_times
  110. }
  111. add_to_json(config.strangers_json_data, face_data)
  112. seen_at = ', '.join(capture_times)
  113. QMessageBox.about(
  114. self,
  115. 'Info',
  116. '%s were captured %d times before at %s.' % (
  117. full_name, len(capture_times), seen_at)
  118. )
  119. self.close()
  120. add_user_to_model(
  121. self.parent.model,
  122. first_name,
  123. last_name,
  124. img_path,
  125. seen_at
  126. )
  127. else:
  128. QMessageBox.about(
  129. self,
  130. 'Error',
  131. 'Bad image: face not shown. Please, upload another image.'
  132. )
  133. else:
  134. QMessageBox.about(self, 'Forbidden!',
  135. 'Please, fill in all the blanks.')
  136.  
  137.  
  138. class EditDialog(QDialog):
  139.  
  140. def __init__(self, title, parent, **dial_attr):
  141. super(EditDialog, self).__init__()
  142. self.title = title
  143. self.parent = parent
  144. self.dial_attr = dial_attr
  145.  
  146. self.buttonBox = QDialogButtonBox(
  147. QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
  148. self.buttonBox.button(QDialogButtonBox.Ok).setText('Edit')
  149. self.buttonBox.accepted.connect(self.submit_edit)
  150. self.buttonBox.rejected.connect(self.reject)
  151.  
  152. self.setWindowTitle(self.title)
  153. self.setWindowIcon(self.dial_attr['favicon'])
  154.  
  155. def show(self):
  156. self.selected_row = [itm.data() for itm in
  157. self.parent.data_view.selectedIndexes()]
  158. if self.selected_row:
  159. super(EditDialog, self).show()
  160. self.old_first_name = self.selected_row[0]
  161. self.old_last_name = self.selected_row[1]
  162. self.old_img_path = self.selected_row[2]
  163. self.old_seen_at = self.selected_row[3]
  164. self.create_form_group_box()
  165. main_layout = QVBoxLayout()
  166. main_layout.addWidget(self.formGroupBox)
  167. main_layout.addWidget(self.buttonBox)
  168. self.setLayout(main_layout)
  169. else:
  170. QMessageBox.about(self, 'Forbidden!',
  171. 'Please, choose a row to edit.')
  172.  
  173. def create_form_group_box(self):
  174. self.formGroupBox = QGroupBox('Edit Member')
  175. layout = QFormLayout()
  176. self.f_name_box = QLineEdit(self.old_first_name)
  177. layout.addRow(QLabel('First name:'), self.f_name_box)
  178. self.l_name_box = QLineEdit(self.old_last_name)
  179. layout.addRow(QLabel('Last name:'), self.l_name_box)
  180. self.img_url_btn = QPushButton('Upload image')
  181. layout.addRow(QLabel('Upload image:'), self.img_url_btn)
  182. self.img_url_btn.clicked.connect(self.img_upload_dialog)
  183. self.formGroupBox.setLayout(layout)
  184.  
  185. @pyqtSlot()
  186. def img_upload_dialog(self):
  187. options = QFileDialog.Options()
  188. options |= QFileDialog.DontUseNativeDialog
  189. self.img_to_upload, _ = QFileDialog.getOpenFileName(
  190. self,
  191. 'Upload an image',
  192. os.path.expanduser('~'),
  193. 'All Files (*);;Image Files (*.jpg *.jpeg *.png *.jfif)',
  194. options=options
  195. )
  196.  
  197. @pyqtSlot()
  198. def submit_edit(self):
  199. first_name = self.f_name_box.text()
  200. last_name = self.l_name_box.text()
  201. if first_name and last_name and self.img_to_upload:
  202. full_name = '%s %s' % (first_name, last_name)
  203. temp_img = face_recognition.load_image_file(self.img_to_upload)
  204. if face_recognition.face_encodings(temp_img):
  205. os.remove(self.old_img_path)
  206. _, ext = os.path.splitext(self.img_to_upload)
  207. img_name = '%s_%s%s' % (
  208. first_name.lower(), last_name.lower(), ext)
  209. img_path = os.path.join(config.member_dir, img_name)
  210. img = Image.open(self.img_to_upload)
  211. img.save(img_path)
  212. edit_user_in_db(
  213. self.old_first_name,
  214. self.old_last_name,
  215. self.old_img_path,
  216. first_name,
  217. last_name,
  218. img_path
  219. )
  220. old_capture_times = []
  221. if self.old_seen_at:
  222. old_capture_times = self.old_seen_at.split(', ')
  223. old_face_data = {
  224. 'full_name': '%s %s' % (self.old_first_name,
  225. self.old_last_name),
  226. 'capture_times': old_capture_times
  227. }
  228. remove_from_json(config.strangers_json_data, old_face_data)
  229. QMessageBox.about(
  230. self,
  231. 'Success',
  232. '%s successfully edited as a customer.' % full_name
  233. )
  234. face = face_recognition.face_encodings(temp_img)[0]
  235. capture_times_in_db, face_encs_in_db = get_stranger_faces()
  236. res = face_recognition.compare_faces(face_encs_in_db, face)
  237. capture_times = [capture_times_in_db[idx].isoformat()
  238. for idx, truth in enumerate(res) if truth]
  239. seen_at = None
  240. if capture_times:
  241. face_data = {
  242. 'full_name': full_name,
  243. 'capture_times': capture_times
  244. }
  245. add_to_json(config.strangers_json_data, face_data)
  246. seen_at = ', '.join(capture_times)
  247. QMessageBox.about(
  248. self,
  249. 'Info',
  250. '%s were captured %d times before at %s.' % (
  251. full_name, len(capture_times), seen_at)
  252. )
  253. self.close()
  254. edit_user_in_model(
  255. self.parent.model,
  256. self.parent.data_view.currentIndex().row(),
  257. first_name,
  258. last_name,
  259. img_path,
  260. seen_at
  261. )
  262. else:
  263. QMessageBox.about(self, 'Error!',
  264. 'Bad image: face not shown. Please,'
  265. 'upload another image.')
  266. else:
  267. QMessageBox.about(self, 'Forbidden!',
  268. 'Please, fill in all the blanks.')
  269.  
  270.  
  271. class EditChannelDialog(QDialog):
  272.  
  273. def __init__(self, title, parent, **dial_attr):
  274. super(EditChannelDialog, self).__init__()
  275. self.title = title
  276. self.parent = parent
  277. self.dial_attr = dial_attr
  278. self.create_form_group_box()
  279.  
  280. self.buttonBox = QDialogButtonBox(
  281. QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
  282. self.buttonBox.button(QDialogButtonBox.Ok).setText('Edit Channel')
  283. self.buttonBox.accepted.connect(self.submit_channel_edit)
  284. self.buttonBox.rejected.connect(self.reject)
  285.  
  286. main_layout = QVBoxLayout()
  287. main_layout.addWidget(self.formGroupBox)
  288. main_layout.addWidget(self.buttonBox)
  289. self.setLayout(main_layout)
  290.  
  291. self.setWindowTitle(self.title)
  292. self.setWindowIcon(self.dial_attr['favicon'])
  293.  
  294. def create_form_group_box(self):
  295. with open('config.json') as conf:
  296. user_conf = json.load(conf)
  297. old_channel = user_conf['channel']
  298. old_uname = user_conf['username']
  299. old_pwd = user_conf['password']
  300. self.formGroupBox = QGroupBox('Edit Channel')
  301. layout = QFormLayout()
  302. self.channel_box = QLineEdit(old_channel)
  303. layout.addRow(QLabel('Channel:'), self.channel_box)
  304. self.uname_box = QLineEdit(old_uname)
  305. layout.addRow(QLabel('Username:'), self.uname_box)
  306. self.pwd_box = QLineEdit(old_pwd)
  307. layout.addRow(QLabel('Password:'), self.pwd_box)
  308. self.formGroupBox.setLayout(layout)
  309.  
  310. @pyqtSlot()
  311. def submit_channel_edit(self):
  312. new_channel = self.channel_box.text()
  313. new_uname = self.uname_box.text()
  314. new_pwd = self.pwd_box.text()
  315. if new_channel:
  316. new_stream_url = new_channel
  317. if new_uname:
  318. sep_pos = new_stream_url.find('//') + 2
  319. protocol = new_stream_url[:sep_pos]
  320. new_stream_url = '%s%s:%s@%s' % (
  321. protocol, new_uname, new_pwd, new_stream_url[sep_pos:])
  322. ret, frame = cv2.VideoCapture(new_stream_url)
  323. if ret and frame:
  324. new_conf = {
  325. 'channel': new_channel,
  326. 'username': new_uname,
  327. 'password': new_uname
  328. }
  329. with open('config.json', 'w') as conf:
  330. json.dump(new_conf, conf)
  331. QMessageBox.about(
  332. self,
  333. 'Success',
  334. 'Channel is successfully edited to %s' % new_stream_url
  335. )
  336. self.close()
  337. else:
  338. QMessageBox.about(
  339. self,
  340. 'Error!',
  341. 'Could not read from the source. Please, make sure the '
  342. 'channel, username and password are all correct.'
  343. )
  344. else:
  345. QMessageBox.about(self, 'Forbidden!', 'Please, specify a channel.')
  346.  
  347.  
  348. class App(QMainWindow):
  349.  
  350. def __init__(self, title, **win_attr):
  351. super().__init__()
  352. self.title = title
  353. self.win_attr = win_attr
  354. self.initUI()
  355.  
  356. def initUI(self):
  357. # Set the grid layout
  358. self.central_widget = QWidget(self)
  359. self.central_widget.resize(800, 640)
  360. grid = QGridLayout(self.central_widget)
  361.  
  362. # Treeview
  363. self.members_data_group_box = QGroupBox('Members')
  364. self.data_view = QTreeView()
  365. self.data_view.setRootIsDecorated(False)
  366. self.data_view.setAlternatingRowColors(True)
  367.  
  368. data_layout = QHBoxLayout()
  369. data_layout.addWidget(self.data_view)
  370. self.members_data_group_box.setLayout(data_layout)
  371.  
  372. self.model = self.create_members_model(self)
  373. self.data_view.setModel(self.model)
  374. populate_model(self.model)
  375. grid.addWidget(self.members_data_group_box, 1, 0, 12, 8)
  376.  
  377. # Define the children dialogs
  378. self.add_new_member_dialog = AddDialog(
  379. 'Add New Member', self, favicon=QIcon('favicon.png'))
  380. self.edit_member_dialog = EditDialog(
  381. 'Edit Member', self, favicon=QIcon('favicon.png'))
  382. self.edit_channel_dialog = EditChannelDialog(
  383. 'Edit Channel', self, favicon=QIcon('favicon.png')
  384. )
  385.  
  386. # Buttons
  387. add_new_member_btn = QPushButton('Add New', self.central_widget)
  388. add_new_member_btn.setToolTip('Add New Customer')
  389. grid.addWidget(add_new_member_btn, 13, 5, 1, 1)
  390. add_new_member_btn.clicked.connect(self.add_new_member_dialog.show)
  391.  
  392. edit_member_btn = QPushButton('Edit', self.central_widget)
  393. edit_member_btn.setToolTip('Edit Customer Info')
  394. grid.addWidget(edit_member_btn, 13, 6, 1, 1)
  395. edit_member_btn.clicked.connect(self.edit_member_dialog.show)
  396.  
  397. remove_member_btn = QPushButton('Remove', self.central_widget)
  398. remove_member_btn.setToolTip('Remove Customer')
  399. grid.addWidget(remove_member_btn, 13, 7, 1, 1)
  400. remove_member_btn.clicked.connect(self.remove_member)
  401.  
  402. watch_live_stream_btn = QPushButton('Get Live Stream',
  403. self.central_widget)
  404. watch_live_stream_btn.setToolTip('Get Live Stream from Camera')
  405. grid.addWidget(watch_live_stream_btn, 15, 0, 1, 4)
  406. watch_live_stream_btn.clicked.connect(watch_live)
  407.  
  408. change_ch_btn = QPushButton('Edit Channel', self.central_widget)
  409. change_ch_btn.setToolTip('Edit Streaming Channel')
  410. grid.addWidget(change_ch_btn, 16, 0, 1, 4)
  411. change_ch_btn.clicked.connect(self.edit_channel_dialog.show)
  412.  
  413. # Set the window components
  414. self.setWindowTitle(self.title)
  415. self.setGeometry(
  416. self.win_attr['left'],
  417. self.win_attr['top'],
  418. self.win_attr['width'],
  419. self.win_attr['height']
  420. )
  421. self.setWindowIcon(self.win_attr['favicon'])
  422. # self.statusBar().showMessage('Status Bar Message.')
  423.  
  424. # Show the window
  425. self.show()
  426.  
  427. @staticmethod
  428. def create_members_model(parent):
  429. model = QStandardItemModel(0, 4, parent)
  430. model.setHeaderData(0, Qt.Horizontal, 'First name')
  431. model.setHeaderData(1, Qt.Horizontal, 'Last name')
  432. model.setHeaderData(2, Qt.Horizontal, 'Image URL')
  433. model.setHeaderData(3, Qt.Horizontal, 'Seen at')
  434. return model
  435.  
  436. def remove_member(self):
  437. selected_row = [itm.data() for itm in self.data_view.selectedIndexes()]
  438. if selected_row:
  439. fname_rem, lname_rem, img_path_rem, seen_at_rem = selected_row
  440. ret = QMessageBox.question(
  441. self,
  442. 'Remove',
  443. 'Are you sure you want to remove %s %s?' % (
  444. fname_rem, lname_rem),
  445. QMessageBox.Yes | QMessageBox.No
  446. )
  447. if ret == QMessageBox.Yes:
  448. capture_times = []
  449. if seen_at_rem:
  450. capture_times = seen_at_rem.split(', ')
  451. face_data = {
  452. 'full_name': '%s %s' % (lname_rem, fname_rem),
  453. 'capture_times': capture_times
  454. }
  455. os.remove(img_path_rem)
  456. remove_user_in_db(fname_rem, lname_rem, img_path_rem)
  457. remove_from_json(config.strangers_json_data, face_data)
  458. remove_user_in_model(
  459. self.model,
  460. self.data_view.currentIndex().row()
  461. )
  462. else:
  463. QMessageBox.about(self, 'Forbidden!',
  464. 'Please, choose a row to remove.')
  465.  
  466.  
  467. def watch_live(): pass
  468.  
  469.  
  470. if __name__ == '__main__':
  471. app = QApplication(sys.argv)
  472. app.setStyle('Fusion')
  473. ex = App(
  474. 'ITS FaceDetect Demo',
  475. left=40,
  476. top=40,
  477. width=800,
  478. height=640,
  479. favicon=QIcon('favicon.png')
  480. )
  481. sys.exit(app.exec_())
Add Comment
Please, Sign In to add comment