shithub: brokentoys

Download patch

ref: 6cef9c8e6d812216fa88288831ec8c414010c265
parent: 8bb495b12b93a9be9578563aa9ca17847040ade3
author: rodri <rgl@antares-labs.eu>
date: Sun Apr 27 14:52:59 EDT 2025

image/convolution: implement the correct convolution formula

--- a/image/convolution.c
+++ b/image/convolution.c
@@ -72,6 +72,19 @@
 	return kern;
 }
 
+static double
+coeffsum(double *k, int dim)
+{
+	double s;
+	int i, j;
+
+	s = 0;
+	for(j = 0; j < dim; j++)
+	for(i = 0; i < dim; i++)
+		s += k[j*dim+i];
+	return s;
+}
+
 static void
 normalize(double *k, int dim)
 {
@@ -78,11 +91,10 @@
 	double avg;
 	int i, j;
 
-	avg = 0;
-	for(j = 0; j < dim; j++)
-	for(i = 0; i < dim; i++)
-		avg += k[j*dim+i];
+	avg = coeffsum(k, dim);
 	avg /= dim*dim;
+	if(avg == 0)
+		avg = 1;
 	for(j = 0; j < dim; j++)
 	for(i = 0; i < dim; i++)
 		k[j*dim+i] /= avg;
@@ -118,14 +130,17 @@
 convolve(double *d, double *s, int dim)
 {
 	int i, j;
-	double r;
+	double denom, r;
 
+	denom = coeffsum(s, dim);
+	denom = denom == 0? 1: 1/denom;
+
 	modulate(d, s, dim);
 	r = 0;
 	for(j = 0; j < dim; j++)
 	for(i = 0; i < dim; i++)
 		r += d[j*dim+i];
-	return r;
+	return fabs(r*denom);
 }
 
 static uchar
@@ -143,6 +158,7 @@
 	double **im;
 	Rectangle imr;
 	Point imc, p, cp;
+	double c;
 	int i;
 
 	im = malloc(d->nchan*sizeof(double*));
@@ -161,14 +177,15 @@
 	for(p.x = s->r.min.x; p.x < s->r.max.x; p.x++){
 		for(cp.y = imr.min.y; cp.y < imr.max.y; cp.y++)
 		for(cp.x = imr.min.x; cp.x < imr.max.x; cp.x++){
-			for(i = 0; i < d->nchan; i++){
-				im[i][cp.y*dim + cp.x] = saturate
-				? clamp(sample(s, addpt(p, subpt(cp, imc)), i), 0, 0xFF)
-				: sample(s, addpt(p, subpt(cp, imc)), i);
-			}
+			for(i = 0; i < d->nchan; i++)
+				im[i][cp.y*dim + cp.x] = sample(s, addpt(p, subpt(cp, imc)), i);
 		}
-		for(i = 0; i < d->nchan; i++)
-			*(byteaddr(d, p) + i) = convolve(im[i], k, dim);
+		for(i = 0; i < d->nchan; i++){
+			c = convolve(im[i], k, dim);
+			if(saturate)
+				c = clamp(c, 0, 0xFF);
+			*(byteaddr(d, p) + i) = c;
+		}
 	}
 
 	for(i = 0; i < d->nchan; i++)
--