問題描述
設置:
- 相機:Blackfly S Mono 20.0 MP
- 鏡頭:光遠心鏡頭 TC23080
- 燈:16 個綠色 LED
- Python:3.7.3
- openCV:4.0+
抱歉圖片鏈接,但一張圖片大約 20MB,也不想失去任何質量
圖像樣本:
https://drive.google.com/file/d/11PU-5fzvSJt1lKlmP-lQXhdsuCJPGKbN/view?usp=sharinghttps://drive.google.com/file/d/1B3lSFx8YvTYv3hzuuuYtphoHBuyEdc4o/view
案例:將有不同形狀的金屬零件,從 5x5 到 10x10 尺寸(cm).在這些金屬部件內部有很多從 2 到 10~ 的圓孔,必須非常準確地檢測出來.孔的實際尺寸是未知的,因為可能的零件種類繁多.目標是使用 OpenCV 編寫一個通用算法,該算法可以處理任何金屬部件并檢測圓孔.
Case: There will be metal parts with different shapes from 5x5 to 10x10 size(cm). Inside these metal parts there are plenty of circular holes from 2 to 10~ that have to be detected very accurately. The actual size of holes are unknown, as there are huge variety of possible parts. The goal is to write a generic algorithm with OpenCV, that could work with any metal parts and detect circular holes.
我們嘗試過的:我們嘗試使用 HoughCircles 算法檢測漏洞,但幾乎沒有成功.該算法要么過于敏感,要么根本沒有檢測到漏洞.我們嘗試了不同的 param1 和 param2 值,但沒有成功.在使用 HoughCircles 之前,我們也嘗試過模糊圖像并通過 Canny,但這種方法并沒有產生更好的結果.同樣的算法在分辨率較低的圖片上效果明顯更好.但是,不能犧牲分辨率,因為準確性在這個項目中非常重要.
What we have tried: We have tried to detect the holes with HoughCircles algorithm with little to no success. The algorithm is either too sensitive, or it does not detect the holes at all. We have experimented with different param1 and param2 values with no success. We have also tried blurring the image and passing it through Canny before using HoughCircles, but such an approach did not produce better results. The very same algorithm works significantly better with lower resolution pictures. However, resolution cannot be sacrificed as accuracy is extremely important in this project.
https://drive.google.com/file/d/1TRdDbperi37bha0uJVALS4C2dBuaNz6u/view?usp=sharing
使用以下參數檢測到上述圓圈:
The above circles were detected with the following parameters:
minradius=0
maxradius=0
dp=1
param1=100
param2=21
通過玩弄上面的參數,我們幾乎可以得到我們想要的結果.當我們對不同的圖片使用相同的參數時,就會出現問題.
By playing around with the above parameters, we can get almost the results that we want. The problem arises when we use the same parameters with different pictures.
我們想要得到的最終結果是給定圓的直徑非常準確,我們希望相同的算法可以用于不同的零件圖片
The end result we want to get is the diameter of a given circle with great accuracy, and we want the same algorithm to be usable on different part pictures
這個問題與其他問題的不同之處在于我們不知道給定圓的大致半徑(因此我們無法操縱 minradius、maxradius、param1、param2 或任何其他值).
What makes this problem different from the other ones posted is that we do not know the approximate radius of a given circle (so we cannot manipulate minradius, maxradius, param1, param2 or any other values).
推薦答案
關于這些圖片,我們知道兩件事:
We know two things about these images:
- 這些物體在明亮的背景上是深色的.
- 孔都是圓形,我們要測量所有孔.
所以我們需要做的就是檢測漏洞.這實際上是微不足道的:
So all we need to do is detect holes. This is actually quite trivial:
- 閾值(背景變成對象,因為它很亮)
- 移除邊緣對象
剩下的是洞.不包括任何接觸圖像邊緣的孔.我們現在可以輕松測量這些孔.由于我們假設它們是循環的,我們可以做三件事:
What is left are the holes. Any holes touching the image edge will not be included. We can now easily measure these holes. Since we assume they're circular, we can do three things:
- 計算對象像素,這是對區域的無偏估計.我們根據面積確定孔徑.
- 檢測輪廓,找到質心,然后使用例如以輪廓點到質心的平均距離為半徑.
- 將圖像強度歸一化,使背景照明的強度為 1,其中有孔的物體的強度為 0.每個孔的強度的積分是該區域的亞像素精度估計值(請參閱在底部快速解釋此方法).
這個 Python 代碼,使用 DIPlib (免責聲明:我是作者)展示了如何做這三種方法:
This Python code, using DIPlib (disclaimer: I'm an author) shows how to do these three approaches:
import diplib as dip
import numpy as np
img = dip.ImageRead('geriausias.bmp')
img.SetPixelSize(1,'um') # Usually this info is in the image file
bin, thresh = dip.Threshold(img)
bin = dip.EdgeObjectsRemove(bin)
bin = dip.Label(bin)
msr = dip.MeasurementTool.Measure(bin, features=['Size','Radius'])
print(msr)
d1 = np.sqrt(np.array(msr['Size'])[:,0] * 4 / np.pi)
print("method 1:", d1)
d2 = np.array(msr['Radius'])[:,1] * 2
print("method 2:", d2)
bin = dip.Dilation(bin, 10) # we need larger regions to average over so we take all of the light
# coming through the hole into account.
img = (dip.ErfClip(img, thresh, thresh/4, "range") - (thresh*7/8)) / (thresh/4)
msr = dip.MeasurementTool.Measure(bin, img, features=['Mass'])
d3 = np.sqrt(np.array(msr['Mass'])[:,0] * 4 / np.pi)
print("method 3:", d3)
這給出了輸出:
| Size | Radius |
- | ---------- | ------------------------------------------------- |
| | Max | Mean | Min | StdDev |
| (μm2) | (μm) | (μm) | (μm) | (μm) |
- | ---------- | ---------- | ---------- | ---------- | ---------- |
1 | 6.282e+04 | 143.9 | 141.4 | 134.4 | 1.628 |
2 | 9.110e+04 | 171.5 | 170.3 | 168.3 | 0.5643 |
3 | 6.303e+04 | 143.5 | 141.6 | 133.9 | 1.212 |
4 | 9.103e+04 | 171.6 | 170.2 | 167.3 | 0.6292 |
5 | 6.306e+04 | 143.9 | 141.6 | 126.5 | 2.320 |
6 | 2.495e+05 | 283.5 | 281.8 | 274.4 | 0.9805 |
7 | 1.176e+05 | 194.4 | 193.5 | 187.1 | 0.6303 |
8 | 1.595e+05 | 226.7 | 225.3 | 219.8 | 0.8629 |
9 | 9.063e+04 | 171.0 | 169.8 | 167.6 | 0.5457 |
method 1: [282.8250363 340.57242408 283.28834869 340.45277017 283.36249824
563.64770132 386.9715443 450.65294139 339.70023023]
method 2: [282.74577033 340.58808144 283.24878097 340.43862835 283.1641869
563.59706479 386.95245928 450.65392268 339.68617582]
method 3: [282.74836803 340.56787463 283.24627163 340.39568372 283.31396961
563.601641 386.89884807 450.62167913 339.68954136]
圖像bin
,在調用dip.Label
之后,是一個整數圖像,其中洞1的像素都為1,洞2的像素都為2,以此類推. 所以我們仍然保留測量尺寸和它們是哪些孔之間的關系.我沒有費心制作顯示圖像尺寸的標記圖像,但是正如您在其他答案中看到的那樣,這很容易做到.
The image bin
, after calling dip.Label
, is an integer image where pixels for hole 1 all have value 1, those for hole 2 have value 2, etc. So we still keep the relationship between measured sizes and which holes they were. I have not bothered making a markup image showing the sizes on the image, but this can easily be done as you've seen in other answers.
因為圖像文件中沒有像素大小信息,所以我對每個像素強加了 1 微米.這可能不正確,您必須進行校準以獲取像素大小信息.
Because there is no pixel size information in the image files, I've imposed 1 micron per pixel. This is likely not correct, you will have to do a calibration to obtain pixel size information.
這里的一個問題是背景照明太亮,導致像素飽和.這會導致孔看起來比實際更大.校準系統非常重要,以便背景照明接近相機可以記錄的最大值,但不能達到最大值或更高.例如,嘗試將背景強度設為 245 或 250.第 3 種方法受光照不好的影響最大.
A problem here is that the background illumination is too bright, giving saturated pixels. This causes the holes to appear larger than they actually are. It is important to calibrate the system so that the background illumination is close to the maximum that can be recorded by the camera, but not at that maximum nor above. For example, try to get the background intensity to be 245 or 250. The 3rd method is most affected by bad illumination.
對于第二張圖像,亮度非常低,導致圖像噪點過多.我需要將 bin = dip.Label(bin)
行修改為:
For the second image, the brightness is very low, giving a more noisy image than necessary. I needed to modify the line bin = dip.Label(bin)
into:
bin = dip.Label(bin, 2, 500) # Imposing minimum object size rather than filtering
改為進行一些噪聲過濾可能更容易.輸出是:
It's maybe easier to do some noise filtering instead. The output was:
| Size | Radius |
- | ---------- | ------------------------------------------------- |
| | Max | Mean | Min | StdDev |
| (μm2) | (μm) | (μm) | (μm) | (μm) |
- | ---------- | ---------- | ---------- | ---------- | ---------- |
1 | 4.023e+06 | 1133. | 1132. | 1125. | 0.4989 |
method 1: [2263.24621554]
method 2: [2263.22724164]
method 3: [2262.90068056]
快速解釋方法#3
該方法在 Lucas van Vliet 的博士論文中有描述(代爾夫特理工大學,1993 年),第 6 章.
這樣想:通過孔的光量與孔的面積成正比(實際上它由面積"x光強度"給出).通過將通過孔的所有光相加,我們就知道了孔的面積.該代碼將對象的所有像素強度以及對象外部的一些像素相加(我在那里使用 10 個像素,要走多遠取決于模糊).
Think of it this way: the amount of light that comes through the hole is proportional to the area of the hole (actually it is given by 'area' x 'light intensity'). By adding up all the light that comes through the hole, we know the area of the hole. The code adds up all pixel intensities for the object as well as some pixels just outside the object (I'm using 10 pixels there, how far out to go depends on the blurring).
erfclip
函數稱為軟剪輯".函數,它確保孔內的強度一致為 1,孔外的強度一致為 0,并且僅在邊緣周圍留下中間灰度值.在這種特殊情況下,此軟剪輯避免了成像系統中的偏移以及對光強度的不良估計的一些問題.在其他情況下,避免被測物體顏色不均勻的問題更為重要.它還可以減少噪音的影響.
The erfclip
function is called a "soft clip" function, it ensures that the intensity inside the hole is uniformly 1, and the intensity outside the hole is uniformly 0, and only around the edges it leaves intermediate gray-values. In this particular case, this soft clip avoids some issues with offsets in the imaging system, and poor estimates of the light intensity. In other cases it is more important, avoiding issues with uneven color of the objects being measured. It also reduces the influence of noise.
這篇關于測量金屬零件孔的直徑圖片,用遠心、單色相機和opencv拍攝的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!