summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
Diffstat (limited to 'libhb')
-rw-r--r--libhb/nlmeans.c111
1 files changed, 108 insertions, 3 deletions
diff --git a/libhb/nlmeans.c b/libhb/nlmeans.c
index 458a76ab5..dd1fe5b3e 100644
--- a/libhb/nlmeans.c
+++ b/libhb/nlmeans.c
@@ -72,8 +72,8 @@
#define NLMEANS_PREFILTER_MODE_MEAN5X5 2
#define NLMEANS_PREFILTER_MODE_MEDIAN3X3 4
#define NLMEANS_PREFILTER_MODE_MEDIAN5X5 8
-#define NLMEANS_PREFILTER_MODE_RESERVED16 16 // Reserved
-#define NLMEANS_PREFILTER_MODE_RESERVED32 32 // Reserved
+#define NLMEANS_PREFILTER_MODE_CSM3X3 16
+#define NLMEANS_PREFILTER_MODE_CSM5X5 32
#define NLMEANS_PREFILTER_MODE_RESERVED64 64 // Reserved
#define NLMEANS_PREFILTER_MODE_RESERVED128 128 // Reserved
#define NLMEANS_PREFILTER_MODE_REDUCE25 256
@@ -385,6 +385,99 @@ static void nlmeans_filter_median(const uint8_t *src,
}
+static void nlmeans_filter_csm(const uint8_t *src,
+ uint8_t *dst,
+ const int w,
+ const int h,
+ const int border,
+ const int size)
+{
+ // CSM filter
+ const int bw = w + 2 * border;
+ const int offset_min = -((size - 1) /2);
+ const int offset_max = (size + 1) /2;
+ uint8_t min, max,
+ min2, max2,
+ min3, max3,
+ median,
+ pixel;
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++)
+ {
+ for (int k = offset_min; k < offset_max; k++)
+ {
+ for (int j = offset_min; j < offset_max; j++)
+ {
+ if (k == 0 && j == 0)
+ {
+ // Ignore origin
+ goto end;
+ }
+ pixel = *(src + bw*(y+j) + (x+k));
+ if (k == offset_min && j == offset_min)
+ {
+ // Start calculating neighborhood thresholds
+ min = pixel;
+ max = min;
+ goto end;
+ }
+ if (pixel < min)
+ {
+ min = pixel;
+ }
+ if (pixel > max)
+ {
+ max = pixel;
+ }
+ }
+ end:
+ continue;
+ }
+
+ // Final neighborhood thresholds
+ // min = minimum neighbor pixel value
+ // max = maximum neighbor pixel value
+
+ // Median
+ median = (min + max) / 2;
+
+ // Additional thresholds for median-like filtering
+ min2 = (min + median) / 2;
+ max2 = (max + median) / 2;
+ min3 = (min2 + median) / 2;
+ max3 = (max2 + median) / 2;
+
+ // Clamp to thresholds
+ pixel = *(src + bw*(y) + (x));
+ if (pixel < min)
+ {
+ *(dst + bw*y + x) = min;
+ }
+ else if (pixel > max)
+ {
+ *(dst + bw*y + x) = max;
+ }
+ else if (pixel < min2)
+ {
+ *(dst + bw*y + x) = min2;
+ }
+ else if (pixel > max2)
+ {
+ *(dst + bw*y + x) = max2;
+ }
+ else if (pixel < min3)
+ {
+ *(dst + bw*y + x) = min3;
+ }
+ else if (pixel > max3)
+ {
+ *(dst + bw*y + x) = max3;
+ }
+ }
+ }
+}
+
static void nlmeans_filter_edgeboost(const uint8_t *src,
uint8_t *dst,
const int w,
@@ -496,7 +589,9 @@ static void nlmeans_prefilter(BorderedPlane *src,
if (filter_type & NLMEANS_PREFILTER_MODE_MEAN3X3 ||
filter_type & NLMEANS_PREFILTER_MODE_MEAN5X5 ||
filter_type & NLMEANS_PREFILTER_MODE_MEDIAN3X3 ||
- filter_type & NLMEANS_PREFILTER_MODE_MEDIAN5X5)
+ filter_type & NLMEANS_PREFILTER_MODE_MEDIAN5X5 ||
+ filter_type & NLMEANS_PREFILTER_MODE_CSM3X3 ||
+ filter_type & NLMEANS_PREFILTER_MODE_CSM5X5)
{
// Source image
@@ -537,6 +632,16 @@ static void nlmeans_prefilter(BorderedPlane *src,
// Mean 3x3
nlmeans_filter_mean(image, image_pre, w, h, border, 3);
}
+ else if (filter_type & NLMEANS_PREFILTER_MODE_CSM3X3)
+ {
+ // CSM 3x3
+ nlmeans_filter_csm(image, image_pre, w, h, border, 3);
+ }
+ else if (filter_type & NLMEANS_PREFILTER_MODE_CSM5X5)
+ {
+ // CSM 5x5
+ nlmeans_filter_csm(image, image_pre, w, h, border, 5);
+ }
// Restore edges
if (filter_type & NLMEANS_PREFILTER_MODE_EDGEBOOST)