Dedicated License Plate Cam project

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
I'm changing the shutter speed by logging into the camera directly using the web interface. I also have a Hikvision NVR, but the NVR does not expose all the camera functionality in its web interface so you need to log into the camera directly.

Here is what the screen looks like.
hik_shutterspeed.png
 

Parley

Known around here
Joined
Dec 19, 2015
Messages
5,642
Reaction score
16,117
Location
Cypress, California
I'm changing the shutter speed by logging into the camera directly using the web interface. I also have a Hikvision NVR, but the NVR does not expose all the camera functionality in its web interface so you need to log into the camera directly.

Here is what the screen looks like.
View attachment 8865
Thanks Steve. That is my problem, using the web interface. I am not sure exactly how to do that. I will do some research and see if I can find out.
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
just type in your cameras IP into your browser window, should get you there.. might ask you to install a plugin or something..

if you cant access your cameras IP directly because of your NVR you may have to plug your computer into the NVR LAN to make the connection..

Update: seems I am about 3 weeks til I get my LPR Cam, it should head my way in about 10 days.. here is hoping it flies through customs and makes it here quickly.
 
Last edited by a moderator:

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
Nayr, I'm looking forward to seeing your results once you get your camera.

I just completed writing a Python script that will read the JSON off of the beanstalk queue that the openalpr daemon uses. The script writes to a CSV file in the format:

Code:
uuid, datetime, plate, confidence, match_pattern

example:
mysite-cam1-DFD343SSDF, 3/8/2016 12:54:23, 1FBF234, 81.65765, True
The last column specifies whether the identified plate matches any of the patterns for California license plates. I plan on inserting this data into a SQL database at some point and the script will be easy to modify to allow that functionality. If anyone is interested in the script let me know and I can post it.
 
Last edited by a moderator:

pozzello

Known around here
Joined
Oct 7, 2015
Messages
2,270
Reaction score
1,117
i'd be interested. I'm in Cali also. :) btw, is there some way to give alpr a 'hint' that most plates will be california plates?
it sure seems to miss that state recognition quite a bit, so i figured telling it to assume cali unless there's clear evidence otherwise might help...
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
alpr has a cli trigger for pattern codes, I am not sure how to get that into alprd.. might try dropping it into the alprd.conf as like pattern = ca

-p <pattern code>, --pattern <pattern code> Attempt to match the plate number against a plate pattern (e.g., md
for Maryland, ca for California)
 

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
I haven't been able to find anyway for the alpr daemon to use a hint for a specific type of plate. When running from the command line there is a -p flag that allows you to specify a state's pattern. I believe the flag just enables a regex pattern match to be done post identification, which is basically what my script does.

- - - Updated - - -

alpr has a cli trigger for pattern codes, I am not sure how to get that into alprd.. might try dropping it into the config
Yep, I tried dropping that parameter into the config file, but it did not seem to have any impact.
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
looking at the code it might be: templatePattern = ca if it reads it at all from from the alprd.conf file.

otherwise I can show you what to change to hardcode it and rebuild.

I think adding this in src/main.cpp around line 136 would do it, pad it with an empty line above and below like:
Code:
[B]  if[/B] (templatePattern.empty() == false)
    alpr.setDefaultRegion(templatePattern);

