如何根据孔数计算对象

时间:2019-04-01 00:06:23

标签: python python-3.x image-processing

我正在处理具有形状的图像,并且试图计算具有1个孔和具有2个孔的对象。

Imgur

我找到了有关它的信息,但是它在MATLAB Segment out those objects that have holes in it中 他们使用了Euler特性,我知道在Python中存在skimage库,但是我不能使用它。

我也找到了一些代码,但我听不懂。 http://www.cis.rit.edu/class/simg782/homework/hw3/hw3solutions.pdf第16页。

PRO hw3 4,A,LA,LC,count
;Find all the holes
Ac=A EQ 0
LC=label region(Ac,/ALL)
;Construct an array with the holes filled in
Afill=(A GT 0) OR (LC GT 1)
;Display the arrays
sa=size(A,/dim)
window,/free,xsize=sa[0],ysize=sa[1]
tvlct,rr,gg,bb,/get
tek color
TV,Afill
window,/free,xsize=sa[0],ysize=sa[1]
TV,LC
;Count the objects with holes. First we
;find all the objects and then match up
;the object labels and the hole labels.
LA=label region(Afill)
window,/free,xsize=sa[0],ysize=sa[1]
TV,LA
ha=histogram(LA)
ia=where(ha ge 0)
print,format=’("Objects",3x,"Count",/,(i2,5x,i7))’,$
[transpose(ia),transpose(ha[ia])]
;Each element of ia corresponds to a filled
;object. Object k is labeled ia[k]. For each
;object that is not background,
;determine whether it has holes.
c=0
print
print,"k ia[k] N C"
For k=1,n elements(ia)-1 DO BEGIN
B=bytarr(sa[0],sa[1]); Make an array with one object
ik=Where(LA eq ia[k]); ;Fill in the object
IF MIN(ik) GE 0 THEN B[ik]=1
;Now see if any of the object pixels match the
;hole image LC. Counts if one or more holes.
IF MAX(B AND (LC GT 0)) GT 0 THEN c++
print,[k,ia[k],n elements(ik),c],format=’(I2,1x,I2,3x,I5,2x,I1)’
END
Print,’Number of objects with one or more holes=’,count
tvlct,rr,gg,bb
END
IDL> hw3 4,A,LA,LC,count

该想法是计算具有1个孔的对象和具有2个孔的对象,并突出显示其边缘。

“一个孔的对象数:2”

“带有两个孔的对象数量:4个”

这就是我所拥有的,我是用一个简单的cv2.HoughCircles完成的:

Imgur

2 个答案:

答案 0 :(得分:1)

那么您始终可以自己实现Euler特性。史蒂夫·埃丁斯(Steve Eddins)在他的MathWorks blog中有一篇很棒的文章。他在其中引用了《机器人视觉》,Berthold KP Horn,麻省理工学院出版社,1989年。,其中的原始作者(显然无法访问源代码)演示了一种O(n)方式来计算(4 -连接)欧拉特性。然后Eddins演示了如何在多标签图像上执行相同的操作,以及一个MATLAB代码示例。

这是我对他的代码进行Numpy转换以及一些OpenCV来实现您想要的漏洞计数:

import numpy as np
import cv2

def EulerNumbers(L):
    '''
    For a label matrix L containing nonnegative integers, returns a vector e
    such that e[k-1] is the 4-connected Euler number of the binary image (L ==
    k), from k = 1 to max(L).

    Adapted from:
    https://blogs.mathworks.com/steve/2014/10/02/lots-and-lots-of-euler-numbers/
    Accessed on 5.4.2019.
    '''

    Lp = np.pad(L, ((1,0), (1,0)), 'constant')

    I_NW = Lp[ :-1,  :-1];
    I_N  = Lp[ :-1, 1:  ];
    I_W  = Lp[1:  ,  :-1];

    is_upstream_convexity = np.logical_and(L,(L != I_N));
    is_upstream_convexity = np.logical_and(is_upstream_convexity, (L != I_NW));
    is_upstream_convexity = np.logical_and(is_upstream_convexity,  (L != I_W));

    is_upstream_concavity = np.logical_and(L,(L != I_NW));
    is_upstream_concavity = np.logical_and(is_upstream_concavity, (L == I_N));
    is_upstream_concavity = np.logical_and(is_upstream_concavity, (L == I_W));

    upstream_convexity_labels = L[is_upstream_convexity];
    upstream_concavity_labels = L[is_upstream_concavity];

    total_upstream_convexities = np.bincount(upstream_convexity_labels)[1:] #Discard the zero bin, which is the background.
    total_upstream_concavities = np.bincount(upstream_concavity_labels)[1:]

    return total_upstream_convexities - total_upstream_concavities;


