def findAstigmatism(fftarray, freq, defocus, resolution, ctfvalues, peakNum=1):
	"""
	find the astigmatism from a radial 1D estimate of the defocus
	"""
	#searchError = resolution/100.

	extrema = ctftools.getCtfExtrema(defocus, freq*1e10,
		ctfvalues['cs'], ctfvalues['volts'], ctfvalues['amplitude_contrast'],
		numzeros=peakNum*2+1, zerotype="all")
	if len(extrema) < 2*peakNum:
		return None
	minEdgeRadius = int(math.ceil(extrema[peakNum-1])) #first peak
	maxEdgeRadius = int(math.ceil(extrema[peakNum])) #second peak
	newshape = (maxEdgeRadius*2, maxEdgeRadius*2)

	print "newshape",newshape

	fftcenter = copy.deepcopy(imagefilter.frame_cut(fftarray, newshape))
	showImage(fftcenter)

	shape = fftcenter.shape
	## create a grid of distance from the center
	xhalfshape = shape[0]/2.0
	x = numpy.arange(-xhalfshape, xhalfshape, 1) + 0.5
	yhalfshape = shape[1]/2.0
	y = numpy.arange(-yhalfshape, yhalfshape, 1) + 0.5
	xx, yy = numpy.meshgrid(x, y)
	radialArray = xx**2 + yy**2 - 0.5
	#radialArray = numpy.sqrt(radial)

	maxVal = fftcenter.max()*2
	minVal = fftcenter.min()
	if debug is True:
		fftcenter = numpy.where(radialArray > maxEdgeRadius**2, maxVal, fftcenter)
		showImage(fftcenter)
		fftcenter = numpy.where(radialArray < minEdgeRadius**2, maxVal, fftcenter)
		showImage(fftcenter)

	angleArray = numpy.arctan2(-yy,xx)
	numSteps = 360
	angleArray += math.pi
	angleArray /= 2*math.pi
	angleArray *= numSteps
	angleArray = numpy.asarray(angleArray, dtype=numpy.uint16)

	showImage(angleArray)

	dataIntegers = numpy.array(range(numSteps))

	xyData = numpy.array(
		scipy.ndimage.measurements.minimum_position(
			fftcenter, angleArray, dataIntegers))

	if debug is True:
		fftcenter[xyData[:,0], xyData[:,1]] = maxVal*3
		showImage(fftcenter)

	ellipseParams = ellipse.totalLeastSquareEllipse(xyData, center=(xhalfshape, yhalfshape))
	if ellipseParams is None:
		return None
	ellipse.printParamsDict(ellipseParams)

	if debug is True:
		numPoints = int(math.pi*(ellipseParams['a']+ellipseParams['b']))
		ellPoints = ellipse.generate_ellipse(ellipseParams['a'], ellipseParams['b'], 
			ellipseParams['alpha'], center=ellipseParams['center'], numpoints=numPoints, integers=True)
		fftcenter[ellPoints[:,0], ellPoints[:,1]] += maxVal
		showImage(fftcenter)

	return ellipseParams
