Find and Crop using OpenCV

To get the value on a display we first need to crop the display in the image.
This is an example source image:

example_image

The only Python package used is opencv.

Import OpenCV:

import cv2

Load image and get middle of image:

image = cv2.imread("../images/1538832301.jpg")
image = image[300:1300, 500:1400]
height, width, channels = image.shape

middle_image

Rotate image:

center = (width / 2, height / 2)
angle = 87
M = cv2.getRotationMatrix2D(center, angle, 1)
image = cv2.warpAffine(image, M, (height, width))

rotated_image

Convert to grayscale:

gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)

grayscale_image

Blur and threshold:

gray = cv2.blur(gray, (11, 11))
thresh = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)[1]

thresh_image

Find contour of box in the middle of the image and plot in green on image. The box has a minimum of 100 pixel width and a minimum of 50 pixel height.

contours,hierarchy = cv2.findContours(thresh, 1, 2)
for cnt in contours:
    x,y,w,h = cv2.boundingRect(cnt)
    if w>100 and h>50:
        break

box_image

Now crop image based on the points of the green box:

cropped = image[y:y+h, x:x+w]

cropped_image

Increase alpha contrast of the image to see the digits and save result to disk:

contrast = cv2.convertScaleAbs(cropped, alpha=3, beta=0)
cv2.imwrite('cropped_image.png', cropped)

result_image

The next step will be to recognize the numbers in the display.

Get GPS data from images

I wanted to extract the gps coordinates of jpg images. I found this solution and modified it for my needs: https://gist.github.com/snakeye/fdc372dbf11370fe29eb

Requires: exifread

import sys
import exifread

def convert_to_degress(value):
    d = float(value.values[0].num) / float(value.values[0].den)
    m = float(value.values[1].num) / float(value.values[1].den)
    s = float(value.values[2].num) / float(value.values[2].den)

    return d + (m / 60.0) + (s / 3600.0)

def get_location(exif_data):
    latitude = exif_data.get('GPS GPSLatitude')
    latitude_ref = exif_data.get('GPS GPSLatitudeRef')
    longitude = exif_data.get('GPS GPSLongitude')
    longitude_ref = exif_data.get('GPS GPSLongitudeRef')

    if not (latitude and latitude_ref and longitude and longitude_ref):
        return None, None

    lat = convert_to_degress(latitude)
    if latitude_ref.values[0] != 'N':
        lat = 0 - lat

    lon = convert_to_degress(longitude)
    if longitude_ref.values[0] != 'E':
        lon = 0 - lon

    return lat, lon

with open(sys.argv[1], 'rb') as f:
    exif_tags = exifread.process_file(f)
lat, long = get_location(exif_tags)
print(lat, long)

This code reads a JPG image and prints latitude and longitude in decimals of that image.

AllenNLP: Run on Production with Django

This post describes howto run a custom AllenNLP model within Django and Django Rest Framework.

The View code:

import json

from rest_framework import status, viewsets
from rest_framework.parsers import JSONParser
from rest_framework.response import Response

from .utils import predict


class PredictViewSet(viewsets.ViewSet):
    parser_classes = (JSONParser,)

    def create(self, request):
        """
        example call:
        curl -X POST "http://localhost:8000/" -H "content-type: application/json" --data '{"source": "1/5/2003"}'
        """
        if isinstance(request.data, str):
            data = json.loads(request.data)
        else:
            data = request.data

        if not "source" in data:
            return Response(
                'Format: {"source": string}', status=status.HTTP_400_BAD_REQUEST
            )
        return Response(predict(data.get("source")))

And the utils.py with the predict method.

from allennlp.common.util import import_submodules
from allennlp.models.archival import load_archive
from allennlp.predictors import Predictor


def predict(source):
    # register custom model code
    # the library code is in the same Django app (main) in the folder "library"
    import_submodules("main.library")

    # load model without using cuda
    archive = load_archive("../models/model.tar.gz", cuda_device=-1)
    # select predictor needed for this model
    predictor = Predictor.from_archive(archive, "seq2seq")

    result = predictor.predict_json({"source": source})
    # add a confidence bool to help ignoring bad results
    confident = True if abs(result["class_log_probabilities"][0]) < 0.05 else False

    return {
        "predicted": "".join(result["predicted_tokens"]),
        "probability": result["class_log_probabilities"][0],
        "confident": confident,
    }