[Bf-blender-cvs] [611752ce334] master: UI: color-band eyedropper now combines samples

Campbell Barton noreply at git.blender.org
Wed Dec 13 05:37:30 CET 2017


Commit: 611752ce334a04acbc7439a0220f57f05fca1e48
Author: Campbell Barton
Date:   Wed Dec 13 15:35:03 2017 +1100
Branches: master
https://developer.blender.org/rB611752ce334a04acbc7439a0220f57f05fca1e48

UI: color-band eyedropper now combines samples

Resulting color-band was too noisy (especially with photos),
use gauss filter to take surrounding samples into account.

===================================================================

M	source/blender/blenkernel/BKE_colorband.h
M	source/blender/blenkernel/intern/colorband.c
M	source/blender/editors/interface/interface_eyedropper_colorband.c

===================================================================

diff --git a/source/blender/blenkernel/BKE_colorband.h b/source/blender/blenkernel/BKE_colorband.h
index 6841d94d360..edb724d2aec 100644
--- a/source/blender/blenkernel/BKE_colorband.h
+++ b/source/blender/blenkernel/BKE_colorband.h
@@ -37,7 +37,7 @@ struct ColorBand;
 
 void              BKE_colorband_init(struct ColorBand *coba, bool rangetype);
 void              BKE_colorband_init_from_table_rgba(
-        struct ColorBand *coba, const float (*array)[4], const int array_len);
+        struct ColorBand *coba, const float (*array)[4], const int array_len, bool filter_sample);
 struct ColorBand *BKE_colorband_add(bool rangetype);
 bool              BKE_colorband_evaluate(const struct ColorBand *coba, float in, float out[4]);
 void              BKE_colorband_evaluate_table_rgba(const struct ColorBand *coba, float **array, int *size);
diff --git a/source/blender/blenkernel/intern/colorband.c b/source/blender/blenkernel/intern/colorband.c
index 0655c51f26c..d35e797ddac 100644
--- a/source/blender/blenkernel/intern/colorband.c
+++ b/source/blender/blenkernel/intern/colorband.c
@@ -163,22 +163,33 @@ static float color_sample_remove_cost(const struct ColorResampleElem *c)
 	return area;
 }
 
+/* TODO(campbell): create BLI_math_filter? */
+static float filter_gauss(float x)
+{
+	const float gaussfac = 1.6f;
+	const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
+	x *= 3.0f * gaussfac;
+	return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x * x / two_gaussfac2);
+}
+
 static void colorband_init_from_table_rgba_resample(
         ColorBand *coba,
-        const float (*array)[4], const int array_len)
+        const float (*array)[4], const int array_len,
+        bool filter_samples)
 {
-	BLI_assert(array_len >= MAXCOLORBAND);
-	/* Use 2x to avoid noise having too much impact, since this is RGBA accumulated. */
-	const float eps_2x = ((1.0f / 255.0f) + 1e-6f) * 2.0f;
+	BLI_assert(array_len >= 2);
+	const float eps_2x = ((1.0f / 255.0f) + 1e-6f);
 	struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__);
 	int carr_len = array_len;
 	c = carr;
