test_projections.py 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals, division, print_function
  3. from math import log, tan, pi, radians
  4. import matplotlib.pyplot as plt
  5. import numpy as np
  6. from django.core.management.base import BaseCommand, CommandError
  7. from django.conf import settings
  8. from panorama.models import Panorama, Reference
  9. def bearing_diff(b1, b2):
  10. """In degrees"""
  11. return (b1 - b2) % 360
  12. def projection_factory(transform):
  13. def projection(location, p1, p2):
  14. """For now, simply returns the scaling factors for x and y given two reference points"""
  15. dx = (p2.x - p1.x) / (radians(bearing_diff(location.bearing(p2.reference_point), location.bearing(p1.reference_point))))
  16. dy = (p2.y - p1.y) / (transform(location.elevation(p2.reference_point)) - transform(location.elevation(p1.reference_point)))
  17. return (dx, dy)
  18. return projection
  19. equirectangular = projection_factory(lambda phi: radians(phi))
  20. cylindrical = projection_factory(lambda phi: tan(radians(phi)))
  21. mercator = projection_factory(lambda phi: log(tan(pi/4 + radians(phi)/2)))
  22. projections = [('equirectangular', equirectangular),
  23. ('cylindrical', cylindrical),
  24. ('mercator', mercator)]
  25. class Command(BaseCommand):
  26. def add_arguments(self, parser):
  27. parser.add_argument('pano_id', type=int)
  28. def handle(self, *args, **options):
  29. p = Panorama.objects.get(pk=options['pano_id'])
  30. for proj_name, proj in projections:
  31. self.stdout.write("\n{}".format(proj_name))
  32. data = {'distx': [], 'disty': [], 'dx': [], 'dy': [], 'ref1': [], 'ref2': [], 'middlex': [], 'ref1.x': []}
  33. for ref1 in p.panorama_references.order_by('x'):
  34. for ref2 in p.panorama_references.order_by('x'):
  35. if ref2 == ref1:
  36. continue
  37. if ref2.x >= ref1.x:
  38. (dx, dy) = proj(p, ref1, ref2)
  39. else:
  40. (dx, dy) = proj(p, ref2, ref1)
  41. distx = ref2.x - ref1.x
  42. disty = ref2.y - ref1.y
  43. middlex = (ref2.x + ref1.x) / 2
  44. data['ref1'].append(ref1)
  45. data['ref2'].append(ref2)
  46. data['ref1.x'].append(ref1.x)
  47. data['distx'].append(distx)
  48. data['disty'].append(disty)
  49. data['middlex'].append(middlex)
  50. data['dx'].append(dx)
  51. data['dy'].append(dy)
  52. #self.stdout.write('{} - {}'.format(ref1.reference_point.name, ref2.reference_point.name))
  53. #self.stdout.write('dx = {}'.format(dx))
  54. #self.stdout.write('dy = {}'.format(dy))
  55. # Detect outliers
  56. for axis in ['dx', 'dy']:
  57. median = np.median(data[axis])
  58. self.stdout.write("\nMedian for {}: {}".format(axis, median))
  59. for ref1, ref2, d in zip(data['ref1'], data['ref2'], data[axis]):
  60. if ref2.pk < ref1.pk:
  61. continue
  62. if abs(d - median) / median >= 0.15:
  63. self.stdout.write("Outlier: ({:5}, {:5}) - ({:5}, {:5}) → {}={}".format(ref1.x, ref1.y, ref2.x, ref2.y, axis, d))
  64. mediandx = np.median(data['dx'])
  65. mediandy = np.median(data['dy'])
  66. if proj_name == 'equirectangular':
  67. for xvar in ['distx', 'disty', 'middlex', 'ref1.x']:
  68. fig, ax = plt.subplots()
  69. ax.scatter(x=data[xvar], y=data['dx'], c=data['ref1.x'], alpha=0.5)
  70. ax.hlines([mediandx], 0, 1, transform=ax.get_yaxis_transform(), colors='r')
  71. ax.set_title('dx as a function of {}'.format(xvar))
  72. plt.show()
  73. for xvar in ['dx', 'distx', 'disty', 'middlex', 'ref1.x']:
  74. fig, ax = plt.subplots()
  75. ax.scatter(x=data[xvar], y=data['dy'], c=data['ref1.x'], alpha=0.5)
  76. ax.hlines([mediandy], 0, 1, transform=ax.get_yaxis_transform(), colors='r')
  77. ax.set_title('dy as a function of {}, for {} projection'.format(xvar, proj_name))
  78. plt.show()