All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.freehep.graphicsio.gif.NeuQuant Maven / Gradle / Ivy

There is a newer version: 2.4
Show newest version
package org.freehep.graphicsio.gif;

/* NeuQuant Neural-Net Quantization Algorithm
 * ------------------------------------------
 *
 * Copyright (c) 1994 Anthony Dekker
 *
 * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
 * See "Kohonen neural networks for optimal colour quantization"
 * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
 * for a discussion of the algorithm.
 * See also  http://www.acm.org/~dekker/NEUQUANT.HTML
 *
 * Any party obtaining a copy of these files from the author, directly or
 * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
 * world-wide, paid up, royalty-free, nonexclusive right and license to deal
 * in this software and documentation files (the "Software"), including without
 * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons who receive
 * copies from any such party to do so, with the only requirement being
 * that this copyright notice remain intact.
 */

public class NeuQuant {

    public static final int ncycles	=	100;			// no. of learning cycles

    public static final int netsize  = 255;		// number of colours used
    public static final int specials  = 3;		// number of reserved colours used
    public static final int bgColour  = specials-1;	// reserved background colour
    public static final int cutnetsize  = netsize - specials;
    public static final int maxnetpos  = netsize-1;

    public static final int initrad	 = netsize/8;   // for 256 cols, radius starts at 32
    public static final int radiusbiasshift = 6;
    public static final int radiusbias = 1 << radiusbiasshift;
    public static final int initBiasRadius = initrad*radiusbias;
    public static final int radiusdec = 30; // factor of 1/30 each cycle

    public static final int alphabiasshift = 10;			// alpha starts at 1
    public static final int initalpha      = 1< 30) throw new RuntimeException ("Sample must be 1..30");
        samplefac = sample;
        setPixels (pixels);
		setUpArrays ();
    }
        
    public int getColorCount () {
    	return netsize;
    }

    public int[] getColorMap() {
    	// keep entry 0 free for transparent color
    	int[] c = new int[netsize+1];
    	c[0] = 0x00000000;
    	for (int i=0; inetsize) hi=netsize;

    	int j = i+1;
    	int k = i-1;
    	int q = 0;
    	while ((jlo)) {
    	    double a = (alpha * (rad*rad - q*q)) / (rad*rad);
    	    q ++;
    		if (jlo) {
    			double [] p = network[k];
    			p[0] -= (a*(p[0] - b));
    			p[1] -= (a*(p[1] - g));
    			p[2] -= (a*(p[2] - r));
    			k--;
    		}
    	}
    }
    
    private int contest (double b, double g, double r) {    // Search for biased BGR values
    	// finds closest neuron (min dist) and updates freq 
    	// finds best neuron (min dist-bias) and returns position 
    	// for frequently chosen neurons, freq[i] is high and bias[i] is negative 
    	// bias[i] = gamma*((1/netsize)-freq[i]) 

    	double bestd = Float.MAX_VALUE;
    	double bestbiasd = bestd;
    	int bestpos = -1;
    	int bestbiaspos = bestpos;
        
    	for (int i=specials; i> radiusbiasshift;
    	if (rad <= 1) rad = 0;
	
//    	System.err.println("beginning 1D learning: samplepixels=" + samplepixels + "  rad=" + rad);

        int step = 0;
        int pos = 0;
        
    	if ((lengthcount%prime1) != 0) step = prime1;
    	else {
    		if ((lengthcount%prime2) !=0) step = prime2;
    		else {
    			if ((lengthcount%prime3) !=0) step = prime3;
    			else step = prime4;
    		}
    	}
	
    	i = 0;
    	while (i < samplepixels) {
    	    int p = pixels [pos / pixels[0].length][pos % pixels[0].length];
	        int red   = (p >> 16) & 0xff;
	        int green = (p >>  8) & 0xff;
	        int blue  = (p      ) & 0xff;

    		double b = blue;
    		double g = green;
    		double r = red;

    		if (i == 0) {   // remember background colour
    			network [bgColour] [0] = b;
    			network [bgColour] [1] = g;
    			network [bgColour] [2] = r;
    		}

    		int j = specialFind (b, g, r);
    		j = j < 0 ? contest (b, g, r) : j;

			if (j >= specials) {   // don't learn for specials
            	double a = (1.0 * alpha) / initalpha;
    			altersingle (a, j, b, g, r);
    			if (rad > 0) alterneigh (a, rad, j, b, g, r);   // alter neighbours
    		}

    		pos += step;
    		while (pos >= lengthcount) pos -= lengthcount;
	        
    		i++;
    		if (i%delta == 0) {	
    			alpha -= alpha / alphadec;
    			biasRadius -= biasRadius / radiusdec;
    			rad = biasRadius >> radiusbiasshift;
    			if (rad <= 1) rad = 0;
    		}
    	}
//    	System.err.println("finished 1D learning: final alpha=" + (1.0 * alpha)/initalpha + "!");
    }

    private void fix() {
        for (int i=0; i 255) x = 255;
                colormap[i][j] = x;
            }
            colormap[i][3] = i;
        }
    }

    private void inxbuild() {
        // Insertion sort of network and building of netindex[0..255]

    	int previouscol = 0;
    	int startpos = 0;

    	for (int i=0; i>1;
    			for (int j=previouscol+1; j>1;
    	for (int j=previouscol+1; j<256; j++) netindex[j] = maxnetpos; // really 256
    }

    public int convert (int pixel) {
        int alfa = (pixel >> 24) & 0xff;
	    int r   = (pixel >> 16) & 0xff;
	    int g = (pixel >>  8) & 0xff;
	    int b  = (pixel      ) & 0xff;
	    int i = inxsearch(b, g, r);
	    int bb = colormap[i][0];
	    int gg = colormap[i][1];
	    int rr = colormap[i][2];
	    return (alfa << 24) | (rr << 16) | (gg << 8) | (bb);
    }

    public int lookup (int pixel) {
	    int r = (pixel >> 16) & 0xff;
	    int g = (pixel >>  8) & 0xff;
	    int b = (pixel      ) & 0xff;
	    int i = inxsearch(b, g, r);
	    // compensate for transparent color
	    return i+1;
    }

    private int not_used_slow_inxsearch(int b, int g, int r) {
        // Search for BGR values 0..255 and return colour index
    	int bestd = 1000;		// biggest possible dist is 256*3
    	int best = -1;
    	for (int i = 0; i=0)) {
    		if (i= bestd) i = netsize;	// stop iter
    			else {
    				if (dist<0) dist = -dist;
    				int a = p[0] - b;   if (a<0) a = -a;
    				dist += a;
    				if (dist=0) {
    			int [] p = colormap[j];
    			int dist = g - p[1]; // inx key - reverse dif
    			if (dist >= bestd) j = -1; // stop iter
    			else {
    				if (dist<0) dist = -dist;
    				int a = p[0] - b;   if (a<0) a = -a;
    				dist += a;
    				if (dist




© 2015 - 2024 Weber Informatics LLC | Privacy Policy