1 # SPDX-License-Identifier: GPL-2.0-or-later
4 "name": "Refine tracking solution",
5 "author": "Stephen Leger",
9 "location": "Clip Editor > Tools > Solve > Refine Solution",
10 "description": "Refine motion solution by setting track weight according"
11 " to reprojection error",
13 "doc_url": "{BLENDER_MANUAL_URL}/addons/video_tools/refine_tracking.html",
14 "category": "Video Tools",
18 from bpy
.types
import (
22 from bpy
.props
import FloatProperty
23 from mathutils
import Vector
26 class TRACKING_OP_refine_solution(Operator
):
27 bl_idname
= "tracking.refine_solution"
29 bl_description
= "Set track weight by error and solve camera motion"
33 def poll(cls
, context
):
34 return (context
.area
and context
.area
.spaces
and
35 hasattr(context
.area
.spaces
.active
, 'clip') and
36 context
.area
.spaces
.active
.clip
is not None
39 def execute(self
, context
):
40 error
= context
.window_manager
.TrackingTargetError
41 smooth
= context
.window_manager
.TrackingSmooth
42 clip
= context
.area
.spaces
.active
.clip
44 tracking
= clip
.tracking
45 tracks
= tracking
.tracks
46 winx
= float(clip
.size
[0])
47 winy
= float(clip
.size
[1])
48 aspy
= 1.0 / tracking
.camera
.pixel_aspect
49 start
= tracking
.reconstruction
.cameras
[0].frame
50 end
= tracking
.reconstruction
.cameras
[-1].frame
54 marker_position
= Vector()
56 for frame
in range(start
, end
):
57 camera
= tracking
.reconstruction
.cameras
.find_frame(frame
=frame
)
58 if camera
is not None:
59 camera_invert
= camera
.matrix
.inverted()
63 for track
in tracking
.tracks
:
64 marker
= track
.markers
.find_frame(frame
)
68 # weight incomplete tracks on start and end
69 if frame
> start
+ smooth
and frame
< end
- smooth
:
70 for m
in track
.markers
:
74 for m
in reversed(track
.markers
):
78 dt
= min(0.5 * (tend
.frame
- tstart
.frame
), smooth
)
80 t0
= min(1.0, (frame
- tstart
.frame
) / dt
)
81 t1
= min(1.0, (tend
.frame
- frame
) / dt
)
88 reprojected_position
= camera_invert
@ track
.bundle
89 if reprojected_position
.z
== 0:
91 track
.keyframe_insert("weight", frame
=frame
)
93 reprojected_position
= reprojected_position
/ -reprojected_position
.z
* \
94 tracking
.camera
.focal_length_pixels
95 reprojected_position
= Vector(
96 (tracking
.camera
.principal_point_pixels
[0] + reprojected_position
[0],
97 tracking
.camera
.principal_point_pixels
[1] * aspy
+ reprojected_position
[1], 0)
100 marker_position
[0] = (marker
.co
[0] + track
.offset
[0]) * winx
101 marker_position
[1] = (marker
.co
[1] + track
.offset
[1]) * winy
* aspy
103 dp
= marker_position
- reprojected_position
107 track
.weight
= min(1.0, tw
* error
/ dp
.length
)
108 track
.keyframe_insert("weight", frame
=frame
)
110 bpy
.ops
.clip
.solve_camera('INVOKE_DEFAULT')
115 class TRACKING_OP_reset_solution(Operator
):
116 bl_idname
= "tracking.reset_solution"
118 bl_description
= "Reset track weight and solve camera motion"
119 bl_options
= {"UNDO"}
122 def poll(cls
, context
):
123 return (context
.area
.spaces
.active
.clip
is not None)
125 def execute(self
, context
):
126 clip
= context
.area
.spaces
.active
.clip
128 tracking
= clip
.tracking
129 tracks
= tracking
.tracks
130 start
= tracking
.reconstruction
.cameras
[0].frame
131 end
= tracking
.reconstruction
.cameras
[-1].frame
135 start
= tracking
.reconstruction
.cameras
[0].frame
136 end
= tracking
.reconstruction
.cameras
[-1].frame
137 for frame
in range(start
, end
):
138 camera
= tracking
.reconstruction
.cameras
.find_frame(frame
=frame
)
141 for track
in tracking
.tracks
:
142 marker
= track
.markers
.find_frame(frame
=frame
)
146 track
.keyframe_insert("weight", frame
=frame
)
148 bpy
.ops
.clip
.solve_camera('INVOKE_DEFAULT')
153 class TRACKING_PT_RefineMotionTracking(Panel
):
154 bl_label
= "Refine solution"
155 bl_space_type
= "CLIP_EDITOR"
156 bl_region_type
= "TOOLS"
157 bl_category
= "Solve"
160 def poll(cls
, context
):
161 return (context
.area
.spaces
.active
.clip
is not None)
163 def draw(self
, context
):
166 col
= layout
.column(align
=True)
167 col
.prop(context
.window_manager
, "TrackingTargetError", text
="Target error")
168 col
.prop(context
.window_manager
, "TrackingSmooth", text
="Smooth transition")
170 sub_box
.scale_y
= 0.25
172 row
= col
.row(align
=True)
173 row
.operator("tracking.refine_solution")
174 row
.operator("tracking.reset_solution")
178 TRACKING_OP_refine_solution
,
179 TRACKING_OP_reset_solution
,
180 TRACKING_PT_RefineMotionTracking
185 bpy
.types
.WindowManager
.TrackingTargetError
= FloatProperty(
187 description
="Refine motion track target error",
191 bpy
.types
.WindowManager
.TrackingSmooth
= FloatProperty(
192 name
="Smooth Transition",
193 description
="Smooth weight transition on start and end of incomplete tracks",
198 bpy
.utils
.register_class(cls
)
202 for cls
in reversed(classes
):
203 bpy
.utils
.unregister_class(cls
)
204 del bpy
.types
.WindowManager
.TrackingTargetError
205 del bpy
.types
.WindowManager
.TrackingSmooth
208 if __name__
== "__main__":