#Load the image
BwI = cv2.imread('BwI.png', cv2.IMREAD_GRAYSCALE)

#Label all the connected components
_, L = cv2.connectedComponents(BwI)

#Compute all the Euler numbers
e = EulerNumbers(L)

# All the regions with no holes will have an Euler number of 1. Regions with one hole
# will have an Euler number of 0. Two holes -> -1 etc. 

num_no_holes = np.sum(e==1)
num_single_hole = np.sum(e==0)
num_two_holes = np.sum(e==-1)
num_three_holes = np.sum(e==-2)
num_more_holes = np.sum(e<-2)

print('Number of objects without holes : %d'%num_no_holes)
print('Number of objects with single hole : %d'%num_single_hole)
print('Number of objects with two holes : %d'%num_two_holes)
print('Number of objects with three holes : %d'%num_three_holes)
print('Number of objects with more than three holes: %d'%num_more_holes)

## Example, colourcode all objects by their amount of holes

Euler2Numholes = lambda e : abs(e-1)

#Label each region by the number of holes it has + 1.
# +1 so the holeless ones won't dissappear.
L_holecounts = np.zeros(L.shape, dtype=np.int32)
for i in range(1, np.max(L)):
    L_holecounts[L == i] = Euler2Numholes(e[i-1])+1

#Spread the small range to [0,255]
plot_L = cv2.normalize(L_holecounts, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8UC1) 
#Note that this will break when there are more than 255 labels. The colormap only works with uint8.

#Colormap it
plot_L = cv2.applyColorMap(plot_L, cv2.COLORMAP_JET)

cv2.imshow('The objects colourcoded by their number of holes', plot_L)
cv2.waitKey(0)

输出:

  

不带孔的物体数量:21
  单孔物体数量:2
  带两个孔的物体数量:4
  带三个孔的对象数量:0
  具有三个以上孔的对象数:0

Colour_coded_labels

答案 1 :(得分:1)

Contour Hierarchy可用于根据对象的孔数对对象进行计数。想象一下,您有100个空的各种大小的盒子,从一个大冰箱盒到一个小首饰盒。您要存储所有100个盒子,因此将一些盒子放在其他较大的盒子中。您还希望以后能够找到这些框,因此可以保留其中一个框的列表。等高线的工作方式相同,此列表称为层次结构。

要查找轮廓和层次结构:

img = cv2.imread('/home/stephen/Desktop/test.png', 0)
_, contours, hierarchy = cv2.findContours(img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)

接下来,遍历每个轮廓以查找其内部是否具有任何轮廓

max_num = np.amax(hierarchy) +1
for c, h in zip(contours, hierarchy[0]):
    # If there is at least one interior contour, find out how many there are
    if h[2] != -1:
        # Make sure it's not the 'zero' contour
        if h[0] == -1:
            num_interior_contours = max_num - h[2]
        else: num_interior_contours = h[0]-h[2]
    else: num_interior_contours = 0

绘制或计算内部具有其他轮廓的轮廓的数量:

if num_interior_contours == 1:
    cv2.drawContours(img_color, [c], -1, (255,0,255), 2)
# Outline the contour in green if there are two holes.
if num_interior_contours == 2:
    cv2.drawContours(img_color, [c], -1, (0,255,0), 2)

shapes with one hole in pink, with two in green