Fix T52833: OBJ triangulate doesn't match viewport
[blender-addons.git] / space_clip_editor_refine_solution.py
bloba3287b78873cd1cc26e778e88fc00836f99a438b
1 # -*- coding:utf-8 -*-
3 # ##### BEGIN GPL LICENSE BLOCK #####
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 # All rights reserved.
19 # ##### END GPL LICENSE BLOCK #####
21 bl_info = {
22 "name": "Refine tracking solution",
23 "author": "Stephen Leger",
24 "license": "GPL",
25 "version": (1, 1, 3),
26 "blender": (2, 7, 8),
27 "location": "Clip Editor > Tools > Solve > Refine Solution",
28 "description": "Refine motion solution by setting track weight according"
29 " to reprojection error",
30 "warning": "",
31 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/"
32 "Motion_Tracking/Refine_Track",
33 "category": "Motion Tracking",
36 import bpy
37 from bpy.types import (
38 Operator,
39 Panel,
41 from bpy.props import FloatProperty
42 from mathutils import Vector
45 class OP_Tracking_refine_solution(Operator):
46 bl_idname = "tracking.refine_solution"
47 bl_label = "Refine"
48 bl_description = "Set track weight by error and solve camera motion"
49 bl_options = {"UNDO"}
51 @classmethod
52 def poll(cls, context):
53 return (context.area.spaces.active.clip is not None)
55 def execute(self, context):
56 error = context.window_manager.TrackingTargetError
57 smooth = context.window_manager.TrackingSmooth
58 clip = context.area.spaces.active.clip
59 try:
60 tracking = clip.tracking
61 tracks = tracking.tracks
62 winx = float(clip.size[0])
63 winy = float(clip.size[1])
64 aspy = 1.0 / tracking.camera.pixel_aspect
65 start = tracking.reconstruction.cameras[0].frame
66 end = tracking.reconstruction.cameras[-1].frame
67 except:
68 return {'CANCELLED'}
70 marker_position = Vector()
72 for frame in range(start, end):
73 camera = tracking.reconstruction.cameras.find_frame(frame)
74 if camera is not None:
75 imat = camera.matrix.inverted()
76 projection_matrix = imat.transposed()
77 else:
78 continue
80 for track in tracking.tracks:
81 marker = track.markers.find_frame(frame)
82 if marker is None:
83 continue
85 # weight incomplete tracks on start and end
86 if frame > start + smooth and frame < end - smooth:
87 for m in track.markers:
88 if not m.mute:
89 tstart = m
90 break
91 for m in reversed(track.markers):
92 if not m.mute:
93 tend = m
94 break
95 dt = min(0.5 * (tend.frame - tstart.frame), smooth)
96 if dt > 0:
97 t0 = min(1.0, (frame - tstart.frame) / dt)
98 t1 = min(1.0, (tend.frame - frame) / dt)
99 tw = min(t0, t1)
100 else:
101 tw = 0.0
102 else:
103 tw = 1.0
105 reprojected_position = track.bundle * projection_matrix
106 if reprojected_position.z == 0:
107 track.weight = 0
108 track.keyframe_insert("weight", frame=frame)
109 continue
110 reprojected_position = reprojected_position / -reprojected_position.z * \
111 tracking.camera.focal_length_pixels
112 reprojected_position = Vector(
113 (tracking.camera.principal[0] + reprojected_position[0],
114 tracking.camera.principal[1] * aspy + reprojected_position[1], 0)
117 marker_position[0] = (marker.co[0] + track.offset[0]) * winx
118 marker_position[1] = (marker.co[1] + track.offset[1]) * winy * aspy
120 dp = marker_position - reprojected_position
121 if dp.length == 0:
122 track.weight = 1.0
123 else:
124 track.weight = min(1.0, tw * error / dp.length)
125 track.keyframe_insert("weight", frame=frame)
127 bpy.ops.clip.solve_camera('INVOKE_DEFAULT')
129 return{'FINISHED'}
132 class OP_Tracking_reset_solution(Operator):
133 bl_idname = "tracking.reset_solution"
134 bl_label = "Reset"
135 bl_description = "Reset track weight and solve camera motion"
136 bl_options = {"UNDO"}
138 @classmethod
139 def poll(cls, context):
140 return (context.area.spaces.active.clip is not None)
142 def execute(self, context):
143 clip = context.area.spaces.active.clip
144 try:
145 tracking = clip.tracking
146 tracks = tracking.tracks
147 start = tracking.reconstruction.cameras[0].frame
148 end = tracking.reconstruction.cameras[-1].frame
149 except:
150 return {'CANCELLED'}
152 start = tracking.reconstruction.cameras[0].frame
153 end = tracking.reconstruction.cameras[-1].frame
154 for frame in range(start, end):
155 camera = tracking.reconstruction.cameras.find_frame(frame)
156 if camera is None:
157 continue
158 for track in tracking.tracks:
159 marker = track.markers.find_frame(frame)
160 if marker is None:
161 continue
162 track.weight = 1.0
163 track.keyframe_insert("weight", frame=frame)
165 bpy.ops.clip.solve_camera('INVOKE_DEFAULT')
167 return{'FINISHED'}
170 class RefineMotionTrackingPanel(Panel):
171 bl_label = "Refine solution"
172 bl_space_type = "CLIP_EDITOR"
173 bl_region_type = "TOOLS"
174 bl_category = "Solve"
176 @classmethod
177 def poll(cls, context):
178 return (context.area.spaces.active.clip is not None)
180 def draw(self, context):
181 layout = self.layout
183 col = layout.column(align=True)
184 col.prop(context.window_manager, "TrackingTargetError", text="Target error")
185 col.prop(context.window_manager, "TrackingSmooth", text="Smooth transition")
186 sub_box = col.box()
187 sub_box.scale_y = 0.25
189 row = col.row(align=True)
190 row.operator("tracking.refine_solution")
191 row.operator("tracking.reset_solution")
194 def register():
195 bpy.types.WindowManager.TrackingTargetError = FloatProperty(
196 name="Target Error",
197 description="Refine motion track target error",
198 default=0.3,
199 min=0.01
201 bpy.types.WindowManager.TrackingSmooth = FloatProperty(
202 name="Smooth Transition",
203 description="Smooth weight transition on start and end of incomplete tracks",
204 default=25,
205 min=1
207 bpy.utils.register_module(__name__)
210 def unregister():
211 bpy.utils.unregister_module(__name__)
212 del bpy.types.WindowManager.TrackingTargetError
213 del bpy.types.WindowManager.TrackingSmooth
216 if __name__ == "__main__":
217 register()