@@ -335,6 +335,232 @@ static void _build_blend_mask(float *clipmask,
335
335
}
336
336
}
337
337
338
+ #define RAWEPS 0.0001f
339
+ float calcRadiusBayer (const float * in ,
340
+ const int width ,
341
+ const int height ,
342
+ const float lowerLimit ,
343
+ const float upperLimit ,
344
+ const uint32_t filters )
345
+ {
346
+ const unsigned int fc [2 ] = {FC (0 , 0 , filters ), FC (1 , 0 , filters )};
347
+ float maxRatio = 1.f ;
348
+ DT_OMP_FOR (reduction (max : maxRatio ))
349
+ for (int row = 4 ; row < height - 4 ; ++ row )
350
+ {
351
+ for (int col = 5 + (fc [row & 1 ] & 1 ); col < width - 4 ; col += 2 )
352
+ {
353
+ const float * cfa = in + row * width + col ;
354
+ const float val00 = cfa [0 ];
355
+ if (val00 > RAWEPS )
356
+ {
357
+ const float val1m1 = cfa [width - 1 ];
358
+ const float val1p1 = cfa [width + 1 ];
359
+ const float maxVal0 = MAX (val00 , val1m1 );
360
+ if (val1m1 > RAWEPS && maxVal0 > lowerLimit )
361
+ {
362
+ const float minVal = MIN (val00 , val1m1 );
363
+ if (maxVal0 > maxRatio * minVal )
364
+ {
365
+ gboolean clipped = FALSE;
366
+ if (maxVal0 == val00 )
367
+ { // check for influence by clipped green in neighborhood
368
+ if (MAX (MAX (cfa [- width - 1 ], cfa [- width + 1 ]), val1p1 ) >= upperLimit )
369
+ {
370
+ clipped = TRUE;
371
+ }
372
+ }
373
+ else
374
+ { // check for influence by clipped green in neighborhood
375
+ if (MAX (MAX (MAX (cfa [-2 ], val00 ), cfa [2 * width - 2 ]), cfa [2 * width ]) >= upperLimit )
376
+ {
377
+ clipped = TRUE;
378
+ }
379
+ }
380
+ if (!clipped )
381
+ {
382
+ maxRatio = maxVal0 / minVal ;
383
+ }
384
+ }
385
+ }
386
+
387
+ const float maxVal1 = MAX (val00 , val1p1 );
388
+ if (val1p1 > RAWEPS && maxVal1 > lowerLimit )
389
+ {
390
+ const float minVal = MIN (val00 , val1p1 );
391
+ if (maxVal1 > maxRatio * minVal )
392
+ {
393
+ if (maxVal1 == val00 )
394
+ { // check for influence by clipped green in neighborhood
395
+ if (MAX (MAX (cfa [- width - 1 ], cfa [- width + 1 ]), val1p1 ) >= upperLimit )
396
+ {
397
+ continue ;
398
+ }
399
+ }
400
+ else
401
+ { // check for influence by clipped green in neighborhood
402
+ if (MAX (MAX (MAX (val00 , cfa [2 ]), cfa [2 * width ]), cfa [2 * width + 2 ]) >= upperLimit )
403
+ {
404
+ continue ;
405
+ }
406
+ }
407
+ maxRatio = maxVal1 / minVal ;
408
+ }
409
+ }
410
+ }
411
+ }
412
+ }
413
+ return sqrtf (1.0f / logf (maxRatio ));
414
+ }
415
+
416
+ float calcRadiusXtrans (const float * in ,
417
+ const float lowerLimit ,
418
+ const float upperLimit ,
419
+ const dt_iop_roi_t * const roi ,
420
+ const uint8_t (* const xtrans )[6 ])
421
+ {
422
+ const int width = roi -> width ;
423
+ const int height = roi -> height ;
424
+
425
+ int startx , starty ;
426
+ gboolean found = FALSE;
427
+ for (starty = 6 ; starty < 12 && !found ; starty ++ )
428
+ {
429
+ for (startx = 6 ; startx < 12 && !found ; startx ++ )
430
+ {
431
+ if (FCxtrans (starty , startx , roi , xtrans ) == 1 )
432
+ {
433
+ if (FCxtrans (starty , startx - 1 , roi , xtrans ) != FCxtrans (starty , startx + 1 , roi , xtrans ))
434
+ {
435
+ if (FCxtrans (starty - 1 , startx , roi , xtrans ) != 1 )
436
+ {
437
+ if (FCxtrans (starty , startx - 1 , roi , xtrans ) != 1 )
438
+ {
439
+ found = TRUE;
440
+ break ;
441
+ }
442
+ }
443
+ }
444
+ }
445
+ }
446
+ }
447
+
448
+ float maxRatio = 1.0f ;
449
+ DT_OMP_FOR (reduction (max : maxRatio ))
450
+ for (int row = starty + 2 ; row < height - 4 ; row += 3 )
451
+ {
452
+ for (int col = startx + 2 ; col < width - 4 ; col += 3 )
453
+ {
454
+ const float * cfa = in + row * width + col ;
455
+ const float valp1p1 = cfa [width + 1 ];
456
+ const gboolean squareClipped = MAX (MAX (MAX (valp1p1 , cfa [width + 2 ]), cfa [2 * width + 1 ]), cfa [2 * width + 2 ]) >= upperLimit ;
457
+ const float greenSolitary = cfa [0 ];
458
+ if (greenSolitary > RAWEPS && MAX (cfa [- width - 1 ], cfa [- width + 1 ]) < upperLimit )
459
+ {
460
+ if (greenSolitary < upperLimit )
461
+ {
462
+ const float valp1m1 = cfa [width - 1 ];
463
+ if (valp1m1 > RAWEPS && MAX (MAX (MAX (cfa [width - 2 ], valp1m1 ), cfa [2 * width - 2 ]), cfa [width - 1 ]) < upperLimit )
464
+ {
465
+ const float maxVal = MAX (greenSolitary , valp1m1 );
466
+ if (maxVal > lowerLimit )
467
+ {
468
+ const float minVal = MIN (greenSolitary , valp1m1 );
469
+ if (maxVal > maxRatio * minVal )
470
+ {
471
+ maxRatio = maxVal / minVal ;
472
+ }
473
+ }
474
+ }
475
+ if (valp1p1 > RAWEPS && !squareClipped )
476
+ {
477
+ const float maxVal = MAX (greenSolitary , valp1p1 );
478
+ if (maxVal > lowerLimit )
479
+ {
480
+ const float minVal = MIN (greenSolitary , valp1p1 );
481
+ if (maxVal > maxRatio * minVal )
482
+ {
483
+ maxRatio = maxVal / minVal ;
484
+ }
485
+ }
486
+ }
487
+ }
488
+ }
489
+
490
+ if (!squareClipped )
491
+ {
492
+ const float valp2p2 = cfa [2 * width + 2 ];
493
+ if (valp2p2 > RAWEPS )
494
+ {
495
+ if (valp1p1 > RAWEPS )
496
+ {
497
+ const float maxVal = MAX (valp1p1 , valp2p2 );
498
+ if (maxVal > lowerLimit )
499
+ {
500
+ const float minVal = MIN (valp1p1 , valp2p2 );
501
+ if (maxVal > maxRatio * minVal )
502
+ {
503
+ maxRatio = maxVal / minVal ;
504
+ }
505
+ }
506
+ }
507
+ const float greenSolitaryRight = cfa [3 * width + 3 ];
508
+ if (MAX (MAX (greenSolitaryRight , cfa [4 * width + 2 ]), cfa [4 * width + 4 ]) < upperLimit )
509
+ {
510
+ if (greenSolitaryRight > RAWEPS )
511
+ {
512
+ const float maxVal = MAX (greenSolitaryRight , valp2p2 );
513
+ if (maxVal > lowerLimit )
514
+ {
515
+ const float minVal = MIN (greenSolitaryRight , valp2p2 );
516
+ if (maxVal > maxRatio * minVal )
517
+ {
518
+ maxRatio = maxVal / minVal ;
519
+ }
520
+ }
521
+ }
522
+ }
523
+ }
524
+ const float valp1p2 = cfa [width + 2 ];
525
+ const float valp2p1 = cfa [2 * width + 1 ];
526
+ if (valp2p1 > RAWEPS )
527
+ {
528
+ if (valp1p2 > RAWEPS )
529
+ {
530
+ const float maxVal = MAX (valp1p2 , valp2p1 );
531
+ if (maxVal > lowerLimit )
532
+ {
533
+ const float minVal = MIN (valp1p2 , valp2p1 );
534
+ if (maxVal > maxRatio * minVal )
535
+ {
536
+ maxRatio = maxVal / minVal ;
537
+ }
538
+ }
539
+ }
540
+ const float greenSolitaryLeft = cfa [3 * width ];
541
+ if (MAX (MAX (greenSolitaryLeft , cfa [4 * width - 1 ]), cfa [4 * width + 1 ]) < upperLimit )
542
+ {
543
+ if (greenSolitaryLeft > RAWEPS )
544
+ {
545
+ const float maxVal = MAX (greenSolitaryLeft , valp2p1 );
546
+ if (maxVal > lowerLimit )
547
+ {
548
+ const float minVal = MIN (greenSolitaryLeft , valp2p1 );
549
+ if (maxVal > maxRatio * minVal )
550
+ {
551
+ maxRatio = maxVal / minVal ;
552
+ }
553
+ }
554
+ }
555
+ }
556
+ }
557
+ }
558
+ }
559
+ }
560
+ return sqrtf (1.0f / logf (maxRatio ));
561
+ }
562
+ #undef RAWEPS
563
+
338
564
void _capture_sharpen (dt_iop_module_t * self ,
339
565
dt_dev_pixelpipe_iop_t * piece ,
340
566
float * in ,
@@ -350,6 +576,7 @@ void _capture_sharpen(dt_iop_module_t *self,
350
576
const size_t pixels = width * height ;
351
577
const dt_iop_demosaic_data_t * d = piece -> data ;
352
578
const dt_iop_demosaic_global_data_t * gd = self -> global_data ;
579
+ dt_iop_demosaic_gui_data_t * g = self -> gui_data ;
353
580
354
581
const uint8_t (* const xtrans )[6 ] = (const uint8_t (* const )[6 ])piece -> pipe -> dsc .xtrans ;
355
582
const uint32_t filters = piece -> pipe -> dsc .filters ;
@@ -359,6 +586,26 @@ void _capture_sharpen(dt_iop_module_t *self,
359
586
wbon ? dsc -> temperature .coeffs [1 ] : 1.0f ,
360
587
wbon ? dsc -> temperature .coeffs [2 ] : 1.0f ,
361
588
0.0f };
589
+ const gboolean autoradius = (pipe -> type & DT_DEV_PIXELPIPE_FULL )
590
+ && g && g -> autoradius ;
591
+ float radius = d -> cs_radius ;
592
+ const gboolean noradius = radius < 0.01f ;
593
+ if (autoradius || noradius )
594
+ {
595
+ radius = filters != 9u
596
+ ? calcRadiusBayer (in , width , height , 0.01f , 1.0f , filters )
597
+ : calcRadiusXtrans (in , 0.01f , 1.0f , roi , xtrans );
598
+
599
+ dt_print_pipe (DT_DEBUG_PIPE , filters != 9u ? "bayer autoradius" : "xtrans autoradius" ,
600
+ pipe , self , DT_DEVICE_CPU , roi , NULL , "autoradius=%.2f" , radius );
601
+ if (autoradius )
602
+ {
603
+ dt_control_log (_ ("calculated radius: %.2f" ), radius );
604
+ dt_iop_gui_enter_critical_section (self );
605
+ g -> newradius = MIN (g -> newradius , radius );
606
+ dt_iop_gui_leave_critical_section (self );
607
+ }
608
+ }
362
609
363
610
char * gauss_idx = NULL ;
364
611
gboolean error = TRUE;
@@ -385,7 +632,7 @@ void _capture_sharpen(dt_iop_module_t *self,
385
632
goto finalize ;
386
633
}
387
634
388
- gauss_idx = _cs_precalc_gauss_idx (self , roi , d -> cs_radius , d -> cs_boost );
635
+ gauss_idx = _cs_precalc_gauss_idx (self , roi , radius , d -> cs_boost );
389
636
if (!gauss_idx ) goto finalize ;
390
637
391
638
for (int iter = 0 ; iter < iterations ; iter ++ )
@@ -434,6 +681,7 @@ int _capture_sharpen_cl(dt_iop_module_t *self,
434
681
const int devid = piece -> pipe -> devid ;
435
682
const dt_iop_demosaic_data_t * d = piece -> data ;
436
683
dt_iop_demosaic_global_data_t * const gd = self -> global_data ;
684
+ dt_iop_demosaic_gui_data_t * g = self -> gui_data ;
437
685
438
686
const float threshold = 0.09f * d -> cs_thrs ;
439
687
const uint32_t filters = piece -> pipe -> dsc .filters ;
@@ -443,6 +691,33 @@ int _capture_sharpen_cl(dt_iop_module_t *self,
443
691
wbon ? dsc -> temperature .coeffs [1 ] : 1.0f ,
444
692
wbon ? dsc -> temperature .coeffs [2 ] : 1.0f ,
445
693
0.0f };
694
+ const gboolean autoradius = (pipe -> type & DT_DEV_PIXELPIPE_FULL )
695
+ && g && g -> autoradius ;
696
+ float radius = d -> cs_radius ;
697
+ const gboolean noradius = radius < 0.01f ;
698
+ if (autoradius || noradius )
699
+ {
700
+ float * in = dt_alloc_align_float ((size_t )width * height );
701
+ if (in )
702
+ {
703
+ if (dt_opencl_read_host_from_device (devid , in , dev_in , width , height , sizeof (float )) == CL_SUCCESS )
704
+ {
705
+ radius = filters != 9u
706
+ ? calcRadiusBayer (in , width , height , 0.01f , 1.0f , filters )
707
+ : calcRadiusXtrans (in , 0.01f , 1.0f , roi , (const uint8_t (* const )[6 ])piece -> pipe -> dsc .xtrans );
708
+ dt_print_pipe (DT_DEBUG_PIPE , filters != 9u ? "bayer autoradius" : "xtrans autoradius" ,
709
+ pipe , self , devid , roi , NULL , "autoradius=%.2f" , radius );
710
+ if (autoradius )
711
+ {
712
+ dt_control_log (_ ("calculated radius: %.2f" ), radius );
713
+ dt_iop_gui_enter_critical_section (self );
714
+ g -> newradius = MIN (g -> newradius , radius );
715
+ dt_iop_gui_leave_critical_section (self );
716
+ }
717
+ }
718
+ dt_free_align (in );
719
+ }
720
+ }
446
721
447
722
cl_mem gcoeffs = NULL ;
448
723
cl_mem gauss_idx = NULL ;
@@ -481,7 +756,7 @@ int _capture_sharpen_cl(dt_iop_module_t *self,
481
756
goto finish ;
482
757
}
483
758
484
- char * f_gauss_idx = _cs_precalc_gauss_idx (self , roi , d -> cs_radius , d -> cs_boost );
759
+ char * f_gauss_idx = _cs_precalc_gauss_idx (self , roi , radius , d -> cs_boost );
485
760
if (f_gauss_idx )
486
761
{
487
762
gcoeffs = dt_opencl_copy_host_to_device_constant (devid , sizeof (float ) * CHAR_MAX * CAPTURE_KERNEL_ALIGN , gd -> gauss_coeffs );
0 commit comments