【问题标题】:Precision Measurement with Opencv python使用 Opencv python 进行精确测量
【发布时间】:2018-03-28 09:24:29
【问题描述】:

我实际上正在使用 OpenCV 和 Python 进行机器视觉项目。

目标:该项目的目标是高精度测量组件的尺寸。

主要硬件

  • Basler 5MP 相机 (aca-2500-14gm)

  • 红色背光灯(100 mm x 100 mm)(我的组件尺寸约为 60mm)

实验

由于我正在查看非常严格的公差限制,因此我首先进行了精密研究。我将组件保留在背光源上,并在不移动部件的情况下拍摄了 100 张图像(想象一下,就像一个 100 帧的视频)。我测量了所有 100 张图像的外径(OD)。我的毫米/像素比率是 0.042。我测量了测量的标准偏差以找出精度,结果发现它在 0.03 毫米左右,这很糟糕。组件和设置都没有被触及,因此我期望的精度为 0.005 mm。但我差了一个数量级。我正在使用 OpenCV 的霍夫圆来计算组件的外径。

代码:

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)

输出:0.024

组件的图片:

由于图像是在不干扰设置的情况下拍摄的,因此我预计测量的可重复性约为 0.005 毫米(5 微米)(对于 100 张图像)。但事实并非如此。是霍夫圆的问题吗?或者我在这里错过了什么

【问题讨论】:

    标签: python opencv computer-vision dimension measurement


    【解决方案1】:

    霍夫设计用于检测,而不是量化。如果您想要精确测量,则必须使用为此设计的库。 OpenCV 不适合量化,因此在这方面的能力很差。

    很久以前,我写了一篇关于使用 Radon 变换更精确地估计大小的论文(Hough 变换是对 Radon 变换进行离散化的一种方法,在某些情况下速度很快,但并不精确):

    但由于您的设置控制得非常好,因此您实际上并不需要所有这些来获得精确的测量值。这是一个非常简单的 Python 脚本来量化这些漏洞:

    import diplib as dip
    import math
    
    # Load image and set pixel size
    img = dip.ImageRead('N6uqw.jpg')
    img.SetPixelSize(0.042, "mm")
    
    # Extract object
    obj = ~dip.Threshold(dip.Gauss(img))[0]
    obj = dip.EdgeObjectsRemove(obj)
    
    # Remove noise
    obj = dip.Opening(dip.Closing(obj,9),9)
    
    # Measure object area
    lab = dip.Label(obj)
    msr = dip.MeasurementTool.Measure(lab,img,['Size'])
    objectArea = msr[1]['Size'][0]
    
    # Measure holes
    obj = dip.EdgeObjectsRemove(~obj)
    lab = dip.Label(obj)
    msr = dip.MeasurementTool.Measure(lab,img,['Size'])
    sz = msr['Size']
    holeAreas = []
    for ii in sz.Objects():
       holeAreas.append(sz[ii][0])
    
    # Add hole areas to main object area
    objectArea += sum(holeAreas)
    
    print('Object diameter = %f mm' % (2 * math.sqrt(objectArea / math.pi)))
    for a in holeAreas:
       print('Hole diameter = %f mm' % (2 * math.sqrt(a / math.pi)))
    

    这给了我输出:

    Object diameter = 57.947768 mm
    Hole diameter = 6.540086 mm
    Hole diameter = 6.695357 mm
    Hole diameter = 15.961935 mm
    Hole diameter = 6.511002 mm
    Hole diameter = 6.623011 mm
    

    请注意,上面的代码中有很多假设。还有一个问题是相机没有正好位于物体上方,您可以看到孔的右侧反射光。这肯定会增加这些测量的不精确性。但还要注意,我在测量物体时没有使用物体是圆形的知识(仅在将面积转换为直径时)。或许可以使用圆度标准来克服一些成像缺陷。

    上面的代码使用了DIPlib,这是一个C++ 库,具有相当粗糙的Python 接口。 Python 语法是 C++ 语法的直接翻译,有些东西还是很别扭和非 Pythonic。但它专门针对量化,因此我建议您在自己的应用程序中尝试一下。

    【讨论】:

    • 感谢图书馆。那是一个很棒的图书馆:)。我得到了更好的结果! (与霍夫相比,精度至少高出 2 倍)但我还没有探索它的全部功能。通过阅读您的文档,我想我什至可以进行亚像素测量。
    • 如何使用您提到的圆度标准?我看到了一个测量圆度的选项,但如何使用它来纠正成像问题?
    • @AbhijitBalaji:圆度度量是根据对象的周长计算的。它无法将圆形度的微小偏差与边界像素中的某些噪声区分开来。 DimensionsEllipsoid 功能对沿周边的噪声具有更强的鲁棒性。它给出了与您的对象相匹配的椭圆的大直径和小直径。它可以告诉您有关图像失真的信息。对于主要对象,您必须先填充孔。
    猜你喜欢
    • 2021-10-30
    • 2018-09-14
    • 2021-12-25
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    • 2014-12-02
    相关资源
    最近更新 更多