def trysplit(ellipses,i,isdone,L,dfore,params): # get datapoints (r,c) = num.where(L==i+1) x = num.hstack((c.reshape(c.size,1),r.reshape(r.size,1))) w = dfore[L==i+1] w = w / num.mean(w) ndata = r.size print 'ndata = %d' % ndata # compute the BIC for one cluster S0 = ell2cov(ellipses[i].major,ellipses[i].minor,ellipses[i].angle) mu0 = num.array([ellipses[i].center.x,ellipses[i].center.y]) print 'loglik: ' print normpdfln2x2cov(c-ellipses[i].center.x,r-ellipses[i].center.y,S0) loglik = num.sum(w*normpdfln2x2cov(c-ellipses[i].center.x,r-ellipses[i].center.y,S0)) BIC0 = -2*loglik + num.log(ndata)*5*1 print 'BIC0 = %f' % BIC0 # try splitting into more clusters ncomponents = 2 while True: (mu,S,priors,gamma,negloglik) = gmm(x,ncomponents,weights=w) print 'for ncomponents = %d:' % ncomponents print 'mu = ' print mu print 'S = ' for j in range(ncomponents): print S[:,:,j] print 'priors = ' print priors print 'negloglik = %f' % negloglik BIC = 2*negloglik + num.log(ndata)*5*ncomponents if BIC >= BIC0: break ncomponents += 1 mu0 = mu S0 = S gamma0 = gamma BIC0 = BIC ncomponents -= 1 if ncomponents == 1: isdone[i] = True else: # get id idx = num.argmax(gamma0,axis=1) # replace ellipses[i].center.x = mu0[0,0] ellipses[i].center.y = mu0[0,1] (ellipses[i].major,ellipses[i].minor,ellipses[i].angle) = cov2ell(S0[:,:,0]) # add new for j in range(1,ncomponents): (a,b,angle) = cov2ell(S0[:,:,j]) area = a*b*angle*4 ellipse = Ellipse( mu[j,0], mu[j,1], b, a, angle, area ) ellipses.append(ellipse) L[r[idx==j],c[idx==j]] = len(ellipses) isdone.append(num.zeros(ncomponents-1,dtype=bool))
def trysplit(ellipses,i,isdone,L,dfore): if DEBUG: print 'trying to split target i=%d: '%i if DEBUG: print str(ellipses[i]) # get datapoints (r,c) = num.where(L==i+1) x = num.hstack((c.reshape(c.size,1),r.reshape(r.size,1))) w = dfore[L==i+1] ndata = r.size ## try increasing threshold # get a bounding box around L == i+1 c1 = num.min(c); c2 = num.max(c); r1 = num.min(r); r2 = num.max(r); dforebox = dfore[r1:r2+1,c1:c2+1].copy() dforebox0 = dforebox.copy() if DEBUG: print 'range r = [%d, %d], range c = [%d, %d]'%(r1,r2,c1,c2) # only look at cc i+1 Lbox = L[r1:r2+1,c1:c2+1].copy() isforebox0 = Lbox == i+1 dforebox[Lbox!=i+1] = 0 for currthresh in num.linspace(params.n_bg_std_thresh_low, min(params.n_bg_std_thresh, num.max(dforebox)),20): # try raising threshold to currthresh isforebox = dforebox >= currthresh # compute connected components (Lbox,ncomponents) = meas.label(isforebox) if DEBUG: print 'for thresh = %.2f, ncomponents = %d'%(currthresh,ncomponents) if ncomponents == 1: continue # remove components with too small area removed = [] for j in range(ncomponents): areaj = num.sum(Lbox==j+1) if areaj < 3: Lbox[Lbox==j+1] = 0 removed += j, if DEBUG: print 'removed = ' + str(removed) for j in range(ncomponents): if num.any(num.array(removed)==j): continue nsmaller = num.sum(num.array(removed)<j) Lbox[Lbox==j+1] = j+1-nsmaller ncomponents -= len(removed) if DEBUG: print 'ncomponents = ' + str(ncomponents) # if we've created a new connected component if ncomponents > 1: if DEBUG: print 'found %d components at thresh %f'%(ncomponents,currthresh) break # end loop trying to increase threshold if ncomponents > 1: # succeeded in splitting into multiple connected components # by raising the threshold, use this as initialization for GMM # get clusters for each cc mu = num.zeros([ncomponents,2]) S = num.zeros([2,2,ncomponents]) priors = num.zeros(ncomponents) for j in range(ncomponents): BWI = Lbox == (j+1) wj = dforebox[BWI] # normalize weights Z = sum(wj) if Z == 0: Z = 1 # compute mean (rj,cj) = num.where(BWI) centerX = sum(cj*wj)/Z centerY = sum(rj*wj)/Z mu[j,0] = centerX + c1 mu[j,1] = centerY + r1 # compute variance S[0,0,j] = sum(wj*cj**2)/Z - centerX**2 S[1,1,j] = sum(wj*rj**2)/Z - centerY**2 S[0,1,j] = sum(wj*cj*rj)/Z - centerX*centerY S[1,0,j] = S[0,1,j] # fix small variances [D,V] = num.linalg.eig(S[:,:,j]) if num.any(D<.01): D[D<.01] = .01 S[:,:,j] = num.dot(V, num.dot(num.diag(D), V.T )) priors[j] = rj.size if DEBUG: print 'component %d: mu = '%j + str(mu[j,:]) + ', S = ' + str(S[:,:,j]) + ', prior = ' + str(priors[j]) priors = priors / num.sum(priors) # label all points (gamma,e) = kcluster.gmmmemberships(mu,S,priors,x,w) # recompute clusters kcluster.gmmupdate(mu,S,priors,gamma,x,w) if DEBUG: print 'after updating, ' if DEBUG: for j in range(ncomponents): print 'component %d: mu = '%j + str(mu[j,:]) + ', S = ' + str(S[:,:,j]) + ', prior = ' + str(priors[j]) area = num.zeros(ncomponents) for j in range(ncomponents): (major,minor,angle) = cov2ell(S[:,:,j]) area[j] = major*minor*num.pi*4.0 removed, = num.where(area <= params.minshape.area) if removed.size > 0: if DEBUG: print 'removing components ' + str(removed) mu = num.delete(mu,removed,axis=0) S = num.delete(S,removed,axis=2) priors = num.delete(priors,removed) ncomponents -= removed.size if DEBUG: print "now there are " + str(ncomponents) + " components" if ncomponents > 1: # recompute memberships (gamma,e) = kcluster.gmmmemberships(mu,S,priors,x,w) # store mu0 = num.zeros([ncomponents,2]) mu0[:,0] = mu[:,0] mu0[:,1] = mu[:,1] gamma0 = gamma major0 = num.zeros(ncomponents) minor0 = num.zeros(ncomponents) angle0 = num.zeros(ncomponents) area0 = num.zeros(ncomponents) #if ncomponents > 2: # print 'Split component %d into %d components'%(i,ncomponents) # params.DOBREAK = True for j in range(ncomponents): (major0[j],minor0[j],angle0[j]) = cov2ell(S[:,:,j]) area0[j] = major0[j]*minor0[j]*num.pi*4.0 if DEBUG: print 'component %d: mu = '%j + str(mu0[j,:]) + ', major = ' + str(major0[j]) + ', minor = ' + str(minor0[j]) + ', angle = ' + str(angle0[j]) + ', area = ' + str(area0[j]) ## are any of the components too small? #if num.any(area0 < params.minshape.area): # print 'split by raising threshold, but one of the components was too small, minarea = ' + str(params.minshape.area) # # undo split # ncomponents = 1 # end if ncomponents > 1 (true if raising threshold successfully # split the component) if ncomponents < 1: print "ncomponents = " + str(ncomponents) + " resetting to 1" ncomponents = 1 if ncomponents == 1: # not able to split the connected component by raising # the threshold if DEBUG: print 'clustering ' # compute the difference between the observation area and the # mean area err0 = num.abs(ellipses[i].area - params.meanshape.area) # try splitting into more clusters ncomponents = 2 while True: if DEBUG: print 'ncomponents = %d'%ncomponents (mu,S,priors,gamma,negloglik) = kcluster.gmm(x,ncomponents,weights=w,kmeansthresh=.1,emthresh=.1,mincov=.25) #(mu,S,priors,gamma,negloglik) = gmm(x,ncomponents,weights=w,nreplicates=4,kmeansiter=10,kmeansthresh=.1,emiters=10,emthresh=.1) if DEBUG: print 'negloglik = %.2f'%negloglik # compute the average distance between each clusters area and the # mean area; greatly penalize areas smaller than minarea err = 0 major = num.zeros(ncomponents) minor = num.zeros(ncomponents) angle = num.zeros(ncomponents) area = num.zeros(ncomponents) for j in range(ncomponents): (major[j],minor[j],angle[j]) = cov2ell(S[:,:,j]) area[j] = major[j]*minor[j]*num.pi*4.0 if area[j] < params.minshape.area: err += 10000 if DEBUG: print 'area[%d] < params.minshape.area = %d, incrementing error by 10000'%(j,round(params.minshape.area)) else: err += num.abs(params.meanshape.area - area[j]) if DEBUG: print 'difference between mean area = %d and area[%d] = %d is %d'%(round(params.meanshape.area),j,round(area[j]),round(num.abs(params.meanshape.area - area[j]))) # end for j in range(ncomponents) if DEBUG: print 'error for ncomponents = %d is %f'%(ncomponents,err) if err >= err0: break ncomponents += 1 mu0 = mu.copy() major0 = major.copy() minor0 = minor.copy() angle0 = angle.copy() area0 = area.copy() err0 = err gamma0 = gamma.copy() # end while True ncomponents -= 1 # end if ncomponents == 1 (was not able to form multiple ccs by # raising threshold) if ncomponents == 1: isdone[i] = True if DEBUG: print 'decided not to split' return isdone else: # get id idx = num.argmax(gamma0,axis=1) # replace ellipses[i].center.x = mu0[0,0] ellipses[i].center.y = mu0[0,1] ellipses[i].major = major0[0] ellipses[i].minor = minor0[0] ellipses[i].angle = angle0[0] ellipses[i].area = area0[0] # if small enough, set to done isdone[i] = ellipses[i].area <= params.maxshape.area # add new for j in range(1,ncomponents): ellipse = Ellipse(mu0[j,0],mu0[j,1],minor0[j],major0[j],angle0[j],area0[j]) ellipses.append(ellipse) isdone = num.append(isdone,ellipse.area <= params.maxshape.area) L[r[idx==j],c[idx==j]] = len(ellipses) if DEBUG: print 'split into %d ellipses: '%ncomponents if DEBUG: print 'ellipses[%d] = '%i + str(ellipses[i]) if DEBUG: for j in range(1,ncomponents): print 'ellipses[%d] = '%(len(ellipses)-j) + str(ellipses[-j]) return isdone
def trysplit(ellipses,i,isdone,L,dfore): print 'trying to split target i=%d'%i # get datapoints (r,c) = num.where(L==i+1) x = num.hstack((c.reshape(c.size,1),r.reshape(r.size,1))) w = dfore[L==i+1] ndata = r.size ## try increasing threshold # get a bounding box around L == i+1 c1 = num.min(c); c2 = num.max(c); r1 = num.min(r); r2 = num.max(r); dforebox = dfore[r1:r2+1,c1:c2+1] dforebox0 = dforebox.copy() # only look at cc i+1 Lbox = L[r1:r2+1,c1:c2+1] isforebox0 = Lbox == i+1 dforebox[Lbox!=i+1] = 0 for currthresh in num.linspace(params.n_bg_std_thresh, min(3*params.n_bg_std_thresh, num.max(dforebox)),10): # try raising threshold to currthresh isforebox = dforebox >= currthresh # compute connected components (Lbox,ncomponents) = meas.label(isforebox) if ncomponents == 1: continue # remove components with too small area removed = [] for j in range(ncomponents): areaj = num.sum(Lbox==j+1) if areaj < 3: Lbox[Lbox==j+1] = 0 removed += j for j in removed: for k in range(j+1,ncomponents): Lbox[Lbox==k+1] = k+1 ncomponents -= len(removed) # if we've created a new connected component if ncomponents > 1: print 'found %d components at thresh %f'%(ncomponents,currthresh) break if ncomponents > 1: # get clusters for each cc mu = num.zeros([ncomponents,2]) S = num.zeros([2,2,ncomponents]) priors = num.zeros(ncomponents) for j in range(ncomponents): BWI = Lbox == (j+1) wj = dforebox[BWI] # normalize weights Z = sum(wj) if Z == 0: Z = 1 # compute mean (rj,cj) = num.where(BWI) centerX = sum(cj*wj)/Z centerY = sum(rj*wj)/Z mu[j,0] = centerX + c1 mu[j,1] = centerY + r1 # compute variance S[0,0,j] = sum(wj*cj**2)/Z - centerX**2 S[1,1,j] = sum(wj*rj**2)/Z - centerY**2 S[0,1,j] = sum(wj*cj*rj)/Z - centerX*centerY S[1,0,j] = S[0,1,j] priors[j] = rj.size print 'component %d: mu = '%j + str(mu[j,:]) + ', S = ' + str(S[:,:,j]) + ', prior = ' + str(priors[j]) priors = priors / num.sum(priors) # label all points (gamma,e) = kcluster.gmmmemberships(mu,S,priors,x,w) # recompute clusters kcluster.gmmupdate(mu,S,priors,gamma,x,w) print 'after updating, ' for j in range(ncomponents): print 'component %d: mu = '%j + str(mu[j,:]) + ', S = ' + str(S[:,:,j]) + ', prior = ' + str(priors[j]) # remove components with too small area area = num.zeros(ncomponents) for j in range(ncomponents): (major,minor,angle) = cov2ell(S[:,:,j]) area[j] = major*minor*num.pi*4.0 print 'component %d: mu = '%j + str(mu[j,:]) + ', major = ' + str(major) + ', minor = ' + str(minor) + ', angle = ' + str(angle) + ', area = ' + str(area[j]) removed, = num.where(area <= params.maxareadelete) if removed.size > 0: print 'removing components ' + str(removed) mu = num.delete(mu,removed,axis=0) S = num.delete(S,removed,axis=2) ncomponents -= removed.size if ncomponents > 1: # recompute memberships (gamma,e) = kcluster.gmmmemberships(mu,S,priors,x,w) # store mu0 = num.zeros([ncomponents,2]) mu0[:,0] = mu[:,0] mu0[:,1] = mu[:,1] gamma0 = gamma major0 = num.zeros(ncomponents) minor0 = num.zeros(ncomponents) angle0 = num.zeros(ncomponents) area0 = num.zeros(ncomponents) for j in range(ncomponents): (major0[j],minor0[j],angle0[j]) = cov2ell(S[:,:,j]) area0[j] = major0[j]*minor0[j]*num.pi*4.0 print 'component %d: mu = '%j + str(mu0[j,:]) + ', major = ' + str(major0[j]) + ', minor = ' + str(minor0[j]) + ', angle = ' + str(angle0[j]) + ', area = ' + str(area0[j]) # are any of the components too small? if num.any(area0 < params.minshape.area): print 'split by raising threshold, but one of the components was too small, minarea = ' + str(params.minshape.area) # undo split ncomponents = 1 if ncomponents == 1: # compute the difference between the observation area and the # mean area err0 = num.abs(ellipses[i].area - params.meanshape.area) # try splitting into more clusters ncomponents = 2 while True: #print 'ncomponents = %d'%ncomponents (mu,S,priors,gamma,negloglik) = kcluster.gmm(x,ncomponents,weights=w,kmeansthresh=.1,emthresh=.1) #(mu,S,priors,gamma,negloglik) = gmm(x,ncomponents,weights=w,nreplicates=4,kmeansiter=10,kmeansthresh=.1,emiters=10,emthresh=.1) #print 'negloglik = %.2f'%negloglik # compute the average distance between each clusters area and the # mean area; greatly penalize areas smaller than minarea err = 0 major = num.zeros(ncomponents) minor = num.zeros(ncomponents) angle = num.zeros(ncomponents) area = num.zeros(ncomponents) for j in range(ncomponents): (major[j],minor[j],angle[j]) = cov2ell(S[:,:,j]) area[j] = major[j]*minor[j]*num.pi*4.0 if area[j] < params.minshape.area: err += 10000 else: err += num.abs(params.meanshape.area - area[j]) # end for j in range(ncomponents) if err >= err0: break ncomponents += 1 mu0 = mu.copy() major0 = major.copy() minor0 = minor.copy() angle0 = angle.copy() area0 = area.copy() err0 = err gamma0 = gamma.copy() # end while True ncomponents -= 1 if ncomponents == 1: isdone[i] = True print 'decided not to split' else: # get id idx = num.argmax(gamma0,axis=1) # replace ellipses[i].center.x = mu0[0,0] ellipses[i].center.y = mu0[0,1] ellipses[i].major = major0[0] ellipses[i].minor = minor0[0] ellipses[i].angle = angle0[0] ellipses[i].area = area0[0] # if small enough, set to done isdone[i] = ellipses[i].area <= params.maxshape.area # add new for j in range(1,ncomponents): ellipse = Ellipse(mu0[j,0],mu0[j,1],minor0[j],major0[j],angle0[j],area0[j]) ellipses.append(ellipse) isdone = num.append(isdone,ellipse.area <= params.maxshape.area) L[r[idx==j],c[idx==j]] = len(ellipses) #num.concatenate((isdone,num.zeros(ncomponents,dtype=bool))) print 'split into %d ellipses: '%ncomponents print ellipses[i] for j in range(1,ncomponents): print ellipses[j]
def trysplit(ellipses, i, isdone, L, dfore): # print 'trying to split target i=%d'%i # get datapoints (r, c) = num.where(L == i + 1) x = num.hstack((c.reshape(c.size, 1), r.reshape(r.size, 1))) w = dfore[L == i + 1] # w = w / num.mean(w) ndata = r.size # compute the difference between the observation area and the # mean area err0 = num.abs(ellipses[i].area - params.meanshape.area) # try splitting into more clusters ncomponents = 2 while True: # print 'ncomponents = %d'%ncomponents (mu, S, priors, gamma, negloglik) = gmm(x, ncomponents, weights=w, kmeansthresh=0.1, emthresh=0.1) # (mu,S,priors,gamma,negloglik) = gmm(x,ncomponents,weights=w,nreplicates=4,kmeansiter=10,kmeansthresh=.1,emiters=10,emthresh=.1) # print 'negloglik = %.2f'%negloglik # compute the average distance between each clusters area and the # mean area; greatly penalize areas smaller than minarea err = 0 major = num.zeros(ncomponents) minor = num.zeros(ncomponents) angle = num.zeros(ncomponents) area = num.zeros(ncomponents) for j in range(ncomponents): (major[j], minor[j], angle[j]) = cov2ell(S[:, :, j]) area[j] = major[j] * minor[j] * num.pi * 4.0 if area[j] < params.minshape.area: err += 10000 else: err += num.abs(params.meanshape.area - area[j]) # err /= ncomponents # print 'err = %.2f'%err if err >= err0: break ncomponents += 1 mu0 = mu.copy() major0 = major.copy() minor0 = minor.copy() angle0 = angle.copy() area0 = area.copy() err0 = err gamma0 = gamma.copy() ncomponents -= 1 if ncomponents == 1: isdone[i] = True # print 'decided not to split' else: # get id idx = num.argmax(gamma0, axis=1) # replace ellipses[i].center.x = mu0[0, 0] ellipses[i].center.y = mu0[0, 1] ellipses[i].major = major0[0] ellipses[i].minor = minor0[0] ellipses[i].angle = angle0[0] ellipses[i].area = area0[0] # if small enough, set to done isdone[i] = ellipses[i].area <= params.maxshape.area # add new for j in range(1, ncomponents): ellipse = Ellipse(mu0[j, 0], mu0[j, 1], minor0[j], major0[j], angle0[j], area0[j]) ellipses.append(ellipse) isdone = num.append(isdone, ellipse.area <= params.maxshape.area) L[r[idx == j], c[idx == j]] = len(ellipses) num.concatenate((isdone, num.zeros(ncomponents, dtype=bool)))
def test(): state = random.get_state() (x,k,w) = initialize() (mu,S,priors,gamma,err) = kcluster.gmm(x,k,weights=w,nreplicates=10)
def test0(): random.set_state(state) (x,k,w) = initialize() (mu,S,priors,gamma,err) = kcluster0.gmm(x,k,weights=w,nreplicates=10) #print "mu = " + str(mu) #print "idx = " + str(idx) if __name__ == "__main__": for trial in range(10): print "trial = " + str(trial) (x,k,w) = initialize() state = random.get_state() if True: (mu0,S0,priors0,gamma0,err0) = kcluster0.gmm(x,k,weights=w,nreplicates=10) random.set_state(state) (mu,S,priors,gamma,err) = kcluster.gmm(x,k,weights=w,nreplicates=10) D = (num.tile(mu[:,0].reshape((k,1)),(1,k)) - mu0[:,0])**2 + \ (num.tile(mu[:,1].reshape((k,1)),(1,k)) - mu0[:,1])**2 (a1,a2) = hungarian.hungarian(D) if True or \ num.max(num.abs(mu - mu0[a1,:])) > .001 or \ num.max(num.abs(S-S0[:,:,a1])) > .001 or \ num.max(num.abs(priors - priors0[a1])) > .001 or \ num.max(num.abs(gamma-gamma0[:,a1])) > .001 or \ num.abs(err - err0) > .001: print "cluster approx cluster0["+str(a1)+"]" print "max(|mu - mu0|) = " + str(num.max(num.abs(mu - mu0[a1,:]))) print "max(|S - S0|) = " + str(num.max(num.abs(S-S0[:,:,a1]))) print "max(|priors - priors0|) = " + str(num.max(num.abs(priors - priors0[a1]))) print "max(|gamma - gamma0|) = " + str(num.max(num.abs(gamma-gamma0))) print "(err - err0)/err0 = " + str((err-err0)/err0)
def trysplit(ellipses, i, isdone, L, dfore, params): # get datapoints (r, c) = num.where(L == i + 1) x = num.hstack((c.reshape(c.size, 1), r.reshape(r.size, 1))) w = dfore[L == i + 1] w = w / num.mean(w) ndata = r.size print 'ndata = %d' % ndata # compute the BIC for one cluster S0 = ell2cov(ellipses[i].major, ellipses[i].minor, ellipses[i].angle) mu0 = num.array([ellipses[i].center.x, ellipses[i].center.y]) print 'loglik: ' print normpdfln2x2cov(c - ellipses[i].center.x, r - ellipses[i].center.y, S0) loglik = num.sum(w * normpdfln2x2cov(c - ellipses[i].center.x, r - ellipses[i].center.y, S0)) BIC0 = -2 * loglik + num.log(ndata) * 5 * 1 print 'BIC0 = %f' % BIC0 # try splitting into more clusters ncomponents = 2 while True: (mu, S, priors, gamma, negloglik) = gmm(x, ncomponents, weights=w) print 'for ncomponents = %d:' % ncomponents print 'mu = ' print mu print 'S = ' for j in range(ncomponents): print S[:, :, j] print 'priors = ' print priors print 'negloglik = %f' % negloglik BIC = 2 * negloglik + num.log(ndata) * 5 * ncomponents if BIC >= BIC0: break ncomponents += 1 mu0 = mu S0 = S gamma0 = gamma BIC0 = BIC ncomponents -= 1 if ncomponents == 1: isdone[i] = True else: # get id idx = num.argmax(gamma0, axis=1) # replace ellipses[i].center.x = mu0[0, 0] ellipses[i].center.y = mu0[0, 1] (ellipses[i].major, ellipses[i].minor, ellipses[i].angle) = cov2ell(S0[:, :, 0]) # add new for j in range(1, ncomponents): (a, b, angle) = cov2ell(S0[:, :, j]) area = a * b * angle * 4 ellipse = Ellipse(mu[j, 0], mu[j, 1], b, a, angle, area) ellipses.append(ellipse) L[r[idx == j], c[idx == j]] = len(ellipses) isdone.append(num.zeros(ncomponents - 1, dtype=bool))