Permalink
Browse files

Conflict managed

  • Loading branch information...
2 parents 14dc947 + fbfac1e commit b3238f7d4fe3ac0bc05176eb5649e78c2160b9c4 @jrasky jrasky committed Sep 22, 2012
Showing with 1,595 additions and 1,792 deletions.
  1. +49 −7 geocamTiePoint/models.py
  2. +29 −9 geocamTiePoint/optimize.py
  3. +123 −169 geocamTiePoint/quadTree.py
  4. +28 −0 geocamTiePoint/static/external/js/matrix.js
  5. +4 −2 geocamTiePoint/static/external/js/splitter.js
  6. +0 −165 geocamTiePoint/static/geocamTiePoint/js/align_images.js
  7. +0 −95 geocamTiePoint/static/geocamTiePoint/js/app.js
  8. +24 −16 geocamTiePoint/static/geocamTiePoint/js/backbone/models.js
  9. +10 −10 geocamTiePoint/static/geocamTiePoint/js/backbone/router.js
  10. +123 −84 geocamTiePoint/static/geocamTiePoint/js/backbone/views.js
  11. +1 −1 geocamTiePoint/static/geocamTiePoint/js/coords.js
  12. +7 −5 geocamTiePoint/static/geocamTiePoint/js/exportZip.js
  13. +29 −18 geocamTiePoint/static/geocamTiePoint/js/maputils.js
  14. +0 −80 geocamTiePoint/static/geocamTiePoint/js/models.js
  15. +184 −331 geocamTiePoint/static/geocamTiePoint/js/optimize.js
  16. +22 −14 geocamTiePoint/static/geocamTiePoint/js/overlay-view.js
  17. +0 −98 geocamTiePoint/static/geocamTiePoint/js/router.js
  18. +406 −139 geocamTiePoint/static/geocamTiePoint/js/transform.js
  19. +7 −7 geocamTiePoint/static/geocamTiePoint/js/util.js
  20. +0 −500 geocamTiePoint/static/geocamTiePoint/js/views/AlignTiePoints.js
  21. 0 geocamTiePoint/static/geocamTiePoint/js/views/ChooseAlignmentMethod.js
  22. 0 geocamTiePoint/static/geocamTiePoint/js/views/EditInfo.js
  23. 0 geocamTiePoint/static/geocamTiePoint/js/views/NewMapOverlay.js
  24. +0 −16 geocamTiePoint/static/geocamTiePoint/js/views/PlaceTiePoints.js
  25. 0 geocamTiePoint/static/geocamTiePoint/js/views/ViewPage.js
  26. +0 −1 geocamTiePoint/templates/geocamTiePoint/overlay-view.html
  27. +75 −0 geocamTiePoint/testTransform.py
  28. +385 −0 geocamTiePoint/transform.py
  29. +4 −0 geocamTiePoint/urls.py
  30. +85 −25 geocamTiePoint/views.py
