Precision Measurement with Opencv python

asked 2018-03-28 04:27:25 -0600

abhijit gravatar image

I am actually working on a Machine Vision project using OpenCV and Python.

Objective : The objective of the project is to measure the dimensions of a component with high accuracy.

Main Hardware :

  • Basler 5MP camera (aca-2500-14gm)

  • A red backlight (100 mm x 100 mm) (Size of my component is around 60mm)

Experiment

Since I am Looking at very tight tolerance limits, I first did a precision study. I kept the component on the backlight source and took 100 images without moving the part (imagine like a video with 100 frames). I measured the Outer Diameter(OD) of all the 100 images. My mm/pixel ratio is 0.042. I measured the standard deviation of the measurement to find out the precision, which turned out to be around 0.03 mm which is bad. The component nor the setup is touched thus I was expecting a precision of 0.005 mm. But I am off by an order of magnitude. I am using OpenCV's Hough circle to calculate the OD of the component.

Code:

import sys
import pickle
import cv2
import matplotlib.pyplot as plt
import glob
import os
import numpy as np
import pandas as pd

def find_circles(image,dp=1.7,minDist=100,param1=50,param2=50,minRadius=0,maxRadius=0):
    """ finds the center of circular objects in image using hough circle transform

    Keyword arguments
    image -- uint8: numpy ndarray of a single image (no default).
    dp -- Inverse ratio of the accumulator resolution to the image resolution (default 1.7).
    minDist -- Minimum distance in pixel distance between the centers of the detected circles (default 100).
    param1 -- First method-specific parameter (default = 50).
    param2 -- Second method-specific parameter (default = 50).
    minRadius -- Minimum circle radius in pixel distance (default = 0).
    maxRadius -- Maximum circle radius in pixel distance (default = 0).

    Output
    center -- tuple: (x,y).
    radius -- int : radius.
    ERROR if circle is not detected. returns(-1) in this case    
    """

    circles=cv2.HoughCircles(image, 
                             cv2.HOUGH_GRADIENT, 
                             dp = dp, 
                             minDist = minDist, 
                             param1=param1, 
                             param2=param2, 
                             minRadius=minRadius, 
                             maxRadius=maxRadius)
    if circles is not None:
            circles = circles.reshape(circles.shape[1],circles.shape[2])
            return(circles)
    else:
        raise ValueError("ERROR!!!!!! circle not detected try tweaking the parameters or the min and max radius")

def find_od(image_path_list):
    image_path_list.sort()
    print(len(image_path_list))
    result_df = pd.DataFrame(columns=["component_name","measured_dia_pixels","center_in_pixels"])
    for i,name in enumerate(image_path_list):
        img = cv2.imread(name,0) # read the image in grayscale
        ret,thresh_img = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY_INV)
        thresh_img = cv2.bilateralFilter(thresh_img,5,91,91) #smoothing
        edges = cv2.Canny(thresh_img,100,200)
        circles = find_circles(edges,dp=1.7,minDist=100,param1=50,param2=30,minRadius=685,maxRadius=700)
        circles = np.squeeze(circles)
        result_df.loc[i] = os.path.basename(name),circles[2]*2,(circles[0],circles[1])
    result_df.sort_values("component_name",inplace=True)
    result_df.reset_index(drop=True,inplace=True)
    return(result_df)

df = find_od(glob.glob("./images/*"))
mean_d = df.measured_dia_pixels.mean()
std_deviation = np.sqrt(np.mean(np.square([abs(x-mean_d) for x in df.measured_dia_pixels])))

mm_per_pixel = 0.042
print(std_deviation * mm_per_pixel)

OUTPUT: 0.024

The ... (more)

edit retag flag offensive close merge delete

Comments

First I hope you don't work with jpg image because jpg format kill signal. Second 5 microns for 100 images : you suppose 0.042mm/sqrt(100) =5 microns ?

LBerger gravatar imageLBerger ( 2018-03-28 04:44:32 -0600 )edit

No I am not working with jpg images. I am using PNG. But when I used tiff or bitmap I observed the same problem. That's not how I arrived at the value 5 microns. Normally When doing measurements it is a thumb rule to go down in steps from tolerance to accuracy and accuracy to precision(a factor in range [3,10]). a tolerance of 0.1 mm may be satisfied with an accuracy of 0.025 (a factor of 4). An accuracy of 0.025 mm may be satisfied with a precision/ repeatability of 0.005 mm (a factor of 5). Intuitively I cannot talk about accuracy until I get my precision/repeatability sorted out

abhijit gravatar imageabhijit ( 2018-03-28 04:58:48 -0600 )edit

Borders in your image are well defined, but still you have 3-4 pixels transition with different grey-values (as far as I can see from the uploaded image). This means you may have a difference affecting the detected diameters of 4 pixel at least (in the better scenario) and I suppose is the source of the error you mention.

David_86 gravatar imageDavid_86 ( 2018-03-28 09:14:33 -0600 )edit

@David_86 Could you please elaborate? Or how can I improve it? Any suggestions?

abhijit gravatar imageabhijit ( 2018-03-28 09:19:09 -0600 )edit

Hi! What is the situation of your project now? I hope you have managed to measure precisely. I am working on similar project like your project. Now, I am looking for a machine vision camera but, I can't be sure which is suitible for precision measuring. Could you recommend a camera for precision measuring?

mehmetaladag gravatar imagemehmetaladag ( 2019-03-14 15:08:56 -0600 )edit

@mehmetaladag, please do not post answers here, if you have a question or a comment, thank you.

berak gravatar imageberak ( 2019-03-14 15:20:22 -0600 )edit