Automatic number plate recognition with Python, Yolov8 and EasyOCR | Computer vision tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're going to work with  automatic number plate recognition and this is   exactly what you will be able to do with this  tutorial you can see that we are detecting all   the license plates in this video and we're also  reading the text from these license plates we're   using 100% python we're going to use an object  detector based on yolo V8 we are going to do   object tracking and we are going to read the text    from the license plates using easyocr so this will be an  amazing tutorial my name is Felipe welcome to my  channel and now let's get started so let's get   started with this tutorial today we are going to  work with automatic number plate recognition and   let me show you a few resources a few repositories  which are going to be super super useful for   today's tutorial the first one is Yolo V8 because  we are going to be detecting license plates and   then we're going to be reading the text from  the license plates right and in order to detect   our license plates we are going to use an object  detector which is based on yolo V8, so yolo V8   is going to be super super important in today's  tutorial and I'm going to show you more details   in a few minutes but for now let me show you the  other repository which we are also going to use   in this tutorial and it's going to be super super  important and it's sort it's an object tracking   algorithm which is called sort because today we're  going to do object detection and we're also going   to do object tracking this is going to be an  amazing tutorial and in order to do object tracking we are   going to use sort and then once we have detected  the license plates once we have implemented all   the object tracking once we have done everything  we need to do we are going to read the   content of the license plate using easyocr so this  is a python Library which is going to be super   super super important in this tutorial and now let  me show you the data we are going to use in this   tutorial let me show you the video we are going to  use in order to test the automatic license plate   recognition software we are going to use in this  tutorial you can see that this is a video of a   highway and we have many many cars which are going  through this highway and the important thing about   this video is that all the cars... we have like a  very very frontal view of absolutely all the cars   and most importantly we have a very frontal view  of all the license plates right you can see that   for absolutely every license plate we detect in  this video we have a very very very frontal view   and this is an ideal point of view to build a  project like this so this is exactly the video we   are going to use in this project and now let me  show you something else if I go to Google and I   search for license plate and I go to images let me  show you something you can see that we have a lot   of diversity when it comes to license plates right  we have many different types of license plates we   have some license plates which are comprised only  with numbers like this one then we have other   license plates which are only letters like these  two and we have many many different examples we   have many different types many different formats  I would say that absolutely every single country,   absolutely every single state, absolutely every  single time in history have its own a license   plate format right its own license plate style  its own license plate system right there are many   many different type of license plates there's a  lot of diversity when it comes to license plates   and obviously that it it's very very challenging  to build an automatic license plate recognition   software to deal with absolutely every single type  of license plate right, it's... I'm not going to say   it's impossible it's not impossible but it's a  very very challenging task so in order to make   it more simple in order to simplify our problem we  are going to focus only on one very specific type   of license plate which is this one we are going  to be working with the United Kingdom license   plate system, with the United Kingdom license plate  format, which is comprised of seven characters the   first two characters are letters then we have two  numbers and then we have three more letters right   so we have two letters two numbers and three  letters and this is the exact structure of the   license plate type we are going to be working  today in this tutorial right, this is the exact   same type we are going to be detecting with the  software we are going to build in this tutorial   but today I'm going to show you a very generic  process and a very generic pipeline so by making   some adjustments into the code we are going to be  making today you will be able to apply the same   process to other types of license plates right we  are going to work with this type in this project   but you will be able to make some adjustments in  everything we're going to be doing today so you   will be able to apply the same process to other  types of license plates right so that's something   I'm going to show you better in a few minutes  but for now let's continue now let me show you   something else, when we were starting this tutorial  I showed you that we were going to use an object   detector based on yolo V8 to detect license plates  now let me show you the data I used in order to   train this license plate detector right this is  exactly the data set I used in order to train this   detector, and I'm going to give you a link to this  dataset in the description of this video, and if   you want to know exactly how I trained this object  detector I invite you to take a look at one of my   previous videos where I show you how I train an  object detector using yolo V8, in that video is   the step-by-step guide of how to train an object  detector using yolo V8 and that's exactly the   same process I followed when I was creating this  license plate detector so this is the data I used   and if you want to know exactly how I trained that  object detector then just take a look at the video   I'm going to be posting over there right so now let's  continue I already showed you all the resources   we were going to use in this tutorial I already  showed you the type of license plate we are going   to be detecting today and now it's time to go to  pycharm so we can start implementing all the code   of today's tutorial, and now let's go to pycharm  let's go to this pycharm project and let me show   you some files I have over here, you can see I have  many many different files and for now let's just   focus on these two: main.py and util.py. main.py  is the file in which we are going to be coding   the entire pipeline of this tutorial right you  can see that this is a sequence of steps which   we are going to follow in order to build this  automatic license plate recognition software   you can see that the first step is loading  the models then loading the video then we're   going to read frames and so on this is the entire  pipeline the entire process we are going to be   building today and then we have this other file  which is util.py, in this utils file we have   five functions let me show you these are the  functions we have defined over here and from   all of these functions we are going to focus  on these two which are read license plate and   get car, these functions... if I open these functions  you can see that they are completely empty right   we need to implement these functions in this  video and then the other three functions they   are already implemented right everything is ready  and we're just going to use them and the idea is   to focus on these two functions over here because  these two functions are way more important from a   computer vision point of view right so these are  the functions we are going to focus the most and   this is the util.py file now if I go back to main.py  now it's time we start with this process now it's   time we start with this Pipeline and in order to  do so we are going to start importing YOLO so I'm   going to say from ultralytics import YOLO and then  we are going to load the models that's the first   step in this process and the interesting part is  that we are going to have two models because we   are going to be detecting license plates but we  are also going to be detecting cars that's going   to be a very important part in this process so  I'm going to be loading two models I'm going to   call the first one of these two models coco model  because this is a model which was trained on the   coco dataset and this is going to be YOLO and  we're only going to use a pre-trained   model from YOLO V8 which is Yolo V8 nano.pt right  we are just going to call this pre-trained model   and this is the model we're going to use in order to detect  cars it's very important we detect cars I know we   are going to detect the license plates and we are  going to read license plates but detecting cars   is going to be super super super important and  you're going to see exactly why in a few minutes   then we're also going to load the license plate  detector and we're going to call it license plate   detector and this is going to be YOLO  and we need to input the path to this   license plate detector and the license plate  detector is located in a directory which is   called models and is called license plate  detector.pt so I'm just going to... models... okay now it's time to load the video we are  going to use today and in order to do so I'm   going to import CV2 and I'm going to call  CV2 video capture and I'm going to input   the video location which is something like the  current directory and it's called sample.mp4 okay and this is going to be cap okay now  we are going to read frames from the video   so I'm going to define a variable which is  ret I'm going to initialize it as true and   then while ret I'm going to read frames from the  video like this ret frame equal to cap dot read   if ret then I am going to continue okay and this is  going to be pretty much all for now so we are   reading frames from the video and now it's time to  continue detecting all the vehicles right we are   going to be detecting all the cars and therefore  we are going to be detecting the vehicles and in   order to do so this is where we are going to use  the first model which is the model trained on the   coco dataset so we are going to do something like  this I'm going to call coco model and I'm going to   input the frame and this is going to be results  right I'm going to call   this object 'detections' and in order to move one  step at the time... I need to access the first element...   in order to move one step at the time I'm going to  print detections and I'm only going to execute   the first 10 frames otherwise it's going to be  very... this is going to take a lot of time so   and frame number lesser than 10 and obviously I  need to Define a variable which is frame number   I'm going to initialize it in -1 and  then I'm just going to increment it here   okay and I don't really need the pass anymore  and let's see what happens if I print detections   okay so everything seems to be working just fine  this is all we got and you can see that this is a   lot of information these are all of our detections  so everything seems to be working just fine   so what I'm going to do now is we are going  to iterate for detection in detections   and this is going to be for detections.boxes  dot data dot to list and let's print detection   again so we know exactly how this looks like  and we know how to access all the information   okay so this is how each one of our detections  looks like right you can see that we have one   two three four five six numbers and the  way this works this is going to be something   like X1 Y1 X2 Y2 then we will have the score  and then we will have the class ID right this   is detection so remember we are using a  model which was trained on the coco dataset   so we are detecting many many different  objects right this is the class ID this is   exactly the type of object we are detecting at  every single time at every single one of these   detections so this is very important and then  we have the confidence value right this is how   confident our object detector is of this specific  detection and then this is the bounding box right   so we have X1 Y1 X2 Y2 the bounding box then  the confidence score and then the class ID   and something that's very very important we are  doing all of this in order to detect Vehicles so   as the coco dataset... as this model which was  trained on the coco dataset is detecting   many many different objects we are going to say  something like this if int class ID in vehicles then we are going to continue and vehicles is a  variable which we haven't defined and we are going   to Define it with the indexes with the class IDs  of all the vehicles in the coco dataset this is   a list of all the objects which we can detect  using this model right you can see that these   are a lot of objects and some of these objects  are related to vehicles and some other objects   are not for example you can see we have person  bicycle car motorbike airplane bus train   truck and so on right so from all this very very  long and very comprehensive list we are going to   make sure we are detecting a vehicle so we are  going to say if the class ID we are detecting is   either a car or a motorbike or a bus or a truck  then we are going to continue and if not we are   going to neglect the bounding box, the detection  we just got, and the indexes we are interested   in are 0, 1, 2 for car so we are just going to put  two then three for motorbike four five for bus   and then six seven for truck right we don't  really have any motorbike in this video I know   for sure because I already watched the video but  nevertheless in order to make this more generic   I'm just going to add a motorbike as well so  if our class ID is within our vehicles then   we are going to continue and I'm going to  create another variable which is detections_   and this is where I'm going to save  all the bonding boxes of all the vehicles we   are going to detect in this video so I'm going  to do something like this if we have detected   a vehicle then I'm going to append the bounding  box and the confidence score to this new variable   and please mind that I'm not saving the class ID  from now on it's not really that important, we are   not really going to care about the specific class  ID we have detected from now on the only thing   we care about about our detections is that they are  Vehicles right and we don't really care to know   exactly what type of vehicles so this is the new  variable in which I'm going to be working from now   on in this tutorial in this process and now let's  continue and now it's the time in which we are   going to implement the object tracking remember  we were going to work with object tracking in   this tutorial and now it's the time where we are  going to implement this tracking functionality   into this project and before we do so let me give  you a very very quick explanation Regarding why   exactly we are using this tracking why exactly  we are going to implement this object tracking   and basically every time we solve a problem every  time we solve not only a computer vision problem   but any type of problem you need to use absolutely  all the information you have available regarding   that problem and in this case we are going to be  tracking license plates which are moving through a   video right we are going to be detecting license  plates on individual frames and these license   plates are objects which are moving through a  video so if we are able to track this license   plate through all this video we will have more  information and this additional information is   going to be super valuable in order to build a  more robust solution so that's pretty much the   reason why we are going to implement this object  tracking and we are going to be tracking... we're   not going to be tracking the license plates  themselves but we are going to be tracking the cars,   the vehicles, and I'm going to show you exactly  why later on so this is what we are going to do   we are going to work with this repository remember  I showed you this repository when we were starting   with this tutorial and the first thing you should  do is cloning this repository into your local   drive into your local directory you need to clone  this repository into the directory into the root   directory of your pycharm project so in my case  this is the root directory of my pycharm project   this is where I have all my Python scripts and  this is where I have all my files related to this   project and you can clone this repository in one  of these two ways let me show you one of the ways   is opening a terminal and typing something like  git clone and the repository URL so I'm going to   click here I'm going to copy the repository URL  and then I'm going to paste the repository URL   here and then the only thing you will need to do  is to press enter right and that's exactly how you   can clone this repository into your local computer  but there is another way in which you can do it   and actually this is a much more simple way and  maybe you prefer to do it like this which is just   downloading the entire repository as a zip file  and once you have downloaded this file this ZIP   file the only thing you need to do is to copy and  paste is to take this directory this sort Master   directory into your local directory right that's  the only thing you need to do is to drag and drop   this directory into your local computer and that's  it and please mind that this directory is called   sort-master but you will need to edit the name  you will need to rename this directory into sort   right you can see here in my computer  this is my directory this is called sort if   I open this directory you can see these are all  the files which are in this repository so basically   remember to rename this directory into sort it's  going to be called sort-master but you need to   rename this directory into sort that's very very  very important otherwise you will have some issues   possibly you will have some issues with the next  steps in this tutorial so let's go back to pycharm   this is the repository you need to clone  into your local directory and remember to call   the directory containing this repository remember  to call this directory sort now let's take it back   to pycharm and what I'm going to do now is just  importing sort... let's call from sort dot sort   I'm going to import everything we are going  to import absolutely everything from this   library and then I'm going to call an object I'm  going to create a new object which is called   mot_tracker and this is going to be equal to sort  right this is the object tracker we are going   to use in order to track all the vehicles  in our video and now let's get back here   and what I'm going to do now is just calling   mot_tracker.update and I'm going to input a numpy array... of this list we have created containing all the  vehicles in our video right and this is going   to be something like track IDs right so track IDs  is going to contain all the bounding boxes of all   the vehicles we have detected in this Frame but  with the tracking information right it's going   to add an additional column an additional field  which is going to be the car ID the vehicle ID   for each one of the cars we are going to detect  and this vehicle ID or this car ID is going to   represent that specific car through all the  video right so let's continue so now we are   tracking all of our objects all of our cars and  now it's the time to detect the license plates   right so far the only thing we have detected is  the cars in the video but now it's the time to   detect the license plates in order to do so we are  going to use this detector over here which is   license plate detector and we're going to do it  exactly the same way as we have detected the   cars right I'm just going to copy and paste  this sentence and I'm going to replace coco_model   by license plate detector right and this  way we are going to be detecting all the license   plates I'm going to call this object license  plates and then I'm going to iterate in all the   license plates we detected within this Frame and  in order to do so I'm going to call for license   plate in license plates dot boxes dot data dot  to list and that's pretty much all and then let's   unwrap all the information we got from this  license plate exactly as we did before so this   is going to be something like X1 Y1 X2 Y2 score  and class ID this is going to be license plate okay then we will need to assign each license  plate to a given car right because we have   detected all the cars in every frame and all  the license plates in every frame but so far   we have cars and we have license plates and we  don't really know which license plates belong to   which car right and we know for sure that every  single license plate will be on one of our cars   but we don't really know which one goes with  which one right so now in this step is where we   are going to assign a car to absolutely every  single one of our license plates right and in   order to do so we are going to use one of the  functions in our util.py file we are going to   use this function which is get car this function  receives a license plate and receives this object   we have over here receives this object  with all the tracking information for all the   cars in that specific frame and it returns a  Tuple containing the vehicle coordinates and   its ID right so we are going to call this function  get car and this function is going to return the   car this license plate belongs to right this  is what we're going to do I'm going to import   from util import get_car and now I'm going to call get_car   I'm going to input the license plate and  I'm going to input this object which is   track IDs remember this object contains all  the bounding boxes and also all the tracking   related information right that's very important  and the return will be the coordinates of the   car this license plate belongs to so it's  going to be something like X car 1 Y car 1 X Car 2 Y Car 2 and then the car ID  for this car right remember every   single car in our video will have an ID  it will have a very unique ID which is   going to identify the car through all the  frames in the video that's very important   and also please mind that this function is  completely empty for now right this function   is only returning some very dummy values and  this function is completely and 100% empty and   this is exactly what we will need to implement  in the next step in this project right once we   are completely ready once we have completed this  pipeline then at the end of this pipeline at the   end of this process then we are going back here  to util.py, to this file to the util.py file, and   we're going to implement this function right so  now we have assigned the license plate to a very   specific car now we know what's the car this license  plate belongs to and now we can continue with the   next step which is cropping the license plate  and this is how we're going to do we are going   to call frame and then we're going to input  the license plate coordinates which is int Y1 int Y2 and then int X1 and int X2  right so this is the license plate crop   and that's pretty much all we need to do in this  step of this process and now let's continue to   the next step which is processing this license  plate right now we are going to apply some image   processing filters to this crop we have over  here in order to further process this image   so we improve this image so it's much simpler  for the OCR technology for easyocr to read the   content from the license plate now it's time to  apply some image processing filters to this crop   and specifically the filters we are going  to apply are a grayscale conversion and then   we are going to apply a threshold so let's see  how we can do that I'm going to call CV2 dot cvt   color I'm going to input the license plate  crop and then I'm going to call CV2 color   bgr 2 gray and this is going to be license plate  Gray license plate crop Gray right now we have   converted the license plate crop into a grayscale  image and now the only thing we need to do is to   call CV2 threshold we are going to input this  grayscale image then is the threshold which   I'm going to set in 64 and then it's the value  at which we are going to take all the pixels   which are lower than the given threshold right  which is 255 and then I say the value at which   we are going to take all the pixels which are  lowered than the threshold because we are going   to use the inverse threshold we are going  to use the thresh binary... thresh binary inverse type of threshold and this type of threshold is  going to take all the pixels which are lower than   64 and is going to take them to 255 and all the pixels  which are higher than 64 is going to take them to   zero right that's exactly how this threshold works  and if you want more details on how this function   works I invite you take a look at one of my  previous videos where I show you an entire course   of opencv with python and one of the lessons in  this course is exactly about thresholding right   it's exactly about this function so I'm going  to be posting a link to this course somewhere   in this video so you are welcome to take a look  at this course and this lesson particularly to   get more details on how thresholding works now  let's continue this is going to be equal to a   variable which we are not going to use in the  tutorial so it doesn't really matter and then   I'm going to call the output license plate crop  threshold right so this is going to be the   thresholded image and its exactly the image we are  going to input into our OCR technology into   our easyocr algorithm, in order to be more more  clear about the difference between these two   images I am going to visualize these images super  super quickly so you see exactly how they look   like I'm going to call imshow and I'm going  to input this image which is license plate crop   I'm going to call this window crop I'm  going to call it original Crop so it's   more clear this is the image we are cropping  from the frame and then I'm going to call   cv2 imshow again and in this case I'm  going to be plotting the threshold and I'm going   to input this other variable and then the only  thing I'm going to do is to call CV2 wait key   and let's take a look at these two images super  super quickly so you see exactly how they look   like and this is what we got and you can see  that this is the frame this is the crop we are   making from the frame so this is the license  plate and this is exactly how we are cropping   this license plate from the frame and this is  the thresholded image right you can see that   in this image absolutely every single Pixel is  either white or black and this type of image   this thresholded image will make it much much  simpler to easyoce to our OCR technology to read   the content from this image right this is the  image we are going to use in order to read the   license plate number because this is going to  make it much much simpler to easyocr so it's   going to be much simpler to our OCR to read the  license plate so that was like a very very quick   way to show you how these two images look like  and now let's continue now it's the time to read   the license plate number we are almost there we  have almost completed the this process and this   is how we're going to do now we're going to call  another function which is defined in util.py and   this function is read license plate and you  can see that this function is not implemented   either this function is completely empty we are  returning some dummy values and this is another   function which we are going to implement later  on we are going to implement after we are happy   with this process once we are completely and  absolutely happy with this pipeline then we   are going to move to util.py and we are going  to implement this function as well. But for   now we are just going to... we're just going to use  this function so I'm going to import it as well   uh no this is not the function name... read license  plate... something like this and now let's see   how we can use this function I'm going to call  util Dot read license plate and this is going   to return two values let's look at the function  documentation to see exactly what are the values   which are going to be returned here... we are going  to... it is going to return a tuple containing the   formatted license plate text and its confidence  score so this is going to be something like   license plate text and then license plate text  confidence score right these are the two values   we are going to be getting from here and the  input should be the license plate crop in our   case we are going to input the thresholded crop  right this thresholded version of our crop and   that's pretty much all right remember we are just  completing the pipeline the most generic process   then we are going to get back here in order to  implement this function and this other function   right and now let's continue now the only thing we  need to do is to write the results we are almost   there we have almost completed this process and  now obviously if we want to take these results and   we want to visualize these results or if we want  to analyze these results whatever thing we want to   do with these results we obviously need to write  these results to our local computer so this is how   we are going to do in order to write these results  we are going to use another function which is also   defined in this util.py file and it's called write csv and this function is implemented this function   is 100% and fully implemented you can see that  this is all the code we have for this function   and everything is just ready and we can just use  this function as it is remember in this tutorial   and in basically all my tutorials we always focus  on the computer vision part of the problems so   writing this csv file is not really that important  from a computer vision point of view so that's why   we are not really going to implement this function  live in this video but this is already implemented   and we're just going to use it so let's see what  this function does and it says write the results   to a CSV file and it receives two arguments which  are the results which is a dictionary containing   the results and then it also receives a path to  the CSV file we are going to produce and this   is going to be the path in which we are going to  write this CSV file right it's the path in which   we are going to save the CSV file we are going to  produce so if we are going to input a dictionary   then we need to produce a dictionary in order to  input into this function right we need to take all   all of our information and we need to put all of  this information into a dictionary right that's   very very important so that's what we are going  to do now because for now the only thing we have   done is just Computing all the information but  we have not saved this information into any type   of dictionary or anything like that so I'm going  to create a new variable which is called results on results is going to be a dictionary and  then this is where I'm going to save all   the information and this is how we are going to  do the first key in this dictionary will be the   frame number right we are going to save all the  information and we are going to start with the   frame number we are going to have a different  key for absolutely every single frame in our   video and then for absolutely every single frame  we are going to save all the information which is   related to all the cars we are detecting  and most importantly to all the license plates   right so then I'm going back to the end of this  pipeline here and I'm going to say something like...   I'm going to make a very quick edit first which  is going back to this function and instead of   returning two None I'm going to be returning two  zeros right because we are going to reserve this   other output we are going to reserve the None, None  output for those times in which we are going   to find an error or we are going to have any type  of issues reading the license plate and this is   going to be much more clear later on once we are  implementing this function but for now just bear   with me that it's much more convenient to return  some dummy values which are different than None   so let's get back here and this is where we're  going to say if license plate text is not None   we are going to save all the information about  this license plate in this dictionary we have just   created so we are going to take this variable  over here which is results for that specific frame   number and we're going to create a new entry with  all the information for the license plate we have detected right and this is how we're  going to do I'm just going to write it first   and I'm going to explain it once it's done once  I'm completed and this is what I'm going to do   I'm going to say the next key is the car ID   right this is going to be results frame number car  ID and then for this car I'm going to create a new   dictionary which is going to have two keys one  of them is car and the other one is license plate for car we are going to have another  dictionary which is the bounding box   and that's it right and for the license plate  we are going to have another dictionary which   is something like bbox... the bounding box  then also the text we have detected then   the confidence value for the bounding box and  then the confidence value for the text right okay and that's pretty much all so I'm just  going to format this a little nicer   and that's pretty much all now let's see what  exactly we need to input in each one of these   fields okay so basically for the car bounding  box we are going to input these values over here   which are the car bounding box right   these are the coordinates of the bounding box   of this specific car and then for the license  plate bounding box we are going to input these   values which are the coordinates for the bounding  box of this license plate and then for the text   we are going to input this value which is license  plate text for bounding box score we are going to   input this value which is the score in for  in which we have detected this license plate then   for text score we are going to input this variable  which is license plate text score and by doing   so we don't have any errors and everything is  okay so for every single frame for every single   frame number we are going to be saving all the  information which is related to each one of our   cars and all the information for each car will  be the information of that specific car where   the car is located and then all the information  about the license plate which we have detected in   that specific car right and for the license plate  we are going to save all the information we have   right and we're going to save all this information  only in those cases in which we have detected the   license plate and every time we have successfully  read the license plate number from this license   plate so this object is not None we are going  to be saving all these information into this   dictionary only in that case only when we have  detected the license plate and when we have read its   license plate number right and please notice the  structure I have built for this information for   this dictionary because remember every time we  detect a license plate it will not be floating   around in space completely isolated no that will  never happen every time we detect a license   plate it will be on a given car and this car will  be on a given frame right so this is exactly why   this structure I have decided for this dictionary  and once we have created all this information the   only thing we need to do is to call... I'm going to  import this function as well, I am going to input   the name was something like write csv so let's  import write csv as well and something is going   on because we are not really using this import  we have over here so if I scroll down I see I'm   not really importing the function itself I think  there we should be okay okay so now let's go back   here and I'm going to call this function which  is write csv and I need to input the dictionary   so I'm going to input results and I'm also going  to input where I want this CSV file to be saved   and I'm going to save all this information into  a CSV file called test.csv so what I'm going to   do now is I'm going to execute this pipeline I'm  going to execute this process as it is and then we   are going to take a look at this file and then we  are going to continue right then we are going to   see if the file we are going to create it  makes sense right so I'm just going to press play   okay the execution is now completed and now if I  go to my local directory to the directory of this   pycharm project this is test csv so this is the  file we have just created and if I open this file   you can see that this is all the information we  have saved and we have extracted from this video   right remember we are processing only the first  10 frames we are still processing only the first   10 frames so this is the all the information we  have extracted so far and please remember we are   just Computing some dummy values from some of...  from some of our functions so this is this   is not really all the information this is all the  information we have compute so far but other than   all of these zeros over here and these zeros over  here you can see everything looks pretty pretty   well right, we are just producing an entire  CSV file with all the information we have computed   from this video we are almost there and actually  we are there we are ready we have completed this   pipeline we have completed this process we are  almost almost there the only thing we need to do   now is going back to ulil.py because we need  to implement these two functions get car and   read license plate and once these functions are  implemented then we are going to be producing   a real file right we are going to be using a  file with the entire information here and   here right we are going to be producing the real  license plate number and the real license plate   score and also the car bounding box and the car  ID for absolutely every single license plate in   absolutely every single frame in which we have a  detection right so we are almost there I am super   excited and now let's continue to the util.py  file so we can Implement these functions and let's   start with get car remember from the main.py  pipeline we were using this function which is   get_car in order to assign which car each license  plate belongs to right we have many many cars and   many many license plates and for each one of these  license plates we want to know what's the car this   license plate belongs to so this is exactly where  we were using this function get car and now let's   see exactly how we are going to implement the  function and in order to do so I'm going to show   you a few pictures this is a random frame from our  video right you can see that this is a frame   we have many many cars and this is only a frame  from the video once we have detected all the cars   we are going to have a situation like this we are  going to have many many many detections because   at every single frame we are going to have many  many many many cars I don't know how many cars   we have in this picture but they are many they are  something like I don't know 20 30 50 maybe 60 cars   they are many many cars so for every single frame  we are going to have many many detections which   are going to be our cars, we are going to have  many bounding boxes for all of our cars and also   at every single frame we are going to have all  of our license plates but please focus please   mind that we are only going to have maybe one  or two or three license plates for every single   frame right so we are going to have many cars but  only a few license plates and the idea is to know   which car this license plate belongs to and the  way we are going to know that is by looking at   all of these bounding Boxes by looking at all of  these cars and by finding the car which contains   the license plate right by finding the bounding  box of the car which contains the bounding box   of this license plate right that's the way we  are going to find what's the car which belongs   to this license plate so that's exactly the idea  of what we are going to be implementing in this   function now let's see exactly how we can do that  the first thing I'm going to do is unwrap all the   information in license plate so in order to do  so I'm going to do something like this because   this is exactly the same object license plate  so I'm just going to do this okay then I'm going   to iterate in all the cars we have over here I'm  going to say for... let's say for j in a len vehicle   track IDs we are going to be iterating in all the  cars we have detected and remember this is the   entire information this is the bounding box and  this is also the car ID remember so now we are   going to unwrap all the information for each one  of these cars and this is going to be something   like x car 1 y car 1 x car 2 y car 2 and car  ID this is exactly the information which is in   each one of the elements of this object vehicle  truak Ids and this is vehicle track ID j okay   so that's pretty much all we are iterating in  absolutely all the bounding boxes of all the   cars we found in this Frame we are iterating  in all these bounding boxes for each one of   these bounding boxes we are going to verify  if it contains the license plate right that's   exactly what we are going to verify and this is  how we're going to do it we are going to see if   X1 is greater... remember X1 is the upper  left coordinate of the license plate if X1   is greater than x car 1 and Y1 is greater than  y car 1 right we are verifying that this   coordinate over here it's greater than this  other coordinate over here we are trying to verify   if we meet this condition right and then the  other condition we need to meet is if this   point we have over here these coordinates  we have over here they are lesser than this   other point we have over here right we need to  meet these two conditions and this is exactly   how we're going to do it if X1 greater than x  car 1 and Y1 greater than y car 1 and X2 lesser than x car 2 and Y2 lesser than y car 2 then we are we are going to... we  have found the bounding box this license   plate belongs to we have found the car on which  this license plate is located right that's   what it means if we have met all of these  conditions that's what it means so in this   situation we are going to... I'm going to  define a new variable which is foundIt and   foundIt is going to be false at the beginning  and then it's going to be true in this case and in this case we're also  going to break the loop right   and then I'm also going to Define  another variable which is going to be   car_index and car index will be j  okay now if foundIt then return this value which is going to be... okay so if we have found the car which contains  this license plate then we are going to return   these values which are the bounding box of the  car and also the car ID and in any other case we   are just going to return this output in order to  make it more clear that we have not found the   car we are going to return something like this so  it's going to be much more clear so that's pretty   much all... that's it, we have implemented this  function which is get car and now let's continue   so now let's let's see if everything works well  now we should have the uh the right values for all   the cars we are detecting and the only thing I'm  going to do is I'm going to execute this script   again and let's see what happens okay I got an  error and I think I know what's the problem I think   we need to iterate in range len vehicle track IDs  and now everything should be okay let's try again   okay now it's completed and now let's see the new  file we have created the new test.csv file and now   you can see that we have some values for car ID  and we also have some values for the car   bounding box so we are moving one step at the time but we  are making progress right so now let's continue   with the util.py file and now let's move to the  next function which is read license plate now   it's time to implement this function over here and  something I'm going to do first is I'm going to   do an if over here and I'm going to continue with  this pipeline only if car ID is different than   -1 right and now let's continue and let's see  how we can implement this function which is read   license plate and the only thing we need to do is  to call easyocr and let's see how we can read the   license plate and let me show you some variables  I have defined over here these variables are going   to be super super important now this variable are  going to be super amazingly important you're going   to see exactly why and then also let me show you  this reader we have here I have already defined I   have already initialized this OCR reader and  you can see that I'm calling easyocr and then   I'm calling this method which is reader so the  only thing we need to do now is calling reader dot read text and I'm going to input the license  plate crop and this is going to be detections   then I'm going to iterate for detection  in detections because remember we could be   detecting many many many many different objects  many different text objects in this image so   for each one of these objects we are going to  unwrap these objects first and this is going   to be something like bounding box text and score  this is going to be the detection right each one   of these detections is going to be something  like the bounding box of the text we have   detected then the text we have detected and then  the confidence value for which we have detected this   text and then we are going to convert this text to  uppercase and we are going to remove all the white   spaces right this is exactly how we are going to  do and this will be equal to text okay and now   it's the time in which we are going to use this  format right remember when we were starting this   tutorial I told you we were going to focus on  this very specific type of license plate right   we are going to work with this type of license  plates each license plate is going to have seven   characters the first two characters are going to  be letters then two numbers and then three letters   this is the format of absolutely every single  license plate we are going to be working with in   this tutorial so we are going to make sure every  single text we detect complies with this format   and in order to do so I have already created a  function which is license complies format this   function returns a Boolean value which is pretty  much the verification of if this license plate   complies with the format or not we are going  to be verifying if we have seven characters   and we're also going to be verifying the first two  characters are letters and then the second... the   third and the fourth characters are numbers and  then the last three characters are letters again   right this is exactly what we are doing with this  function and this is a very important function   we are going to use now so let me show you  exactly how we are going to use this function   if license complies format text then and  only then we are going to return the text and the   confidence score we are going to return these two  values, these two variables, which are text and   score right only if the text complies with the  format we are asking absolutely all the license   plates right only in this case we are going to  be returning these values and in any other case   we are going to return None right this is very  very very important and this is going to make   our solution way more robust and way way better  and something that makes the solution even better   is that we are not going to return the text on  itself we are going to call another function which   is format license and let me show you exactly  what we are going to be doing with this function   I'm going to call format license text and let me  show you the... let me give you the idea, the   high level idea behind this function sometimes  when we are using an OCR technology when we are   using a library like easyocr sometimes it's very  challenging to tell some characters apart for   example it's very challenging to tell a five apart  from an S right so you can see that the letter   S and the number five are very similar and it's  very very very challenging for an OCR to tell   the difference between these two characters and  we are going to have exactly the same situation   for the letter I and the number 1 or for the  letter O and the number 0 for example right   those are characters which are very very hard  to differentiate, they are very hard   to tell apart so this function I have over here  format license the only thing it does is going   through all the characters in the license plate  in the text and for each one of these characters   it fixes whatever issue we may have with  this type of confusion right if for example we are   reading this character over here and easyocr,  the OCR technology we are using, it says is the   letter S we know for sure it's not the letter  S because we are expecting a number here so if   we have detected the letter S then we convert this  value to the number 5 and the same happens here   if we are reading this value this character and  we are getting the number 5 we know for sure   for a fact that that's not the number 5 because  we are expecting a letter here so we are going to   convert the number 5 into the letter S that's  exactly the idea the high level idea of   what we are going to be doing with this function  we are going to be going through absolutely all   the characters in the license plate and for each  one of these characters we are going to be fixing   these type of issues in case we find any type of  issues like this and that's pretty much all and I   invite you to take a look at these two functions  to format license and to license complex format   and to take a much closer look and to properly  understand exactly how they work right that's   your homework that's your homework from this  video so you properly understand how they work   so now let's continue and now we are returning  format license text and score if our license   complies with our format and we are returning  none in any other case and we are done we are   completed now we have completed our process now  let's see what happens now I'm going to execute   this file again and let's see what happens I'm  going to make a very very small change I'm only   going to execute it for 10 frames but I'm going  to do it like this if ret then if frame number   um greater than 10 then I'm going to break the  loop this is going to be much better and now let's   see what happens I'm going to execute main again  okay it seems I have a typo over here this is   obviously not remove but this is replace I got  confused because I was removing the white spaces   but this is obviously not the name of the function  we want to use here so now let's see what happens   okay now the execution has been completed and  now we have produced a new test.csv file and   if I open this file you can see that we still  have all the information related to the car ID   and the car bounding box and now we have all the  license plate numbers we have read from the frames   from the license plates and also the confidence  score for each one of these license plates so we   made it we have completed this process now  we are completed we are done so everything   is ready the only thing I'm going to do now  is to execute this script execute this main   pipeline for the entire video so I'm just going  to remove this break over here and that's pretty   much all and now I'm going to press play again  and then I'm going to show you how to visualize   this data so everything looks like the video I  showed you in the intro so let's see what happens and now let's go back to pycharm so I can show  you exactly how you can create a visualization   as the one I showed you when we were starting  this video in order to do so this is where we   are going to use these two files visualize.py  and add missing data.py and you're going to   find these two files in the GitHub repository  of today's tutorial so you can just go ahead and   use them in your project and before using these  two files let me show you something first if I   go back here to the test.csv file we have created  let me do something I'm going to filter by car ID   I'm going to show you all the data all the  information we have extracted for only one   of our cars I'm going to select only the car ID  number three right this is only a random car ID in   our data you can see that all the frame numbers we  have detected for this car ID are not consecutive   so this means that we have detected the number  zero... the frame number zero then the number one   then it jumps to the number four then it jumps to  the number nine then 12 13 14 15 16 17 then 27 so   we have many many missing frames right for some  reason we don't have the information for this car   ID for many frames which are in between these... these  two for example right we don't have the information   for the frame number two the frame number three  or the frame number five six seven eight uh 10 11   right there are many many missing  frames for this car ID so that's something that's   going on and remember that we are not saving all  the information because we are only saving the   information for those license plates for which  we have detected the car the license plate   it is on right? the license plate... the car  where the license plate is located and also we're   only saving the information the license plates  for which we have read a license plate... a license plate   number which complies with our format right  so we are not saving all the information,   there's a lot of information which we are not  saving into this CSV file remember how the OCR   Technologies usually work I mean they are very  very good they perform very good but in some   cases they have errors they have mistakes so if  in some cases they are not reading a number which   complies with this format then we are not going  to be saving the information for those frames   so that's the reason why we have some missing  frames over here that's the first thing I want   you to notice then another thing which is going to  be much more important is take a look what happens   with the license plate numbers now we have read  the license plate numbers in all of these frames   and we have read a number which complies with  our format so everything it's okay but you can   see that we have many numbers right for example  we have many many different values many different   numbers if I show you the number we have detected  in the first frame it's different than the one we   have detected here in the frame number four right  and then if I continue scrolling down you can   see that we have also detected other values for  example here this is different and if I continue   scrolling down this is also different here we have  an N we have a P so for every single car ID we   are going to have many many different values for  the license plate and this is a huge issue this   is this is a very very important thing we need to  solve because obviously every single car has only   one valid value for its license plate  so if we have so many values if now we have   so many values for the license plate how do we  make a decision how do we know what's the   the real one right what's the real value the  most accurate value for the license plate how do   we make a decision what's our criteria that's a  huge problem and this is exactly where the object   tracking is involved because for every single car  in the video... because we are going to be tracking   the car through all the different frames in the  video, for every single car we are going to have   the value for the license plate we have detected  in that given frame for that car so if we want to   know what's the value for the license plate of a  given car through all the frames in the video the   only thing we need to do is to select the license  plate we have read we have detected with the   highest confidence score right you can see this  column is the confidence score in which we have   detected every single one of these license plates  so the only thing we need to do is to take a look   what's the license plate we have detected with  the highest confidence and that's it,    that's going to be your criteria to know what's  the license plate number of this car and that's it   that's the way we are going to solve our problem  and that's exactly where the object tracking is   involved and that's exactly why it's so important  to track... to apply to implement an object   tracking algorithm into this problem because this  is how we are going to solve this problem this is   going to be our criteria to select the license  plate number for every single car in this video   so remember we have these two problems this  is how we are going to solve   this problem and then we have we still have this  other problem which is that we have some missing   frames for every single car right this  problem actually is not... it's not really a big   problem and the only thing is going to affect is  the visualization right because now we are going   to take all this information and we are going to  visualize this information so the only thing is   going to happen with all these missing frames is  that we are just not going   to visualize the license plate and we are not  going to visualize the license plate value for   that given frame so let me show you what happens  if we visualize if we create a video from the   text file... the CSV file I just showed you  we will have a visualization which looks like   this which will be okay I guess but it's like  um but... it's not an ideal visualization right   it's like uh it's it's not really pretty it's not  really good looking this doesn't really look good   ideally we would like to have a visualization  which is more stable for every single license   plate we would like to see the license plate on  a fixed position through all the different frames   in which we are detecting the license plate for  that car right that's exactly what we eould expect   and this is not really good looking this doesn't  really look good right so in order to fix this   problem which again is not a huge problem  and the only thing it does is to affect the   visualization we are going to use one of these  two scripts which is called add missing data   and the only thing this script does is interpolate  all of those frames in which we have not detected   a license plate or in which we are not extracting  the information for the license plate so the only   thing we're going to do is interpolate the  values for the bounding boxes for the car and   the license plate in all of those frames, we are  going to interpolate the values and that's it for   example in the frame number 41 you can see we have  the information for the frame number 40 and we   have the information in the frame number 42 but we  don't have the information in the frame number 41   so the only thing the add missing data.py script  does is going to consider the bounding boxes    for this Frame and the founding boxes for  this Frame and it's going to take the average   of all the different coordinates and by taking the  average it's going to compute what it's the value   of the found inbox in the missing frame right and  it's going to compute exactly the same process in   absolutely all the other missing frames so that's  the way we are going to solve this problem all   the missing frames remember this is only a problem  of visualization this is a matter of visualization is   not a huge problem and then once we have fixed  that issue then we can just create the video and   that's it so these two files I'm going to give you  these two files in the GitHub repository of this   tutorial and now let me show you how this works  so the first thing you need to do is to execute   add missing data and you need to change here the  path to the file name you are going to interpolate   right in our case its test.csv and then you need to  specify what's the file name of the CSV you are   going to create with the interpolated data let me  show you super quickly how this file looks like   I'm going to filter by car ID and I'm going to  select the number three again and you can see that   in this case we have computed absolutely every  single frame right we are starting the number zero   just as before but now we have computed absolutely  every single... the values for the bounding boxes for   absolutely every single frame until the number 65  which is the last frame in which we have detected   this car right so this exactly the data  we are creating with add missing data.py   and once we have created this data this new CSV  file then we go to visualize.py and then we input   something like test interpolated.csv and then we  specify what's the file name of the video we are   going to create in this case out dot mp4 and the  only thing we need to do is to execute this file   and then to execute this file and then after a  few minutes we are going to have a video which   looks exactly like this and this is going to be  all for today my name is Felipe I'm a computer   vision engineer and these are exactly the type  of videos and the type of tutorials I make in   this channel if you enjoyed this video remember  to click the like button and also remember to   subscribe to my channel this is going to be all  for today and see you on my next video [Music]
Info
Channel: Computer vision engineer
Views: 88,685
Rating: undefined out of 5
Keywords:
Id: fyJB1t0o0ms
Channel Id: undefined
Length: 70min 50sec (4250 seconds)
Published: Mon Jun 19 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.