Have you ever wondered what distance the ball of a pen travels when you take your notes? Well, if so, you don’t have to wonder anymore, because OpenCV will give you a very precise answer. A light and fast script will recognize the contours (with a given cutoff accuracy), count how many pixels they occupy, and then convert the pixels to the actual length. An observation: OpenCV prefers to recognize contours from bottom to top. Any practical application of this script?

Hint: You need to know the exact pixel/mm ratio

Hint2: The animation snippet is only for visualizing purpose, the script could work faster without it.

import time
import cv2
import numpy as np

def preprocess_image(image_path):
    # Load the image and convert to grayscale
    image = cv2.imread(image_path)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # Smoothing and binarizing the image
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    _, thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    return image, thresh

def get_text_contours(thresh_image):
    # Finding contours on the image
    contours, _ = cv2.findContours(thresh_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    return contours

def calculate_length(contours):
    # Calculating the total length of contour lines
    total_length = 0
    for contour in contours:
        total_length += cv2.arcLength(contour, True)
    return total_length

def display_contours_and_length(image, contours, total_length_mm):
    # Displaying contours one by one
    for i, contour in enumerate(contours):
        # Drawing a single contour in red
        cv2.drawContours(image, [contour], -1, (0, 0, 255), 1)

        # Displaying the image
        cv2.imshow('Contours Animation', image)
        cv2.waitKey(30)  # Time to display the image in milliseconds before moving to the next contour

        # Delay for smooth animation
        time.sleep(0.05)

    # Text to be displayed
    text = f"Total length: {total_length_mm/1000:.2f} m"
    font = cv2.FONT_HERSHEY_SIMPLEX
    font_scale = 1
    font_thickness = 2

    # Calculating the size of the text
    text_size = cv2.getTextSize(text, font, font_scale, font_thickness)[0]

    # Position of the text
    text_x = 50
    text_y = 250

    # Drawing a white rectangle as a background for the text
    cv2.rectangle(image, (text_x, text_y - text_size[1] - 10), (text_x + text_size[0], text_y + 10), (255, 255, 255), cv2.FILLED)

    # Drawing the text
    cv2.putText(image, text, (text_x, text_y), font, font_scale, (255, 0, 255), font_thickness)

    # Displaying the image with text
    cv2.imshow('Contours Animation', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# Image path
image_path = 'example.jpg'

# Image processing
image, thresh = preprocess_image(image_path)

# Extracting contours
contours = get_text_contours(thresh)

# Calculating the length of lines
total_length = calculate_length(contours)
# Calculating the scale
actual_length_mm = 5.5  # Actual length of the ruler in mm
length_in_pixels = 24     # Length of the ruler in the image in pixels
scale = actual_length_mm / length_in_pixels  # Scale in mm per pixel

# Assuming `total_length` is the total length of contours in pixels
total_length_mm = total_length * scale
print("Total line length in millimeters:", total_length_mm)

# Optionally: Display image with contours
# Sequentially displaying contours
display_contours_and_length(image.copy(), contours, total_length_mm)
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments