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 #####
22 "name": "Refine tracking solution",
23 "author": "Stephen Leger",
27 "location": "Clip Editor > Tools > Solve > Refine Solution",
28 "description": "Refine motion solution by setting track weight according"
29 " to reprojection error",
31 "wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/"
32 "Motion_Tracking/Refine_Track",
33 "category": "Motion Tracking",
37 from bpy
.types
import (
41 from bpy
.props
import FloatProperty
42 from mathutils
import Vector
45 class OP_Tracking_refine_solution(Operator
):
46 bl_idname
= "tracking.refine_solution"
48 bl_description
= "Set track weight by error and solve camera motion"
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
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
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()
80 for track
in tracking
.tracks
:
81 marker
= track
.markers
.find_frame(frame
)
85 # weight incomplete tracks on start and end
86 if frame
> start
+ smooth
and frame
< end
- smooth
:
87 for m
in track
.markers
:
91 for m
in reversed(track
.markers
):
95 dt
= min(0.5 * (tend
.frame
- tstart
.frame
), smooth
)
97 t0
= min(1.0, (frame
- tstart
.frame
) / dt
)
98 t1
= min(1.0, (tend
.frame
- frame
) / dt
)
105 reprojected_position
= track
.bundle
* projection_matrix
106 if reprojected_position
.z
== 0:
108 track
.keyframe_insert("weight", frame
=frame
)
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
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')
132 class OP_Tracking_reset_solution(Operator
):
133 bl_idname
= "tracking.reset_solution"
135 bl_description
= "Reset track weight and solve camera motion"
136 bl_options
= {"UNDO"}
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
145 tracking
= clip
.tracking
146 tracks
= tracking
.tracks
147 start
= tracking
.reconstruction
.cameras
[0].frame
148 end
= tracking
.reconstruction
.cameras
[-1].frame
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
)
158 for track
in tracking
.tracks
:
159 marker
= track
.markers
.find_frame(frame
)
163 track
.keyframe_insert("weight", frame
=frame
)
165 bpy
.ops
.clip
.solve_camera('INVOKE_DEFAULT')
170 class RefineMotionTrackingPanel(Panel
):
171 bl_label
= "Refine solution"
172 bl_space_type
= "CLIP_EDITOR"
173 bl_region_type
= "TOOLS"
174 bl_category
= "Solve"
177 def poll(cls
, context
):
178 return (context
.area
.spaces
.active
.clip
is not None)
180 def draw(self
, context
):
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")
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")
195 bpy
.types
.WindowManager
.TrackingTargetError
= FloatProperty(
197 description
="Refine motion track target error",
201 bpy
.types
.WindowManager
.TrackingSmooth
= FloatProperty(
202 name
="Smooth Transition",
203 description
="Smooth weight transition on start and end of incomplete tracks",
207 bpy
.utils
.register_module(__name__
)
211 bpy
.utils
.unregister_module(__name__
)
212 del bpy
.types
.WindowManager
.TrackingTargetError
213 del bpy
.types
.WindowManager
.TrackingSmooth
216 if __name__
== "__main__":