Even though you won't need a lot of zoom, with more zoom you cam move your capture zone further down the road and decrease the effective angle of the plate to the camera, which will reduce motion blur, and improve accuracy of ANPR if you choose to run it.
That's a brilliant idea. I've been trying something similar with batch files but using the output from the openalpr itself, so that when a plate is matched, a snapshot is pulled from the camera.
Has worked ok with the 4 megapixel .mp4 test files I was using. I was going to run it on the 720P substream but I am having trouble working out what the URL is to pull that stream off the camera.
http://USER:pASS@<IP>/cam/realmonitor?action=getStream&channel=1&subtype=1 that I found in the API documentation gives me a 404 error. If anyone knows the URL for substream 2 on a Dahua I'm all ears.
Test1.bat which looked for the results from alpr looked like this
Code:
)
set _alpr_cmd=alpr -c au -p nsw C:\openalpr_64\samples\anprtest.mp4
)
FOR /F "tokens=3" %%G IN ('%_alpr_cmd%^|find "results"') DO test2
and test2.bat looked like this
Code:
)
For /f "tokens=1-4 delims=/:." %%a in ("%TIME%") do (
SET HH24=%%a
SET MI=%%b
SET SS=%%c
SET FF=%%d
)
For /f "tokens=1-4 delims=/:." %%a in ("%TIME%") do (
SET HH24=%%a
SET MI=%%b
SET SS=%%c
SET FF=%%d
)
curl -o C:\openalpr_64\samples\ANPR_%date%_%HH24%-%MI%-%SS%.jpg -u USER:PASS --digest "http://<IP>/cgi-bin/snapshot.cgi?
Which grabbed a time stamped snapshot.
Your way seems like a much less processor intensive way of doing it than trying to analyse the stream in real time. I'd love to see, and blatantly plagiarise, your code if you are willing to share.
Here is the python code for the three files I use. One analyzes, one does the image pulls from the cam, and the other adjusts the focus at sunrise/sunset. Hopefully this helps some, I am not a professional programmer so you can probably make it a lot better.
----ANALYZER----
from openalpr import Alpr
from PIL import ImageFont
from PIL import ImageDraw
from PIL import Image
from PIL import ImageChops
import sys
import time
import os
import csv
import getpass
import sqlite3 as lite
import datetime
sqlite3file='c:\\sql\\plates.db'
con = lite.connect(sqlite3file)
cur = con.cursor()
EMAILpassword = password = getpass.getpass("Email pass: ")
#Directory to watch for new files to analyze in
watchdir = 'c:/sql/snaps/'
contents = os.listdir(watchdir)
count = len(watchdir)
dirmtime = os.stat(watchdir).st_mtime
alpr = Alpr("us", "C:/OpenALPR/openalpr_32bit/openalpr.conf", "C:/OpenALPR/openalpr_32bit/runtime_data")
if not alpr.is_loaded():
print("Error loading OpenALPR")
sys.exit(1)
#Only show top 10 best guesses when analyzing a plate.
alpr.set_top_n(10)
#Email
def send_email(alertmessage,EMAILpassword):
import smtplib
gmail_user = "FROM ACCOUNT"
gmail_pwd = EMAILpassword
FROM = 'FROM ACCOUNT'
BCC = ['TO ACCOUNT',]
SUBJECT = "LPR ALERT" + ' ' + alertmessage
TEXT = alertmessage
message = """\From: %s\nBCC: %s\nSubject: %s\n\n%s
""" % (FROM, ", ".join(BCC), SUBJECT, TEXT)
try:
server = smtplib.SMTP("smtp.gmail.com", 587)
server.ehlo()
server.starttls()
server.login(gmail_user, gmail_pwd)
server.sendmail(FROM, BCC, message)
server.close()
print 'successfully sent the mail'
except:
print "failed to send mail"
PLATEID = []
OWNERID = []
#Loads plates to get email alerts on from a CSV file that is PLATEID, DESCRIPTION
with open('hotlist.csv') as csvfile:
readCSV = csv.reader(csvfile, delimiter=',')
for row in readCSV:
print row[0] + ' ' + row[1]
PLATEID.append(row[0])
OWNERID.append(row[1])
while True:
print 'Analyzing Files'
This_Run = []
#Monitor folder for changes.
newmtime = os.stat(watchdir).st_mtime
if newmtime != dirmtime:
dirmtime = newmtime
newcontents = os.listdir(watchdir)
added = set(newcontents).difference(contents)
#If added is from monitoring the folder for new images to analyze.
if added:
for item in added:
#Analyzers the file for plates.
results = alpr.recognize_file("c:/sql/snaps/" + item)
DrawPlates = []
#Makes sure there are plate(s) detected before proceeding.
if len(results['results']) > 0:
print str(item)
#Check to see if there has already been a match on this same plate ID.
if str(results['results'][0]['candidates'][0]['plate']) not in This_Run:
#This run is used to de-duplicate the same files that have the same best plate match.
This_Run.append(str(results['results'][0]['candidates'][0]['plate']))
#File name made of the plate guess and file name.
saveName = results['results'][0]['candidates'][0]['plate'] + '-' + item
#Inserts all the plates into the database.
for cand in results['results'][0]['candidates']:
DrawPlates.append(str(cand['plate']))
cur.execute("INSERT INTO plate_trans (plate_id,photo,seen) VALUES(?,?,?)", (str(cand['plate']), saveName, datetime.datetime.now()))
con.commit()
#Box adjusts the image. I take off the bottom and top because of other wording in them such as a YIELD sign. I also remove the cameras time overlay from the photo and stamp one on. I leave the overlay on for the
Blue Iris recording.
box = (-750, 250, 2688, 1320)
#Opens up the image for editting.
picTxt = Image.open("c:/sql/snaps/" + item).crop(box)
draw = ImageDraw.Draw(picTxt)
font = ImageFont.truetype("impact.ttf", 34)
#Drawcount is used to set the starting point and increment line spacing.
drawcount = 10
#First_Seen is the first time the plate was seen in the database
first_seen = ''
#Adds header line and spaces more.
draw.text((30,drawcount), 'Plate Recognition Top Matches', font=font)
drawcount = drawcount + 50
#Adds all the guesses to the image then saves it.
for plates2draw in DrawPlates:
cur.execute(u"""select * from plate_trans where plate_id = '{0:s}'""".format(plates2draw))
first_seen = cur.fetchone()[3]
draw.text((30,drawcount), plates2draw + ' First Seen:' + str(first_seen), font=font,)
drawcount = drawcount + 50
drawcount = drawcount + 200
draw.text((120,drawcount), str(datetime.datetime.now()), font=font)
picTxt.save("history/" + saveName, quality=100)
count = 0
#Alert criteria. Looks through all the guesses for a match in the hotlist.txt file. PLATEID and OWNERID are from the CSV earlier up in the code.
for row in PLATEID:
for plates2draw in DrawPlates:
if plates2draw == row:
alertmessage = PLATEID[count] + ' ' + OWNERID[count]
send_email(alertmessage,EMAILpassword)
count = count + 1
contents = newcontents
#Cleanup Work - Remove Older Files. Change os.remove to print curpath to test run it.
dir_to_search = 'C:/sql/snaps/'
for dirpath, dirnames, filenames in os.walk(dir_to_search):
for file in filenames:
curpath = os.path.join(dirpath, file)
file_modified = datetime.datetime.fromtimestamp(os.path.getmtime(curpath))
if datetime.datetime.now() - file_modified > datetime.timedelta(hours=2):
os.remove(curpath)
time.sleep(30)
alpr.unload()
---Python SNAPSHOT File--- (My cars are going 10-15mph so it may not be quick enough for fast cars)
import cv2
import time
cap = cv2.VideoCapture("rtsp://admin
ASSWORD@192.168.2.205:554/cam/realmonitor?channel=1@subtype=0")
count = 0
while(True):
# Capture frame-by-frame
ret, frame = cap.read()
#This is the folder the analyzer is monitoring
cv2.imwrite('c:/sql/snaps/' + str(time.time()) + '.png',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
#this is how many photos to take.
if count == 8:
break
count = count + 1
#this is the delay between photos.
time.sleep(0.25)
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()
----Zoom/Focus Script @ Sunset & Sunrise----
import datetime
import requests
import time
from requests.auth import HTTPDigestAuth
lastchange = ''
while True:
try:
now = str(datetime.datetime.now()).split(' ')[1].split(':')[0]
if int(now) > (int(sunrise_string) + 1) and int(now) < (int(sunset_string) - 1):
if lastchange != 'up':
#Switches cam to the day profile settings
url = '
http://192.168.2.205/cgi-bin/configManager.cgi?action=setConfig&VideoInMode[0].Config[0]=0'
r = requests.get(url, auth=HTTPDigestAuth('admin', 'PASSWORD'))
print r.status_code
#Delay for auto focus to sort itself out
time.sleep(30)
#resets the focus to my calibrated setting for day.
url = '
http://192.168.2.205/cgi-bin/devVideoInput.cgi?action=adjustFocus&focus=0.161491&zoom=1'
r = requests.get(url, auth=HTTPDigestAuth('admin', 'PASSWORD'))
print r.status_code)
lastchange = 'up'
print str(datetime.datetime.now()) + ' sun is up'
else:
if lastchange != 'down':
#Switches the profile in the cam to the Night settings
url = '
http://192.168.2.205/cgi-bin/configManager.cgi?action=setConfig&VideoInMode[0].Config[0]=1'
r = requests.get(url, auth=HTTPDigestAuth('admin', 'PASSWORD'))
print r.status_code
#Gives time for the auto-focus to stop
time.sleep(30)
#resets the focus to my calibrated setting for night.
url = '
http://192.168.2.205/cgi-bin/devVideoInput.cgi?action=adjustFocus&focus=0.155280&zoom=1'
r = requests.get(url, auth=HTTPDigestAuth('admin', 'PASSWORD'))
print r.status_code
lastchange = 'down'
print str(datetime.datetime.now()) + ' sun is down'
time.sleep(600)
except:
print 'crashed'
time.sleep(600)