Example #2
0
def ellipseRANSAC(edgeMap, ellipseThresh=2, minPercentGoodPoints=0.001, 
                certainProb=0.9, maxiter=10000, maxRatio=4.0):
        """
        takes 2D edge map from image and trys to find a good ellipse in the data
        """
        shrinkEdgeMap = numpy.float64(trimZeroEdges(edgeMap))
        #shrinkEdgeMap = numpy.float64(edgeMap)
        shape = shrinkEdgeMap.shape
        print "RANSAC shape", shape

        ## make a list of edges, with x, y radii
        bottomEdgeMap = numpy.copy(shrinkEdgeMap)
        bottomEdgeMap[:shape[0]/2,:] = 0
        topEdgeMap = numpy.copy(shrinkEdgeMap)
        topEdgeMap[shape[0]/2:,:] = 0
        rightEdgeMap = numpy.copy(shrinkEdgeMap)
        rightEdgeMap[:,:shape[1]/2] = 0
        leftEdgeMap = numpy.copy(shrinkEdgeMap)
        leftEdgeMap[:,shape[1]/2:] = 0

        #sort edges into quadrants and choose that way
        center = numpy.array(shape, dtype=numpy.float64)/2.0 - 0.5
        edgeList = numpy.array(numpy.where(shrinkEdgeMap), dtype=numpy.float64).transpose() - center
        bottomEdgeList = numpy.array(numpy.where(bottomEdgeMap), dtype=numpy.float64).transpose() - center
        topEdgeList = numpy.array(numpy.where(topEdgeMap), dtype=numpy.float64).transpose() - center
        rightEdgeList = numpy.array(numpy.where(rightEdgeMap), dtype=numpy.float64).transpose() - center
        leftEdgeList = numpy.array(numpy.where(leftEdgeMap), dtype=numpy.float64).transpose() - center

        numEdges = shrinkEdgeMap.sum()
        if numEdges != len(edgeList):
                print "something weird in array sizes"
                return None

        numSamples = 4

        ## count rejects
        areaReject = 0
        distReject = 0
        ratioReject = 0
        sizeReject = 0
        validEllipse = 0

        ## reject criteria
        maxDistFromCenter = math.hypot(shape[0], shape[1])/10.0
        squareArea = max(edgeMap.shape)**2/4 #quarter of the image, little less than indcribed circle
        maxShrinkRadius = int(max(shape)*0.7) #to the corner of shrink image
        maxNormRadius = max(edgeMap.shape)/2 #to the side of full image
        maxRadius = min(maxShrinkRadius, maxNormRadius)
        minGoodPoints = minPercentGoodPoints*numEdges
        finalMinEdges = numEdges*(1.0 - math.exp( math.log(1.0-certainProb)/maxiter ) )**(1.0/numSamples)

        mostGoodPoints = 0
        bestEllipseParams = None # {'center':(x,y), 'a':a, 'b':b, 'alpha':radians}
        iternum = 0
        t0 = time.time()
        while iternum <= maxiter:
                iternum += 1

                currentProb = 1.0 - math.exp( math.log(1.0-certainProb)/iternum )
                currentProb = currentProb**(1.0/numSamples)

                if iternum % 500 == 0:
                        print ("RANSAC iter=%d/%d, points=%d, need=%d->%d, bestProb=%.1f, timePer=%.4f"
                                %(iternum, maxiter, mostGoodPoints, currentProb*numEdges, 
                                        finalMinEdges, mostGoodPoints/float(numEdges)*100, 
                                        (time.time()-t0)/float(iternum)))

                ## check to see if we can stop
                if mostGoodPoints > currentProb*numEdges:
                        #currentProb = mostGoodPoints/float(numEdges)
                        #print "currentProb", currentProb
                        #successProb = 1.0 - math.exp( iternum * math.log(1.0 - currentProb**numSamples) )
                        print "\nRANSAC SUCCESS"
                        break

                if currentProb < minPercentGoodPoints:
                        print "\nRANSAC FAILURE"
                        break

                if iternum >= maxiter:
                        print "\nRANSAC GAVE UP"
                        break

                #choose random edges
                #might be better to sort edges into quadrants and choose that way
                currentEdges = []
                if len(bottomEdgeList) > 0:
                        currentEdges.append(random.choice(bottomEdgeList))
                if len(topEdgeList) > 0:
                        currentEdges.append(random.choice(topEdgeList))
                if len(leftEdgeList) > 0:
                        currentEdges.append(random.choice(leftEdgeList))
                if len(rightEdgeList) > 0:
                        currentEdges.append(random.choice(rightEdgeList))
                ##NEIL IDEA: could select a random edge instead of an edge point???
                if len(currentEdges) < 3:
                        print "error not enough edges"
                        break
                currentEdges = numpy.array(currentEdges, dtype=numpy.int16)

                ## convert rows, columns into x, y by swapping columns
                convertEdges = currentEdges.copy()
                convertEdges[:,[0, 1]] = currentEdges[:,[1, 0]]
                convertEdges = numpy.vstack( (currentEdges[:,1], currentEdges[:,0]) ).T

                # solve centered ellipse, fixed center
                centeredParams = ellipse.solveEllipseOLS(convertEdges)
                #print centeredParams
                if centeredParams is None:
                        #sys.stderr.write("c")
                        continue
                ## check to see if ellipse has a area smaller than circle inscribed in image
                area = centeredParams['a'] * centeredParams['b']
                if area > squareArea:
                        areaReject += 1
                        #sys.stderr.write("A%d "%(areaReject))
                        continue
                radius = max(centeredParams['a'],centeredParams['b'])
                if radius > maxRadius:
                        sizeReject += 1
                        #sys.stderr.write("S%d "%(sizeReject))
                        continue        
                ratio = centeredParams['a']/float(centeredParams['b'])
                if ratio > maxRatio or ratio < 1.0/maxRatio:
                        ratioReject += 1
                        #sys.stderr.write("R%d "%(ratioReject))
                        continue        

                ## check to see if ellipse has a circumference smaller than something

                # solve general ellipse, floating center
                ## only a few points, can use solveEllipseGander fit
                #generalParams = ellipse.solveEllipseB2AC(convertEdges)
                generalParams = ellipse.solveEllipseGander(convertEdges)
                if generalParams is not None:
                        ## check center to see if its reasonably close to center
                        distFromCenter = math.hypot(generalParams['center'][0], generalParams['center'][1])
                        if distFromCenter > maxDistFromCenter:
                                distReject += 1
                                #sys.stderr.write("D%d "%(distReject))
                                continue
                        ## check to see if ellipse has a area smaller than circle inscribed in image
                        area = math.pi * centeredParams['a'] * centeredParams['b']
                        if area > squareArea:
                                areaReject += 1
                                #sys.stderr.write("a%d "%(areaReject))
                                continue
                        radius = max(centeredParams['a'],centeredParams['b'])
                        if radius > maxRadius:
                                sizeReject += 1
                                #sys.stderr.write("s%d "%(sizeReject))
                                continue        
                        ratio = centeredParams['a']/float(centeredParams['b'])
                        if ratio > maxRatio or ratio < 1.0/maxRatio:
                                ## should be a > b
                                ratioReject += 1
                                #sys.stderr.write("r%d "%(ratioReject))
                                continue        

                ## create an outline of the ellipse
                ellipseMap = generateEllipseRangeMap2(centeredParams, ellipseThresh, shape)
                if ellipseMap is None:
                        continue

                ## take overlap of edges and fit area to determine number of good points
                goodPoints = (shrinkEdgeMap*ellipseMap).sum()

                #if goodPoints > mostGoodPoints or iternum%100 == 0:
                #       print ("\ngood points=%d (best=%d; need=%d->%d, bestProb=%.1f, iter=%d/%d, timePer=%.4f)"
                #               %(goodPoints, mostGoodPoints, currentProb*numEdges, finalMinEdges,
                #                       mostGoodPoints/float(numEdges)*100, iternum, maxiter, 
                #                       (time.time()-t0)/float(iternum)))

                validEllipse += 1

                if goodPoints < minGoodPoints or goodPoints < mostGoodPoints:
                        #sys.stderr.write(".")
                        continue

                if goodPoints > mostGoodPoints:
                        ### refine the ellipse parameters to see if we can do better
                        centeredEllipseMap1 = generateEllipseRangeMap2(centeredParams, ellipseThresh, shape)
                        centeredEllipseList1 = numpy.array(numpy.where(centeredEllipseMap1), dtype=numpy.float64).transpose() - center
                        betterEllipseParams1 = ellipse.totalLeastSquareEllipse(centeredEllipseList1)
                        betterEllipseMap1 = generateEllipseRangeMap2(betterEllipseParams1, ellipseThresh, shape)
                        betterGoodPoints1 = (shrinkEdgeMap*betterEllipseMap1).sum()
                        centeredEllipseMap2 = generateEllipseRangeMap2(centeredParams, ellipseThresh*8, shape)
                        centeredEllipseList2 = numpy.array(numpy.where(centeredEllipseMap2), dtype=numpy.float64).transpose() - center
                        betterEllipseParams2 = ellipse.totalLeastSquareEllipse(centeredEllipseList2)
                        betterEllipseMap2 = generateEllipseRangeMap2(betterEllipseParams2, ellipseThresh, shape)
                        betterGoodPoints2 = (shrinkEdgeMap*betterEllipseMap2).sum()
                        #print goodPoints, betterGoodPoints1, betterGoodPoints2

                        if betterGoodPoints1 > goodPoints and betterGoodPoints1 > betterGoodPoints2:
                                bestEllipseParams = betterEllipseParams1
                                mostGoodPoints = betterGoodPoints1
                        elif betterGoodPoints2 > goodPoints:
                                bestEllipseParams = betterEllipseParams2
                                mostGoodPoints = betterGoodPoints2
                        else:
                                bestEllipseParams = centeredParams
                                mostGoodPoints = goodPoints

                        printParams(bestEllipseParams)
                        #if iternum > 100:
                        #       imagefile.arrayToJpeg(centeredEllipseMap1, "map%05d.jpg"%(iternum))

        ### end loop and do stuff
        #bestEllipseMap = generateEllipseRangeMap2(bestEllipseParams, ellipseThresh*1.5, edgeMap.shape)
        #bestEllipseList = numpy.array(numpy.where(bestEllipseMap), dtype=numpy.float64).transpose() - center
        #betterEllipseParams = ellipse.solveEllipseOLS(bestEllipseList)

        print "total iterations", iternum
        print "\tpercent good points %.1f"%(mostGoodPoints/float(numEdges)*100)
        print "\ttime per iter %.2f ms"%(1000.*(time.time()-t0)/float(iternum))
        print "\tvalid ellipses", validEllipse
        print "\toff-center rejects", distReject
        print "\tlarge area rejects", areaReject
        print "\tlarge radius rejects", sizeReject
        print "\toblong ratio rejects", ratioReject
        if bestEllipseParams is not None:
                printParams(bestEllipseParams)
        else:
                print "Fit failed"
                return None

        return bestEllipseParams
