PD CM 0209

PD CM 0209
CSIR Centre for Mathematical
Modelling and Computer
Simulation
HOLE COUNTING
Anand Kumar
Project Document CM 0209
December 2002
Bangalore 560 037, India
Hole counting
Anand Kumar
CSIR Centre for Mathematical Modelling & Computer Simulation
Bangalore 560037
We give a simple algorithm for hole counting, where holes are disconnected regions
dened by some criterion, e.g. the value of an attribute lower than a cuto value. Hole
counting or object counting is required in various image processing applications, such
as in medical imaging, material science, chemistry, geophysics etc.
The present algorithm is based on the idea that when a dye is injected into a hole
it spreads to ll the entire hole Hole counting is thus reduced to nding independent
injection points. The algorithm also gives the shape and size of the holes (e.g. the
tumors). The algorithm can also deal with periodic data (e.g., coming from a computation); the hole location, however, is only obtained for non-periodic data. The
computer programme for hole counting, applicable to both two and three dimensions,
is given in the Appendix A. A sample input and its output (Appendix B) are also
given.
Some applications of the hole counting algorithm are presented. Hole counting in a
computed dewetting pattern is shown in Fig. 1. Using a test attribute, we show in
Fig. 2 the most aected regions in a medical image by suitably choosing a threshold
value of the attribute.
1
(a)
(b)
Figure 1: Hole counting in a computed dewetting pattern, (a) computed pattern, (b)
the hole pattern obtained by prescribing a value of the height (attribute) which is
slightly above the minimum value of the height. The data which is periodic in both
directions, is found to have 12 holes.
(a)
(b)
Figure 2: Most aected regions in a medical image (a test attribute is used), (a)
the aected region pattern as given by the test attribute, (b) most aected regions
choosing a threshold value of the attribute.
2
Appendix A
Computer programme listing
c=======================================================================
c
hole counting
c---------------------------------------------------------------------72
c
Author: A. Kumar, C-MMACS, Bangalore
c
Ref.: "Hole counting", C-MMACS PD, December 2002
c---------------------------------------------------------------------72
c
input: the attribute (the data can be periodic, e.g., output
c
from a computation), and a hole criterion.
c
output: number of holes, size, and centroid of the holes
c
(note: centroid is not printed for periodic data)
c---------------------------------------------------------------------72
c
method:
c
get a hole-point (search_a_hole), and inject dye to fill
c
the hole (fill_the hole). repeat until no more new holes.
c
thus, no. of holes = no. of independent injection points.
c---------------------------------------------------------------------72
c
variables:
c
x,y,z = coordinates
c
h(x,y,z) = attribute
c
h_cutoff: here, if h<h_cutoff => hole, else no-hole
c
ihole=1 => hole point, 0=no hole
c
idone=1 => the hole point is filled (initially idone=0)
c
n_periodic(i)=1 => periodic data along direction i, 0=not per.
c---------------------------------------------------------------------72
c
the programme calls:
c
c
read_attrib: read attribute
c
gen_test_attrib: generate a test attribute, if required
c
define_holes: define holes (attribute < a given cutoff value)
c
c
init_idone: initialise idone
c
search_a_hole: locate a hole-point
c
fill_the_hole: allow dye to fill the hole
c
(note: this subroutine is recursively called)
c
c
print_hole_pattern: outputs, as desired
c---------------------------------------------------------------------72
parameter(ill=500000)
dimension x(ill),y(ill),z(ill),h(ill),ihole(ill),idone(ill)
,vol(ill)
common/per/ n_periodic(3)
c.....................................................................72
c
Read in data
c
dimension of the grid (kl=1 in two-dimension).
read(5,*) il,jl,kl
c
n_read_ic=1 => read the given attribute;
c
=0 => generate a test attribute
read(5,*) n_read_ic
c
n_periodic(i)=1 => the given data is periodic along direction i;
c
=0 => the data is not periodic along i
if(kl.eq.1) read(5,*) (n_periodic(i),i=1,2)
if(kl.gt.1) read(5,*) (n_periodic(i),i=1,3)
.
3
if(n_periodic(1).eq.1) print*,' Given data: i-periodic'
if(n_periodic(2).eq.1) print*,' Given data: j-periodic'
if(kl.ne.1.and.n_periodic(3).eq.1)
.
print*,' Given data: k-periodic'
iper=n_periodic(1)+n_periodic(2)
if(kl.gt.1) iper=iper+n_periodic(3)
c
hole criterion (h < h_cutoff => hole)
read(5,*) h_cutoff
c.....................................................................72
c
read attribute
if(n_read_ic.eq.1) then
call read_attrib(il,jl,kl,x,y,z,vol,h)
else
call gen_test_attrib(il,jl,kl,x,y,z,vol,h)
endif
c.....................................................................72
c
define holes (put your hole criterion here)
call define_holes(il,jl,kl,ihole,h,h_cutoff)
c.....................................................................72
c
initially idone=0 (set idone=1 when a hole point is filled)
call init_idone(il,jl,kl,idone)
c.....................................................................72
no_of_holes=0
10
continue
c
search for a new hole point (injection point for the dye)
call search_a_hole(il,jl,kl,ihole,idone,i,j,k,no_more)
if(no_more.eq.1) goto 20
c.....................................................................72
no_of_holes=no_of_holes+1
print*,'hole number',no_of_holes,' found'
c
take moment to find centroid (not ok for periodic data).
size=0.
xmom=0.
ymom=0.
zmom=0.
c
allow the dye to fill the hole
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,i,j,k,
.
xmom,ymom,zmom,size)
xcen=xmom/size
ycen=ymom/size
zcen=zmom/size
c
centroid not printed for periodic data
if(iper.eq.0) write(6,900) size,xcen,ycen,zcen
if(iper.gt.0) write(6,910) size
900
format(2x,' size=',f10.5,' location=',3f10.5)
910
format(2x,' size=',f10.5)
goto 10
c.....................................................................72
20
print*,'no more holes'
c
print hole-pattern
c
(the hole-pattern is given by filled hole-points, idone=1)
call print_hole_pattern(il,jl,kl,x,y,z,idone)
print*,'total number of holes', no_of_holes
stop
4
end
c=======================================================================
subroutine define_holes(il,jl,kl,ihole,h,h_cutoff)
c
put your hole criterion here:
c
ihole=1 if h < h_cutoff (hole-point), else ihole=0 (no-hole)
c---------------------------------------------------------------------72
dimension ihole(il,jl,kl),h(il,jl,kl)
do k=1,kl
do j=1,jl
do i=1,il
if(h(i,j,k).lt.h_cutoff) then
ihole(i,j,k)=1
else
ihole(i,j,k)=0
endif
enddo
enddo
enddo
return
end
c=======================================================================
subroutine init_idone(il,jl,kl,idone)
c
set idone=0
c---------------------------------------------------------------------72
dimension idone(il,jl,kl)
do k=1,kl
do j=1,jl
do i=1,il
idone(i,j,k) = 0
enddo
enddo
enddo
return
end
c=======================================================================
subroutine search_a_hole(il,jl,kl,ihole,idone,i,j,k,no_more)
c
search a hole point which has not been filled
c---------------------------------------------------------------------72
dimension idone(il,jl,kl),ihole(il,jl,kl)
no_more=0
do k=1,kl
do j=1,jl
do i=1,il
if(ihole(i,j,k).eq.1.and.idone(i,j,k).eq.0) goto 10
enddo
enddo
enddo
c
no more holes
5
no_more=1
10
return
end
c=======================================================================
subroutine fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,
.
i,j,k,xmom,ymom,zmom,size)
c
allow the dye to fill the hole.
c
note: this subroutine is recursively called.
c---------------------------------------------------------------------72
dimension x(il,jl,kl),y(il,jl,kl),z(il,jl,kl),vol(il,jl,kl)
dimension ihole(il,jl,kl),idone(il,jl,kl)
common/per/ n_periodic(3)
c
this hole-point is now filled:
idone(i,j,k) = 1
update size and moments to find centroid
size=size+vol(i,j,k)
xmom=xmom+x(i,j,k)*vol(i,j,k)
ymom=ymom+y(i,j,k)*vol(i,j,k)
zmom=zmom+z(i,j,k)*vol(i,j,k)
c
c
c
.
.
spread the dye to the neighbouring hole-points if idone=0:
(note: only points along the axes are checked)
ii=i+1
if(n_periodic(1).eq.1.and.i.eq.il) ii=1
if(ii.le.il.and.ihole(ii,j,k).eq.1.and.idone(ii,j,k).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,ii,j,k,
xmom,ymom,zmom,size)
.
.
ii=i-1
if(n_periodic(1).eq.1.and.i.eq.1) ii=il
if(ii.ge. 1.and.ihole(ii,j,k).eq.1.and.idone(ii,j,k).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,ii,j,k,
xmom,ymom,zmom,size)
.
.
jj=j+1
if(n_periodic(2).eq.1.and.j.eq.jl) jj=1
if(jj.le.jl.and.ihole(i,jj,k).eq.1.and.idone(i,jj,k).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,i,jj,k,
xmom,ymom,zmom,size)
.
.
jj=j-1
if(n_periodic(2).eq.1.and.j.eq.1) jj=jl
if(jj.ge. 1.and.ihole(i,jj,k).eq.1.and.idone(i,jj,k).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,i,jj,k,
xmom,ymom,zmom,size)
c
return if two-dimensional
if(kl.eq.1) return
.
kk=k+1
if(n_periodic(3).eq.1.and.k.eq.kl) kk=1
if(kk.le.kl.and.ihole(i,j,kk).eq.1.and.idone(i,j,kk).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,i,j,kk,
6
.
.
.
xmom,ymom,zmom,size)
kk=k-1
if(n_periodic(3).eq.1.and.k.eq.1) kk=kl
if(kk.ge. 1.and.ihole(i,j,kk).eq.1.and.idone(i,j,kk).eq.0)
call fill_the_hole(il,jl,kl,x,y,z,vol,ihole,idone,i,j,kk,
xmom,ymom,zmom,size)
return
end
c=======================================================================
subroutine read_attrib(il,jl,kl,x,y,z,vol,h)
c
read attribute (use a reading procedure, as desired)
c---------------------------------------------------------------------72
dimension x(il,jl,kl),y(il,jl,kl),z(il,jl,kl),h(il,jl,kl),
.
vol(il,jl,kl)
c
a sample reading procedure:
ifile=21
open(ifile,file='MY_DATA.bin',form='unformatted')
read(ifile) time
read(ifile) (((x(i,j,k),i=1,il),j=1,jl),k=1,kl)
read(ifile) (((y(i,j,k),i=1,il),j=1,jl),k=1,kl)
read(ifile) (((z(i,j,k),i=1,il),j=1,jl),k=1,kl)
read(ifile) (((h(i,j,k),i=1,il),j=1,jl),k=1,kl)
read(ifile) (((vol(i,j,k),i=1,il),j=1,jl),k=1,kl)
close(ifile)
c
generate output for plotting (optional).
ifile=31
open(ifile,file='holesi.TEC',form='formatted')
write(ifile,*) 'TITLE = "holes"'
write(ifile,*) 'VARIABLES= "x" "y" "z" "u"'
write(ifile,900) time,il,jl,kl
format('ZONE T = "',e13.5,'", I=',i4,', J=',i4,', K=',i4,
', F=BLOCK')
write(ifile,910) (((x(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((y(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((z(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((h(i,j,k),i=1,il),j=1,jl),k=1,kl)
format(8f10.5)
close(ifile)
900
910
.
return
end
c=======================================================================
subroutine gen_test_attrib(il,jl,kl,x,y,z,vol,h)
c
generate a test attribute
c---------------------------------------------------------------------72
dimension x(il,jl,kl),y(il,jl,kl),z(il,jl,kl),h(il,jl,kl),
.
vol(il,jl,kl)
common/per/ n_periodic(3)
time=0.
7
dx = 1./float(il)
dy = 1./float(jl)
dz = 1./float(kl)
vol1=dx*dy*dz
x0=0.50
y0=0.50
x1=0.80
y1=0.50
x2=0.30
y2=0.70
if(kl.eq.1) then
z0=0.
z1=0.
z2=0.
else
z0=0.5
z1=0.5
z2=0.5
endif
ampl0=-1.2
ampl1=-1.0
ampl2=-1.1
alpha0=50.
alpha1=50.
alpha2=50.
.
.
do k=1,kl
do j=1,jl
do i=1,il
x(i,j,k)=(i-1)*dx
y(i,j,k)=(j-1)*dy
z(i,j,k)=(k-1)*dz
vol(i,j,k) = vol1
r0=sqrt((x(i,j,k)-x0)**2+(y(i,j,k)-y0)**2+(z(i,j,k)-z0)**2)
r1=sqrt((x(i,j,k)-x1)**2+(y(i,j,k)-y1)**2+(z(i,j,k)-z1)**2)
r2=sqrt((x(i,j,k)-x2)**2+(y(i,j,k)-y2)**2+(z(i,j,k)-z2)**2)
h(i,j,k) = ampl0*exp(-alpha0*r0**2)
+ampl1*exp(-alpha1*r1**2)
+ampl2*exp(-alpha2*r2**2)
enddo
enddo
enddo
if(n_periodic(1).eq.0) then
do j=1,jl
do k=1,kl
vol(1,j,k) = vol(1,j,k)/2.
vol(il,j,k) = vol(il,j,k)/2.
enddo
enddo
endif
if(n_periodic(2).eq.0) then
do i=1,il
8
do k=1,kl
vol(i,1,k) = vol(i,1,k)/2.
vol(i,jl,k) = vol(i,jl,k)/2.
enddo
enddo
endif
if(n_periodic(3).eq.0) then
do j=1,jl
do i=1,il
vol(i,j,1) = vol(i,j,1)/2.
vol(i,j,kl) = vol(i,j,kl)/2.
enddo
enddo
endif
c
900
910
.
generate output for plotting (optional).
ifile=31
open(ifile,file='holesi.TEC',form='formatted')
write(ifile,*) 'TITLE = "holes"'
write(ifile,*) 'VARIABLES= "x" "y" "z" "u"'
write(ifile,900) time,il,jl,kl
format('ZONE T = "',e13.5,'", I=',i4,', J=',i4,', K=',i4,
', F=BLOCK')
write(ifile,910) (((x(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((y(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((z(i,j,k),i=1,il),j=1,jl),k=1,kl)
write(ifile,910) (((h(i,j,k),i=1,il),j=1,jl),k=1,kl)
format(8f10.5)
close(ifile)
return
end
c=======================================================================
subroutine print_hole_pattern(il,jl,kl,x,y,z,idone)
c
print hole-pattern
c.....................................................................72
dimension x(il,jl,kl),y(il,jl,kl),z(il,jl,kl)
dimension idone(il,jl,kl)
c
890
c
avoid printing in 3-d (here, only k-mid-plane is printed)
kk = (kl+1)/2
print*,' hole pattern on plane k=',kk
do j=jl,1,-1
write(6,890) (idone(i,j,kk),i=1,il)
format(80i1)
enddo
generate output for plotting (optional).
ifile=31
time=0.
open(ifile,file='holesf.TEC',form='formatted')
write(ifile,*) 'TITLE = "holes"'
write(ifile,*) 'VARIABLES= "x" "y" "z" "u"'
write(ifile,900) time,il,jl,kl
9
900
910
920
.
format('ZONE T =
',
write(ifile,910)
write(ifile,910)
write(ifile,910)
write(ifile,920)
format(8f10.5)
format(40i2)
close(ifile)
"',e13.5,'", I=',i4,', J=',i4,', K=',i4,
F=BLOCK')
(((x(i,j,k),i=1,il),j=1,jl),k=1,kl)
(((y(i,j,k),i=1,il),j=1,jl),k=1,kl)
(((z(i,j,k),i=1,il),j=1,jl),k=1,kl)
(((idone(i,j,k),i=1,il),j=1,jl),k=1,kl)
return
end
c=======================================================================
10
Appendix B
A typical data and output
32, 32,
0
0, 0, 0
-0.95
32
!
!
!
!
il,jl,kl = dimension of the grid
n_read_ic(1=read given data, 0=use the test attribute)
periodicity along i,j,k (1=periodic, 0=not periodic)
h_cutoff for hole definition
Ouput
hole number
1 found
size=
0.00208 location=
0.49908
hole number
2 found
size=
0.00031 location=
0.79688
hole number
3 found
size=
0.00095 location=
0.30746
no more holes
hole pattern on plane k=
16
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000011100000000000000000000
00000000011100000000000000000000
00000000011100000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000011000000000000000
00000000000000111110000000000000
00000000000000111110000001100000
00000000000000011110000000000000
00000000000000001000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
00000000000000000000000000000000
total number of holes
3
11
0.50460
0.50000
0.50000
0.50000
0.69254
0.50000