convolve_grey8_grey8
Tcl_Obj* imageObj
Tcl_Obj* kernelImageObj
int scale
int offset

/*
 * Generic convolution operator. The kernel to convole with is specified as a
 * grey8 image together with a scaling factor. This way we do not need a
 * separate matrix Tcl_ObjType, nor floating point math.
 *
 * This convolver should be used only for small kernels, as it uses direct
 * convolution. For larger kernels it is planned to provide an FFT based
 * convolver.
 */

crimp_image*     result;
crimp_image*     image;
crimp_image*     kernel;
int              xo, yo, xi, yi, xk, yk, dx, dy, kw, kh;

crimp_input (imageObj,         image,    grey8);
crimp_input (kernelImageObj,   kernel,   grey8);

if (((kernel->w % 2) == 0) ||
    ((kernel->h % 2) == 0)) {
    Tcl_SetResult(interp, "bad kernel dimensions, expected odd size", TCL_STATIC);
    return TCL_ERROR;
}

kw = kernel->w/2;
kh = kernel->h/2;

result = crimp_new (image->itype, image->w - 2*kw, image->h - 2*kh);

for (yo = 0, yi = kh; yo < result->h; yo++, yi++) {
    for (xo = 0, xi = kw; xo < result->w; xo++, xi++) {

	/*
	 * We convolve all channels with the same kernel, but otherwise
	 * identically
	 */

	int sum = 0;

	for (yk = 0, dy = -kh; yk < kernel->h; yk++, dy++) {
	    for (xk = 0, dx = -kw; xk < kernel->w; xk++, dx++) {

		sum += SGREY8 (kernel, xk, yk) * GREY8 (image, xi-dx, yi-dy);
	    }
	}

	sum /= scale; sum += offset; GREY8 (result, xo, yo) = CLAMP (0, sum, 255);
    }
}

Tcl_SetObjResult(interp, crimp_new_image_obj (result));
return TCL_OK;


/* vim: set sts=4 sw=4 tw=80 et ft=c: */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 78
 * End:
 */