Skip to content

Commit 89c7d4e

Browse files
Merge branch 'main' into feat/dg-154-expose-sam3-visual-segment-endpoint
2 parents c4ed280 + d6d7061 commit 89c7d4e

File tree

3 files changed

+59
-5
lines changed
  • inference/core

3 files changed

+59
-5
lines changed

inference/core/interfaces/webrtc_worker/utils.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ def detect_image_output(
4141
def process_frame(
4242
frame: VideoFrame,
4343
frame_id: int,
44+
declared_fps: float,
45+
measured_fps: float,
46+
comes_from_video_file: bool,
4447
inference_pipeline: InferencePipeline,
4548
stream_output: Optional[str] = None,
4649
render_output: bool = True,
@@ -59,9 +62,9 @@ def process_frame(
5962
image=np_image,
6063
frame_id=frame_id,
6164
frame_timestamp=datetime.datetime.now(),
62-
comes_from_video_file=False,
63-
fps=30, # placeholder
64-
measured_fps=30, # placeholder
65+
comes_from_video_file=comes_from_video_file,
66+
fps=declared_fps,
67+
measured_fps=measured_fps,
6568
)
6669
workflow_output = inference_pipeline._on_video_frame([video_frame])[0]
6770
except Exception as e:

inference/core/interfaces/webrtc_worker/webrtc.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def __init__(
231231
realtime_processing: bool = True,
232232
is_preview: bool = False,
233233
):
234+
self._file_processing = False
234235
self._loop = asyncio_loop
235236
self._termination_date = termination_date
236237
self._terminate_event = terminate_event
@@ -620,6 +621,9 @@ async def _process_frame_async(
620621
process_frame,
621622
frame,
622623
frame_id,
624+
self._declared_fps,
625+
self._declared_fps, # TODO: measure fps
626+
self._file_processing,
623627
self._inference_pipeline,
624628
stream_output,
625629
render_output,
@@ -1140,6 +1144,7 @@ async def on_upload_message(message):
11401144
None, process_video_upload_message, message, video_processor
11411145
)
11421146
if video_path:
1147+
video_processor._file_processing = True
11431148
logger.info(
11441149
"Video upload complete, processing: realtime=%s, path=%s",
11451150
webrtc_request.webrtc_realtime_processing,

inference/core/workflows/core_steps/transformations/camera_calibration/v1.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
WorkflowImageData,
1010
)
1111
from inference.core.workflows.execution_engine.entities.types import (
12+
BOOLEAN_KIND,
1213
FLOAT_KIND,
1314
IMAGE_KIND,
1415
Selector,
@@ -153,6 +154,14 @@ class BlockManifest(WorkflowBlockManifest):
153154
description="Second tangential distortion coefficient. Part of the camera's distortion parameters used to correct additional tangential distortion effects. p2 works together with p1 to correct lens misalignment distortions. Obtained through camera calibration. For well-aligned lenses, p1 and p2 are often close to zero.",
154155
examples=[0.123, "$inputs.p2"],
155156
)
157+
use_fisheye_model: Union[
158+
Optional[bool],
159+
Selector(kind=[BOOLEAN_KIND]),
160+
] = Field(
161+
default=False,
162+
description="Enable Fisheye distortion model (Rational/Divisional). If true, uses a different mathematical model better suited for fisheye lenses. When enabled, k1 is the primary parameter, and other coefficients are typically 0.",
163+
examples=[True, "$inputs.use_fisheye_model"],
164+
)
156165

157166
@classmethod
158167
def describe_outputs(cls) -> List[OutputDefinition]:
@@ -183,6 +192,7 @@ def run(
183192
k3: float,
184193
p1: float,
185194
p2: float,
195+
use_fisheye_model: bool = False,
186196
) -> BlockResult:
187197
return {
188198
OUTPUT_CALIBRATED_IMAGE_KEY: remove_distortions(
@@ -196,6 +206,7 @@ def run(
196206
k3=k3,
197207
p1=p1,
198208
p2=p2,
209+
use_fisheye_model=use_fisheye_model,
199210
)
200211
}
201212

@@ -211,12 +222,47 @@ def remove_distortions(
211222
k3: float,
212223
p1: float,
213224
p2: float,
225+
use_fisheye_model: bool = False,
214226
) -> Optional[WorkflowImageData]:
215227
img = image.numpy_image
216228
h, w = img.shape[:2]
217229

218-
cameraMatrix = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float64)
219-
distCoeffs = np.array([k1, k2, p1, p2, k3], dtype=np.float64)
230+
if use_fisheye_model:
231+
# 1. Generate grid for the destination (undistorted) image
232+
grid_y, grid_x = np.mgrid[0:h, 0:w].astype(np.float32)
233+
234+
# 2. Normalize coordinates using original matrix (results in a center crop)
235+
x = (grid_x - cx) / fx
236+
y = (grid_y - cy) / fy
237+
r2 = x**2 + y**2
238+
239+
# 3. Apply the SimpleDivisional Distortion formula (matches GeoCalib)
240+
if abs(k1) < 1e-8:
241+
scale = 1.0
242+
else:
243+
# Formula: p_dist = p_undist * (1 - sqrt(1 - 4*k1*r2)) / (2*k1*r2)
244+
discriminant = 1 - 4 * k1 * r2
245+
# Clamp to 0 to avoid NaNs
246+
discriminant[discriminant < 0] = 0
247+
scale = (1 - np.sqrt(discriminant)) / (2 * k1 * r2)
248+
# Handle center pixel or very small r2 to avoid division by zero / instability
249+
scale[np.abs(r2) < 1e-8] = 1.0
250+
251+
# 4. Map back to Source (distorted) pixels
252+
map_x = (x * scale * fx) + cx
253+
map_y = (y * scale * fy) + cy
254+
255+
# 5. Remap using OpenCV
256+
dst = cv.remap(
257+
img, map_x.astype(np.float32), map_y.astype(np.float32), cv.INTER_LINEAR
258+
)
259+
return WorkflowImageData(
260+
parent_metadata=image.parent_metadata,
261+
numpy_image=dst,
262+
)
263+
264+
cameraMatrix = np.array([[fx, 0, cx], [0, fy, cy], [0, 0, 1]], dtype=np.float32)
265+
distCoeffs = np.array([k1, k2, p1, p2, k3], dtype=np.float32)
220266

221267
# https://docs.opencv.org/4.11.0/d9/d0c/group__calib3d.html#ga7a6c4e032c97f03ba747966e6ad862b1
222268
newcameramtx, roi = cv.getOptimalNewCameraMatrix(

0 commit comments

Comments
 (0)