-	const float step_size = 1.0f / (float)(array_len - 1);
-	for (int i = 0; i < array_len; i++, c++) {
-		copy_v4_v4(carr[i].rgba, array[i]);
-		c->next = c + 1;
-		c->prev = c - 1;
-		c->pos = i * step_size;
+	{
+		const float step_size = 1.0f / (float)(array_len - 1);
+		for (int i = 0; i < array_len; i++, c++) {
+			copy_v4_v4(carr[i].rgba, array[i]);
+			c->next = c + 1;
+			c->prev = c - 1;
+			c->pos = i * step_size;
+		}
 	}
 	carr[0].prev = NULL;
 	carr[array_len - 1].next = NULL;
@@ -225,13 +236,56 @@ static void colorband_init_from_table_rgba_resample(
 	}
 	BLI_heap_free(heap, NULL);
 
-	BLI_assert(carr_len < MAXCOLORBAND);
-	int i = 0;
 	/* First member is never removed. */
-	for (c = carr; c != NULL; c = c->next, i++) {
-		copy_v4_v4(&coba->data[i].r, c->rgba);
-		coba->data[i].pos = c->pos;
-		coba->data[i].cur = i;
+	int i = 0;
+	BLI_assert(carr_len < MAXCOLORBAND);
+	if (filter_samples == false) {
+		for (c = carr; c != NULL; c = c->next, i++) {
+			copy_v4_v4(&coba->data[i].r, c->rgba);
+			coba->data[i].pos = c->pos;
+			coba->data[i].cur = i;
+		}
+	}
+	else {
+		for (c = carr; c != NULL; c = c->next, i++) {
+			const int steps_prev = c->prev ? (c - c->prev) - 1 : 0;
+			const int steps_next = c->next ? (c->next - c) - 1 : 0;
+			if (steps_prev == 0 && steps_next == 0) {
+				copy_v4_v4(&coba->data[i].r, c->rgba);
+			}
+			else {
+				float rgba[4];
+				float rgba_accum = 1;
+				copy_v4_v4(rgba, c->rgba);
+
+				if (steps_prev) {
+					const float step_size = 1.0 / (float)(steps_prev + 1);
+					int j = steps_prev;
+					for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) {
+						const float step_pos = (float)j * step_size;
+						BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+						const float f = filter_gauss(step_pos);
+						madd_v4_v4fl(rgba, c_other->rgba, f);
+						rgba_accum += f;
+					}
+				}
+				if (steps_next) {
+					const float step_size = 1.0 / (float)(steps_next + 1);
+					int j = steps_next;
+					for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) {
+						const float step_pos = (float)j * step_size;
+						BLI_assert(step_pos > 0.0f && step_pos < 1.0f);
+						const float f = filter_gauss(step_pos);
+						madd_v4_v4fl(rgba, c_other->rgba, f);
+						rgba_accum += f;
+					}
+				}
+
+				mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum);
+			}
+			coba->data[i].pos = c->pos;
+			coba->data[i].cur = i;
+		}
 	}
 	BLI_assert(i == carr_len);
 	coba->tot = i;
@@ -242,15 +296,18 @@ static void colorband_init_from_table_rgba_resample(
 
 void BKE_colorband_init_from_table_rgba(
         ColorBand *coba,
-        const float (*array)[4], const int array_len)
+        const float (*array)[4], const int array_len,
+        bool filter_samples)
 {
-	if (array_len < MAXCOLORBAND) {
+	/* Note, we could use MAXCOLORBAND here, but results of re-sampling are nicer,
+	 * avoid different behavior when limit is hit. */
+	if (array_len < 2) {
 		/* No Re-sample, just de-duplicate. */
 		colorband_init_from_table_rgba_simple(coba, array, array_len);
 	}
 	else {
 		/* Re-sample */
-		colorband_init_from_table_rgba_resample(coba, array, array_len);
+		colorband_init_from_table_rgba_resample(coba, array, array_len, filter_samples);
 	}
 }
 
diff --git a/source/blender/editors/interface/interface_eyedropper_colorband.c b/source/blender/editors/interface/interface_eyedropper_colorband.c
index 655c2c46c6c..85339ff0322 100644
--- a/source/blender/editors/interface/interface_eyedropper_colorband.c
+++ b/source/blender/editors/interface/interface_eyedropper_colorband.c
@@ -165,7 +165,9 @@ static void eyedropper_colorband_exit(bContext *C, wmOperator *op)
 static void eyedropper_colorband_apply(bContext *C, wmOperator *op)
 {
 	EyedropperColorband *eye = op->customdata;
-	BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len);
+	/* Always filter, avoids noise in resulting color-band. */
+	bool filter_samples = true;
+	BKE_colorband_init_from_table_rgba(eye->color_band, eye->color_buffer, eye->color_buffer_len, filter_samples);
 	RNA_property_update(C, &eye->ptr, eye->prop);
 }



More information about the Bf-blender-cvs mailing list