NeuQuant.cs
上传用户:lqb116
上传日期:2014-04-04
资源大小:2712k
文件大小:13k
源码类别:

P2P编程

开发平台:

C#

  1. using System;
  2. namespace LanMsg.Gif.Components
  3. {
  4. public class NeuQuant 
  5. {
  6. protected static readonly int netsize = 256; /* number of colours used */
  7. /* four primes near 500 - assume no image has a length so large */
  8. /* that it is divisible by all four primes */
  9. protected static readonly int prime1 = 499;
  10. protected static readonly int prime2 = 491;
  11. protected static readonly int prime3 = 487;
  12. protected static readonly int prime4 = 503;
  13. protected static readonly int minpicturebytes = ( 3 * prime4 );
  14. /* minimum size for input image */
  15. /* Program Skeleton
  16.    ----------------
  17.    [select samplefac in range 1..30]
  18.    [read image from input file]
  19.    pic = (unsigned char*) malloc(3*width*height);
  20.    initnet(pic,3*width*height,samplefac);
  21.    learn();
  22.    unbiasnet();
  23.    [write output image header, using writecolourmap(f)]
  24.    inxbuild();
  25.    write output image using inxsearch(b,g,r)      */
  26. /* Network Definitions
  27.    ------------------- */
  28. protected static readonly int maxnetpos = (netsize - 1);
  29. protected static readonly int netbiasshift = 4; /* bias for colour values */
  30. protected static readonly int ncycles = 100; /* no. of learning cycles */
  31. /* defs for freq and bias */
  32. protected static readonly int intbiasshift = 16; /* bias for fractions */
  33. protected static readonly int intbias = (((int) 1) << intbiasshift);
  34. protected static readonly int gammashift = 10; /* gamma = 1024 */
  35. protected static readonly int gamma = (((int) 1) << gammashift);
  36. protected static readonly int betashift = 10;
  37. protected static readonly int beta = (intbias >> betashift); /* beta = 1/1024 */
  38. protected static readonly int betagamma =
  39. (intbias << (gammashift - betashift));
  40. /* defs for decreasing radius factor */
  41. protected static readonly int initrad = (netsize >> 3); /* for 256 cols, radius starts */
  42. protected static readonly int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */
  43. protected static readonly int radiusbias = (((int) 1) << radiusbiasshift);
  44. protected static readonly int initradius = (initrad * radiusbias); /* and decreases by a */
  45. protected static readonly int radiusdec = 30; /* factor of 1/30 each cycle */
  46. /* defs for decreasing alpha factor */
  47. protected static readonly int alphabiasshift = 10; /* alpha starts at 1.0 */
  48. protected static readonly int initalpha = (((int) 1) << alphabiasshift);
  49. protected int alphadec; /* biased by 10 bits */
  50. /* radbias and alpharadbias used for radpower calculation */
  51. protected static readonly int radbiasshift = 8;
  52. protected static readonly int radbias = (((int) 1) << radbiasshift);
  53. protected static readonly int alpharadbshift = (alphabiasshift + radbiasshift);
  54. protected static readonly int alpharadbias = (((int) 1) << alpharadbshift);
  55. /* Types and Global Variables
  56. -------------------------- */
  57. protected byte[] thepicture; /* the input image itself */
  58. protected int lengthcount; /* lengthcount = H*W*3 */
  59. protected int samplefac; /* sampling factor 1..30 */
  60. //   typedef int pixel[4];                /* BGRc */
  61. protected int[][] network; /* the network itself - [netsize][4] */
  62. protected int[] netindex = new int[256];
  63. /* for network lookup - really 256 */
  64. protected int[] bias = new int[netsize];
  65. /* bias and freq arrays for learning */
  66. protected int[] freq = new int[netsize];
  67. protected int[] radpower = new int[initrad];
  68. /* radpower for precomputation */
  69. /* Initialise network in range (0,0,0) to (255,255,255) and set parameters
  70.    ----------------------------------------------------------------------- */
  71. public NeuQuant(byte[] thepic, int len, int sample) 
  72. {
  73. int i;
  74. int[] p;
  75. thepicture = thepic;
  76. lengthcount = len;
  77. samplefac = sample;
  78. network = new int[netsize][];
  79. for (i = 0; i < netsize; i++) 
  80. {
  81. network[i] = new int[4];
  82. p = network[i];
  83. p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;
  84. freq[i] = intbias / netsize; /* 1/netsize */
  85. bias[i] = 0;
  86. }
  87. }
  88. public byte[] ColorMap() 
  89. {
  90. byte[] map = new byte[3 * netsize];
  91. int[] index = new int[netsize];
  92. for (int i = 0; i < netsize; i++)
  93. index[network[i][3]] = i;
  94. int k = 0;
  95. for (int i = 0; i < netsize; i++) 
  96. {
  97. int j = index[i];
  98. map[k++] = (byte) (network[j][0]);
  99. map[k++] = (byte) (network[j][1]);
  100. map[k++] = (byte) (network[j][2]);
  101. }
  102. return map;
  103. }
  104. /* Insertion sort of network and building of netindex[0..255] (to do after unbias)
  105.    ------------------------------------------------------------------------------- */
  106. public void Inxbuild() 
  107. {
  108. int i, j, smallpos, smallval;
  109. int[] p;
  110. int[] q;
  111. int previouscol, startpos;
  112. previouscol = 0;
  113. startpos = 0;
  114. for (i = 0; i < netsize; i++) 
  115. {
  116. p = network[i];
  117. smallpos = i;
  118. smallval = p[1]; /* index on g */
  119. /* find smallest in i..netsize-1 */
  120. for (j = i + 1; j < netsize; j++) 
  121. {
  122. q = network[j];
  123. if (q[1] < smallval) 
  124. { /* index on g */
  125. smallpos = j;
  126. smallval = q[1]; /* index on g */
  127. }
  128. }
  129. q = network[smallpos];
  130. /* swap p (i) and q (smallpos) entries */
  131. if (i != smallpos) 
  132. {
  133. j = q[0];
  134. q[0] = p[0];
  135. p[0] = j;
  136. j = q[1];
  137. q[1] = p[1];
  138. p[1] = j;
  139. j = q[2];
  140. q[2] = p[2];
  141. p[2] = j;
  142. j = q[3];
  143. q[3] = p[3];
  144. p[3] = j;
  145. }
  146. /* smallval entry is now in position i */
  147. if (smallval != previouscol) 
  148. {
  149. netindex[previouscol] = (startpos + i) >> 1;
  150. for (j = previouscol + 1; j < smallval; j++)
  151. netindex[j] = i;
  152. previouscol = smallval;
  153. startpos = i;
  154. }
  155. }
  156. netindex[previouscol] = (startpos + maxnetpos) >> 1;
  157. for (j = previouscol + 1; j < 256; j++)
  158. netindex[j] = maxnetpos; /* really 256 */
  159. }
  160. /* Main Learning Loop
  161.    ------------------ */
  162. public void Learn() 
  163. {
  164. int i, j, b, g, r;
  165. int radius, rad, alpha, step, delta, samplepixels;
  166. byte[] p;
  167. int pix, lim;
  168. if (lengthcount < minpicturebytes)
  169. samplefac = 1;
  170. alphadec = 30 + ((samplefac - 1) / 3);
  171. p = thepicture;
  172. pix = 0;
  173. lim = lengthcount;
  174. samplepixels = lengthcount / (3 * samplefac);
  175. delta = samplepixels / ncycles;
  176. alpha = initalpha;
  177. radius = initradius;
  178. rad = radius >> radiusbiasshift;
  179. if (rad <= 1)
  180. rad = 0;
  181. for (i = 0; i < rad; i++)
  182. radpower[i] =
  183. alpha * (((rad * rad - i * i) * radbias) / (rad * rad));
  184. //fprintf(stderr,"beginning 1D learning: initial radius=%dn", rad);
  185. if (lengthcount < minpicturebytes)
  186. step = 3;
  187. else if ((lengthcount % prime1) != 0)
  188. step = 3 * prime1;
  189. else 
  190. {
  191. if ((lengthcount % prime2) != 0)
  192. step = 3 * prime2;
  193. else 
  194. {
  195. if ((lengthcount % prime3) != 0)
  196. step = 3 * prime3;
  197. else
  198. step = 3 * prime4;
  199. }
  200. }
  201. i = 0;
  202. while (i < samplepixels) 
  203. {
  204. b = (p[pix + 0] & 0xff) << netbiasshift;
  205. g = (p[pix + 1] & 0xff) << netbiasshift;
  206. r = (p[pix + 2] & 0xff) << netbiasshift;
  207. j = Contest(b, g, r);
  208. Altersingle(alpha, j, b, g, r);
  209. if (rad != 0)
  210. Alterneigh(rad, j, b, g, r); /* alter neighbours */
  211. pix += step;
  212. if (pix >= lim)
  213. pix -= lengthcount;
  214. i++;
  215. if (delta == 0)
  216. delta = 1;
  217. if (i % delta == 0) 
  218. {
  219. alpha -= alpha / alphadec;
  220. radius -= radius / radiusdec;
  221. rad = radius >> radiusbiasshift;
  222. if (rad <= 1)
  223. rad = 0;
  224. for (j = 0; j < rad; j++)
  225. radpower[j] =
  226. alpha * (((rad * rad - j * j) * radbias) / (rad * rad));
  227. }
  228. }
  229. //fprintf(stderr,"finished 1D learning: readonly alpha=%f !n",((float)alpha)/initalpha);
  230. }
  231. /* Search for BGR values 0..255 (after net is unbiased) and return colour index
  232.    ---------------------------------------------------------------------------- */
  233. public int Map(int b, int g, int r) 
  234. {
  235. int i, j, dist, a, bestd;
  236. int[] p;
  237. int best;
  238. bestd = 1000; /* biggest possible dist is 256*3 */
  239. best = -1;
  240. i = netindex[g]; /* index on g */
  241. j = i - 1; /* start at netindex[g] and work outwards */
  242. while ((i < netsize) || (j >= 0)) 
  243. {
  244. if (i < netsize) 
  245. {
  246. p = network[i];
  247. dist = p[1] - g; /* inx key */
  248. if (dist >= bestd)
  249. i = netsize; /* stop iter */
  250. else 
  251. {
  252. i++;
  253. if (dist < 0)
  254. dist = -dist;
  255. a = p[0] - b;
  256. if (a < 0)
  257. a = -a;
  258. dist += a;
  259. if (dist < bestd) 
  260. {
  261. a = p[2] - r;
  262. if (a < 0)
  263. a = -a;
  264. dist += a;
  265. if (dist < bestd) 
  266. {
  267. bestd = dist;
  268. best = p[3];
  269. }
  270. }
  271. }
  272. }
  273. if (j >= 0) 
  274. {
  275. p = network[j];
  276. dist = g - p[1]; /* inx key - reverse dif */
  277. if (dist >= bestd)
  278. j = -1; /* stop iter */
  279. else 
  280. {
  281. j--;
  282. if (dist < 0)
  283. dist = -dist;
  284. a = p[0] - b;
  285. if (a < 0)
  286. a = -a;
  287. dist += a;
  288. if (dist < bestd) 
  289. {
  290. a = p[2] - r;
  291. if (a < 0)
  292. a = -a;
  293. dist += a;
  294. if (dist < bestd) 
  295. {
  296. bestd = dist;
  297. best = p[3];
  298. }
  299. }
  300. }
  301. }
  302. }
  303. return (best);
  304. }
  305. public byte[] Process() 
  306. {
  307. Learn();
  308. Unbiasnet();
  309. Inxbuild();
  310. return ColorMap();
  311. }
  312. /* Unbias network to give byte values 0..255 and record position i to prepare for sort
  313.    ----------------------------------------------------------------------------------- */
  314. public void Unbiasnet() 
  315. {
  316. int i, j;
  317. for (i = 0; i < netsize; i++) 
  318. {
  319. network[i][0] >>= netbiasshift;
  320. network[i][1] >>= netbiasshift;
  321. network[i][2] >>= netbiasshift;
  322. network[i][3] = i; /* record colour no */
  323. }
  324. }
  325. /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|]
  326.    --------------------------------------------------------------------------------- */
  327. protected void Alterneigh(int rad, int i, int b, int g, int r) 
  328. {
  329. int j, k, lo, hi, a, m;
  330. int[] p;
  331. lo = i - rad;
  332. if (lo < -1)
  333. lo = -1;
  334. hi = i + rad;
  335. if (hi > netsize)
  336. hi = netsize;
  337. j = i + 1;
  338. k = i - 1;
  339. m = 1;
  340. while ((j < hi) || (k > lo)) 
  341. {
  342. a = radpower[m++];
  343. if (j < hi) 
  344. {
  345. p = network[j++];
  346. try 
  347. {
  348. p[0] -= (a * (p[0] - b)) / alpharadbias;
  349. p[1] -= (a * (p[1] - g)) / alpharadbias;
  350. p[2] -= (a * (p[2] - r)) / alpharadbias;
  351. catch (Exception e) 
  352. {
  353. } // prevents 1.3 miscompilation
  354. }
  355. if (k > lo) 
  356. {
  357. p = network[k--];
  358. try 
  359. {
  360. p[0] -= (a * (p[0] - b)) / alpharadbias;
  361. p[1] -= (a * (p[1] - g)) / alpharadbias;
  362. p[2] -= (a * (p[2] - r)) / alpharadbias;
  363. catch (Exception e) 
  364. {
  365. }
  366. }
  367. }
  368. }
  369. /* Move neuron i towards biased (b,g,r) by factor alpha
  370.    ---------------------------------------------------- */
  371. protected void Altersingle(int alpha, int i, int b, int g, int r) 
  372. {
  373. /* alter hit neuron */
  374. int[] n = network[i];
  375. n[0] -= (alpha * (n[0] - b)) / initalpha;
  376. n[1] -= (alpha * (n[1] - g)) / initalpha;
  377. n[2] -= (alpha * (n[2] - r)) / initalpha;
  378. }
  379. /* Search for biased BGR values
  380.    ---------------------------- */
  381. protected int Contest(int b, int g, int r) 
  382. {
  383. /* finds closest neuron (min dist) and updates freq */
  384. /* finds best neuron (min dist-bias) and returns position */
  385. /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
  386. /* bias[i] = gamma*((1/netsize)-freq[i]) */
  387. int i, dist, a, biasdist, betafreq;
  388. int bestpos, bestbiaspos, bestd, bestbiasd;
  389. int[] n;
  390. bestd = ~(((int) 1) << 31);
  391. bestbiasd = bestd;
  392. bestpos = -1;
  393. bestbiaspos = bestpos;
  394. for (i = 0; i < netsize; i++) 
  395. {
  396. n = network[i];
  397. dist = n[0] - b;
  398. if (dist < 0)
  399. dist = -dist;
  400. a = n[1] - g;
  401. if (a < 0)
  402. a = -a;
  403. dist += a;
  404. a = n[2] - r;
  405. if (a < 0)
  406. a = -a;
  407. dist += a;
  408. if (dist < bestd) 
  409. {
  410. bestd = dist;
  411. bestpos = i;
  412. }
  413. biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));
  414. if (biasdist < bestbiasd) 
  415. {
  416. bestbiasd = biasdist;
  417. bestbiaspos = i;
  418. }
  419. betafreq = (freq[i] >> betashift);
  420. freq[i] -= betafreq;
  421. bias[i] += (betafreq << gammashift);
  422. }
  423. freq[bestpos] += beta;
  424. bias[bestpos] -= betagamma;
  425. return (bestbiaspos);
  426. }
  427. }
  428. }