简 介: 本文讨论了在对金属模板中的圆环直径检测过程中,将轮廓面积方法与边缘亮度曲线建模的方法相结合,看是否能够提高圆环的精度。从测试结果上来看,并没有显出两种结合方法的优势。
关键词
: 圆环检测,边界面积,中心
§01 圆环检测
1.1 问题背景
在 利用边缘灰度变化建模,来提高圆环直径求取精度 讨论了利用抑菌圈金属模板图片圆环边界亮度变化建模来增加测量精度的方法。最终证明:
- 该方法可以提高原来基于HoughCircles变换所得到的圆形半径;
- 但是比起 利用圆形轮廓面积测量圆形半径 的方法来说,上述利用变换亮度变化建模还没有达到面积测量精度。
因此,遗留下一个问题,是否可以将这两种方法结合在一起最终提高测量精度呢?
1.1.1 方法结合
将边缘亮度建模与轮廓面积统计两者结合可以有以下两种方式:
1. 利用边缘亮度建模中的参数提供给轮廓面积中的二值化阈值;
2. 利用轮廓面积的中心点给边缘亮度建模提供中心点;
下面通过实验研究来验证以上两种方法的结合是否有效果。
1.2 轮廓面积方法
处理的程序来自于利用圆形轮廓面积测量圆形半径博文最后的处理程序。处理图片数据为模板在扫描以上对角线平移所得到的100张数据。
1.2.1 轮廓面积计算圆形半径
下面是利用轮廓面积计算出的圆形半径随着金属模板在扫描仪表面对角线平移所得到的半径的变化。可以看到无论是大圆还是小圆的半径,半径数据都随着平移呈现周期波动,而且两个圆的波动的相位恰好互补,大约呈现180°的相位差。
▲ 图1.2.1 利用轮廓面积获得圆形半径的数据
1.2.2 大圆、小圆半径取平均
根据上面的波动情况,将两个大圆,两个小圆分成两个组别,进行平均,查看平均后的数值变化。
下图显示了大圆和小圆分别进行平均后的测量曲线变化:
- 的确原来的波动大为减少;
- 但是波动并没有完全消失;
▲ 两个大圆,两个小圆分别进行平均值后对应的测量结果
下面显示了平均后的数据极差:
max(r1a)-min(r1a): 0.409755637718888
max(r2a)-min(r2a): 0.742439612301439
下面是原来四个圆半径对应的方差和极差,可以看到经过平均值后,这些极差也相对减少了。
std(rdim1): 0.10686994419992152
std(rdim2): 0.12228622717628217
std(rdim3): 0.24442592829855
std(rdim4): 0.2037604935717777
max(rdim1)-min(rdim1): 0.49655149847501434
max(rdim2)-min(rdim2): 0.6161167744770495
max(rdim3)-min(rdim3): 0.9954571335234874
max(rdim4)-min(rdim4): 0.8185206978833861
但是减少的并不多的原因来自于在原来的数据波动的基础上,还存在着一个大的数据增加的趋势。这个变化成为数据极差主要的贡献。
§02 方法融合
2.1 第一种融合方案
第一种融合方案就是利用圆形的边缘灰度建模,通过建模参数来估计出图片分割的阈值。
2.1.1 代码变动部分
#------------------------------------------------------------
cealldiag = '/home/aistudio/work/Scanner/cealldiag.npz'
cealldata = load(cealldiag, allow_pickle=True)
ceall = cealldata['ceall']
#------------------------------------------------------------
def sigmoidx(x, a,b,c,d):
return a/(1+exp(-(x-c)*d)) + b
#------------------------------------------------------------
block_side = 140
def img2block(img, circles):
block = []
for c in circles:
left = int(c[0] - block_side)
right = left + block_side*2
top = int(c[1] - block_side)
bottom = top + block_side*2
block.append(img[top:bottom, left:right, :])
return block
#------------------------------------------------------------
rdim1 = []
rdim2 = []
rdim3 = []
rdim4 = []
threshold = 100
threshdim = []
for id,f in tqdm(enumerate(allfile)):
img = cv2.imread(f)
cc = alldim[id]
ce = ceall[id]
# if id >= 41: break
#--------------------------------------------------------
'''
for c in cc:
printt(c:)
cv2.circle(img, (c[0], c[1]), int(c[2]), (0,0,255), 10)
plt.figure(figsize=(10,10))
plt.imshow(img[:,:,::-1])
break
'''
#--------------------------------------------------------
block = img2block(img, cc)
#--------------------------------------------------------
'''
plt.figure(figsize=(10,10))
plt.subplot(2,2,1)
plt.imshow(block[0])
plt.subplot(2,2,2)
plt.imshow(block[1])
plt.subplot(2,2,3)
plt.imshow(block[2])
plt.subplot(2,2,4)
plt.imshow(block[3])
plt.savefig('/home/aistudio/stdout.jpg')
break
'''
#--------------------------------------------------------
# plt.figure(figsize=(10,10))
ratioDim = []
x = linspace(0, 100, 100, endpoint=False)
for iidd,b in enumerate(block):
y = ce[iidd]
param = [140, 20, 50, 0.2]
param, conv=curve_fit(sigmoidx, x, y, p0=param)
bgray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY)
# threshold = mean(bgray.flatten())
threshold = (param[0]/2+param[1])
threshdim.append(threshold)
ret,thresh = cv2.threshold(bgray, threshold, 255, 0)
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(b, contours, -1, (0, 0, 255), 3)
areaDim = []
for id,c in enumerate(contours):
areaDim.append(cv2.contourArea(c))
asorted = sorted(areaDim)
a = asorted[-2]
r = sqrt(a/pi)
ratioDim.append(r)
# plt.subplot(2,2,iidd+1)
# plt.hist(bgray.flatten(), bins=20)
# plt.imshow(b[:,:,::-1])
# printt(ratioDim:)
if len(ratioDim) != 4:
printt(ratioDim:)
break
rdim1.append(ratioDim[0])
rdim2.append(ratioDim[1])
rdim3.append(ratioDim[2])
rdim4.append(ratioDim[3])
# plt.savefig('/home/aistudio/stdout.jpg')
# plt.show()
# break
2.1.2 处理结果
▲ 图2.1.1 处理结果
max(r1a)-min(r1a): 0.42009826663701233
max(r2a)-min(r2a): 0.7635241870300433
std(rdim1): 0.10759563831366077
std(rdim2): 0.12086249841122422
std(rdim3): 0.24667243762087157
std(rdim4): 0.21136071101720186
max(rdim1)-min(rdim1): 0.5210168958673478
max(rdim2)-min(rdim2): 0.619309102259777
max(rdim3)-min(rdim3): 0.95698803317228
max(rdim4)-min(rdim4): 0.8067502496432724
无论从处理数据曲线,还是从最后的统计数字来看,这种结合并没有改善。改善效果非常的微弱。
2.2 第二种方案
第二种方案就是利用边界的中心来修正在边缘亮度曲线建模中的中心点。
2.2.1 寻找边界中心
在博文 OpenCV center of contour 给出了利用cv2.moments函数计算contoursde中的方法。
M = cv2.moments(c)
m00 = M['m00']
if m00 > 0:
cX = M['m10'] / M['m00']
cY = M['m01'] / M['m00']
else:
cX = 0
cY = 0
利用上述方法来获取圆形边界的中心点。
(1)处理结果
▲ 图2.2.1 处理结果
std(rdim1): 0.111475597768182
std(rdim2): 0.12480667032700701
std(rdim3): 0.2491116756143372
std(rdim4): 0.21128501595131527
max(rdim1)-min(rdim1): 0.5198071417283359
max(rdim2)-min(rdim2): 0.6324433245598016
max(rdim3)-min(rdim3): 1.0217870978580805
max(rdim4)-min(rdim4): 0.8341840265537286
结果分析,这种结合方式并没有取得明显的效果。结果与直接使用边界中心所得到的基本上是一致的。
※ 总 结 ※
本文讨论了在对金属模板中的圆环直径检测过程中,将轮廓面积方法与边缘亮度曲线建模的方法相结合,看是否能够提高圆环的精度。从测试结果上来看,并没有显出两种结合方法的优势。
■ 相关文献链接:
● 相关图表链接:
处理程序
#!/usr/local/bin/python
# -*- coding: gbk -*-
#============================================================
# TEST1.PY -- by Dr. ZhuoQing 2022-01-26
#
# Note:
#============================================================
from headm import * # =
import cv2
from tqdm import tqdm
from scipy.optimize import curve_fit
#------------------------------------------------------------
npzdiag = '/home/aistudio/work/Scanner/ScanDiagBlock.npz'
scandiagdir = '/home/aistudio/work/Scanner/ScanDiagBlock'
#npzdiag = '/home/aistudio/work/Scanner/ScanRowBlock.npz'
#scandiagdir = '/home/aistudio/work/Scanner/ScanRowBlock'
#npzdiag = '/home/aistudio/work/Scanner/ScanVertBlock.npz'
#scandiagdir = '/home/aistudio/work/Scanner/ScanVertBlock'
#filedim = sorted([s for s in os.listdir(scandiagdir) if s.find("jpg") > 0])
#printt(filedim:)
alldata = load(npzdiag, allow_pickle=True)
#printt(alldata.files:)
alldim = alldata['alldim']
allfile = alldata['allfile']
#printt(alldim:, allfile:)
#------------------------------------------------------------
cealldiag = '/home/aistudio/work/Scanner/cealldiag.npz'
cealldata = load(cealldiag, allow_pickle=True)
ceall = cealldata['ceall']
#------------------------------------------------------------
def sigmoidx(x, a,b,c,d):
return a/(1+exp(-(x-c)*d)) + b
#------------------------------------------------------------
block_side = 140
def img2block(img, circles):
block = []
for c in circles:
left = int(c[0] - block_side)
right = left + block_side*2
top = int(c[1] - block_side)
bottom = top + block_side*2
block.append(img[top:bottom, left:right, :])
return block
#------------------------------------------------------------
CIRCLE_NUM = 100
DELTA_RATIO = 7
SAMPLE_NUM = 300
theta = linspace(0, 2*pi, SAMPLE_NUM)
def circleEdges(img, circles, xy):
clight = []
for iidd,c in enumerate(circles):
rdim = linspace(c[-1]-DELTA_RATIO, c[-1]+DELTA_RATIO, CIRCLE_NUM)
rmean = []
xx = xy[iidd][0]
yy = xy[iidd][1]
for id,r in enumerate(rdim):
thetadim = []
for a in theta:
x = int(xx + r*cos(a))
y = int(yy + r*sin(a))
thetadim.append(img[y,x])
rmean.append(mean(thetadim))
clight.append(rmean)
return clight
#------------------------------------------------------------
rdim1 = []
rdim2 = []
rdim3 = []
rdim4 = []
threshold = 100
for id,f in tqdm(enumerate(allfile)):
img = cv2.imread(f)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cc = alldim[id]
rdim = alldim[id]
ce = ceall[id]
block = img2block(img, cc)
x = linspace(0, 100, 100, endpoint=False)
xydim = []
for iidd,b in enumerate(block):
bgray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY)
threshold = mean(bgray.flatten())
ret,thresh = cv2.threshold(bgray, threshold, 255, 0)
contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cv2.drawContours(b, contours, -1, (0, 0, 255), 3)
areaDim = []
momentDim = []
bcc = cc[iidd]
bx = bcc[0] - block_side
by = bcc[1] - block_side
for id,c in enumerate(contours):
areaDim.append(cv2.contourArea(c))
M = cv2.moments(c)
m00 = M['m00']
if m00 > 0:
cX = M['m10'] / M['m00']
cY = M['m01'] / M['m00']
else:
cX = 0
cY = 0
momentDim.append((cX + bx,cY + by))
asorted = sorted(list(zip(areaDim, momentDim)), key=lambda x:x[0])
# printt(len(asorted))
a = asorted[-2][0]
xydim.append(asorted[-2][1])
#--------------------------------------------------------
# img = cv2.imread(f)
# gray = cv2.cvtColor(img, cv2.COLOR_BGR2COLOR)
ce = circleEdges(gray, cc, xydim )
x = linspace(0, 100, 100, endpoint=False)
N = 100
delta=7
ratioDim = []
for i,c in enumerate(ce):
y = c
# printt(c:)
param = (140, 20, 50, 0.2)
param, conv = curve_fit(sigmoidx, x, y, p0=param)
r0 = rdim[i][-1]
rmod = r0 + (param[2] - N/2)*(2*delta/N)
ratioDim.append(rmod)
#--------------------------------------------------------
rdim1.append(ratioDim[0])
rdim2.append(ratioDim[1])
rdim3.append(ratioDim[2])
rdim4.append(ratioDim[3])
# break
#------------------------------------------------------------
r1a = (array(rdim1) + array(rdim2)) / 2
r2a = (array(rdim3) + array(rdim4)) / 2
printt(max(r1a)-min(r1a):)
printt(max(r2a)-min(r2a):)
#------------------------------------------------------------
plt.clf()
plt.figure(figsize=(10,6))
plt.plot(rdim1, label='Ratio1')
plt.plot(rdim2, label='Ratio2')
plt.plot(rdim3, label='Ratio3')
plt.plot(rdim4, label='Ratio4')
#plt.plot(r1a, label='Big')
#plt.plot(r2a, label='Little')
plt.legend(loc="upper right")
plt.xlabel("n")
plt.ylabel("Ratio")
plt.grid(True)
plt.tight_layout()
plt.savefig('/home/aistudio/stdout.jpg')
plt.show()
#------------------------------------------------------------
printt(std(rdim1):,std(rdim2):,std(rdim3):,std(rdim4):)
printt(max(rdim1)-min(rdim1):)
printt(max(rdim2)-min(rdim2):)
printt(max(rdim3)-min(rdim3):)
printt(max(rdim4)-min(rdim4):)
#------------------------------------------------------------
# END OF FILE : TEST1.PY
#============================================================