MEDIAN.C 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /*
  2. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  3. SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
  4. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  5. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  6. IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  7. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  8. FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  9. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
  10. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  11. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
  12. */
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include <stdio.h>
  19. #include <io.h>
  20. #include <dos.h>
  21. #include <graph.h>
  22. #include <malloc.h>
  23. #include <math.h>
  24. #include <conio.h>
  25. typedef unsigned char BYTE;
  26. typedef unsigned short WORD;
  27. typedef unsigned int DWORD;
  28. #define BITS (5)
  29. #define LEVELS (1<<BITS)
  30. #define MAXVAL (LEVELS-1)
  31. // 0 = Red, 2=Green, 1=Blue
  32. static int BoxRedLo[256];
  33. static int BoxRedHi[256];
  34. static int BoxGreenLo[256];
  35. static int BoxGreenHi[256];
  36. static int BoxBlueLo[256];
  37. static int BoxBlueHi[256];
  38. static int BoxNumElements[256];
  39. static int TotalPixels;
  40. int Frequency[32768];
  41. static unsigned char * VideoMemory = (unsigned char *)0xA0000;
  42. static void Shrink( int BoxIndex ) {
  43. int RedIndex, BlueIndex, GreenIndex, Index;
  44. int RedLo = BoxRedLo[BoxIndex];
  45. int RedHi = BoxRedHi[BoxIndex];
  46. int GreenLo = BoxGreenLo[BoxIndex];
  47. int GreenHi = BoxGreenHi[BoxIndex];
  48. int BlueLo = BoxBlueLo[BoxIndex];
  49. int BlueHi = BoxBlueHi[BoxIndex];
  50. for (RedIndex=RedLo; RedIndex<=RedHi; RedIndex++ )
  51. for (BlueIndex=BlueLo; BlueIndex<=BlueHi; BlueIndex++ ) {
  52. Index = (RedIndex<<(BITS+BITS)) + (GreenLo<<BITS) + BlueIndex;
  53. for (GreenIndex=GreenLo; GreenIndex<=GreenHi; GreenIndex++, Index+=32 )
  54. if ( Frequency[ Index ] )
  55. goto Next1;
  56. }
  57. Next1:
  58. BoxRedLo[BoxIndex] = RedIndex;
  59. RedLo = RedIndex;
  60. for (RedIndex=RedHi; RedIndex>=RedLo; RedIndex-- )
  61. for (BlueIndex=BlueHi; BlueIndex>=BlueLo; BlueIndex-- ) {
  62. Index=(RedIndex<<(BITS+BITS)) + (GreenHi<<BITS) + BlueIndex;
  63. for (GreenIndex=GreenHi; GreenIndex>=GreenLo; GreenIndex--, Index -= 32 )
  64. if ( Frequency[ Index ] )
  65. goto Next2;
  66. }
  67. Next2:
  68. BoxRedHi[BoxIndex] = RedIndex;
  69. RedHi = RedIndex;
  70. for (BlueIndex=BlueLo; BlueIndex<=BlueHi; BlueIndex++ )
  71. for (RedIndex=RedLo; RedIndex<=RedHi; RedIndex++ ) {
  72. Index = (RedIndex<<(BITS+BITS)) + BlueIndex + (GreenLo<<BITS);
  73. for (GreenIndex=GreenLo; GreenIndex<=GreenHi; GreenIndex++, Index += 32 )
  74. if ( Frequency[ Index ] )
  75. goto Next3;
  76. }
  77. Next3:
  78. BoxBlueLo[BoxIndex] = BlueIndex;
  79. BlueLo = BlueIndex;
  80. for (BlueIndex=BlueHi; BlueIndex>=BlueLo; BlueIndex-- )
  81. for (RedIndex=RedHi; RedIndex>=RedLo; RedIndex-- ) {
  82. Index=(RedIndex<<(BITS+BITS)) + (GreenHi<<BITS) + BlueIndex;
  83. for (GreenIndex=GreenHi; GreenIndex>=GreenLo; GreenIndex--, Index -= 32 )
  84. if ( Frequency[ Index ] )
  85. goto Next4;
  86. }
  87. Next4:
  88. BoxBlueHi[BoxIndex] = BlueIndex;
  89. BlueHi = BlueIndex;
  90. for (GreenIndex=GreenLo; GreenIndex<=GreenHi; GreenIndex++ )
  91. for (RedIndex=RedLo; RedIndex<=RedHi; RedIndex++ ) {
  92. Index=(RedIndex<<(BITS+BITS)) + (GreenIndex<<BITS) + BlueLo;
  93. for (BlueIndex=BlueLo; BlueIndex<=BlueHi; BlueIndex++, Index++ )
  94. if ( Frequency[ Index ] )
  95. goto Next5;
  96. }
  97. Next5:
  98. BoxGreenLo[BoxIndex] = GreenIndex;
  99. GreenLo = GreenIndex;
  100. for (GreenIndex=GreenHi; GreenIndex>=GreenLo; GreenIndex-- )
  101. for (RedIndex=RedHi; RedIndex>=RedLo; RedIndex-- ) {
  102. Index=(RedIndex<<(BITS+BITS)) + (GreenIndex<<BITS) + BlueHi;
  103. for (BlueIndex=BlueHi; BlueIndex>=BlueLo; BlueIndex--, Index-- )
  104. if ( Frequency[ Index ] )
  105. goto Next6;
  106. }
  107. Next6:
  108. BoxGreenHi[BoxIndex] = GreenIndex;
  109. // John's way...
  110. /*
  111. NewGreenLo = GreenHi; NewGreenHi = GreenLo;
  112. NewRedLo = RedHi; NewRedHi = RedLo;
  113. NewBlueLo = BlueHi; NewBlueHi = BlueLo;
  114. for (GreenIndex=GreenHi; GreenIndex>=GreenLo; GreenIndex-- )
  115. for (RedIndex=RedHi; RedIndex>=RedLo; RedIndex-- ) {
  116. Index=(RedIndex<<(BITS+BITS)) + (GreenIndex<<BITS) + BlueHi;
  117. for (BlueIndex=BlueHi; BlueIndex>=BlueLo; BlueIndex--, Index-- ) {
  118. f = Frequency[ Index ]
  119. if ( f ) {
  120. if ( RedIndex < NewRedLo ) NewRedLo = RedIndex;
  121. if ( GreenIndex < NewGreenLo ) NewGreenLo = GreenIndex;
  122. if ( BlueIndex < NewBlueLo ) NewBlueLo = BlueIndex;
  123. }
  124. }
  125. */
  126. }
  127. void MedianClearFrequencies( int * freq_buffer );
  128. #pragma aux MedianClearFrequencies= \
  129. "push es" \
  130. "push ds" \
  131. "pop es" \
  132. "xor eax, eax" \
  133. "mov ecx, 32768" \
  134. "rep stosd" \
  135. "pop es" \
  136. parm [EDI] \
  137. modify [ EAX ECX ];
  138. void MedianReadFrequencies(WORD * source, int numpixels);
  139. #pragma aux MedianReadFrequencies = \
  140. "xor eax, eax" \
  141. "next_one: mov ax, word ptr [esi]" \
  142. "add esi,2" \
  143. "inc Frequency[eax*4]" \
  144. "loop next_one" \
  145. parm [ESI] [ECX] \
  146. modify [ EAX ];
  147. void MedianPutImage( WORD * source, unsigned char * dest, int numpixels );
  148. #pragma aux MedianPutImage = \
  149. "xor eax, eax" \
  150. "next_pixel: mov ax, word ptr [esi]" \
  151. "add esi, 2" \
  152. "mov eax, Frequency[eax*4]" \
  153. "mov [edi], al" \
  154. "inc edi" \
  155. "loop next_pixel" \
  156. parm [ESI] [EDI] [ECX] \
  157. modify [ EAX ];
  158. static int FindNextBoxToSplit(int NumBoxes)
  159. {
  160. int c, SelectedBox, LongMax;
  161. LongMax = 0;
  162. SelectedBox = -1;
  163. // Find box with most elements that includes more than 1 color...
  164. // if none, we're done...
  165. for (c=0; c<NumBoxes; c++ ) {
  166. if ( (BoxNumElements[c] > LongMax) &&
  167. ( (BoxRedLo[c] != BoxRedHi[c]) ||
  168. (BoxBlueLo[c] != BoxBlueHi[c]) ||
  169. (BoxGreenLo[c] != BoxGreenHi[c]) ))
  170. {
  171. LongMax = BoxNumElements[c];
  172. SelectedBox = c;
  173. }
  174. }
  175. return SelectedBox;
  176. }
  177. static void SplitBoxRed( int SelectedBox, int TargetBox )
  178. {
  179. int ElementSum, PlaneSum, RedIndex, GreenIndex, BlueIndex;
  180. ElementSum = 0;
  181. for (RedIndex=BoxRedLo[SelectedBox]; RedIndex<=BoxRedHi[SelectedBox]; RedIndex++ ) {
  182. PlaneSum = 0;
  183. for (BlueIndex=BoxBlueLo[SelectedBox]; BlueIndex<=BoxBlueHi[SelectedBox]; BlueIndex++ )
  184. for (GreenIndex=BoxGreenLo[SelectedBox]; GreenIndex<=BoxGreenHi[SelectedBox]; GreenIndex++ )
  185. PlaneSum += Frequency[ RedIndex<<(BITS+BITS) | GreenIndex<<BITS | BlueIndex ];
  186. ElementSum += PlaneSum;
  187. if (ElementSum > BoxNumElements[SelectedBox]/2)
  188. break;
  189. }
  190. if (RedIndex == BoxRedHi[SelectedBox] ) {
  191. RedIndex--;
  192. ElementSum -= PlaneSum;
  193. }
  194. BoxRedLo[TargetBox] = BoxRedLo[SelectedBox];
  195. BoxRedHi[TargetBox] = BoxRedHi[SelectedBox];
  196. BoxBlueLo[TargetBox] = BoxBlueLo[SelectedBox];
  197. BoxBlueHi[TargetBox] = BoxBlueHi[SelectedBox];
  198. BoxGreenLo[TargetBox] = BoxGreenLo[SelectedBox];
  199. BoxGreenHi[TargetBox] = BoxGreenHi[SelectedBox];
  200. BoxRedLo[TargetBox] = RedIndex+1;
  201. BoxNumElements[TargetBox] = BoxNumElements[SelectedBox] - ElementSum;
  202. BoxRedHi[SelectedBox] = RedIndex;
  203. BoxNumElements[SelectedBox] = ElementSum;
  204. }
  205. static void SplitBoxBlue( int SelectedBox, int TargetBox )
  206. {
  207. int ElementSum, PlaneSum, RedIndex, GreenIndex, BlueIndex;
  208. ElementSum = 0;
  209. for (BlueIndex=BoxBlueLo[SelectedBox]; BlueIndex<=BoxBlueHi[SelectedBox]; BlueIndex++ ) {
  210. PlaneSum = 0;
  211. for (RedIndex=BoxRedLo[SelectedBox]; RedIndex<=BoxRedHi[SelectedBox]; RedIndex++ )
  212. for (GreenIndex=BoxGreenLo[SelectedBox]; GreenIndex<=BoxGreenHi[SelectedBox]; GreenIndex++ )
  213. PlaneSum += Frequency[ RedIndex<<(BITS+BITS) | GreenIndex<<BITS | BlueIndex ];
  214. ElementSum += PlaneSum;
  215. if (ElementSum > BoxNumElements[SelectedBox]/2)
  216. break;
  217. }
  218. if (BlueIndex == BoxBlueHi[SelectedBox]) {
  219. BlueIndex--;
  220. ElementSum -= PlaneSum;
  221. }
  222. BoxRedLo[TargetBox] = BoxRedLo[SelectedBox];
  223. BoxRedHi[TargetBox] = BoxRedHi[SelectedBox];
  224. BoxBlueLo[TargetBox] = BoxBlueLo[SelectedBox];
  225. BoxBlueHi[TargetBox] = BoxBlueHi[SelectedBox];
  226. BoxGreenLo[TargetBox] = BoxGreenLo[SelectedBox];
  227. BoxGreenHi[TargetBox] = BoxGreenHi[SelectedBox];
  228. BoxBlueLo[TargetBox] = BlueIndex+1;
  229. BoxNumElements[TargetBox] = BoxNumElements[SelectedBox] - ElementSum;
  230. BoxBlueHi[SelectedBox] = BlueIndex;
  231. BoxNumElements[SelectedBox] = ElementSum;
  232. }
  233. static void SplitBoxGreen( int SelectedBox, int TargetBox )
  234. {
  235. int ElementSum, PlaneSum, RedIndex, GreenIndex, BlueIndex;
  236. ElementSum = 0;
  237. for (GreenIndex=BoxGreenLo[SelectedBox]; GreenIndex<=BoxGreenHi[SelectedBox]; GreenIndex++ ) {
  238. PlaneSum = 0;
  239. for (RedIndex=BoxRedLo[SelectedBox]; RedIndex<=BoxRedHi[SelectedBox]; RedIndex++ )
  240. for (BlueIndex=BoxBlueLo[SelectedBox]; BlueIndex<=BoxBlueHi[SelectedBox]; BlueIndex++ )
  241. PlaneSum += Frequency[ RedIndex<<(BITS+BITS) | GreenIndex<<BITS | BlueIndex ];
  242. ElementSum += PlaneSum;
  243. if (ElementSum > BoxNumElements[SelectedBox]/2)
  244. break;
  245. }
  246. if (GreenIndex == BoxGreenHi[SelectedBox]) {
  247. GreenIndex--;
  248. ElementSum -= PlaneSum;
  249. }
  250. BoxRedLo[TargetBox] = BoxRedLo[SelectedBox];
  251. BoxRedHi[TargetBox] = BoxRedHi[SelectedBox];
  252. BoxBlueLo[TargetBox] = BoxBlueLo[SelectedBox];
  253. BoxBlueHi[TargetBox] = BoxBlueHi[SelectedBox];
  254. BoxGreenLo[TargetBox] = BoxGreenLo[SelectedBox];
  255. BoxGreenHi[TargetBox] = BoxGreenHi[SelectedBox];
  256. BoxGreenLo[TargetBox] = GreenIndex+1;
  257. BoxNumElements[TargetBox] = BoxNumElements[SelectedBox] - ElementSum;
  258. BoxGreenHi[SelectedBox] = GreenIndex;
  259. BoxNumElements[SelectedBox] = ElementSum;
  260. }
  261. static int FindAxisToSplit(int box )
  262. {
  263. int c, Max, axis;
  264. Max = BoxRedHi[box] - BoxRedLo[box];
  265. axis = 0;
  266. if (Max<(c=(BoxBlueHi[box]-BoxBlueLo[box]))) {
  267. Max = c;
  268. axis = 1;
  269. }
  270. if (Max<(c=(BoxGreenHi[box]-BoxGreenLo[box]))) {
  271. Max = c;
  272. axis = 2;
  273. }
  274. return axis;
  275. }
  276. static int FindTargetBox( int NumBoxes )
  277. {
  278. int c;
  279. for (c=0; c<NumBoxes; c++ )
  280. if (BoxNumElements[c] == 0 )
  281. return c;
  282. return NumBoxes;
  283. }
  284. static void MedianSetPalette( int NumBoxes, char * palette )
  285. {
  286. int Index,r,b,g;
  287. int rsum,bsum,gsum,tmp;
  288. int n=0;
  289. // outp( 0x3c8, 0 );
  290. for (Index=0; Index < NumBoxes; Index++ ) {
  291. rsum = bsum = gsum = 0;
  292. for (r=BoxRedLo[Index]; r<=BoxRedHi[Index]; r++ )
  293. for (b=BoxBlueLo[Index]; b<=BoxBlueHi[Index]; b++ )
  294. for (g=BoxGreenLo[Index]; g<=BoxGreenHi[Index]; g++ ) {
  295. tmp = Frequency[ r<<(BITS+BITS) | g<<BITS | b ];
  296. Frequency[r<<(BITS+BITS) | g<<BITS | b] = Index;
  297. rsum += r*tmp;
  298. bsum += b*tmp;
  299. gsum += g*tmp;
  300. n++;
  301. }
  302. r = ((rsum)*2)/BoxNumElements[Index];
  303. g = ((gsum)*2)/BoxNumElements[Index];
  304. b = ((bsum)*2)/BoxNumElements[Index];
  305. *palette++ = r;
  306. *palette++ = g;
  307. *palette++ = b;
  308. //outp( 0x3c9, r );
  309. //outp( 0x3c9, g );
  310. //outp( 0x3c9, b );
  311. }
  312. fprintf( stderr, "Inv table has %d entries\n", n );
  313. fprintf( stderr, "NumBoxes are %d\n", NumBoxes );
  314. }
  315. void mediancut( WORD * data, int num_pixels, int num_colors, void * dest_bitmap, char * palette )
  316. {
  317. unsigned char r,g,b;
  318. int i, axis, SelectedBox, TargetBox;
  319. int TargetColors;
  320. int NumBoxes;
  321. TotalPixels = num_pixels;
  322. TargetColors = num_colors;
  323. //for ( i=0; i< 32768; i++ )
  324. // Frequency[i] = 0;
  325. //MedianClearFrequencies(Frequency);
  326. BoxRedLo[0] = 0;
  327. BoxRedHi[0] = MAXVAL;
  328. BoxBlueLo[0] = 0;
  329. BoxBlueHi[0] = MAXVAL;
  330. BoxGreenLo[0] = 0;
  331. BoxGreenHi[0] = MAXVAL;
  332. /* for ( i=0; i< TotalPixels; i++ ) {
  333. if ((Frequency[ data[i] ]++)==0) {
  334. r = (data[i]>>10)&31;
  335. g = (data[i]>>5)&31;
  336. b = (data[i]>>0)&31;
  337. if ( r < BoxRedLo[0] )
  338. BoxRedLo[0] = r;
  339. else if( r > BoxRedHi[0] )
  340. BoxRedHi[0] = r;
  341. if ( g < BoxGreenLo[0] )
  342. BoxGreenLo[0] = g;
  343. else if( g > BoxGreenHi[0] )
  344. BoxGreenHi[0] = g;
  345. if ( b < BoxBlueLo[0] )
  346. BoxBlueLo[0] = b;
  347. else if( b > BoxBlueHi[0] )
  348. BoxBlueHi[0] = b;
  349. }
  350. }
  351. */
  352. BoxNumElements[0] = TotalPixels;
  353. NumBoxes = 1;
  354. //for ( i=0; i< TotalPixels; i++ )
  355. // Frequency[ data[i] ]++;
  356. //MedianReadFrequencies( data,TotalPixels );
  357. Shrink(0);
  358. while(NumBoxes < TargetColors ) {
  359. SelectedBox = FindNextBoxToSplit(NumBoxes);
  360. if (SelectedBox == -1 ) break;
  361. TargetBox = FindTargetBox( NumBoxes );
  362. axis = FindAxisToSplit( SelectedBox );
  363. switch(axis) {
  364. case 0: SplitBoxRed( SelectedBox, TargetBox );
  365. break;
  366. case 1: SplitBoxBlue( SelectedBox, TargetBox );
  367. break;
  368. case 2: SplitBoxGreen( SelectedBox, TargetBox );
  369. break;
  370. }
  371. Shrink(SelectedBox);
  372. Shrink(TargetBox);
  373. if (TargetBox == NumBoxes ) NumBoxes++;
  374. }
  375. //for ( i=0; i< TotalPixels; i++ )
  376. // VideoMemory[i] = Frequency[ bmp->Bits[i] ];
  377. MedianSetPalette( NumBoxes, palette );
  378. // MedianPutImage( data, dest_bitmap, TotalPixels );
  379. }
  380.