利用圆圈轮廓面积求取圆环半径:cv2.findContours, contourArea

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用圆圈轮廓面积求取圆环半径:cv2.findContours, contourArea相关的知识,希望对你有一定的参考价值。

简 介: 利用圆环的面积反向计算圆的半径,可以获得更加稳定的圆的半径。对于标准模板在扫描仪上的移动,可以看到对应的测量得到的结果变化规律。下面对于造成这样变化进行初步分析。

关键词 抑菌圈测量仪OpenCV轮廓

图片预处理 目 录
Contents
预先提取圆环位置 圆环面积 求取面积等效半径 测试总结 遗留问题

 

§01 片预处理


  基于扫描仪的 抑菌圈 测量仪中是根据图片中由抑菌药物所形成的抑菌圈的大小来评估药物性能。现在的标准是通过它的直径大小来刻画。

▲ 图1.1.1 使用扫描仪获取金属圆形模板内的圆环直径

  由于在测量过程中存在移动过程:

  • 测量菌盘的摆放;
  • 扫描仪的移动等;

  在获取的图片过程中会出现图像的失真,为了避免这种失真对于测量结果的影响,需要通过已经标定的金属模板反过来对于所采用的机械结构进行测试对应的失真问题。

  在 获取棋盘格与标准模板在扫描仪上不同位置图片 获取了喷涂有黄色油漆的抑菌圈金属模板在扫描以上不同的位置和高度扫描的图片。通过后面的算法来研究扫描仪对于图像获取过程的性能。

  在前期已经通过OpenCV中的HoughCircles获取了金属模板的相对位置,由于HoughCircles所得到的位置、大小精度不高,需要采用其他超分辨率的方式获得金属抑菌圈的圆环半径的估计。

1.1 预先提取圆环位置

  为了提高计算速度,下面现对于采集到的图片进行预处理。

1.1.1 提取方法

  预处理的方式包括两个:

▲ 图1.1.1 四个圆环排列顺序

(1)预处理算法

from headm import *                 # =
import cv2
from tqdm import tqdm

scandiagblock = '/home/aistudio/work/Scanner/ScanDiagBlock'
scanrowblock = '/home/aistudio/work/Scanner/ScanRowBlock'
scanvertblock = '/home/aistudio/work/Scanner/ScanVertBlock'
scandir = '/home/aistudio/work/Scanner'

filedir = scanrowblock
npzfile = os.path.join(scandir, os.path.basename(filedir)+'.npz')

filedim = sorted([s for s in os.listdir(filedir) if s.find("jpg") > 0])

def sortcircles(cc):
    cca = mean(cc[0], axis=0)

    angle = [math.atan2(c[1]-cca[1], c[0]-cca[0])*180/pi for c in cc[0]]
    angle = [s if s >= 0 else 360+s for s in angle]

    ar = sorted(zip(angle, cc[0].T[2], cc[0]))
    sortr = [s[1] for s in ar]
    rcompare = list(array(sortr) > 100)
    ccc = [s[2] for s in ar]

    for i in range(3):
        rc = roll(rcompare, i+1)
        rsr = roll(sortr, i+1)
        cccr = roll(ccc, i + 1, axis=0)

        if rc[0] == True and rc[1] == True:
            break

    return rsr, cccr

def modelArg(filename):
    img = cv2.imread(os.path.join(filedir, filename))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 50,
                               param1=150, param2=40,
                               minRadius=90, maxRadius=115)
    bigcircle = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 50,
                                 param1=200, param2=60,
                                 minRadius=530, maxRadius=580)

    cc = []
    bcx = bigcircle[0][0][0]
    bcy = bigcircle[0][0][1]
    bcr = bigcircle[0][0][2]

    for c in circles[0]:
        cx = c[0]
        cy = c[1]

        dist = sqrt((cx-bcx)**2 + (cy-bcy)**2)
        if dist < bcr*0.75 and c[0] <900:
            cc.append(c)

    return img, array([cc])

gifpath = '/home/aistudio/GIF'
if not os.path.isdir(gifpath):
    os.makedirs(gifpath)
