1 /************************************************************************
2 * chemins des lignes de niveaux pour la version à chemins constants
3 * Ne sont conservés que pour comparaison GPU/CPU -> à faire disparaître
5 * une ligne = un chemin
6 ************************************************************************/
7 __constant__ int pathDi[PSIZE_I][PSIZE_J-1] =
39 __constant__ int pathDj[PSIZE_I][PSIZE_J-1] =
73 // valeurs des tangentes des angles de base pour la génération initiale des chemins
74 // pour la version à chemins de longueur paramétrable
75 __constant__ float tangente[] = {0.000, 0.268, 0.577, 1.000} ;
77 // declarations des textures
78 texture<int, 2, cudaReadModeElementType> tex_img_in ;
79 texture<int, 2, cudaReadModeElementType> tex_img_estim ;
80 texture<int, 2, cudaReadModeElementType> tex_img_lniv ;
81 texture<int2, 2, cudaReadModeElementType> tex_paths ;
87 * \brief calcule les chemins
88 * \author NB - PhyTI, modifié by zulu pour adaptater aux chemins paramétrables
90 * \param[in] r longueur des chemins
92 * \param[out] d_paths matrice des déplacements relatifs (chemins)
94 * Cette fonction utilise le tableau constant des tangentes des angles
95 * considérés pour le calcul de chemins (float tangente[]).
98 __global__ void kernel_calcul_paths( int2 * d_paths, unsigned int r){
100 unsigned int idpath = 0 ;
101 int ic, jc, iprec, jprec ;
103 unsigned int basepath = 0 ;
106 for (int a=0 ; a< 4 ; a++){ // les 4 angles 0,15,30 et 45
107 for (int p=0 ; p< r ; p++){ // les r points
108 ic = r-1 - floor(tangente[a]*p + offset) ;
110 d_paths[idpath*(r-1)+p-1].x = ic - iprec ;
111 d_paths[idpath*(r-1)+p-1].y = 1 ;
118 for (int a=2 ; a>0 ; a--){ // les 2 angles 60 et 75
119 for (int p=0 ; p< r ; p++){ // les r points
120 jc = floor(tangente[a]*p + offset) ;
122 d_paths[idpath*(r-1)+p-1].x = -1 ;
123 d_paths[idpath*(r-1)+p-1].y = jc - jprec ;
132 for (int a=0 ; a< 6 ; a++){ // les 6 angles 90,105,120,135,150,165
133 for (int p=0 ; p<r-1 ; p++){ // les r points
134 d_paths[idpath*(r-1)+p].x = -d_paths[(idpath - basepath)*(r-1)+p].y ;
135 d_paths[idpath*(r-1)+p].y = d_paths[(idpath - basepath)*(r-1)+p].x ;
142 for (int a=0 ; a< 6 ; a++){ // les 6 angles 180,195,210,225,240,255
143 for (int p=0 ; p<r-1 ; p++){ // les r points
144 d_paths[idpath*(r-1)+p].x = -d_paths[(idpath - basepath)*(r-1)+p].x ;
145 d_paths[idpath*(r-1)+p].y = -d_paths[(idpath - basepath)*(r-1)+p].y ;
152 for (int a=0 ; a< 6 ; a++){ // les 6 angles 270,285,300,315,330,345
153 for (int p=0 ; p<r-1 ; p++){ // les r points
154 d_paths[idpath*(r-1)+p].x = d_paths[(idpath - basepath)*(r-1)+p].y ;
155 d_paths[idpath*(r-1)+p].y = -d_paths[(idpath - basepath)*(r-1)+p].x ;
163 * \brief calcule l'estimation initiale
166 * \param[in] L Largeur de l'image
167 * \param[in] H Hauteur de l'image
168 * \param[in] r coté de la fenêtre de moyenneage
170 * \param[out] d_estim Image estimee 0
172 * Version texture : l'img originale est supposée en texture.
173 * L'estimation réalisée correspond a un moyenneur de 'rayon' r
174 * Execution sur des blocs de threads 2D et une grille 2D
175 * selon les dimensions de l'image.
178 __global__ void kernel_neutre_img2estim(unsigned int *d_estim, unsigned int L, unsigned int H){
180 // coordonnes du point dans l'image
181 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
182 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
183 unsigned int pos = i*L +j ;
185 d_estim[ pos ] = tex2D(tex_img_in, j, i) ;
192 * \brief calcule l'estimation initiale
195 * \param[in] L Largeur de l'image
196 * \param[in] H Hauteur de l'image
197 * \param[in] r coté de la fenêtre de moyenneage
199 * \param[out] d_estim Image estimee 0
201 * Version texture : l'img originale est supposée en texture.
202 * L'estimation réalisée correspond a un moyenneur de 'rayon' r
203 * Execution sur des blocs de threads 2D et une grille 2D
204 * selon les dimensions de l'image.
207 __global__ void kernel_init_estim_from_img_in(unsigned int * d_estim, unsigned int L, unsigned int H, unsigned int r){
208 // coordonnes du point dans l'image
209 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
210 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
211 unsigned int pos = i*L +j ;
212 unsigned int ic , jc, ng ;
214 if( (i>r)&&(i<H-r)&&(j>r)&&(j<L-r) ){
216 for (ic = i - r ; ic <= i + r ; ic++){
217 for (jc = j - r ; jc <= j + r ; jc++){
218 ng += tex2D(tex_img_in, jc, ic ) ;
221 d_estim[ pos ] = ng/((2*r+1)*(2*r+1)) ;
224 // pour les bords : pas de traitement
226 d_estim[ pos ] = tex2D(tex_img_in, j, i) ;
234 * \brief calcule l'estimation initiale
237 * \param[in] d_data image originale
238 * \param[in] L Largeur de l'image
239 * \param[in] H Hauteur de l'image
240 * \param[in] r coté de la fenêtre de moyenneage
242 * \param[out] d_estim Image estimee 0
244 * Version global mem : l'img originale est en mémoire globale, passée en param.
245 * L'estimation réalisée correspond a un moyenneur de 'rayon' r
246 * Execution sur des blocs de threads 2D et une grille 2D
247 * selon les dimensions de l'image.
248 * Moins rapide que les 2 autres solutions.
251 __global__ void kernel_init_estim_from_img_in_global_mem(unsigned int * d_data, unsigned int * d_estim,
252 unsigned int L, unsigned int H, unsigned int r){
253 // coordonnes du point dans l'image
254 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
255 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
256 unsigned int pos = i*L +j ;
257 unsigned int ic , jc, ng ;
259 if( (i>r)&&(i<H-r)&&(j>r)&&(j<L-r) ){
261 for (ic = i - r ; ic <= i + r ; ic++){
262 for (jc = j - r ; jc <= j + r ; jc++){
263 ng += d_data[ ic*L + jc ] ;
266 d_estim[ pos ] = ng/((2*r+1)*(2*r+1)) ;
274 * \brief calcule les niveaux de gris de l'estimation n+1
277 * \param[in] L Largeur de l'image
278 * \param[in] H Hauteur de l'image
279 * \param[in] p poids du terme lniv
281 * \param[out] d_estim Image estimee n+1
283 * Version mixte : l'img originale est supposee en texture,
284 * l'img lniv en mémoire globale, passée en param.
285 * Cela évite la copie en texture de l'img lniv à chaque itération.
286 * Execution sur des blocs de threads 2D et une grille 2D
287 * selon les dimensions de l'image.
288 * Moins rapide que 'texture' mais plus rapide que 'globalmem'
291 __global__ void kernel_estim_next_step_hybrid(unsigned int * d_estim, unsigned int * d_lniv, unsigned int L, unsigned int H, unsigned int p){
292 // coordonnes du point dans l'image
293 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
294 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
295 unsigned int pos = i*L +j ;
297 d_estim[ pos ] = ( tex2D(tex_img_in, j, i) + p*d_lniv[ pos ] )/(1+p) ;
303 * \brief calcule les niveaux de gris de l'estimation n+1
306 * \param[in] L Largeur de l'image
307 * \param[in] H Hauteur de l'image
308 * \param[in] p poids du terme lniv
310 * \param[out] d_estim Image estimee n+1
312 * Version texture : Les donnees (img originale, img lniv) sont supposees en textures.
313 * Execution sur des blocs de threads 2D et une grille 2D
314 * selon les dimensions de l'image.
315 * Plus rapide que les 2 autres solutions
318 __global__ void kernel_estim_next_step_texture(unsigned int * d_estim, unsigned int L, unsigned int H, unsigned int p){
319 // coordonnes du point dans l'image
320 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
321 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
322 unsigned int pos = i*L +j ;
324 d_estim[ pos ] = ( tex2D(tex_img_in, j, i) + p*tex2D(tex_img_lniv, j, i ))/(1+p) ;
330 * \brief calcule les niveaux de gris de l'estimation n+1
333 * \param[in] d_lniv Image des lniv n
334 * \param[in] d_data Image originale
335 * \param[in] L Largeur de l'image
336 * \param[in] H Hauteur de l'image
337 * \param[in] p poids du terme lniv
339 * \param[out] d_estim Image estimee n+1
341 * Version mémoire globale : les données sont passées en params.
342 * Execution sur des blocs de threads 2D et une grille 2D
343 * selon les dimensions de l'image.
346 __global__ void kernel_estim_next_step_global_mem(unsigned int * d_estim, unsigned int * d_lniv, unsigned int * d_data,
347 unsigned int L, unsigned int H, unsigned int p){
348 // coordonnes du point dans l'image
349 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
350 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
351 unsigned int pos = i*L +j ;
353 d_estim[ pos ] = ( d_data[ pos ] + p*d_lniv[ pos ])/(1+p) ;
359 * \brief determine les lniv en chaque point de l'image
362 * \param[in] L Largeur de l'image
363 * \param[in] H Hauteur de l'image
364 * \param[in] r longueur des segments
366 * \param[out] img_out image des lniv
368 * Execution sur des blocs de threads 2D et une grille 2D
369 * selon les dimensions de l'image.
370 * L'image d'entrée doit être au préalable en mémoire texture pointée par "tex_img_estim".
371 * Les matrices des chemins sont, elles, pointées par "tex_paths"
372 * Cette version ne fournit pas les indices des chemins pour les tracé éventuel des lniv.
374 __global__ void kernel_levelines_texture(unsigned int * img_out, unsigned int L, unsigned int H, unsigned int r)
376 // coordonnes du point dans l'image
377 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
378 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;
380 // nb de points par chemin
382 unsigned int ic, jc, zc, z ;
384 unsigned int mse_min, mse_cur, val ;
388 if((i>=lpath)&&(i<=H-lpath)&&(j>=lpath)&&(j<=L-lpath)){
389 z = tex2D(tex_img_estim, j, i) ;
390 for( idpath=0; idpath < PSIZE_I ; idpath++) {
395 for( idpix=0; idpix < lpath-1 ; idpix++ ) {
396 ic += tex2D(tex_paths, idpix, idpath).x ;
397 jc += tex2D(tex_paths, idpix, idpath).y ;
398 zc = tex2D(tex_img_estim, jc, ic) ;
402 // critere de selection du chemin ( SUM_(X2) - SUM_(X)2 / lpath )
403 // TODO cherchera ameliorer pour vitesse
404 mse_cur = ( mse.y - ( mse.x / lpath ) * mse.x ) ;
405 if ( (idpath == 0) || (mse_cur < mse_min) ) {
410 img_out[ i*L + j ] = val / lpath ;
417 * \brief determine les lniv en chaque point de l'image
420 * \param[in] L Largeur de l'image
421 * \param[in] H Hauteur de l'image
422 * \param[in] r longueur des segments
424 * \param[out] img_out image des lniv
426 * Execution sur des blocs de threads 2D et une grille 2D
427 * selon les dimensions de l'image.
428 * L'image d'entrée doit être au préalable en mémoire texture pointée par "tex_img_estim".
429 * Les matrices des chemins sont, elles, pointées par "tex_paths"
430 * Cette version ne fournit pas les indices des chemins pour les tracé éventuel des lniv.
431 * Cette version tente d'utiliser la shared memory pour compenser la baisse de perf due aux chemins
432 * paramétrables non constants.
435 __global__ void kernel_levelines_texture_smem(unsigned int * img_out, unsigned int L, unsigned int H, unsigned int r)
437 // coordonnées du point dans le bloc
438 unsigned int iib = threadIdx.x ;
439 unsigned int jib = threadIdx.y ;
440 // coordonnes du point dans l'image
441 unsigned int i = blockIdx.x*blockDim.x + iib ;
442 unsigned int j = blockIdx.y*blockDim.y + jib ;
444 // nb de points par chemin
448 unsigned int val, mse_cur, mse_min, z, zc ;
451 //__shared__ unsigned int val_img[16*16] ;
453 //val_img[jib*16+iib] = tex2D(tex_img_estim, j, i) ;
455 if((i>=lpath)&&(i<=H-lpath)&&(j>=lpath)&&(j<=L-lpath)){
456 z = tex2D(tex_img_estim, j, i) ;
457 for( idpath=0; idpath < PSIZE_I ; idpath++) {
462 mse_min = mse_data.y - mse_data.x/lpath*mse_data.y ;
463 for( idpix=0; idpix < lpath-1 ; idpix++ ) {
464 ic += tex2D(tex_paths, idpix, idpath).x ;
465 jc += tex2D(tex_paths, idpix, idpath).y ;
466 zc = tex2D(tex_img_estim, jc, ic) ;
468 mse_data.y += zc*zc ;
470 // critere de selection du chemin ( SUM_(X2) - SUM_(X)2 / lpath )
471 // TODO cherchera ameliorer pour vitesse
472 mse_cur = ( mse_data.y - ( mse_data.x / lpath ) * mse_data.x ) ;
473 if ( mse_cur < mse_min ){
478 img_out[ i*L + j ] = val / lpath ;
484 * \brief trace les segments sur un maillage carré
487 * \param[in] img_in image d'entree
488 * \param[in] dir tableaux des directions
489 * \param[in] L Largeur de l'image
490 * \param[in] H Hauteur de l'image
491 * \param[in] pas coté du maillage
492 * \param[in] ng niveau de gris des segments
493 * \param[in] r longueur des segments
495 * \param[out] img_out image + les segments superposés
497 * Kernel trivial. Ne trace rien sur les bords.
498 * execution sur des blocs de threads 2D et une grille 2D
499 * selon les dimensions de l'image
501 __global__ void kernel_trace_levelines(unsigned int * img_in, unsigned int * dir, unsigned int * img_out,
502 unsigned int L, unsigned int H, unsigned int pas, unsigned int ng,
504 // coordonnes du point dans l'image
505 unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
506 unsigned int j = blockIdx.y*blockDim.y + threadIdx.y;;
508 // nb de points par chemin
510 unsigned int ic, jc, idpix ;
511 unsigned int idpath ;
513 img_out[ i*L + j ] = img_in[ i*L + j ] ;
515 if ( !(i%pas+j%pas)&&(i>lpath)&&(i<H-lpath)&&(j>lpath)&&(j<L-lpath) ){
518 idpath = dir[ic*L+jc] ;
519 img_out[ ic*L+jc ] = ng ;
520 for ( idpix=0 ; idpix < lpath-1 ; idpix++ ){
521 ic += tex2D(tex_paths, idpix, idpath).x ; // pathDi[idpath][idpix] ;
522 jc += tex2D(tex_paths, idpix, idpath).y ; // pathDj[idpath][idpix] ;
523 img_out[ ic*L + jc ] = ng ;