http://wiki.agisoft.com/w/index.php?title=Quick_layout.py&feed=atom&action=history
Quick layout.py - Revision history
2024-03-29T09:30:49Z
Revision history for this page on the wiki
MediaWiki 1.24.1
http://wiki.agisoft.com/w/index.php?title=Quick_layout.py&diff=202&oldid=prev
Alexey at 12:13, 17 February 2017
2017-02-17T12:13:42Z
<p></p>
<table class='diff diff-contentalign-left'>
<col class='diff-marker' />
<col class='diff-content' />
<col class='diff-marker' />
<col class='diff-content' />
<tr style='vertical-align: top;'>
<td colspan='2' style="background-color: white; color:black; text-align: center;">← Older revision</td>
<td colspan='2' style="background-color: white; color:black; text-align: center;">Revision as of 12:13, 17 February 2017</td>
</tr><tr><td colspan="2" class="diff-lineno">Line 1:</td>
<td colspan="2" class="diff-lineno">Line 1:</td></tr>
<tr><td class='diff-marker'>−</td><td style="color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;"><div><pre>import PhotoScan as ps</div></td><td class='diff-marker'>+</td><td style="color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div><pre></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div><ins class="diffchange diffchange-inline">#created by GeoScan Ltd. (http://geoscan.aero)</ins></div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div> </div></td></tr>
<tr><td colspan="2"> </td><td class='diff-marker'>+</td><td style="color:black; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;"><div>import PhotoScan as ps</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;"><div>import math</div></td><td class='diff-marker'> </td><td style="background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;"><div>import math</div></td></tr>
<tr><td class='diff-marker'> </td><td style="background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;"><div>import os, sys</div></td><td class='diff-marker'> </td><td style="background-color: #f9f9f9; color: #333333; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #e6e6e6; vertical-align: top; white-space: pre-wrap;"><div>import os, sys</div></td></tr>
</table>
Alexey
http://wiki.agisoft.com/w/index.php?title=Quick_layout.py&diff=200&oldid=prev
Alexey: Created page with "<pre>import PhotoScan as ps import math import os, sys import time try: from PySide2.QtGui import * from PySide2.QtCore import * from PySide2.QtWidgets import * ex..."
2017-02-16T11:00:53Z
<p>Created page with "<pre>import PhotoScan as ps import math import os, sys import time try: from PySide2.QtGui import * from PySide2.QtCore import * from PySide2.QtWidgets import * ex..."</p>
<p><b>New page</b></p><div><pre>import PhotoScan as ps<br />
import math<br />
import os, sys<br />
import time<br />
try:<br />
from PySide2.QtGui import *<br />
from PySide2.QtCore import *<br />
from PySide2.QtWidgets import *<br />
except ImportError:<br />
from PySide.QtGui import *<br />
from PySide.QtCore import *<br />
import copy<br />
<br />
<br />
def time_measure(func):<br />
def wrapper(*args, **kwargs):<br />
t1 = time.time()<br />
res = func(*args, **kwargs)<br />
t2 = time.time()<br />
print("Finished processing in {} sec.".format(t2 - t1))<br />
return res<br />
return wrapper<br />
<br />
<br />
def delta_vector_to_chunk(v1, v2):<br />
chunk = ps.app.document.chunk<br />
v1 = chunk.crs.unproject(v1)<br />
v2 = chunk.crs.unproject(v2)<br />
v1 = chunk.transform.matrix.inv().mulp(v1)<br />
v2 = chunk.transform.matrix.inv().mulp(v2)<br />
z = v2 - v1<br />
z.normalize()<br />
<br />
return z<br />
<br />
<br />
def get_chunk_vectors(lat, lon):<br />
z = delta_vector_to_chunk(ps.Vector([lon, lat, 0]), ps.Vector([lon, lat, 1]))<br />
y = delta_vector_to_chunk(ps.Vector([lon, lat, 0]), ps.Vector([lon + 0.001, lat, 0]))<br />
x = delta_vector_to_chunk(ps.Vector([lon, lat, 0]), ps.Vector([lon, lat+0.001, 0]))<br />
return x,y,-z<br />
<br />
<br />
def wgs_to_chunk(chunk, point):<br />
return chunk.transform.matrix.inv().mulp(chunk.crs.unproject(point))<br />
<br />
<br />
def show_message(msg):<br />
msgBox = QMessageBox()<br />
print(msg)<br />
msgBox.setText(msg)<br />
msgBox.exec()<br />
<br />
<br />
def check_chunk(chunk):<br />
if chunk is None or len(chunk.cameras) == 0:<br />
show_message("Empty chunk!")<br />
return False<br />
<br />
if chunk.crs is None:<br />
show_message("Initialize chunk coordinate system first")<br />
return False<br />
<br />
return True<br />
<br />
<br />
# returns distance estimation between two cameras in chunk<br />
def get_photos_delta(chunk):<br />
mid_idx = int(len(chunk.cameras) / 2)<br />
if mid_idx == 0:<br />
return ps.Vector([0,0,0])<br />
c1 = chunk.cameras[:mid_idx][-1]<br />
c2 = chunk.cameras[:mid_idx][-2]<br />
print(c1.reference.location)<br />
print(c2.reference.location)<br />
offset = c1.reference.location - c2.reference.location<br />
for i in range(len(offset)):<br />
offset[i] = math.fabs(offset[i])<br />
return offset<br />
<br />
<br />
def get_chunk_bounds(chunk):<br />
min_latitude = min(c.reference.location[1] for c in chunk.cameras if c.reference.location is not None)<br />
max_latitude = max(c.reference.location[1] for c in chunk.cameras if c.reference.location is not None)<br />
min_longitude = min(c.reference.location[0] for c in chunk.cameras if c.reference.location is not None)<br />
max_longitude = max(c.reference.location[0] for c in chunk.cameras if c.reference.location is not None)<br />
offset = get_photos_delta(chunk)<br />
offset_factor = 2<br />
delta_latitude = offset_factor * offset.y<br />
delta_longitude = offset_factor * offset.x<br />
<br />
min_longitude -= delta_longitude<br />
max_longitude += delta_longitude<br />
min_latitude -= delta_latitude<br />
max_latitude += delta_latitude<br />
<br />
return min_latitude, min_longitude, max_latitude, max_longitude<br />
<br />
<br />
# Evaluates rotation matrices for cameras that have location<br />
# algorithm is straightforward: we assume copter has zero pitch and roll,<br />
# and yaw is evaluated from current copter direction<br />
# current direction is evaluated simply subtracting location of<br />
# current camera from the next camera location<br />
# i and j are unit axis vectors in chunk coordinate system<br />
# i || North<br />
def estimate_rotation_matrices(chunk, i, j):<br />
groups = copy.copy(chunk.camera_groups)<br />
<br />
groups.append(None)<br />
for group in groups:<br />
group_cameras = list(filter(lambda c: c.group == group, chunk.cameras))<br />
<br />
if len(group_cameras) == 0:<br />
continue<br />
<br />
if len(group_cameras) == 1:<br />
if group_cameras[0].reference.rotation is None:<br />
group_cameras[0].reference.rotation = ps.Vector([0,0,0])<br />
continue<br />
<br />
<br />
for idx, c in enumerate(group_cameras[0:-1]):<br />
next_camera = group_cameras[idx+1]<br />
<br />
if c.reference.rotation is None:<br />
if c.reference.location is None or next_camera.reference.location is None:<br />
continue<br />
direction = delta_vector_to_chunk(c.reference.location, next_camera.reference.location)<br />
<br />
cos_yaw = direction * j<br />
yaw = math.degrees(math.acos(cos_yaw)) + 90 # TODO not sure about this offset<br />
<br />
if direction * i > 0:<br />
yaw = -yaw<br />
<br />
c.reference.rotation = ps.Vector([yaw, 0, 0])<br />
<br />
group_cameras[-1].reference.rotation = group_cameras[-2].reference.rotation<br />
<br />
@time_measure<br />
def align_cameras(chunk, min_latitude, min_longitude):<br />
if chunk.transform.scale is None:<br />
chunk.transform.scale = 1<br />
chunk.transform.rotation = ps.Matrix([[1,0,0], [0,1,0], [0,0,1]])<br />
chunk.transform.translation = ps.Vector([0,0,0])<br />
<br />
i, j, k = get_chunk_vectors(min_latitude, min_longitude) # i || North<br />
estimate_rotation_matrices(chunk, i, j)<br />
<br />
for c in chunk.cameras:<br />
if c.transform is not None:<br />
continue<br />
<br />
location = c.reference.location<br />
if location is None:<br />
continue<br />
chunk_coordinates = wgs_to_chunk(chunk, location)<br />
fi = c.reference.rotation.x + 90<br />
fi = math.radians(fi)<br />
roll = math.radians(c.reference.rotation.z)<br />
pitch = math.radians(c.reference.rotation.y)<br />
<br />
roll_mat = ps.Matrix([[1, 0, 0], [0, math.cos(roll), -math.sin(roll)], [0, math.sin(roll), math.cos(roll)]])<br />
pitch_mat = ps.Matrix([[math.cos(pitch), 0, math.sin(pitch)], [0, 1, 0], [-math.sin(pitch), 0, math.cos(pitch)]])<br />
yaw_mat = ps.Matrix([[math.cos(fi), -math.sin(fi), 0], [math.sin(fi), math.cos(fi), 0], [0, 0, 1]])<br />
<br />
r = roll_mat * pitch_mat * yaw_mat<br />
<br />
ii = r[0, 0] * i + r[1, 0] * j + r[2, 0] * k<br />
jj = r[0, 1] * i + r[1, 1] * j + r[2, 1] * k<br />
kk = r[0, 2] * i + r[1, 2] * j + r[2, 2] * k<br />
<br />
c.transform = ps.Matrix([[ii.x, jj.x, kk.x, chunk_coordinates[0]],<br />
[ii.y, jj.y, kk.y, chunk_coordinates[1]],<br />
[ii.z, jj.z, kk.z, chunk_coordinates[2]],<br />
[0, 0, 0, 1]])<br />
<br />
<br />
def run_camera_alignment():<br />
doc = ps.app.document<br />
chunk = doc.chunk<br />
<br />
if not check_chunk(chunk):<br />
return<br />
<br />
min_latitude, min_longitude, max_latitude, max_longitude = get_chunk_bounds(chunk)<br />
try:<br />
align_cameras(chunk, min_latitude, min_longitude)<br />
except Exception as e:<br />
print(e)<br />
<br />
ps.app.addMenuItem("Plugins" + "/" + "Apply Vertical Camera Alignment", run_camera_alignment)</pre></div>
Alexey