Example #3
0
def findAstigmatism(fftarray, freq, defocus, resolution, ctfvalues, peakNum=1):
        """
        find the astigmatism from a radial 1D estimate of the defocus
        """
        #searchError = resolution/100.

        extrema = ctftools.getCtfExtrema(defocus, freq*1e10,
                ctfvalues['cs'], ctfvalues['volts'], ctfvalues['amplitude_contrast'],
                numzeros=peakNum*2+1, zerotype="all")
        if len(extrema) < 2*peakNum:
                return None
        minEdgeRadius = int(math.ceil(extrema[peakNum-1])) #first peak
        maxEdgeRadius = int(math.ceil(extrema[peakNum])) #second peak
        newshape = (maxEdgeRadius*2, maxEdgeRadius*2)

        print "newshape",newshape

        fftcenter = copy.deepcopy(imagefilter.frame_cut(fftarray, newshape))
        showImage(fftcenter)

        shape = fftcenter.shape
        ## create a grid of distance from the center
        xhalfshape = shape[0]/2.0
        x = numpy.arange(-xhalfshape, xhalfshape, 1) + 0.5
        yhalfshape = shape[1]/2.0
        y = numpy.arange(-yhalfshape, yhalfshape, 1) + 0.5
        xx, yy = numpy.meshgrid(x, y)
        radialArray = xx**2 + yy**2 - 0.5
        #radialArray = numpy.sqrt(radial)

        maxVal = fftcenter.max()*2
        minVal = fftcenter.min()
        if debug is True:
                fftcenter = numpy.where(radialArray > maxEdgeRadius**2, maxVal, fftcenter)
                showImage(fftcenter)
                fftcenter = numpy.where(radialArray < minEdgeRadius**2, maxVal, fftcenter)
                showImage(fftcenter)

        angleArray = numpy.arctan2(-yy,xx)
        numSteps = 360
        angleArray += math.pi
        angleArray /= 2*math.pi
        angleArray *= numSteps
        angleArray = numpy.asarray(angleArray, dtype=numpy.uint16)

        showImage(angleArray)

        dataIntegers = numpy.array(range(numSteps))

        xyData = numpy.array(
                scipy.ndimage.measurements.minimum_position(
                        fftcenter, angleArray, dataIntegers))

        if debug is True:
                fftcenter[xyData[:,0], xyData[:,1]] = maxVal*3
                showImage(fftcenter)

        ellipseParams = ellipse.totalLeastSquareEllipse(xyData, center=(xhalfshape, yhalfshape))
        if ellipseParams is None:
                return None
        ellipse.printParamsDict(ellipseParams)

        if debug is True:
                numPoints = int(math.pi*(ellipseParams['a']+ellipseParams['b']))
                ellPoints = ellipse.generate_ellipse(ellipseParams['a'], ellipseParams['b'], 
                        ellipseParams['alpha'], center=ellipseParams['center'], numpoints=numPoints, integers=True)
                fftcenter[ellPoints[:,0], ellPoints[:,1]] += maxVal
                showImage(fftcenter)

        return ellipseParams