1. skeleton now works completely from taking video to putting together a file. 2. outputframe uses mp.Queue for taking frames from. 3. Still cannot display frames as they are being received in outputframeThread owing to a bug related to PyQt5.refactoring
@@ -11,7 +11,6 @@ class PARAMS(object): | |||
_YOLOV3_OD_INPUT_IMAGE_SIZE = (416,416) #(Width, Height) | |||
#_YOLOV3_OD_NUMBER_PLATE_OBJECT_LIST = ['car','bus','truck','motorbike'] | |||
_YOLOV3_OD_NUMBER_PLATE_OBJECT_LIST = ['car'] | |||
_OBJECT_DETECTION_PROCESS_CORES = 2 | |||
# Number Plate Detection | |||
_YOLOV3_NP_WEIGHT = os.path.join(_CMD_PMT_,'resources/trainedModels/yolov3_number_plate_detection/lapi.weights') | |||
@@ -1,91 +1,116 @@ | |||
import argparse | |||
import multiprocessing as mp | |||
import os | |||
import random | |||
import threading as th | |||
import time | |||
from datetime import datetime | |||
from queue import Queue | |||
import numpy as np | |||
os.environ['DISPLAY'] = ':0' | |||
import cv2 | |||
inputQueue = mp.Queue() | |||
vehicleDetectionQueue = mp.Queue() | |||
outputQueue = mp.Queue() | |||
IMAGE_HEIGHT = mp.Value('i',0) | |||
IMAGE_WIDTH = mp.Value('i',0) | |||
class ReadFrame(th.Thread): | |||
global inputQueue | |||
global IMAGE_HEIGHT,IMAGE_WIDTH | |||
def __init__(self,source,name='Input thread',custom_id=1) -> None: | |||
super().__init__() | |||
self.frameId = 1 | |||
self.stopped = False | |||
self.grabbed = True | |||
self.name = f'{name} {custom_id}' | |||
self.videoCaptureObject = cv2.VideoCapture(source) | |||
if(self.videoCaptureObject.isOpened()): | |||
IMAGE_HEIGHT.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |||
IMAGE_WIDTH.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_WIDTH)) | |||
print(f'Reading from source = {source}') | |||
global inputQueue | |||
def run(self): | |||
while (self.grabbed): | |||
(self.grabbed, self.frame) = self.videoCaptureObject.read() | |||
IMAGE_HEIGHT.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |||
IMAGE_WIDTH.value = int(self.videoCaptureObject.get(cv2.CAP_PROP_FRAME_WIDTH)) | |||
inputQueue.put((self.frame,self.frameId)) | |||
print(f"{self.name}frame added with id {self.frameId}\n") | |||
print(f"{self.name} frame added with id {self.frameId}\n") | |||
self.frameId+=1 | |||
print('--Done reading frames--\n') | |||
self.videoCaptureObject.release() | |||
return | |||
class VehicleDetection(mp.Process): | |||
global inputQueue | |||
global vehicleDetectionQueue | |||
def __init__(self,name='Vehicle Detection Process',custom_id=1): | |||
super(VehicleDetection,self).__init__() | |||
self.name = f'{name} {custom_id}' | |||
global inputQueue | |||
def run(self): | |||
while (True): | |||
if(inputQueue.qsize() == 0): | |||
vehicleDetectionQueue.put(None) | |||
print(f'{self.name} exiting !! \n') | |||
return | |||
(frame,frameId) = inputQueue.get() | |||
#inputQueue.task_done() | |||
print(f"{self.name}Got frame with ID {frameId} qsize = {inputQueue.qsize()}\n") | |||
print(f"{self.name} Got frame with ID {frameId} qsize = {inputQueue.qsize()}\n") | |||
#do some processing here. | |||
time.sleep(.5) | |||
vehicleDetectionQueue.put_nowait((frame,frameId)) | |||
vehicleDetectionQueue.put((frame,frameId)) | |||
class NumberPlateOcr(mp.Process): | |||
global vehicleDetectionQueue | |||
global outputQueue | |||
def __init__(self,name='Number plate OCR Process',custom_id=1): | |||
super(NumberPlateOcr,self).__init__() | |||
self.name=f'{name} {custom_id}' | |||
global inputQueue | |||
global vehicleDetectionQueue | |||
global outputQueue | |||
def run(self): | |||
while True: | |||
(frame,frameId) = vehicleDetectionQueue.get() | |||
#inputQueue.task_done() | |||
value = vehicleDetectionQueue.get() | |||
if(value == None): | |||
print(f'{self.name} exiting !! \n') | |||
outputQueue.put(None) | |||
return | |||
(frame,frameId) = value | |||
print(f"{self.name} Got frame with ID {frameId}\n") | |||
#do some processing here. | |||
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): | |||
outputQueue.put((frame,frameId)) | |||
class OutputFrame(th.Thread): | |||
global IMAGE_HEIGHT,IMAGE_WIDTH | |||
global outputQueue | |||
def __init__(self,name='output thread',custom_id=1,outputfilename="output.avi"): | |||
super().__init__() | |||
self.name = f'{name} {custom_id}' | |||
self.outputfilename = outputfilename | |||
print(f'frame size {IMAGE_HEIGHT.value} {IMAGE_WIDTH.value}') | |||
self.videoWriterObject = cv2.VideoWriter(outputfilename,cv2.VideoWriter_fourcc(*'MJPG'),30,(IMAGE_WIDTH.value,IMAGE_HEIGHT.value)) | |||
self.winName = "DISPLAY" | |||
def run(self): | |||
cv2.namedWindow(self.winName,cv2.WINDOW_NORMAL) | |||
while True: | |||
(frame,frameId) = outputQueue.get() | |||
print(f'{self.name} got frame {frameId}\n') | |||
try: | |||
value = outputQueue.get() | |||
if(value == None): | |||
return | |||
(frame,frameId) = value | |||
print(f'{self.name} got frame with ID {frameId} shape = {frame.shape}') | |||
cv2.imshow(self.winName,frame) | |||
self.videoWriterObject.write(frame) | |||
except(AttributeError): | |||
continue | |||
if __name__ == '__main__': | |||
import cProfile | |||
@@ -97,16 +122,25 @@ if __name__ == '__main__': | |||
parser.add_argument('--realtime',help='Camera Connected Input') | |||
args = parser.parse_args() | |||
#Name of the video file. | |||
outputvideo = f'output {os.path.basename(args.video)[:-4]} {datetime.now()}.avi' | |||
print(f'-----> Writing to file {outputvideo} <-------\n') | |||
#enable profiler here. | |||
app_profiler.enable() | |||
readFramesThread = ReadFrame(args.video) | |||
vehicleDetectionProcess = VehicleDetection() | |||
numberPlateOcrProcess = NumberPlateOcr() | |||
outputframeThread = OutputFrame(outputfilename = outputvideo) | |||
readFramesThread.start() | |||
time.sleep(.25) | |||
vehicleDetectionProcess.start() | |||
numberPlateOcrProcess.start() | |||
outputframeThread.start() | |||
print(f'{vehicleDetectionProcess.name} {vehicleDetectionProcess.pid} \n') | |||
print(f'{numberPlateOcrProcess.name} {numberPlateOcrProcess.pid} \n') | |||
readFramesThread.join() | |||
print(f'readframesthread {readFramesThread.is_alive()}\n') | |||
@@ -114,11 +148,14 @@ if __name__ == '__main__': | |||
print(f'vehicleDetectionProcess {vehicleDetectionProcess.is_alive()}\n') | |||
numberPlateOcrProcess.join() | |||
print(f'numberPlateOcrProcess {numberPlateOcrProcess.is_alive()}\n') | |||
outputframeThread.join() | |||
print(f'{outputframeThread.name} {outputframeThread.is_alive()}') | |||
#disable profiler here. | |||
app_profiler.disable() | |||
profile_name = str('temp.prof'.format(os.path.basename(args.video)[0:-4])) | |||
profile_name = str('{}.prof'.format(os.path.basename(args.video)[0:-4])) | |||
print("------------------------\nEnd of execution, dumping profile stats\n-------------------------") | |||
app_profiler.dump_stats(profile_name) |
@@ -115,7 +115,7 @@ class ObjectDetection(object): | |||
return boxes, confidences, classids | |||
def run_object_detection(self,img,frameId,imageH,imageW,vehicleDetectionQueue,doPlotBoxNLabel = True): | |||
def run_object_detection(self,img,imageH,imageW,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,6 +149,5 @@ 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, frameId, boxes, confidences, classids, idxs, status | |||
return img, boxes, confidences, classids, idxs,status |
@@ -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 | |||
@@ -1,16 +1,11 @@ | |||
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 | |||
@@ -18,9 +13,6 @@ 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 | |||
@@ -36,16 +28,9 @@ 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) | |||
@@ -82,85 +67,62 @@ 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(outputfile, | |||
self.vid_writer = cv.VideoWriter(self.outputfile, | |||
cv.VideoWriter_fourcc(*"MJPG"), 30, | |||
(round(imgW),round(imgH))) | |||
progress_bar=tqdm(total = totalFrames) | |||
# start reading frame | |||
while True : | |||
grabbed1, frame1 = videoObj.read() | |||
grabbed2, frame2 = videoObj.read() | |||
frame1_id+=1 | |||
frame2_id+=2 | |||
while True: | |||
grabbed, frame = videoObj.read() | |||
#frame[:,450:,:] = 0 | |||
# end of frame | |||
if not grabbed1: | |||
if not grabbed: | |||
break | |||
frame_count +=1 | |||
#print('Frame_count-',frame_count) | |||
#Use jump argument to skip frames. | |||
# 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 | |||
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() | |||
def parseObjDetectInfo(self,object_roi_info): | |||
boxes, confidences, classids, idxs, status = object_roi_info | |||
#[[list of bbox ][list of conf and labels]] | |||
@@ -285,7 +247,7 @@ class TrafficApp(object): | |||
if __name__ == '__main__': | |||
import cProfile | |||
import cProfile, pstats | |||
app_profiler = cProfile.Profile() | |||
parser = argparse.ArgumentParser(description='BitSilica Traffic Analysis Solution') | |||
@@ -294,14 +256,12 @@ 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('--debug',type=bool,default=False, help='print time taken by function') | |||
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') | |||
args = parser.parse_args() | |||
#enable profiler here. | |||
app_profiler.enable() | |||
app = TrafficApp(args = args) | |||
#disable profiler here. | |||
app_profiler.disable() | |||
profile_name = str('{}.prof'.format(os.path.basename(args.video)[0:-4])) | |||
profile_name = str('profile_info-{}.prof'.format(args.jump)) | |||
app_profiler.dump_stats(profile_name) |