@@ -10,6 +10,7 @@
import os
import datetime
import re
+import logging
try:
from cStringIO import StringIO
except ImportError:
@@ -25,7 +26,16 @@
from geocamUtil import anyjson as json
from geocamUtil.models.ExtrasDotField import ExtrasDotField
-from geocamTiePoint import quadTree, settings
+from geocamTiePoint import quadTree, transform, settings
+
+
+# poor man's local memory cache for one quadtree tile generator. a
+# common access pattern is that the same instance of the app gets
+# multiple tile requests on the same quadtree. optimize for that case by
+# keeping the generator in memory. note: an alternative approach would
+# use the memcached cache, but that would get rid of much of the benefit
+# in terms of serialization/deserialization.
+cachedGeneratorG = {'key': None, 'value': None}
def getNewImageFileName(instance, filename):
@@ -115,19 +125,41 @@ def convertImageToRgbaIfNeeded(self, image):
self.imageData.contentType = 'image/png'
self.imageData.save()
+ def getImage(self):
+ im = PIL.Image.open(self.imageData.image.file)
+ self.convertImageToRgbaIfNeeded(im)
+ return im
+
+ def getGeneratorCacheKey(self):
+ return 'geocamTiePoint.QuadTreeGenerator.%s' % self.id
+
+ def getGeneratorWithCache(self):
+ global cachedGeneratorG
+ cachedGeneratorCopy = cachedGeneratorG
+ key = self.getGeneratorCacheKey()
+ if cachedGeneratorCopy['key'] == key:
+ logging.debug('getGeneratorWithCache hit %s', key)
+ result = cachedGeneratorCopy['value']
+ else:
+ logging.debug('getGeneratorWithCache miss %s', key)
+ result = self.getGenerator()
+ cachedGeneratorG = dict(key=key, value=result)
+ return result
+
def getGenerator(self):
- image = PIL.Image.open(self.imageData.image.file)
- self.convertImageToRgbaIfNeeded(image)
+ image = self.getImage()
if self.transform:
return (quadTree.WarpedQuadTreeGenerator
- (image,
+ (self.id,
+ image,
json.loads(self.transform)))
else:
- return quadTree.SimpleQuadTreeGenerator(image)
+ return quadTree.SimpleQuadTreeGenerator(self.id,
+ image)
def generateExportZip(self, exportName, metaJson):
- gen = self.getGenerator()
+ gen = self.getGeneratorWithCache()
writer = quadTree.ZipWriter(exportName)
gen.writeQuadTree(writer)
writer.writeData('meta.json', dumps(metaJson))
@@ -152,6 +184,7 @@ class Overlay(models.Model):
alignedQuadTree = models.ForeignKey(QuadTree, null=True, blank=True,
related_name='alignedOverlays',
on_delete=models.SET_NULL)
+ isPublic = models.BooleanField(default=False)
# extras: a special JSON-format field that holds additional
# schema-free fields in the overlay model. Members of the field can
@@ -190,7 +223,11 @@ def getJsonDict(self):
'[Y].jpg'])
result['unalignedTilesZoomOffset'] = quadTree.ZOOM_OFFSET
if self.alignedQuadTree is not None:
- result['alignedTilesUrl'] = reverse('geocamTiePoint_tile',
+ if self.isPublic:
+ urlName = 'geocamTiePoint_publicTile'
+ else:
+ urlName = 'geocamTiePoint_tile'
+ result['alignedTilesUrl'] = reverse(urlName,
args=[str(self.alignedQuadTree.id),
'[ZOOM]',
'[X]',
@@ -264,3 +301,8 @@ def generateExportZip(self):
(self.getExportName(),
self.getJsonDict()))
return self.alignedQuadTree.exportZip
+
+ def updateAlignment(self):
+ toPts, fromPts = transform.splitPoints(self.extras.points)
+ tform = transform.getTransform(toPts, fromPts)
+ self.extras.transform = tform.getJsonDict()
@@ -4,18 +4,23 @@
# All Rights Reserved.
# __END_LICENSE__
-"""
-Levenberg-Marquardt optimization algorithm. This is a Python adaptation of
-the C++ L-M implementation from the NASA Vision Workbench.
-"""
-
import logging
from geocamTiePoint import settings
import numpy
from numpy.linalg import norm
+try:
+ from scipy.optimize import leastsq
+ HAVE_SCIPY_LEASTSQ = True
+except ImportError:
+ HAVE_SCIPY_LEASTSQ = False
+
+if HAVE_SCIPY_LEASTSQ:
+ import threading
+ scipyLeastSqLockG = threading.Lock()
+
# default arguments
LM_DEFAULT_ABS_TOLERANCE = 1e-16
LM_DEFAULT_REL_TOLERANCE = 1e-16
@@ -40,7 +45,7 @@ def jacobian(x):
result = numpy.zeros((n, k))
for i in xrange(k):
xp = x.copy()
- eps = 1e-7 + 1e-7 * x[i]
+ eps = 1e-7 + abs(1e-7 * x[i])
xp[i] += eps
yp = f(xp)
result[:, i] = (yp - y) / eps
@@ -64,6 +69,9 @@ def lm(y, f, x0,
in the neighborhood of x0. The default diff function is simple
subtraction. You can improve numerical stability by providing an
analytical jacobian for f.
+
+ This is a Python adaptation of the C++ L-M implementation from the
+ NASA Vision Workbench.
"""
logger = logging.getLogger('LM')
logger.setLevel(getattr(logging, settings.GEOCAM_TIE_POINT_OPTIMIZE_LOG_LEVEL))
@@ -106,9 +114,9 @@ def lm(y, f, x0,
J = jacobian(x)
- delJ = -1.0 * Rinv * (J.transpose() * error)
+ delJ = -1.0 * Rinv * J.transpose().dot(error)
# Hessian of cost function (using Gauss-Newton approximation)
- hessian = Rinv * (J.transpose() * J)
+ hessian = Rinv * J.transpose().dot(J)
iterations = 0
normTry = normStart + 1.0
@@ -121,7 +129,7 @@ def lm(y, f, x0,
# Solve for update
soln, _residues, _rank, _sngVal = numpy.linalg.lstsq(hessianLm, delJ)
- deltaX = soln.diagonal()
+ deltaX = soln
# update parameter vector
xTry = x - deltaX
@@ -178,6 +186,18 @@ def lm(y, f, x0,
return x, status
+def optimize(y, f, x0):
+ if HAVE_SCIPY_LEASTSQ:
+ # ack! scipy.optimize.leastsq is not thread-safe
+ scipyLeastSqLockG.acquire()
+ x, _cov = leastsq(lambda x: y - f(x), x0)
+ scipyLeastSqLockG.release()
+ return x
+ else:
+ x, _status = lm(y, f, x0)
+ return x
+
+
def test():
logging.basicConfig(level=logging.DEBUG)
Oops, something went wrong.

0 comments on commit b3238f7

Please sign in to comment.