[B]  if[/B] (templatePattern.empty() == true)
    alpr.setDefaultRegion("ca");

  [B]if[/B] (alpr.isLoaded() == false)
  {
 
Last edited by a moderator:

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
Nayr, good catch with the templatePattern parameter. I failed to examine the code myself to check that. In any case, my script already handles the regex so I will leave it as is. I've pasted it below for others to use and modify as needed.

Code:
#!/usr/bin/python
import beanstalkc
import datetime
import json
import os
import time
import csv
import re


def main():
    
    # CA license plate regex
    # Formats: #@@@###, #@#####, ###@@@, #####@#
    plate_patterns = [r'^[0-9][A-Z]{3}[0-9]{3}$',r'^[0-9][A-Z][0-9]{5}$',r'^[0-9]{3}[A-Z]{3}$',r'^[0-9]{5}[A-Z][0-9]$'] 


    csvfile_loc = '/location/to/output/myplates.csv'
    plateimage_loc = '/var/lib/openalpr/plateimages/'


    # known bad reads to be ignored; add any plates that commonly come up as incorrect via bad images
    bad_plates = ['554A1A2']


    #db = MySQLdb.connect("localhost", "root", "YOUR_MySQL_PASSWORD","alprdb")
    beanstalk = beanstalkc.Connection(host='localhost', port=11300)


    #cur = db.cursor()
    beanstalk.watch('alprd')
   
    #print beanstalk.stats_tube('alprd')
   
    job = beanstalk.reserve(timeout=0)


    while job is not None:
        #print job.body
        #print job.stats()
        json_body = json.loads(job.body)
        
        uuid = json_body['uuid']
        datetime = time.strftime('%m/%d/%Y %H:%M:%S', time.localtime(json_body['epoch_time']/1000))


        print 'uuid: ' + uuid
        print 'datetime: ' + datetime
  
        #print 'len:' + str(len(json_body['results']))


        for result in json_body['results']:
            plate = result['plate']
            confidence = result['confidence'] 
            pattern_match = False   # whether the plate matches specified pattern           


            print 'plate: ' + plate + ' - ' + str(confidence)


            # Match license plate pattern
            for plate_format in plate_patterns:
                is_match = re.search(plate_format, plate)
                if is_match:
                    print 'Found pattern match: ' + is_match.group(0)
                    pattern_match = True
                    break


            # If we did not find a pattern match, check the list of candidates
            if not pattern_match:
                for candidate in result['candidates']:
                    plate_c = candidate['plate']
                    confidence_c = candidate['confidence']


                    print 'candidate: ' + plate_c + ' - ' + str(confidence_c)


                    for plate_format in plate_patterns:
                        is_match = re.search(plate_format, plate_c)
                        if is_match:
                            print 'Found pattern match: ' + is_match.group(0)
                            pattern_match = True
                            break


                    if pattern_match: 
                        # override plate at top level with one that matches
                        plate = plate_c
                        confidence = confidence_c
                        break            


            if plate in bad_plates:
                print 'ignoring invalid plate: ' + plate 
                ## try to delete file ## 
                #try:
                #    file_to_delete = plateimage_loc + uuid + '.jpg'
                #    os.remove(file_to_delete)
                #except OSError, e:  ## if failed, report it back to the user ##
                #    print ("Error: %s - %s." % (e.filename,e.strerror))
                
            else:
                print 'storing result: ' + plate + ', ' + str(confidence) + ', matched: ' + str(pattern_match)
                with open(csvfile_loc, 'a+b') as f:
                    csvrow = [uuid, datetime, plate, str(confidence), str(pattern_match)]
                    writer = csv.writer(f)
                    writer.writerow(csvrow)


                f.close()


        job.delete()
        job = beanstalk.reserve(timeout=0)
    


if __name__ == "__main__":
   main()
 

nbstl68

Getting comfortable
Joined
Dec 15, 2015
Messages
1,399
Reaction score
322
ALPR sounds prettty cool, but I dont really understand the requirements for implementing its use.

Does ALPR only work with certain cameras and/or certain other software?
Also, for people like me who have no programming knowledge, is ALPR even an option?
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
hows it been working for you so far steve? been getting pretty good results? I just ordered a Dahua NVR and looking through the API I can pull RSTP streams of stored video directly off the NVR, I might be able to just queue things up on my NVR and have OpenALPR go through them on its own.

@nbstl68, you can get cameras with functionallity built in.. costs alot of money, you can use some free software but it takes alot of knowledge and expertise.. you pretty much have to dedicate a camera to the task, its going to be useless for anything other than LPR at night when tuned to look at plates, and you also need alot of processing power to do it externally.

right now there is not much as far as easy to roll out solutions, not without paying big bux.. if you want to do it cheaply like us, then its still going to cost yeh and programing abilities will get you along ways.
 

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
I'm getting decent results, but definitely need to upgrade my server as it is not able to keep up with the RTSP stream. The only way I can eliminate the tearing is to have the iframe set to every frame (1), but unfortunately with that setting the image out of the camera is not nearly as sharp and severely pixelated. The minimum iframe setting I can use to regain the clarity is around 3. I'm experimenting with upping the bitrate when using an iframe setting of 1 and will see how that goes. I tried using a bitrate of 16384 (max), but am getting tearing even with an iframe interval of 1. Not sure what is going on there, but will continue to experiment.

Currently with the camera facing out through a window with the pixelated images, I am only getting around 75% recognition. I feel I can easily increase the recognition once I move the camera outside and resolve the pixelated image issue. I also tend to get a bunch of false readings, since there is a "Slow children at play" sign in the view of the camera and it keeps trying to detect a plate off of the sign. I was planning on upgrading my server anyways, so having one more reason to do so may actually push me to do the upgrade.
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
hrmm, give this a try.. setup a iptables rule to reject all URP 554 traffic.. with any luck this will force RSTP to fall back to TCP.

iptables -A OUTPUT -p udp --dport 554 -j REJECT
iptables -A INPUT -p udp --dport 554 -j REJECT

if its using udp tearing is alot more likely as dropped iframes wont be resent like w/TCP
 

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
Thanks, Nayr. I've updated my iptables and will see how it goes. I'm actually not sure if I was getting tearing with my iframe interval set to 1. What I am seeing is a bunch of purple on the image as if the camera is not fully writing out the image. That is my guess, but I have no idea. I've upped the iframe interval up now to see what happens.

home-site-cam1-1457821690215.jpg
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
it might not do jack, or i guess it could break it entirely lol.. I found that trick playing with my RPi2 display.. omxplayer was just a wrapper for ffmpeg, and by default ffmpeg tries UDP first and falls back to TCP for RSTP.. so I blocked all UDP traffic and all my tearing issues magically disappeared.. I ended up patching the code so I could pass tcp flags to ffmpeg and that worked w/out needing the iptables rules.

I suspect somewhere within OpenALPR also lies ffmpeg or equivalent, so the technique might just work.. Most networks and interfaces now days are not tuned to handle heavy UDP traffic and the Pi's default configuration does not provide enough buffer space thats needed for alot of video data.
 

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
After entering the commands, I'm seeing my iptables as shown below. Does this look correct? I'm wondering why I don't see port 554 listed and instead see icmp-port-unreachable?

Code:
sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
REJECT     udp  --  anywhere             anywhere             udp dpt:rtsp reject-with icmp-port-unreachable


Chain FORWARD (policy ACCEPT)
target     prot opt source               destination         


Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
REJECT     udp  --  anywhere             anywhere             udp dpt:rtsp reject-with icmp-port-unreachable
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
iptables -nL and I actually got it slightly wrong

iptables -A OUTPUT -p udp --dport 554 -j REJECT
iptables -A INPUT -p udp --sport 554 -j REJECT

output to 554 - rejected, input from 554 - rejected.
 

nbstl68

Getting comfortable
Joined
Dec 15, 2015
Messages
1,399
Reaction score
322
you can get cameras with functionallity built in.. costs alot of money, you can use some free software but it takes alot of knowledge and expertise... you also need alot of processing power to do it externally.

right now there is not much as far as easy to roll out solutions....
@nayr, thanks. "...A lot of external processing power to do it externally"...So, if all my cameras are going through a NVR, would that mean I could not do this at all?
If through something like BI already using a separate switch \ computer, would I do something with like a mirrored video stream, (ALPR built into the camera or otherwise)?

Sounds like other than buying a "built in" functionality camera, LP video "capture" can be done easily for manual review of the video but LPR "recognition" to a database for analytics is far beyond a basic 101 setup.
 
Last edited by a moderator:

steve457

Getting the hang of it
Joined
Jan 7, 2016
Messages
113
Reaction score
37
Location
USA
iptables -nL and I actually got it slightly wrong

iptables -A OUTPUT -p udp --dport 554 -j REJECT
iptables -A INPUT -p udp --sport 554 -j REJECT

output to 554 - rejected, input from 554 - rejected.
Ahh, ok. Let me try again, as I was going to mention the prior settings did not seem to have any impact and may have actually made things worse :).
 

nayr

IPCT Contributor
Joined
Jul 16, 2014
Messages
9,329
Reaction score
5,325
Location
Denver, CO
got my LPR camera today, yay.. and weather is nice, going to stick to a tripod and toss it out in the front yard.
 
Top