Measuring Device Using Scipy on Raspberry Pi
By: Mohanasundaram Palanisamy
Tags: Scipy, Object Detection, Raspberry Pi 4, Raspberry Pi

Raspberry Pi and its camera is really a powerful tool to exhibit various iteration of the new scheme of products.

Obviously, these devices(the products you make out of rpi) very much depend on the programming and use of raspberry pi in its own domain.

Many counts, this project is more centered around OpenCV-python and scipy, but raspberry pi plays a vital role in being it as a product as it is very mobile-oriented.

Measurement is an important thing in real-world aspect, What special about Raspberry pi based Measuring device.

This makes an interesting debate on measuring a pixel vs measuring on a scale.

“Machine-made hardware vs Machine coded software”

The steps for doing this are centric around image manipulation techniques, like finding contours and its corner points among the objects placed in for measurement and play around it.

Okay, let’s get into programming,

Python3 dependencies

If you don’t have the above library kindly install using pip command.

I have used a preloaded image, but also tested with the picam just change the image source line into cv2.VideoCapture(0) before doing it kindly enable the camera.

Here is my output, hope you could also try it out.

Scipy

Opencv

imutils

If you don’t have the above library kindly install using pip command.

from scipy.spatial.distance import euclidean

from imutils import perspective

from imutils import contours

import numpy as np

import imutils

import cv2 # Function to show array of images (intermediate results)

def show_images(images):

for i, img in enumerate(images):

cv2.imshow("image_" + str(i), img)

cv2.waitKey(0)

cv2.destroyAllWindows() img_path = "images/coins.png" # Read image and preprocess

image = cv2.imread(img_path) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

blur = cv2.GaussianBlur(gray, (9, 9), 0) edged = cv2.Canny(blur, 50, 100)

edged = cv2.dilate(edged, None, iterations=1)

edged = cv2.erode(edged, None, iterations=1) #show_images([blur, edged]) # Find contours

cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnts = imutils.grab_contours(cnts) # Sort contours from left to right as leftmost contour is reference object

(cnts, _) = contours.sort_contours(cnts) # Remove contours which are not large enough

cnts = [x for x in cnts if cv2.contourArea(x) > 100] #cv2.drawContours(image, cnts, -1, (0,255,0), 3) #show_images([image, edged])

#print(len(cnts)) # Reference object dimensions

# Here for reference I have used a 2cm x 2cm square

ref_object = cnts[0]

box = cv2.minAreaRect(ref_object)

box = cv2.boxPoints(box)

box = np.array(box, dtype="int")

box = perspective.order_points(box)

(tl, tr, br, bl) = box

dist_in_pixel = euclidean(tl, tr)

dist_in_cm = 2

pixel_per_cm = dist_in_pixel/dist_in_cm # Draw remaining contours

for cnt in cnts:

box = cv2.minAreaRect(cnt)

box = cv2.boxPoints(box)

box = np.array(box, dtype="int")

box = perspective.order_points(box)

(tl, tr, br, bl) = box

cv2.drawContours(image, [box.astype("int")], -1, (0, 0, 255), 2)

mid_pt_horizontal = (tl[0] + int(abs(tr[0] - tl[0])/2), tl[1] + int(abs(tr[1] - tl[1])/2))

mid_pt_verticle = (tr[0] + int(abs(tr[0] - br[0])/2), tr[1] + int(abs(tr[1] - br[1])/2))

wid = euclidean(tl, tr)/pixel_per_cm

ht = euclidean(tr, br)/pixel_per_cm

cv2.putText(image, "{:.1f}cm".format(wid), (int(mid_pt_horizontal[0] - 15), int(mid_pt_horizontal[1] - 10)),

cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2)

cv2.putText(image, "{:.1f}cm".format(ht), (int(mid_pt_verticle[0] + 10), int(mid_pt_verticle[1])),

cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 2) show_images([image])

Originally published at https://www.techiebouncer.com.