/* @(#)  Calculates the spatial grey level differnce
 * @(#)  matrix of an image and some of its
 * @(#) features.  The 256x1 difference matrix of im is held by m
 * @(#) There should be enough margin around the box so the (dx,dy) can
 * @(#) access neighbouring pixels outside the box
 * @(#)
 * @(#) Usage:
 * @(#) int im_glds_matrix(im, m, xpos, ypos, xsize, ysize, dx, dy)
 * @(#) IMAGE *im, *m;
 * @(#) int xpos, ypos, xsize, ysize;  location of the box within im
 * @(#) int dx, dy;    displacements
 * @(#)
 * @(#) int im_glds_asm(m, asmoment)
 * @(#) IMAGE *m;
 * @(#) double *asmoment;
 * @(#)
 * @(#) int im_glds_contrast(m, contrast)
 * @(#) IMAGE *m;
 * @(#) double *contrast;
 * @(#)
 * @(#) int im_glds_entropy(m, entropy)
 * @(#) IMAGE *m;
 * @(#) double *entropy;
 * @(#)
 * @(#) int im_glds_mean(m, mean)
 * @(#) IMAGE *m;
 * @(#) double *mean;
 * @(#)
 * @(#) All functions return 0 on success and -1 on error
 *
 * Copyright:  N. Dessipris, 1991
 * Written on: 2/12/1991
 * Modified on:
 * 22/7/93 JC
 *	- im_incheck() added
 */

/*

	This file is part of VIPS.

	VIPS is free software; you can redistribute it and/or modify
	it under the terms of the GNU Lesser General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Lesser General Public License for more details.

	You should have received a copy of the GNU Lesser General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
	02110-1301  USA

 */

/*

	These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <glib/gi18n-lib.h>

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <vips/vips.h>
#include <vips/vips7compat.h>

/* Keep the greylevel difference matrix as a 256x1 double image */

int
im_glds_matrix(IMAGE *im, IMAGE *m,
	int xpos, int ypos, int xsize, int ysize, int dx, int dy)
{
	PEL *in, *cpin;
	int *b, *pb;
	double *l, *pl;
	int x, y;
	int ofs;
	int tmp;
	int norm;

	if (im_iocheck(im, m) == -1)
		return -1;

	if ((im->Bands != 1) || (im->BandFmt != IM_BANDFMT_UCHAR)) {
		im_error("im_glds_matrix", "%s", _("Wrong input"));
		return -1;
	}

	if ((xpos + xsize + dx > im->Xsize) || (ypos + ysize + dy > im->Ysize)) {
		im_error("im_glds_matrix", "%s", _("wrong args"));
		return -1;
	}

	if (im_cp_desc(m, im) == -1)
		return -1;
	m->Xsize = 256;
	m->Ysize = 1;
	m->BandFmt = IM_BANDFMT_DOUBLE;
	m->Type = IM_TYPE_B_W;

	if (im_setupout(m) == -1)
		return -1;

	b = (int *) calloc((unsigned) m->Xsize, sizeof(int));
	l = (double *) calloc((unsigned) m->Xsize, sizeof(double));
	if ((b == NULL) || (l == NULL)) {
		im_error("im_glds_matrix", "%s", _("calloc failed"));
		return -1;
	}

	in = (PEL *) im->data;
	in += (ypos * im->Xsize + xpos);
	ofs = dy * im->Xsize + dx;
	for (y = 0; y < ysize; y++) {
		cpin = in;
		in += im->Xsize;
		for (x = 0; x < xsize; x++) {
			tmp = abs((int) *cpin - (int) (*(cpin + ofs)));
			pb = (b + tmp);
			(*pb)++;
			cpin++;
		}
	}

	norm = xsize * ysize;
	pb = b;
	pl = l;
	for (x = 0; x < m->Xsize; x++)
		*pl++ = ((double) (*pb++)) / (double) norm;
	if (im_writeline(0, m, (PEL *) l) == -1)
		return -1;

	free((char *) b);
	free((char *) l);
	return 0;
}

/* @(#)  Calculates the asmoment of the sglds matrix held by m
 */
int
im_glds_asm(IMAGE *m, double *asmoment)
{
	double temp, tmpasm, *in;
	int i;

	if (im_incheck(m))
		return -1;

	if (m->Xsize != 256 || m->Ysize != 1 ||
		m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) {
		im_error("im_glds_asm", "%s", _("unable to accept input"));
		return -1;
	}
	tmpasm = 0.0;
	in = (double *) m->data;
	for (i = 0; i < m->Xsize; i++) {
		temp = *in++;
		tmpasm += (temp * temp);
	}
	*asmoment = tmpasm;
	return 0;
}

/* @(#)     Calculates the contrast of the coocurence matrix passed in buffer
 */
int
im_glds_contrast(IMAGE *m, double *contrast)
{
	double tmpcon, *in;
	int i;

	if (im_incheck(m))
		return -1;

	if (m->Xsize != 256 || m->Ysize != 1 ||
		m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) {
		im_error("im_glds_contrast", "%s", _("wrong input"));
		return -1;
	}
	tmpcon = 0.0;
	in = (double *) m->data;
	for (i = 0; i < m->Xsize; i++) {
		tmpcon += (((double) i) * ((double) i) * (*in));
		in++;
	}
	*contrast = tmpcon;
	return 0;
}

/* @(#)     Calculates the entropy of the glds vector passed in buffer
 * @(#) Function returns the entropy based on log base 2.
 */
int
im_glds_entropy(IMAGE *m, double *entropy)
{
	double tmpent, dtemp, *in;
	int i;

	if (im_incheck(m))
		return -1;

	if (m->Xsize != 256 || m->Ysize != 1 ||
		m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) {
		im_error("im_glds_entropy", "%s", _("wrong input"));
		return -1;
	}
	tmpent = 0.0;
	in = (double *) m->data;
	for (i = 0; i < m->Xsize; i++) {
		if (*in != 0) {
			dtemp = *in;
			tmpent += (dtemp * log10(dtemp));
		}
		in++;
	}
	*entropy = ((-1) * tmpent / log10(2.0));
	return 0;
}

/* @(#)     Calculates the mean of the sglds matrix passed in m
 */
int
im_glds_mean(IMAGE *m, double *mean)
{
	double tmpmean, *in;
	int i;

	if (im_incheck(m))
		return -1;

	if (m->Xsize != 256 || m->Ysize != 1 ||
		m->Bands != 1 || m->BandFmt != IM_BANDFMT_DOUBLE) {
		im_error("im_glds_mean", "%s", _("wrong input"));
		return -1;
	}
	tmpmean = 0.0;
	in = (double *) m->data;
	for (i = 0; i < m->Xsize; i++) {
		tmpmean += (((double) i) * (*in));
		in++;
	}
	tmpmean = tmpmean / ((double) m->Xsize);
	*mean = tmpmean;
	return 0;
}
