You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 line
6.7 KiB

  1. import argparse
  2. import multiprocessing as mp
  3. import os
  4. import threading as th
  5. import time
  6. from datetime import datetime
  7. from time import perf_counter
  8. os.environ['DISPLAY'] = ':0'
  9. import cv2
  10. inputQueue = mp.Queue(100)
  11. vehicleDetectionQueue = mp.Queue(100)
  12. outputQueue = mp.Queue(100)
  13. IMAGE_HEIGHT = mp.Value('i',0)
  14. IMAGE_WIDTH = mp.Value('i',0)
  15. class ReadFrame(th.Thread):
  16. global inputQueue
  17. global IMAGE_HEIGHT,IMAGE_WIDTH
  18. def __init__(self,source,name='Input thread',custom_id=1) -> None:
  19. super().__init__()
  20. self.frameId = 1
  21. self.stopped = False
  22. self.grabbed = True
  23. self.name = f'{name} {custom_id}'
  24. self.videoCaptureObject = cv2.VideoCapture(source)
  25. if(self.videoCaptureObject.isOpened()):
  26. # set self.grabbed here.
  27. IMAGE_HEIGHT.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_HEIGHT))
  28. IMAGE_WIDTH.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_WIDTH))
  29. print(f'Reading from source = {source}')
  30. def run(self):
  31. initial = perf_counter()
  32. while (self.grabbed):
  33. (self.grabbed, self.frame) = self.videoCaptureObject.read()
  34. #IMAGE_HEIGHT.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_HEIGHT))
  35. #IMAGE_WIDTH.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_WIDTH))
  36. inputQueue.put((self.frame,self.frameId))
  37. print(f"{self.name} frame added with id {self.frameId}\n")
  38. self.frameId+=1
  39. print('--Done reading frames--\n')
  40. self.videoCaptureObject.release()
  41. end = perf_counter()
  42. print(f'Total time taken by {self.name} = {end - initial}\n')
  43. return
  44. #Create seperate classes for threads and processes and pass global variables as arguments to __init__()
  45. class VehicleDetection(mp.Process):
  46. global inputQueue
  47. global vehicleDetectionQueue
  48. def __init__(self,name='Vehicle Detection Process',custom_id=1):
  49. super(VehicleDetection,self).__init__()
  50. self.name = f'{name} {custom_id}'
  51. def run(self):
  52. while (True):
  53. #Add a end token for vehicleDetection
  54. if(inputQueue.qsize() == 0):
  55. vehicleDetectionQueue.put(None)
  56. print(f'{self.name} exiting !! \n')
  57. end = perf_counter()
  58. print(f'Total time taken by {self.name} = {end - initial}\n')
  59. return
  60. (frame,frameId) = inputQueue.get()
  61. print(f"{self.name} Got frame with ID {frameId} qsize = {inputQueue.qsize()}\n")
  62. #do some processing here.
  63. #time.sleep(.5)
  64. vehicleDetectionQueue.put((frame,frameId))
  65. class NumberPlateOcr(mp.Process):
  66. global vehicleDetectionQueue
  67. global outputQueue
  68. def __init__(self,name='Number plate OCR Process',custom_id=1):
  69. super(NumberPlateOcr,self).__init__()
  70. self.name=f'{name} {custom_id}'
  71. def run(self):
  72. initial = perf_counter()
  73. while True:
  74. value = vehicleDetectionQueue.get()
  75. #Change the value of end token for consumer/producer relationship.
  76. if(value == None):
  77. print(f'{self.name} exiting !! \n')
  78. outputQueue.put(None)
  79. end = perf_counter()
  80. print(f'Total time taken by {self.name} = {end - initial}\n')
  81. return
  82. (frame,frameId) = value
  83. print(f"{self.name} Got frame with ID {frameId}\n")
  84. #do some processing here.
  85. #time.sleep(.25)
  86. outputQueue.put((frame,frameId))
  87. class OutputFrame(th.Thread):
  88. global IMAGE_HEIGHT,IMAGE_WIDTH
  89. global outputQueue
  90. def __init__(self,name='output thread',custom_id=1,outputfilename="output.avi"):
  91. super().__init__()
  92. self.name = f'{name} {custom_id}'
  93. self.outputfilename = outputfilename
  94. print(f'frame size {IMAGE_HEIGHT.value} {IMAGE_WIDTH.value}')
  95. self.videoWriterObject = cv2.VideoWriter(outputfilename,cv2.VideoWriter_fourcc(*'MJPG'),30,(IMAGE_WIDTH.value,IMAGE_HEIGHT.value))
  96. def run(self):
  97. initial = perf_counter()
  98. while True:
  99. try:
  100. value = outputQueue.get()
  101. #change the end token
  102. if(value == None):
  103. end = perf_counter()
  104. print(f'Total time taken by {self.name} = {end - initial}\n')
  105. return
  106. (frame,frameId) = value
  107. print(f'{self.name} got frame with ID {frameId} shape = {frame.shape}')
  108. self.videoWriterObject.write(frame)
  109. except(AttributeError):
  110. continue
  111. if __name__ == '__main__':
  112. import cProfile
  113. app_profiler = cProfile.Profile()
  114. parser = argparse.ArgumentParser(description='BitSilica Traffic Analysis Solution')
  115. parser.add_argument('--image', help=' Full Path to image file.')
  116. parser.add_argument('--video', help='Full Path to video file.')
  117. parser.add_argument('--realtime',help='Camera Connected Input')
  118. args = parser.parse_args()
  119. #Name of the video file.
  120. outputvideo = f'output {os.path.basename(args.video)[:-4]} {datetime.now()}.avi'
  121. print(f'-----> Writing to file {outputvideo} <-------\n')
  122. #enable profiler here after the debug is set to true.
  123. initial = perf_counter()
  124. app_profiler.enable()
  125. readFramesThread = ReadFrame(args.video)
  126. vehicleDetectionProcess = VehicleDetection()
  127. numberPlateOcrProcess = NumberPlateOcr()
  128. outputframeThread = OutputFrame(outputfilename = outputvideo)
  129. readFramesThread.start()
  130. # add a condition for checking the input token for starting.
  131. time.sleep(.25)
  132. vehicleDetectionProcess.start()
  133. numberPlateOcrProcess.start()
  134. outputframeThread.start()
  135. print(f'{vehicleDetectionProcess.name} {vehicleDetectionProcess.pid} \n')
  136. print(f'{numberPlateOcrProcess.name} {numberPlateOcrProcess.pid} \n')
  137. readFramesThread.join()
  138. print(f'readframesthread {readFramesThread.is_alive()}\n')
  139. vehicleDetectionProcess.join()
  140. print(f'vehicleDetectionProcess {vehicleDetectionProcess.is_alive()}\n')
  141. numberPlateOcrProcess.join()
  142. print(f'numberPlateOcrProcess {numberPlateOcrProcess.is_alive()}\n')
  143. outputframeThread.join()
  144. print(f'{outputframeThread.name} {outputframeThread.is_alive()}')
  145. #disable profiler here on debug set to true.
  146. app_profiler.disable()
  147. end = perf_counter()
  148. print(f'Total time taken by __main__ = {end - initial}\n')
  149. profile_name = str('{}.prof'.format(os.path.basename(args.video)[0:-4]))
  150. print("------------------------\nEnd of execution, dumping profile stats\n-------------------------")
  151. app_profiler.dump_stats(profile_name)