1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
#pragma once
// Procedure used to generate the inverse warping function
// Terminologies:
// - Input : image captured by the camera
// - Intermediate : projection of "Input" to an intermediate sphere of radius = 1
// - Output: an equi-rectangular projection of the Intermediate sphere onto a cylinder
#define WARPCOORD_OUTPUT_TO_INPUT_KERNEL(fromSphereToInput, isWithin, distortionMetersTransform, \
distortionPixelsTransform) \
__global__ void \
warpCoordOutputToInputKernel_##fromSphereToInput##_##isWithin##_##distortionMetersTransform##_##distortionPixelsTransform( \
float2* g_odata, uint32_t* g_mask, int id, int offsetX, int offsetY, int croppedWidth, int croppedHeight, \
int panoWidth, int panoHeight, int inputWidth, int inputHeight, int cropLeft, int cropRight, int cropTop, \
int cropBottom, const float2 panoScale, const vsfloat3x4 perspectiveMatrix, const float2 inputScale, \
const vsDistortion distortion, const float2 centerShift) { \
/* Calculate the normalized texture coordinates */ \
const int x = blockIdx.x * blockDim.x + threadIdx.x; \
const int y = blockIdx.y * blockDim.y + threadIdx.y; \
\
if (x < croppedWidth && y < croppedHeight) { \
float2 uv = make_float2((x + offsetX) % panoWidth, y + offsetY); \
\
/*To Center coordinates*/ \
uv.x -= panoWidth / 2.0f; \
uv.y -= panoHeight / 2.0f; \
\
uv = mapPanoramaToInput_##fromSphereToInput##_##distortionMetersTransform##_##distortionPixelsTransform( \
uv, panoScale, perspectiveMatrix, inputScale, distortion, centerShift); \
\
/** \
* Move to center-based coordinate \
*/ \
uv.x += inputWidth / 2.0f; \
uv.y += inputHeight / 2.0f; \
\
/* check if uv stay inside of the input buffer coordinate */ \
if (isWithin(uv, (float)inputWidth, (float)inputHeight, (float)cropLeft, (float)cropRight, (float)cropTop, \
(float)cropBottom)) { \
g_odata[y * croppedWidth + x] = uv - make_float2(0.5, 0.5); \
g_mask[y * croppedWidth + x] = 1 << id; \
} else if (g_mask[y * croppedWidth + x] == 0) { \
/* This is a hack to solve the discretization problem when smaller map is used for coordinate lookup \
* When it is just a bit outside of the mask, search around its neighbor and set the first valid coord to the \
* lookup mask \
* @TODO: Find a proper way to deal with this \
*/ \
const float dir[2] = {1, -1}; \
for (float r = 0; r <= 3; r += 0.5) { \
for (float j = 0; j <= r; j += 0.1) { \
float i = sqrt(r * r - j * j); \
for (int dirX = 0; dirX < 2; dirX++) \
for (int dirY = 0; dirY < 2; dirY++) { \
if (isWithin(uv + make_float2(dir[dirX] * i, dir[dirY] * j), (float)inputWidth, (float)inputHeight, \
(float)cropLeft, (float)cropRight, (float)cropTop, (float)cropBottom)) { \
g_odata[y * croppedWidth + x] = \
uv - make_float2(0.5, 0.5) + make_float2(dir[dirX] * i, dir[dirY] * j); \
g_mask[y * croppedWidth + x] = 1 << id; \
return; \
} \
} \
} \
} \
g_odata[y * croppedWidth + x] = make_float2(INVALID_FLOW_VALUE, INVALID_FLOW_VALUE); \
g_mask[y * croppedWidth + x] = 0; \
} \
} \
}
#define WARPCOORD_OUTPUT_TO_INPUT_KERNEL2(RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToRect, isWithinCropRect, RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToErect, isWithinCropRect, RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToFisheye, isWithinCropCircle, RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToFisheye, isWithinCropRect, RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToExternal, isWithinCropCircle, RADIAL1, RADIAL2) \
WARPCOORD_OUTPUT_TO_INPUT_KERNEL(SphereToExternal, isWithinCropRect, RADIAL1, RADIAL2)