From 94af4b54a305f2ee8e9eeba26c57c8a2e93639dd Mon Sep 17 00:00:00 2001 From: Atmadeep Arya Date: Mon, 8 Mar 2021 16:56:25 +0530 Subject: [PATCH] refactor(processes/threads exit/join cleanly upto vehicledetectionProcess()): intermediate Commit. 1. readFramesThread() exits cleanly. Populate the inputQueue using time.sleep() after the start() 2. vehicleDetectionProcess() exits cleanly. 3. numberPlateOcr doesn't exit cleanly. Do not checkout. --- example2.py | 30 ++++++--- skeleton.py | 39 +++++++---- src/objectDetection.py | 7 +- src/ocrNumberPlate.py | 2 +- src/schedule_1.py | 11 ---- src/trafficApp.py | 146 ++++++++++++++++++++++++++--------------- 6 files changed, 146 insertions(+), 89 deletions(-) delete mode 100644 src/schedule_1.py diff --git a/example2.py b/example2.py index 7c1947e..f0f7caa 100644 --- a/example2.py +++ b/example2.py @@ -8,39 +8,48 @@ inputQueue = mp.JoinableQueue() inputQueue2 = mp.Queue(10) class ProducerThread(Thread): - def __init__(self,name='',custom_id,daemon=False): + def __init__(self,name='producer thread',custom_id=0,daemon=False): super(ProducerThread, self).__init__() self.name = "{}-{}".format(name,custom_id) self.setDaemon(daemon) - + + #def threadjoin(self): + # super(ProducerThread,self).join() + global inputQueue def run(self): - numbers = range(40) + numbers = range(10) counter = 0 while counter < 20: num = random.choice(numbers) inputQueue.put(num) print("\nPut",num) - time.sleep(.08) + time.sleep(0.5) counter+=1 + -class ConsumerProcess1(Thread): - def __init__(self,name,custom_id,daemon=False): +class ConsumerProcess1(mp.Process): + def __init__(self,name='consumer thread',custom_id=0,daemon=False): super(ConsumerProcess1,self).__init__() self.name = "{}-{}".format(name,custom_id) self.daemon = daemon + #def consumerjoin(self): + # super(ConsumerProcess1,self).join() + # return + global inputQueue def run(self): while (not inputQueue.empty()): num = inputQueue.get() inputQueue.task_done() print("\nGot", num) - time.sleep(.1) + time.sleep(1) if __name__ == "__main__": + print("this is example 2") time.sleep(2) a=ProducerThread(name = 'producer thread',custom_id=1,daemon=False) @@ -50,4 +59,9 @@ if __name__ == "__main__": b.start() print(a.ident,a.name,"\n") - print(b.ident,b.name,"\n") \ No newline at end of file + print(b.ident,b.name,"\n") + + a.join() + b.join() + + print('end of program mark') \ No newline at end of file diff --git a/skeleton.py b/skeleton.py index ce8ee73..1501c96 100644 --- a/skeleton.py +++ b/skeleton.py @@ -1,12 +1,13 @@ -import os -import cv2 import argparse -import time -import random import multiprocessing as mp +import os +import random import threading as th +import time from queue import Queue +import cv2 + inputQueue = mp.Queue() vehicleDetectionQueue = mp.Queue() outputQueue = mp.Queue() @@ -30,6 +31,7 @@ class ReadFrame(th.Thread): inputQueue.put((self.frame,self.frameId)) print(f"{self.name}frame added with id {self.frameId}\n") self.frameId+=1 + print('--Done reading frames--\n') return @@ -41,31 +43,35 @@ class VehicleDetection(mp.Process): global inputQueue def run(self): while (True): + if(inputQueue.qsize() == 0): + return (frame,frameId) = inputQueue.get() #inputQueue.task_done() print(f"{self.name}Got frame with ID {frameId} qsize = {inputQueue.qsize()}\n") #do some processing here. - vehicleDetectionQueue.put((frame,frameId)) - if(inputQueue.qsize() < 1): - return - - - + time.sleep(.5) + vehicleDetectionQueue.put_nowait((frame,frameId)) + class NumberPlateOcr(mp.Process): def __init__(self,name='Number plate OCR Process',custom_id=1): super(NumberPlateOcr,self).__init__() self.name=f'{name} {custom_id}' - global inputQueue - global numberPlateOcrQueue + global vehicleDetectionQueue + global outputQueue + def run(self): while True: (frame,frameId) = vehicleDetectionQueue.get() #inputQueue.task_done() print(f"{self.name} Got frame with ID {frameId}\n") #do some processing here. - outputQueue.put((frame,frameId)) + time.sleep(.25) + outputQueue.put_nowait((frame,frameId)) + if((inputQueue.empty()) and (vehicleDetectionQueue.empty())): + return + class outputframe(th.Thread): def __init__(self,name='output thread',custom_id=1): @@ -98,9 +104,16 @@ if __name__ == '__main__': vehicleDetectionProcess = VehicleDetection() numberPlateOcrProcess = NumberPlateOcr() readFramesThread.start() + time.sleep(.25) vehicleDetectionProcess.start() numberPlateOcrProcess.start() + readFramesThread.join() + print(f'readframesthread {readFramesThread.is_alive()}\n') + vehicleDetectionProcess.join() + print(f'vehicleDetectionProcess {vehicleDetectionProcess.is_alive()}\n') + numberPlateOcrProcess.join() + print(f'numberPlateOcrProcess {numberPlateOcrProcess.is_alive()}\n') #disable profiler here. diff --git a/src/objectDetection.py b/src/objectDetection.py index 04456fc..74ba71a 100644 --- a/src/objectDetection.py +++ b/src/objectDetection.py @@ -115,7 +115,7 @@ class ObjectDetection(object): return boxes, confidences, classids - def run_object_detection(self,img,imageH,imageW,doPlotBoxNLabel = True): + def run_object_detection(self,img,frameId,imageH,imageW,vehicleDetectionQueue,doPlotBoxNLabel = True): status = True # Image preprocess - make RGB,Resize,Scale by 1/255 blob = cv.dnn.blobFromImage(img, 1 / 255.0, PARAMS._YOLOV3_OD_INPUT_IMAGE_SIZE, @@ -149,5 +149,6 @@ class ObjectDetection(object): if doPlotBoxNLabel: # Draw labels and boxes on the image img = self.draw_labels_and_boxes(img, boxes, confidences, classids, idxs, self.colors, self.labels) - - return img, boxes, confidences, classids, idxs,status + + return img, frameId, boxes, confidences, classids, idxs, status + diff --git a/src/ocrNumberPlate.py b/src/ocrNumberPlate.py index 25e857c..61f963a 100644 --- a/src/ocrNumberPlate.py +++ b/src/ocrNumberPlate.py @@ -160,7 +160,7 @@ def extract_all_number_plates_text(img, region_of_interests): # ============================================================================ -def get_number_plate_ocr_from_rois(img, np_rois_info, save_number_plate): +def get_number_plate_ocr_from_rois(img, np_rois_info,save_number_plate): np_roi_text_dict= {} for idx,roiinfo in enumerate(np_rois_info): conf, classID, roi = roiinfo diff --git a/src/schedule_1.py b/src/schedule_1.py deleted file mode 100644 index 02841df..0000000 --- a/src/schedule_1.py +++ /dev/null @@ -1,11 +0,0 @@ -import os -import argparse - -parser = argparse.ArgumentParser(description="Job scheduler for sampling decision") -parser.add_argument("--jump",type=int,default=1,help = 'integer value for jumping frames') -args = parser.parse_args() -for i in range (1,11): - videoname = "sample_video_{}.mp4".format(i) - command = "python src/trafficApp.py --video ./resources/{} --saveoutput true --jump {} ".format(videoname,args.jump) - os.system(command) - \ No newline at end of file diff --git a/src/trafficApp.py b/src/trafficApp.py index 378350d..fec2026 100644 --- a/src/trafficApp.py +++ b/src/trafficApp.py @@ -1,11 +1,16 @@ import argparse import cv2 as cv + import numpy as np -from tqdm import tqdm + import os +import signal +import multiprocessing as mp os.environ['DISPLAY'] = ':0' + + from config.config import PARAMS from src.numberPlateRoiDetection import NumberPlateROIDetection from src.objectDetection import ObjectDetection @@ -13,6 +18,9 @@ from src.ocrNumberPlate import get_number_plate_ocr_from_rois from src.parkingDetection import ParkingDetection from src.trackingManager import TrackerManager +# TODO 2 processes for objectdetection using queues (queue1) +# TODO implement queue for taking frames, frameid from queue1 + class TrafficApp(object): def __init__(self,args): self.args = args @@ -28,9 +36,16 @@ class TrafficApp(object): if self.args.video is not None: self.vid_writer = None self.runVideoFlow() - + def runVideoFlow(self): frame_count = 0 + frame1_id=0 + frame2_id= 1 + + vehicleDetectionQueue = mp.Queue() + framesList=[] + outputfile = "output-{}.mp4".format(os.path.basename(args.video)[:-4]) + if args.video is not None: try: videoObj = cv.VideoCapture(args.video) @@ -67,62 +82,85 @@ class TrafficApp(object): print('Frames-{},Height-{}, Width-{}'.format(totalFrames,imgH,imgW)) if self.args.saveoutput and (imgH > 0 and imgW > 0): - self.vid_writer = cv.VideoWriter(self.args.outputfile, + self.vid_writer = cv.VideoWriter(outputfile, cv.VideoWriter_fourcc(*"MJPG"), 30, (round(imgW),round(imgH))) - progress_bar=tqdm(total = totalFrames) + # start reading frame - while True: - grabbed, frame = videoObj.read() + while True : + grabbed1, frame1 = videoObj.read() + grabbed2, frame2 = videoObj.read() + frame1_id+=1 + frame2_id+=2 + + #frame[:,450:,:] = 0 # end of frame - if not grabbed: + if not grabbed1: break frame_count +=1 - #print('Frame_count-',frame_count) #Use jump argument to skip frames. - if (frame_count % self.args.jump == 0): - - # get object detection on this frame - img_objectMarking, boxes, confidences, classids, idxs,status = self.objectDetection.run_object_detection(frame.copy(),imageH=imgH,imageW=imgW) - '''Assign Trcakers''' - object_detect_info = [boxes, confidences, classids, idxs, status] - bbox_labels_tracking = self.parseObjDetectInfo(object_detect_info) - TrackerManager.FrameCount = frame_count - TrackerManager.manageTracker(bbox_labels_tracking) - - ''' Get Parking Status''' - if PARAMS._ALGO_MODE_PARKING: - self.parkingDetection.getParkingStatus(TrackerManager.TrackerList) - - '''Filter ROIs for Number Plate Detection''' - tentative_numberplate_rios = self.objectDetection.filterRoiforNumberPlate(boxes, classids, idxs) - - - ''' Get Number Plate ROI''' - detected_np_info = self.numberPlateDetection.run_number_plate_detection_rois(image=frame.copy(),rois=tentative_numberplate_rios) - - - ''' Get Number plate OCR ''' - number_plate_ocr_dict = get_number_plate_ocr_from_rois(frame.copy(),detected_np_info, False) - - #Display frame - displayFrame = self.displayFrame(frame.copy(),detected_np_info,number_plate_ocr_dict,object_detect_info) - - winName = 'YOLOV3 Object Detection' - cv.namedWindow(winName, cv.WINDOW_NORMAL) - #cv.imshow(winName, displayFrame) - #cv.resizeWindow('objectDetection',680,420) - if self.vid_writer: - self.vid_writer.write(displayFrame.astype(np.uint8)) - c = cv.waitKey(1) - if c & 0xFF == ord('q'): - self.vid_writer.release() - videoObj.release() - break - progress_bar.close() + # get object detection on this frame + objectDetectionProcess1=mp.Process(name='Object Detection Process 1',target=self.objectDetection.run_object_detection, args=(frame1.copy(),frame1_id,imgH,imgW,vehicleDetectionQueue)) + objectDetectionProcess2=mp.Process(name='Object Detection Process 2',target=self.objectDetection.run_object_detection, args=(frame2.copy(),frame2_id,imgH,imgW,vehicleDetectionQueue)) + + objectDetectionProcess1.start() + objectDetectionProcess2.start() + + print(f'{objectDetectionProcess1.name},{objectDetectionProcess1.pid},\n' ) + print(f'{objectDetectionProcess2.name},{objectDetectionProcess2.pid} \n' ) + + #print(f'Vehicle detection Queue size = {vehicleDetectionQueue.qsize()}') + #img_objectMarking, boxes, confidences, classids, idxs,status = self.objectDetection.run_object_detection(frame.copy(),imageH=imgH,imageW=imgW) + img, frameId, boxes, confidences, classids, idxs,status = vehicleDetectionQueue.get() + #append the frames and frameid. + framesList.append((img,frameId)) + print(f'frames stored = {len(framesList)} \n') + '''Assign Trackers''' + object_detect_info = [boxes, confidences, classids, idxs, status] + bbox_labels_tracking = self.parseObjDetectInfo(object_detect_info) + TrackerManager.FrameCount = frame_count + TrackerManager.manageTracker(bbox_labels_tracking) + + ''' Get Parking Status''' + if PARAMS._ALGO_MODE_PARKING: + self.parkingDetection.getParkingStatus(TrackerManager.TrackerList) + + '''Filter ROIs for Number Plate Detection''' + tentative_numberplate_rios = self.objectDetection.filterRoiforNumberPlate(boxes, classids, idxs) + + + ''' Get Number Plate ROI''' + detected_np_info = self.numberPlateDetection.run_number_plate_detection_rois(image=img,rois=tentative_numberplate_rios) + + + ''' Get Number plate OCR ''' + number_plate_ocr_dict = get_number_plate_ocr_from_rois(img,detected_np_info, False) + + objectDetectionProcess1.join() + objectDetectionProcess2.join() + + #Display frame + displayFrame = self.displayFrame(img,detected_np_info,number_plate_ocr_dict,object_detect_info) + # ISSUE how to kil the processes? New processes spawn on every iteration. + print(f'objectDetectionProcess1 is alive = {objectDetectionProcess1.is_alive()}\n') + print(f'objectDetectionProcess2 is alive = {objectDetectionProcess2.is_alive()}\n') + print("+++++++++++++++++++end of cycle++++++++++++++++++") + + #winName = 'YOLOV3 Object Detection' + #cv.namedWindow(winName, cv.WINDOW_NORMAL) + #cv.imshow(winName, displayFrame) + #cv.resizeWindow('objectDetection',680,420) + if self.vid_writer: + self.vid_writer.write(displayFrame.astype(np.uint8)) + c = cv.waitKey(1) + if c & 0xFF == ord('q'): + self.vid_writer.release() + videoObj.release() + break + def parseObjDetectInfo(self,object_roi_info): boxes, confidences, classids, idxs, status = object_roi_info #[[list of bbox ][list of conf and labels]] @@ -247,7 +285,7 @@ class TrafficApp(object): if __name__ == '__main__': - import cProfile, pstats + import cProfile app_profiler = cProfile.Profile() parser = argparse.ArgumentParser(description='BitSilica Traffic Analysis Solution') @@ -256,12 +294,14 @@ if __name__ == '__main__': parser.add_argument('--realtime', help='Camera Connected Input') parser.add_argument('--target', type=str,default = 'CPU',help='Target for CNN to run') parser.add_argument('--saveoutput',type=bool,default=True, help='save video or not') - parser.add_argument('--outputfile',type=str,default='./result.avi', help='save video path') - parser.add_argument('--debug',type=bool,default=False, help='print time taken by function') - parser.add_argument('--jump',type=int,default=1,help='integer value for jumping frames') + parser.add_argument('--debug',type=bool,default=False, help='print time taken by function') args = parser.parse_args() + #enable profiler here. app_profiler.enable() + app = TrafficApp(args = args) + + #disable profiler here. app_profiler.disable() - profile_name = str('profile_info-{}.prof'.format(args.jump)) + profile_name = str('{}.prof'.format(os.path.basename(args.video)[0:-4])) app_profiler.dump_stats(profile_name) \ No newline at end of file