使用Opencv python进行精确测量 [英] Precision Measurement with Opencv python

查看:224
本文介绍了使用Opencv python进行精确测量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

主要硬件:

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

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

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

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

实验

由于我正在研究非常严格的公差极限,因此我首先进行了精密研究.我将组件保持在背光源上,并在不移动部件的情况下拍摄了100张图像(就像具有100帧的视频一样).我测量了所有100张图像的外径(OD).我的毫米/像素比率是 0.042 .我测量了测量的标准偏差以找出精度,结果发现精度在 0.03 mm左右附近.组件或设置均未触及,因此我期望的精度为0.005 mm.但是我离开了一个数量级.我正在使用OpenCV的Hough圆来计算组件的OD.

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.

代码:

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张图像),但事实并非如此.这是霍夫圈的问题吗?或者我在这里想念什么

Since the Images are taken without disturbing the setup, I expect the measurement's repeatability to be around 0.005 mm (5 microns) (For 100 images).But this is not so. Is it a problem of hough circle? or what am I missing here

推荐答案

Hough设计用于检测,而不是用于量化.如果需要精确的度量,则必须使用为此设计的库. OpenCV并非用于量化,因此功能不佳.

Hough is designed for detecting, not for quantifying. If you want precise measures, you'll have to use a library designed for that. OpenCV is not meant for quantification, and consequently has poor capabilities there.

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

A long time ago I wrote a paper about more precise estimates of size using the Radon transform (the Hough transform is one way of discretizing the Radon transform, it's fast for some cases, but not precise):

  • C.L. Luengo Hendriks,M.van Ginkel,P.W. Verbeek和LJ van Vliet,《广义Radon变换:采样,准确性和存储注意事项》,模式识别38(12):2494–2505,2005, doi:10.1016/j.patcog.2005.04.018 . 这是PDF .

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

But because your setup is so well controlled, you don't really need all that to get a precise measure. Here is a very straight-forward Python script to quantify these holes:

import PyDIP as dip
import math

# Load image and set pixel size
img = dip.ImageReadTIFF('/home/cris/tmp/machined_piece.tif')
img.SetPixelSize(dip.PixelSize(0.042 * dip.Units("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

请注意,上面的代码中有很多假设.还有一个问题,就是摄像头没有正好位于对象上方的正中,您可以看到孔的右侧反射了光.这无疑会增加这些测量的不精确性.但也请注意,在测量对象时,我并没有使用对象是圆形的知识(仅当将面积转换为直径时).可能可以使用圆度标准来克服某些成像缺陷.

Note that there are a lot of assumptions in the code above. There is also an issue with the camera not being centered exactly above the object, you can see the right side of the holes reflecting light. This will certainly add imprecision to these measurements. But note also that I didn't use the knowledge that the object is round when measuring it (only when converting area to diameter). It might be possible to use the roundness criterion to overcome some of the imaging imperfections.

上面的代码使用PyDIP,这是C ++库的非常粗糙的Python接口, DIPlib 3 . Python语法是C ++语法的直接翻译,对于Python人士来说有些事情还是很尴尬的(我认为实际上,在C ++中使用起来更容易!).但这是专门针对量化的,因此,我建议您尝试将其用于您的应用程序.

The code above uses PyDIP, a very rough Python interface to a C++ library, DIPlib 3. The Python syntax is a direct translation of the C++ syntax, and some things are still quite awkward for a Python person (actually it's easier to use in C++, I think!). But it is aimed specifically at quantification, and hence I recommend you try it out for your application.

这篇关于使用Opencv python进行精确测量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