// This program is free software: you can use, modify and/or redistribute it // under the terms of the simplified BSD License. You should have received a // copy of this license along this program. If not, see // . // // Copyright (C) 2012, Javier Sánchez Pérez // Copyright (C) 2014, Agustín Salgado de la Nuez // Copyright (C) 2014, 2015 Nelson Monzón López // All rights reserved. #ifndef SMOOTHNESS_H #define SMOOTHNESS_H #include #include #define EPSILON 0.001 #define XI 0.05 #define TAU 0.94 #define BETA 0.001 /** * * Compute the coefficients of the robust functional (smoothness term) * **/ void psi_smooth( const float *ux, //gradient of x component of the optical flow const float *uy, //gradient of x component of the optical flow const float *vx, //gradient of y component of the optical flow const float *vy, //gradient of y component of the optical flow const float *expo, //exponential smoothing factor const int size_flow, float *psi //output coefficients ) { //compute 1/(sqrt(ux²+uy²+vx²+vy²+e²) in each pixel #pragma omp parallel for for(int i = 0; i < size_flow; i++) { const float du = expo[i] * ux[i] * ux[i] + expo[i] * uy[i] * uy[i]; const float dv = expo[i] * vx[i] * vx[i] + expo[i] * vy[i] * vy[i]; const float normFlow = du + dv; psi[i] = expo[i] / sqrt(normFlow + EPSILON * EPSILON); } } void max_gradients( const float *Ix, // Computed Image 1 derivative in x const float *Iy, // Computed Image 1 derivative in y const int size, // Total image size (height * weight * nchannels) const int nz, // nº channels float *maximum_gradients_per_pixel // vector with the maximum gradients per pixel ){ int index_flow = 0; for(int index_image = 0; index_image < size; index_image+=nz){ maximum_gradients_per_pixel[index_flow] = sqrt(Ix[index_image]*Ix[index_image] + Iy[index_image]*Iy[index_image]); for(int index_multichannel = 1; index_multichannel < nz; index_multichannel++){ const int real_index = index_image + index_multichannel; const float gradient_in_this_pixel = sqrt(Ix[real_index]*Ix[real_index] + Iy[real_index]*Iy[real_index]); if (maximum_gradients_per_pixel[index_flow] < gradient_in_this_pixel) maximum_gradients_per_pixel[index_flow] = gradient_in_this_pixel; } index_flow++; } return; } /** * Calculate the lambda optimum using the maximum gradient from all the multi-channel image * It also return the maximum gradient per pixel **/ float lambda_optimum_using_maximum_gradient_per_pixel( const float *Ix, // Computed Image 1 derivative in x const float *Iy, // Computed Image 1 derivative in y const int size, // Total image size (height * weight * nchannels) const int size_flow, // Total flow size (height * weight) const int nz, // nº channels const float alpha, // smoothness weight float *lambda_per_pixel, // local lambda per pixel float *maximum_gradients_per_pixel // vector with the maximum gradients per pixel ) { int index_flow = 0; for(int index_image = 0; index_image < size; index_image+=nz){ maximum_gradients_per_pixel[index_flow] = sqrt(Ix[index_image]*Ix[index_image] + Iy[index_image]*Iy[index_image]); for(int index_multichannel = 1; index_multichannel < nz; index_multichannel++){ const int real_index = index_image + index_multichannel; const float gradient_in_this_pixel = sqrt(Ix[real_index]*Ix[real_index] + Iy[real_index]*Iy[real_index]); if (maximum_gradients_per_pixel[index_flow] < gradient_in_this_pixel) maximum_gradients_per_pixel[index_flow] = gradient_in_this_pixel; } lambda_per_pixel[index_flow] = (-log(XI) + log(alpha)) / maximum_gradients_per_pixel[index_flow]; index_flow++; } std::vector gradients_ordered(size_flow); #pragma omp parallel for for (int index_flow = 0; index_flow < size_flow; index_flow++) gradients_ordered[index_flow] = maximum_gradients_per_pixel[index_flow]; std::sort(gradients_ordered.begin(), gradients_ordered.end()); const float c = -log(XI) + log(alpha); int pos_ref = TAU * size_flow; float lambda_pi = c / gradients_ordered[pos_ref-1]; while ((pos_ref < size_flow) && (c/2 > gradients_ordered[pos_ref-1])) pos_ref++; if (pos_ref == size_flow) lambda_pi = 0; else lambda_pi = (c / gradients_ordered[pos_ref-1]); return lambda_pi; } /** ** Calculate the exponential values. ** **/ void exponential_calculation( const float *Ix, // Computed Image 1 derivative in x const float *Iy, // Computed Image 1 derivative in y const int size_flow, // size of the flow field const int size, // size of the multi-channel image const int nz, // nº of image channels const float alpha, // smoothness weight const float lambda, // Coeffient for decreasing function const int method_type, // (1 = DF, 2 = DF_BETA, 3 = DF_AUTO) float *expo // e^(lambda * DI) ) { float *maximum_gradients_per_pixel = new float[size_flow]; switch(method_type){ case 1: case 2:{ float beta = 0; if (method_type == 2) // For Exponential Beta Approximation beta = BETA; max_gradients(Ix, Iy, size, nz, maximum_gradients_per_pixel); #pragma omp parallel for for(int index_flow = 0; index_flow < size_flow; index_flow++){ expo[index_flow] = exp(- lambda * maximum_gradients_per_pixel[index_flow]) + beta; } break; } case 3:{ float *lambda_per_pixel = new float[size_flow]; float lambda_omega = lambda_optimum_using_maximum_gradient_per_pixel(Ix, Iy, size, size_flow, nz, alpha, lambda_per_pixel, maximum_gradients_per_pixel); #pragma omp parallel for for(int index_flow = 0; index_flow < size_flow; index_flow++){ float lambda_pi = lambda_omega; if(lambda_omega > lambda_per_pixel[index_flow]) lambda_pi = lambda_per_pixel[index_flow]; expo[index_flow] = exp(- lambda_pi * maximum_gradients_per_pixel[index_flow]); } delete [] lambda_per_pixel; break; } } // End switch delete [] maximum_gradients_per_pixel; } #endif