shithub: brokentoys

Download patch

ref: 317cb407d207055980e3b700e5dc5a5178b0672b
parent: 5961a8b6d2f95e29c0b7b0b450eb988763b12c40
author: rodri <rgl@antares-labs.eu>
date: Sat Apr 26 17:53:52 EDT 2025

add image processing tools

--- /dev/null
+++ b/image/add.c
@@ -1,0 +1,58 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s img1 img2\n", argv0);
+	exits(nil);
+}
+
+void
+main(int argc, char *argv[])
+{
+	Memimage *img1, *img2;
+	uchar *p1, *p2;
+	uchar *p1e;
+	int fd;
+
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc != 2)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img1 = readmemimage(fd);
+	if(img1 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	fd = open(argv[1], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img2 = readmemimage(fd);
+	if(img2 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	if(img1->chan != img2->chan || !eqrect(img1->r, img2->r))
+		sysfatal("images shapes differ");
+
+	p1 = img1->data->bdata;
+	p2 = img2->data->bdata;
+	p1e = p1 + Dx(img1->r)*Dy(img1->r)*img1->nchan;
+	while(p1 < p1e)
+		*p1++ += *p2++;
+
+	if(writememimage(1, img1) < 0)
+		sysfatal("writememimage: %r");
+
+	freememimage(img2);
+	freememimage(img1);
+	exits(nil);
+}
--- /dev/null
+++ b/image/convolution.c
@@ -1,0 +1,212 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <memdraw.h>
+
+#define min(a,b)	((a)<(b)?(a):(b))
+#define max(a,b)	((a)>(b)?(a):(b))
+#define clamp(a,b,c)	min(max(a,b),c)
+
+static int dim;
+
+static void
+fprintm(int fd, double *m, int dim)
+{
+	int i, j;
+
+	for(j = 0; j < dim; j++)
+	for(i = 0; i < dim; i++)
+		fprint(fd, "%g%c", m[j*dim+i], i == dim-1? '\n': '\t');
+}
+
+static double *
+readkernel(int fd)
+{
+	Biobuf *bin;
+	double *kern;
+	char *line, *f[10];
+	int nf, i, j;
+
+	bin = Bfdopen(fd, OREAD);
+	if(bin == nil)
+		sysfatal("Bfdopen: %r");
+	do{
+		line = Brdline(bin, '\n');
+		if(line == nil)
+			sysfatal("Brdline: %r");
+		dim = tokenize(line, f, nelem(f));
+	}while(dim < 1);
+	kern = malloc(dim*dim*sizeof(double));
+	if(kern == nil)
+		sysfatal("malloc: %r");
+	for(j = i = 0; i < dim; i++)
+		kern[j*dim+i] = strtod(f[i], nil);
+	j++;
+
+	while((line = Brdline(bin, '\n')) != nil){
+		if((nf = tokenize(line, f, nelem(f))) < 1)
+			continue;
+		if(nf != dim)
+			sysfatal("expected a %dx%d matrix", dim, dim);
+		for(i = 0; i < dim; i++)
+			kern[j*dim+i] = strtod(f[i], nil);
+		j++;
+	}
+	Bterm(bin);
+
+	if(j != dim)
+		sysfatal("expected a %dx%d matrix", dim, dim);
+
+	return kern;
+}
+
+static void
+normalize(double *k, int dim)
+{
+	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 /= dim*dim;
+	for(j = 0; j < dim; j++)
+	for(i = 0; i < dim; i++)
+		k[j*dim+i] /= avg;
+}
+
+static double *
+reverse(double *k, int dim)
+{
+	double *ck;
+	int i, j;
+
+	ck = malloc(dim*dim*sizeof(double));
+	if(ck == nil)
+		sysfatal("malloc: %r");
+
+	for(j = 0; j < dim; j++)
+	for(i = 0; i < dim; i++)
+		ck[j*dim+i] = k[(dim-j-1)*dim+(dim-i-1)];
+	return ck;
+}
+
+static void
+modulate(double *d, double *s, int dim)
+{
+	int i, j;
+
+	for(j = 0; j < dim; j++)
+	for(i = 0; i < dim; i++)
+		d[j*dim+i] *= s[j*dim+i];
+}
+
+static double
+convolve(double *d, double *s, int dim)
+{
+	int i, j;
+	double r;
+
+	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;
+}
+
+static uchar
+sample(Memimage *i, Point p, int off)
+{
+	if(p.x < i->r.min.x || p.y < i->r.min.y
+	|| p.x >= i->r.max.x || p.y >= i->r.max.y)
+		return 0;	/* edge handler: constant */
+	return *(byteaddr(i, p) + off);
+}
+
+static void
+imgconvolution(Memimage *d, Memimage *s, double *k, int dim)
+{
+	double **im;
+	Rectangle imr;
+	Point imc, p, cp;
+	int i;
+
+	im = malloc(d->nchan*sizeof(double*));
+	if(im == nil)
+		sysfatal("malloc: %r");
+	for(i = 0; i < d->nchan; i++){
+		im[i] = malloc(dim*dim*sizeof(double));
+		if(im[i] == nil)
+			sysfatal("malloc: %r");
+	}
+
+	imr = Rect(0,0,dim,dim);
+	imc = Pt(dim/2, dim/2);
+
+	for(p.y = s->r.min.y; p.y < s->r.max.y; p.y++)
+	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] = 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++)
+		free(im[i]);
+	free(im);
+}
+
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s imgfile\n", argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+	Memimage *in, *out;
+	double *kern, *ckern;
+	int fd;
+
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc != 1)
+		usage();
+
+	kern = readkernel(0);
+	ckern = reverse(kern, dim);
+	free(kern);
+	kern = ckern;
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	in = readmemimage(fd);
+	if(in == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	out = allocmemimage(in->r, in->chan);
+	if(out == nil)
+		sysfatal("allocmemimage: %r");
+
+	imgconvolution(out, in, kern, dim);
+	if(writememimage(1, out) < 0)
+		sysfatal("writememimage: %r");
+
+	freememimage(out);
+	freememimage(in);
+	free(kern);
+	exits(nil);
+}
--- /dev/null
+++ b/image/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+BIN=$home/bin/$objtype
+TARG=\
+	convolution\
+	add\
+	sub\
+	sobel\
+
+</sys/src/cmd/mkmany
--- /dev/null
+++ b/image/sobel.c
@@ -1,0 +1,58 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s img1 img2\n", argv0);
+	exits(nil);
+}
+
+void
+main(int argc, char *argv[])
+{
+	Memimage *img1, *img2;
+	uchar *p1, *p2;
+	uchar *p1e;
+	int fd;
+
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc != 2)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img1 = readmemimage(fd);
+	if(img1 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	fd = open(argv[1], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img2 = readmemimage(fd);
+	if(img2 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	if(img1->chan != img2->chan || !eqrect(img1->r, img2->r))
+		sysfatal("images shapes differ");
+
+	p1 = img1->data->bdata;
+	p2 = img2->data->bdata;
+	p1e = p1 + Dx(img1->r)*Dy(img1->r)*img1->nchan;
+	while(p1 < p1e)
+		*p1++ = sqrt(*p1**p1 + *p2**p2++);
+
+	if(writememimage(1, img1) < 0)
+		sysfatal("writememimage: %r");
+
+	freememimage(img2);
+	freememimage(img1);
+	exits(nil);
+}
--- /dev/null
+++ b/image/sub.c
@@ -1,0 +1,58 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+
+static void
+usage(void)
+{
+	fprint(2, "usage: %s img1 img2\n", argv0);
+	exits(nil);
+}
+
+void
+main(int argc, char *argv[])
+{
+	Memimage *img1, *img2;
+	uchar *p1, *p2;
+	uchar *p1e;
+	int fd;
+
+	ARGBEGIN{
+	default: usage();
+	}ARGEND;
+	if(argc != 2)
+		usage();
+
+	fd = open(argv[0], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img1 = readmemimage(fd);
+	if(img1 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	fd = open(argv[1], OREAD);
+	if(fd < 0)
+		sysfatal("open: %r");
+	img2 = readmemimage(fd);
+	if(img2 == nil)
+		sysfatal("readmemimage: %r");
+	close(fd);
+
+	if(img1->chan != img2->chan || !eqrect(img1->r, img2->r))
+		sysfatal("images shapes differ");
+
+	p1 = img1->data->bdata;
+	p2 = img2->data->bdata;
+	p1e = p1 + Dx(img1->r)*Dy(img1->r)*img1->nchan;
+	while(p1 < p1e)
+		*p1++ -= *p2++;
+
+	if(writememimage(1, img1) < 0)
+		sysfatal("writememimage: %r");
+
+	freememimage(img2);
+	freememimage(img1);
+	exits(nil);
+}
--