gifdim = os.listdir(gifpath)
for f in gifdim:
    fn = os.path.join(gifpath, f)
    if os.path.isfile(fn):
        os.remove(fn)

alldim = []
allfile = []
for id,f in tqdm(enumerate(filedim)):
    img,c = modelArg(f)
    cc,cccr = sortcircles(c)

    alldim.append(cccr)
    allfile.append(os.path.join(filedir, f))

    img[where(img<50)] =0
    for ccc in cccr:
        cv2.circle(img, (ccc[0], ccc[1]), int(ccc[-1]), (0,0,255), 10)

    plt.figure(figsize=(10,10))
    plt.imshow(img[:,:,::-1])
    savefile = os.path.join(gifpath, '%03d.jpg'%id)
    plt.savefig(savefile)
    plt.close()

    if len(c[0]) != 4:
        printt(c:)
        break
    else:
        pass

savez(npzfile, alldim=alldim, allfile=allfile)

1.1.2 提取结果

(1)横行扫描图片

  这是让圆环在扫村民以横向进行平移50步所得到的图片的切割情况,在最后一张中,由于背景的干扰,使得检测小圆环出现了差错。实际无误的图片之后前面大约42张图片。

▲ 图1.1.2 横行扫描图片预提取圆环的位置

(2)对角线扫描

  下面是100张让圆环沿着扫描仪的对角线平移后所得到的图像的扫描分割图像。利用HoughCircles已经将四个圆环的位置以及顺序进行了预处理。

▲ 图1.1.3 对角线平移扫描的图片

(3)垂直提升圆环

  垂直提升圆环模板会使得图片变形厉害。在前期用于Hough变换中的参数只能够适应前面的13张图片。剩下的图片检测结果就无法满足要求了。对于这种类型的变化,确定后期的图像参数的时候,将利用第一张检测四个圆环的位置作为处理的统一标准。

▲ 图1.1.4 垂直移动的圆圈图片

 

§02 环面积


  用圆环的面积 S S S ,反过来根据圆形 S = π r 2 S = \\pi r^2 S=πr2 反过来定义圆环的半径(直径)。

▲ 图2.1 分割后的各个圆圈

2.1 求取面积等效半径

2.1.1 获取圆环边界

zipfilediag = '/home/aistudio/work/Scanner/ScanDiagBlock.npz'
scandirdiag = '/home/aistudio/work/Scanner/ScanDiagBlock'
alldata = load(zipfilediag, allow_pickle=True)

alldim = alldata['alldim']
allfile = alldata['allfile']

(1)将图像转换成黑白图

  转换成灰度图之后,对像素的亮度进行统计。可以看到如果进行二值化,最合适的阈值 t h r e s h = 70 thresh = 70 thresh=70

▲ 图2.1.1 转换成灰度图像素亮度统计

(2)在黑白图上寻找轮廓

▲ 图2.1.2 寻找到黑白图中的轮廓

2.1.2 通过边界获得半径

(1)寻找正确面积

  通过 cv2.contourArea() 计算所有Contours的面积。可以看到圆的面积应该是结果中的第二大面积。

areaDim: [77841.0, 39682.0, 0.5, 0.0]	
areaDim: [77841.0, 39398.5, 1.0, 0.5, 0.0]
areaDim: [77841.0, 27712.0, 0.0, 0.0, 0.0, 1.0]
areaDim: [77841.0, 27963.5, 0.0, 0.0, 0.0, 0.0]

  利用 r = A / π r = \\sqrt A/\\pi r=A/π 计算圆的等效半径。

ratioDim: [112.38849097458859, 111.98630296072854, 93.92019785927417, 94.34542120474333]

2.1.3 对角线平移模板半径

(1)70

  圆形金属模板在扫描仪上面对角线平移,获得100张移动。处理所有的图片获得所有圆环半径。

▲ 图2.1.3 四个圆环半径随着移动产生的变化

  下面给出了四个圆环对应的方差与极差:

