Process folder with images using OpenCV

This post is a followup to https://madflex.de/posts/find-and-crop-using-opencv/.

The goal is to process a folder with images to get the ones with a display in it. To find errors a version with a rectangle and height/width is saved and a version with the display cropped.

The resulting rectangular image is:

rect_image

And the crop:

crop_image

Sourcecode:

from pathlib import Path
import imutils
import cv2


def find_and_crop(filename):
    fn = filename.stem
    year, month = str(filename.parents[0]).split("/")[-2:]
    output_rect = filename.parents[3] / "output" / f"{year}-{month}-{fn}-rect.png"
    output_crop = filename.parents[3] / "output" / f"{year}-{month}-{fn}-crop.png"

    image = cv2.imread(str(filename))
    image = image[300:1300, 500:1400]
    height, width, channels = image.shape

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

    # resize
    resized = imutils.resize(image, width=300)
    ratio = height / float(resized.shape[0])

    # greyscale
    gray = cv2.cvtColor(image.copy(), cv2.COLOR_BGR2GRAY)
    gray = cv2.blur(gray, (11, 11))
    thresh = cv2.threshold(gray, 60, 255, cv2.THRESH_BINARY)[1]

    contours, hierarchy = cv2.findContours(thresh, 1, 2)
    for cnt in contours:
        x, y, w, h = cv2.boundingRect(cnt)
        if w > 200 and w < 400 and h > 100 and h < 230:
            break
    else:
        # set because "break" was not triggered -> no rectangle / crop
        x = None

    if x:
        rect = cv2.rectangle(image.copy(), (x, y), (x + w, y + h), (0, 255, 0), 2)

        rect = cv2.putText(
            rect,
            f"h:{h} | w:{w}",
            (10, 50),
            fontFace=cv2.FONT_HERSHEY_SIMPLEX,
            fontScale=1.5,
            color=(255, 0, 0),
            lineType=3,
        )

        cv2.imwrite(str(output_rect), rect)

        # crop image and increase brightness
        cropped = image[y : y + h, x : x + w]
        contrast = cv2.convertScaleAbs(cropped, alpha=3, beta=0)
        cv2.imwrite(str(output_crop), contrast)


def main(base_folder):
    base_folder = Path("../images/")

    for fn in sorted(base_folder.glob("201*/*/*jpg")):
        find_and_crop(fn)

I now have 3700 cropped displays with digits in it. The next step is now detecting the digits (for real this time).

Get exif data for all files in a folder

Goal: Generate a json for every folder with all the gps data of all the images in the folder.

import json
from exif import get_location
from pathlib import Path
import exifread

base = Path("images")
for folder in sorted(base.glob("201*")):
    if folder.is_dir():
        gps_data = {}
        json_fn = folder / "gps.json"
        if json_fn.exists():
            continue
        for fn in sorted(folder.glob("*.JPG"):
            with open(folder / fn, "rb") as f:
               gps_data[fn.name] = get_location(exifread.process_file(f))
        if gps_data:
           json.dump(gps_data, open(json_fn, "w"))

this code uses get_location from this blog post: https://madflex.de/posts/get-gps-data-from-images/

Plot on an OSM map using Python

I want to plot a circle (and later possible a lot of circles) on a static openstreetmap map.
The library best suited seems staticmap from komoot: https://github.com/komoot/staticmap

This code plots a circle on a map of Stuttgart-Vaihingen:

from staticmap import StaticMap, CircleMarker
m = StaticMap(200, 200)

marker = CircleMarker((9.1065541, 48.7324794), '#0036FF', 5)
m.add_marker(marker)

image = m.render(zoom=15)
image.save('marker.png')

I want to generate quite some images on a large map so I added a cache to the tiles system in staticmap: https://github.com/mfa/staticmap/commit/4f922e913d6a3976c645e3b7551af441880763a5