Using Python, OpenCV and AWS Lambda to gather crime statistics – Part 2

Using Python, OpenCV and AWS Lambda to gather crime statistics – Part 2

This is part two in my quest to determine the long-term crime statistics, in the city where I intend to buy a house. Click here for part one, where I collect the images weekly from the police’s site. In this step, I’ll pick the images out of the S3 bucket, and attempt to find all the pins
The pins are relatively easy to find, thanks to OpenCV + python-cv. I separated out a red pin and yellow pin  and have saved these as the sample of what to look for. The code below will take an image, find all instances of the red and yellow pins in this image.
#!/usr/local/bin/python3
import cv2
import numpy as np

class KeyPoint:
    filename = ''
    px_lat = 0
    px_lon = 0
    dg_lat = 0.0
    dg_lon = 0.0
    found = False

mapimg = KeyPoint()

mapimg.filename = "1502053315-einbruchradar-koeln02_2.jpg"
mapimg.dg_lat = 0.0
mapimg.dg_lon = 0.0

img_rgb = cv2.imread(mapimg.filename)

yellowdot = cv2.imread('yellow_dot.png')
reddot = cv2.imread('red_dot.png')
# Both dots are the same size, so we'll just use yellow as our size ref
d, w, h = yellowdot.shape[::-1]

# matchTemplate searches img_rgb for yellowdot
yres = cv2.matchTemplate(img_rgb,yellowdot,cv2.TM_CCOEFF_NORMED)
rres = cv2.matchTemplate(img_rgb,reddot,cv2.TM_CCOEFF_NORMED)

# only consider tiles which are a 75% or better match
threshold = 0.75
locy = np.where(yres >= threshold)
locr = np.where(rres >= threshold)

# For each found tile, let's draw a rectangle arund it
for pt in zip(*locy[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,255,255), 2)
    # The offset between pin dot and the point which it is actually stuck is
    # 26 pixels down (+) and 2 pixels to the left (-)
    cv2.rectangle(img_rgb, (pt[0] - 2 , pt[1] + 26), (pt[0] -1 , pt[1] + 25), (255,0,0), 2)
    print("Placing yellow point at %d,%d" % (pt[0],pt[1]))

for pt in zip(*locr[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
    cv2.rectangle(img_rgb, (pt[0] - 2 , pt[1] + 26), (pt[0] -1 , pt[1] + 25), (255,0,0), 2)
    print("Placing red point at %d,%d" % (pt[0],pt[1]))

cv2.imwrite('test_result.png',img_rgb)

This first attempt seems to work, and draws a red box around all red pins, a yellow box around all yellow pins, and a small blue dot at the base of every pin where it is actually centered:

There are however a few issues which require some fine-tuning. One pin is correctly identified as red:

 

 

 

 

 

 

however in the log, it is actually identified as yellow first, then re-found as red afterwards:

Placing yellow point at 344,746
Placing red point at 344,746

There is also a double break-in at the same location (probably two apartments in the same block):
The first issue can be tuned by changing the threshold. I tried also changing the algorithms, but there was no difference dependinging on which algorith was used — they all had the exact same result. Moving the threshold up to 76% helped, as well as re-creating the pin from scratch (rather than from a screenshot. I’m now getting acceptable recognition, still a few duplicates or false positives, but those can be removed based on location (if two are within a pixel). Also, my goal is to get rough statistics, so this is now ‘good enough’, at least until I can try Tensorflow.
Here is the result after some tuning:
 
In part 3 I will try to apply geo coordinates to the identified pins, and in part 4 I will load the data into Kibana