|
|
|
@ -553,84 +553,122 @@ namespace cv { namespace gpu { namespace device |
|
|
|
|
level, block, stream); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <bool calcErr, bool GET_MIN_EIGENVALS> |
|
|
|
|
__global__ void lkDense(const PtrStepb I, const PtrStepb J, const PtrStep<short> dIdx, const PtrStep<short> dIdy, |
|
|
|
|
PtrStepf u, PtrStepf v, PtrStepf err, const int rows, const int cols) |
|
|
|
|
texture<uchar, cudaTextureType2D, cudaReadModeElementType> tex_I(false, cudaFilterModePoint, cudaAddressModeClamp); |
|
|
|
|
texture<float, cudaTextureType2D, cudaReadModeElementType> tex_J(false, cudaFilterModeLinear, cudaAddressModeClamp); |
|
|
|
|
|
|
|
|
|
template <bool calcErr> |
|
|
|
|
__global__ void lkDense(PtrStepf u, PtrStepf v, const PtrStepf prevU, const PtrStepf prevV, PtrStepf err, const int rows, const int cols) |
|
|
|
|
{ |
|
|
|
|
const int x = blockIdx.x * blockDim.x + threadIdx.x; |
|
|
|
|
const int y = blockIdx.y * blockDim.y + threadIdx.y; |
|
|
|
|
extern __shared__ int smem[]; |
|
|
|
|
|
|
|
|
|
const int patchWidth = blockDim.x + 2 * c_halfWin_x; |
|
|
|
|
const int patchHeight = blockDim.y + 2 * c_halfWin_y; |
|
|
|
|
|
|
|
|
|
int* I_patch = smem; |
|
|
|
|
int* dIdx_patch = I_patch + patchWidth * patchHeight; |
|
|
|
|
int* dIdy_patch = dIdx_patch + patchWidth * patchHeight; |
|
|
|
|
|
|
|
|
|
const int xBase = blockIdx.x * blockDim.x; |
|
|
|
|
const int yBase = blockIdx.y * blockDim.y; |
|
|
|
|
|
|
|
|
|
for (int i = threadIdx.y; i < patchHeight; i += blockDim.y) |
|
|
|
|
{ |
|
|
|
|
for (int j = threadIdx.x; j < patchWidth; j += blockDim.x) |
|
|
|
|
{ |
|
|
|
|
float x = xBase - c_halfWin_x + j + 0.5f; |
|
|
|
|
float y = yBase - c_halfWin_y + i + 0.5f; |
|
|
|
|
|
|
|
|
|
I_patch[i * patchWidth + j] = tex2D(tex_I, x, y); |
|
|
|
|
|
|
|
|
|
// Sharr Deriv |
|
|
|
|
|
|
|
|
|
dIdx_patch[i * patchWidth + j] = 3 * tex2D(tex_I, x+1, y-1) + 10 * tex2D(tex_I, x+1, y) + 3 * tex2D(tex_I, x+1, y+1) - |
|
|
|
|
(3 * tex2D(tex_I, x-1, y-1) + 10 * tex2D(tex_I, x-1, y) + 3 * tex2D(tex_I, x-1, y+1)); |
|
|
|
|
|
|
|
|
|
dIdy_patch[i * patchWidth + j] = 3 * tex2D(tex_I, x-1, y+1) + 10 * tex2D(tex_I, x, y+1) + 3 * tex2D(tex_I, x+1, y+1) - |
|
|
|
|
(3 * tex2D(tex_I, x-1, y-1) + 10 * tex2D(tex_I, x, y-1) + 3 * tex2D(tex_I, x+1, y-1)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
__syncthreads(); |
|
|
|
|
|
|
|
|
|
const int x = xBase + threadIdx.x; |
|
|
|
|
const int y = yBase + threadIdx.y; |
|
|
|
|
|
|
|
|
|
if (x >= cols || y >= rows) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
// extract the patch from the first image, compute covariation matrix of derivatives |
|
|
|
|
|
|
|
|
|
float A11 = 0; |
|
|
|
|
float A12 = 0; |
|
|
|
|
float A22 = 0; |
|
|
|
|
int A11i = 0; |
|
|
|
|
int A12i = 0; |
|
|
|
|
int A22i = 0; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < c_winSize_y; ++i) |
|
|
|
|
{ |
|
|
|
|
for (int j = 0; j < c_winSize_x; ++j) |
|
|
|
|
{ |
|
|
|
|
int ixval = dIdx(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
int iyval = dIdy(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
int dIdx = dIdx_patch[(threadIdx.y + i) * patchWidth + (threadIdx.x + j)]; |
|
|
|
|
int dIdy = dIdy_patch[(threadIdx.y + i) * patchWidth + (threadIdx.x + j)]; |
|
|
|
|
|
|
|
|
|
A11 += ixval * ixval; |
|
|
|
|
A12 += ixval * iyval; |
|
|
|
|
A22 += iyval * iyval; |
|
|
|
|
A11i += dIdx * dIdx; |
|
|
|
|
A12i += dIdx * dIdy; |
|
|
|
|
A22i += dIdy * dIdy; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
A11 *= SCALE; |
|
|
|
|
A12 *= SCALE; |
|
|
|
|
A22 *= SCALE; |
|
|
|
|
float A11 = A11i; |
|
|
|
|
float A12 = A12i; |
|
|
|
|
float A22 = A22i; |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
float D = A11 * A22 - A12 * A12; |
|
|
|
|
float minEig = (A22 + A11 - ::sqrtf((A11 - A22) * (A11 - A22) + 4.f * A12 * A12)) / (2 * c_winSize_x * c_winSize_y); |
|
|
|
|
|
|
|
|
|
if (calcErr && GET_MIN_EIGENVALS) |
|
|
|
|
err(y, x) = minEig; |
|
|
|
|
if (D < numeric_limits<float>::epsilon()) |
|
|
|
|
{ |
|
|
|
|
if (calcErr) |
|
|
|
|
err(y, x) = numeric_limits<float>::max(); |
|
|
|
|
|
|
|
|
|
if (minEig < c_minEigThreshold || D < numeric_limits<float>::epsilon()) |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
D = 1.f / D; |
|
|
|
|
|
|
|
|
|
A11 *= D; |
|
|
|
|
A12 *= D; |
|
|
|
|
A22 *= D; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float2 nextPt; |
|
|
|
|
nextPt.x = x - c_halfWin_x + u(y, x); |
|
|
|
|
nextPt.y = y - c_halfWin_y + v(y, x); |
|
|
|
|
nextPt.x = x + prevU(y/2, x/2) * 2.0f; |
|
|
|
|
nextPt.y = y + prevV(y/2, x/2) * 2.0f; |
|
|
|
|
|
|
|
|
|
for (int k = 0; k < c_iters; ++k) |
|
|
|
|
{ |
|
|
|
|
if (nextPt.x < -c_winSize_x || nextPt.x >= cols || nextPt.y < -c_winSize_y || nextPt.y >= rows) |
|
|
|
|
if (nextPt.x < 0 || nextPt.x >= cols || nextPt.y < 0 || nextPt.y >= rows) |
|
|
|
|
{ |
|
|
|
|
if (calcErr) |
|
|
|
|
err(y, x) = numeric_limits<float>::max(); |
|
|
|
|
|
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
float b1 = 0; |
|
|
|
|
float b2 = 0; |
|
|
|
|
int b1 = 0; |
|
|
|
|
int b2 = 0; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < c_winSize_y; ++i) |
|
|
|
|
{ |
|
|
|
|
for (int j = 0; j < c_winSize_x; ++j) |
|
|
|
|
{ |
|
|
|
|
int I_val = I(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
int I = I_patch[(threadIdx.y + i) * patchWidth + threadIdx.x + j]; |
|
|
|
|
int J = tex2D(tex_J, nextPt.x - c_halfWin_x + j + 0.5f, nextPt.y - c_halfWin_y + i + 0.5f); |
|
|
|
|
|
|
|
|
|
int diff = linearFilter(J, nextPt, j, i) - CV_DESCALE(I_val * (1 << W_BITS), W_BITS1 - 5); |
|
|
|
|
int diff = (J - I) * 32; |
|
|
|
|
|
|
|
|
|
b1 += diff * dIdx(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
b2 += diff * dIdy(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
int dIdx = dIdx_patch[(threadIdx.y + i) * patchWidth + (threadIdx.x + j)]; |
|
|
|
|
int dIdy = dIdy_patch[(threadIdx.y + i) * patchWidth + (threadIdx.x + j)]; |
|
|
|
|
|
|
|
|
|
b1 += diff * dIdx; |
|
|
|
|
b2 += diff * dIdy; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
b1 *= SCALE; |
|
|
|
|
b2 *= SCALE; |
|
|
|
|
|
|
|
|
|
float2 delta; |
|
|
|
|
delta.x = A12 * b2 - A22 * b1; |
|
|
|
|
delta.y = A12 * b1 - A11 * b2; |
|
|
|
@ -642,57 +680,50 @@ namespace cv { namespace gpu { namespace device |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
u(y, x) = nextPt.x - x + c_halfWin_x; |
|
|
|
|
v(y, x) = nextPt.y - y + c_halfWin_y; |
|
|
|
|
u(y, x) = nextPt.x - x; |
|
|
|
|
v(y, x) = nextPt.y - y; |
|
|
|
|
|
|
|
|
|
if (calcErr && !GET_MIN_EIGENVALS) |
|
|
|
|
if (calcErr) |
|
|
|
|
{ |
|
|
|
|
float errval = 0.0f; |
|
|
|
|
int errval = 0; |
|
|
|
|
|
|
|
|
|
for (int i = 0; i < c_winSize_y; ++i) |
|
|
|
|
{ |
|
|
|
|
for (int j = 0; j < c_winSize_x; ++j) |
|
|
|
|
{ |
|
|
|
|
int I_val = I(y - c_halfWin_y + i, x - c_halfWin_x + j); |
|
|
|
|
int diff = linearFilter(J, nextPt, j, i) - CV_DESCALE(I_val * (1 << W_BITS), W_BITS1 - 5); |
|
|
|
|
errval += ::fabsf((float)diff); |
|
|
|
|
int I = I_patch[(threadIdx.y + i) * patchWidth + threadIdx.x + j]; |
|
|
|
|
int J = tex2D(tex_J, nextPt.x - c_halfWin_x + j + 0.5f, nextPt.y - c_halfWin_y + i + 0.5f); |
|
|
|
|
|
|
|
|
|
errval += ::abs(J - I); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
errval /= 32 * c_winSize_x_cn * c_winSize_y; |
|
|
|
|
|
|
|
|
|
err(y, x) = errval; |
|
|
|
|
err(y, x) = static_cast<float>(errval) / (c_winSize_x * c_winSize_y); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void lkDense_gpu(DevMem2Db I, DevMem2Db J, DevMem2D_<short> dIdx, DevMem2D_<short> dIdy, |
|
|
|
|
DevMem2Df u, DevMem2Df v, DevMem2Df* err, bool GET_MIN_EIGENVALS, cudaStream_t stream) |
|
|
|
|
void lkDense_gpu(DevMem2Db I, DevMem2Df J, DevMem2Df u, DevMem2Df v, DevMem2Df prevU, DevMem2Df prevV, |
|
|
|
|
DevMem2Df err, int2 winSize, cudaStream_t stream) |
|
|
|
|
{ |
|
|
|
|
dim3 block(32, 8); |
|
|
|
|
dim3 block(16, 16); |
|
|
|
|
dim3 grid(divUp(I.cols, block.x), divUp(I.rows, block.y)); |
|
|
|
|
|
|
|
|
|
if (err) |
|
|
|
|
{ |
|
|
|
|
if (GET_MIN_EIGENVALS) |
|
|
|
|
{ |
|
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(lkDense<true, true>, cudaFuncCachePreferL1) ); |
|
|
|
|
bindTexture(&tex_I, I); |
|
|
|
|
bindTexture(&tex_J, J); |
|
|
|
|
|
|
|
|
|
lkDense<true, true><<<grid, block, 0, stream>>>(I, J, dIdx, dIdy, u, v, *err, I.rows, I.cols); |
|
|
|
|
cudaSafeCall( cudaGetLastError() ); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(lkDense<true, false>, cudaFuncCachePreferL1) ); |
|
|
|
|
int2 halfWin = make_int2((winSize.x - 1) / 2, (winSize.y - 1) / 2); |
|
|
|
|
const int patchWidth = block.x + 2 * halfWin.x; |
|
|
|
|
const int patchHeight = block.y + 2 * halfWin.y; |
|
|
|
|
size_t smem_size = 3 * patchWidth * patchHeight * sizeof(int); |
|
|
|
|
|
|
|
|
|
lkDense<true, false><<<grid, block, 0, stream>>>(I, J, dIdx, dIdy, u, v, *err, I.rows, I.cols); |
|
|
|
|
if (err.data) |
|
|
|
|
{ |
|
|
|
|
lkDense<true><<<grid, block, smem_size, stream>>>(u, v, prevU, prevV, err, I.rows, I.cols); |
|
|
|
|
cudaSafeCall( cudaGetLastError() ); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
cudaSafeCall( cudaFuncSetCacheConfig(lkDense<false, false>, cudaFuncCachePreferL1) ); |
|
|
|
|
|
|
|
|
|
lkDense<false, false><<<grid, block, 0, stream>>>(I, J, dIdx, dIdy, u, v, PtrStepf(), I.rows, I.cols); |
|
|
|
|
lkDense<false><<<grid, block, smem_size, stream>>>(u, v, prevU, prevV, PtrStepf(), I.rows, I.cols); |
|
|
|
|
cudaSafeCall( cudaGetLastError() ); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|