std(rdim1): 0.09883722204508248
std(rdim2): 0.1129093828814647
std(rdim3): 0.25045297377194586
std(rdim4): 0.21107984867821605

max(rdim1)-min(rdim1): 0.4408802395310687	
max(rdim2)-min(rdim2): 0.5670444141300806
max(rdim3)-min(rdim3): 1.0083621030471193
max(rdim4)-min(rdim4): 0.8065292585312562

(2)阈值设置为100

▲ 图2.1.4 四个圆环移动对应的等效半径

std(rdim1): 0.09900553310591087
std(rdim2): 0.11370717076338002
std(rdim3): 0.24494327932253113
std(rdim4): 0.20506054635254523

max(rdim1)-min(rdim1): 0.45511065871777134	
max(rdim2)-min(rdim2): 0.5779160789730753
max(rdim3)-min(rdim3): 0.9834303156866042
max(rdim4)-min(rdim4): 0.8077211123899559

  通过上面测试可以看到,二值化阈值的变化会影响最终计算输出的边境大小。

2.1.4 水平平移处理结果

▲ 图2.1.5 水平平移处理圆半径的结果

std(rdim1): 0.07740474002858148
std(rdim2): 0.2576855459715819
std(rdim3): 0.062140286077771424
std(rdim4): 0.18995941552228443
max(rdim1)-min(rdim1): 0.33682920013815476
max(rdim2)-min(rdim2): 0.9113135673927246
max(rdim3)-min(rdim3): 0.21424740050024127
max(rdim4)-min(rdim4): 0.7100089867722801

2.1.5 垂直移动求取的半径

▲ 图2.1.6 垂直移动对应的圆半径

std(rdim1): 0.42990733097629413
std(rdim2): 0.44317522551733896
std(rdim3): 0.3398756613002497
std(rdim4): 0.35404918503322796
max(rdim1)-min(rdim1): 1.482045089816367
max(rdim2)-min(rdim2): 1.4698391609185535
max(rdim3)-min(rdim3): 1.1608641856747255
max(rdim4)-min(rdim4): 1.188417000120964

  根据 扫描仪标准模板滑动采集图像及其处理 给出的运动参数,移动100步,移动距离大约是20mm。所以在上述移动20步左右,对应的上升距离为4mm,半径出现的像素变化为1.25像素,对应150dpi的时候变化像素为0.625。对于实际尺寸为0.11mm。因此,每移动1mm,对应的实际半径变化为:0.0265;直径大约变化0.05。

 

试总结 ※


  用圆环的面积反向计算圆的半径,可以获得更加稳定的圆的半径。对于标准模板在扫描仪上的移动,可以看到对应的测量得到的结果变化规律。下面对于造成这样变化进行初步分析。

  • 沿着横向运动,可以看到圆四个圆半径变化规律不通相同,其中原因有可能是因为背景光线的干扰;
  • 沿着对角线运动的 圆圈出现的波动。猜测这有可能是因为扫描仪对应的补光光源引起金属模板边缘亮度变化而产生的的影响;
  • 对于模板垂直上升引起圆半径减小,这个原因是比较明确的。通过数据可以计算出,高度每变化1mm,直径测量结果缩小0.05mm。

3.1 遗留问题

  现在还遗留以下问题:
  1. 前面获得测量结果随着高度的变化而引起的比例变化系数。需要寻找一定的方法进行补偿。
  2. 对于纵向、横向英东所产生的的波动,需要通过实验进一步寻找原因,并给出修正方法。


■ 相关文献链接:

● 相关图表链接:

#!/usr/local/bin/python
# -*- coding: gbk -*-
#=================================================&#

以上是关于利用圆圈轮廓面积求取圆环半径:cv2.findContours, contourArea的主要内容,如果未能解决你的问题,请参考以下文章

抑菌圈扫描校正模板

图像处理halcon计算图像中轮廓周长面积半径等特征

图像处理halcon计算图像中轮廓周长面积半径等特征

结合面积和边缘亮度过度来提高圆环检测精度

python编写圆的面积的程序

如何用C语言计算圆的面积