TestVideo.Mod 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. MODULE TestVideo; (** AUTHOR "thomas.frey@alumni.ethz.ch"; PURPOSE "Computer Vision Experiments"; *)
  2. IMPORT
  3. Kernel, Modules, Raster, VideoExample, Commands, Options, KernelLog, Random, WMGraphics, WMRectangles, Kernel32, SYSTEM, Vectors := W3dVectors, Math := MathL;
  4. CONST
  5. Ok* = 0;
  6. TooManyLabels* = 1;
  7. PathTooLong* = 2;
  8. DirN = 0; DirNE = 1; DirE = 2; DirSE = 3; DirS = 4; DirSW = 5; DirW = 6; DirNW = 7;
  9. DebugLabeler = FALSE;
  10. DebugTracer = FALSE;
  11. DebugLiner = FALSE;
  12. TYPE
  13. LabelInfo* = RECORD
  14. firstPos : LONGINT;
  15. nofPixels : LONGINT;
  16. label : INTEGER;
  17. END;
  18. Point = RECORD
  19. x, y : INTEGER;
  20. END;
  21. VAR
  22. threshold, pixThreshold : LONGINT;
  23. labelBuffer : POINTER TO ARRAY OF INTEGER;
  24. equivalence : ARRAY 32*1024 OF INTEGER;
  25. labelInfo : ARRAY 32*1024 OF LabelInfo;
  26. labelColor : ARRAY 32*1024 OF LONGINT;
  27. g : WMGraphics.BufferCanvas;
  28. dirX, dirY : ARRAY 8 OF LONGINT;
  29. rectified : VideoExample.PreviewWindow;
  30. intensityBuffer, thresholdBuffer : POINTER TO ARRAY OF CHAR;
  31. PROCEDURE RGBToYUVReal(r, g, b : LONGINT; VAR y, u, v : LONGINT);
  32. BEGIN
  33. y := ENTIER(0.299 * r + 0.587 * g + 0.114 * b);
  34. u := ENTIER(128 - 0.16874 * r - 0.33126 * g + 0.5 * b);
  35. v := ENTIER(128 + 0.5 * r - 0.41869 * g - 0.08131 * b);
  36. END RGBToYUVReal;
  37. (** Analytical solution for homography for the case of 4 points mapping to the unit rectangle.
  38. According to "ProjectiveMappings for Image Warping" by Paul Heckbert, 15-869, Image-Based Modeling and Rendering *)
  39. PROCEDURE CalculateUnitSquareHomography(CONST p : ARRAY OF Point; VAR H, inverse : ARRAY OF LONGREAL);
  40. VAR sx, sy, dx1, dy1, dx2, dy2, a, b, c, d, e, f, g, h, z : LONGREAL;
  41. BEGIN
  42. sx := (p[0].x - p[1].x) + (p[2].x - p[3].x);
  43. sy := (p[0].y - p[1].y) + (p[2].y - p[3].y);
  44. dx1 := p[1].x - p[2].x;
  45. dx2 := p[3].x - p[2].x;
  46. dy1 := p[1].y - p[2].y;
  47. dy2 := p[3].y - p[2].y;
  48. z := dx1 * dy2 - dy1 * dx2;
  49. g := (sx * dy2 - sy * dx2) / z;
  50. h := (sy * dx1 - sx * dy1) / z;
  51. a := p[1].x - p[0].x + g * p[1].x;
  52. b := p[3].x - p[0].x + h * p[3].x;
  53. c := p[0].x;
  54. d := p[1].y - p[0].y + g * p[1].y;
  55. e := p[3].y - p[0].y + h * p[3].y;
  56. f := p[0].y;
  57. H[0] := a; H[1] := b; H[2] := c;
  58. H[3] := d; H[4] := e; H[5] := f;
  59. H[6] := g; H[7] := h; H[8] := 1;
  60. (* inverse transformation *)
  61. inverse[0] := e - f * h; inverse[1] := c * h - b; inverse[2] := b * f - c * e;
  62. inverse[3] := f * g - d; inverse[4] := a - c * g; inverse[5] := c * d - a * f;
  63. inverse[6] := d * h - e * g; inverse[7] := b * g - a * h; inverse[8] := a * e - b * d
  64. END CalculateUnitSquareHomography;
  65. PROCEDURE MapProjective(CONST H : ARRAY OF LONGREAL; u, v : LONGREAL; VAR x, y : LONGREAL);
  66. BEGIN
  67. x := (H[0] * u + H[1] * v + H[2]) / (H[6] * u + H[7] * v + 1);
  68. y := (H[3] * u + H[4] * v + H[5]) / (H[6] * u + H[7] * v + 1)
  69. END MapProjective;
  70. PROCEDURE MapInverseProjective(CONST H : ARRAY OF LONGREAL; u, v : LONGREAL; VAR x, y : LONGREAL);
  71. VAR z : LONGREAL;
  72. BEGIN
  73. x := (H[0] * u + H[1] * v + H[2]) / (H[6] *u + H[7] * v + 1);
  74. y := (H[3] * u + H[4] * v + H[5]) / (H[6] *u + H[7] * v + 1);
  75. z := (H[6] * u + H[7] * v + H[8]) / (H[6] *u + H[7] * v + 1);
  76. x := x / z;
  77. y := y / z;
  78. END MapInverseProjective;
  79. PROCEDURE Transform(src, dst : Raster.Image; CONST points : ARRAY OF Point);
  80. VAR h, hinv : ARRAY 9 OF LONGREAL;
  81. x, y, six, siy : LONGINT;
  82. u, v, sx, sy : LONGREAL;
  83. mode : Raster.Mode;
  84. pix : Raster.Pixel;
  85. BEGIN
  86. Raster.InitMode(mode, Raster.srcCopy);
  87. CalculateUnitSquareHomography(points, h, hinv);
  88. FOR y := 0 TO dst.height - 1 DO
  89. v := y / dst.height;
  90. FOR x := 0 TO dst.width - 1 DO
  91. u := x / dst.width;
  92. MapProjective(h, u, v, sx, sy);
  93. six := ENTIER(sx + 0.5); siy := ENTIER(sy + 0.5);
  94. IF (six > 0) & (siy > 0) & (six < src.width) & (siy < src.height) THEN
  95. Raster.Get(src, six, siy, pix, mode);
  96. ELSE Raster.SetRGBA(pix, 0, 0, 0, 255)
  97. END;
  98. Raster.Put(dst, x, y, pix, mode)
  99. END
  100. END
  101. END Transform;
  102. PROCEDURE SearchHVLines(buffer : Raster.Image);
  103. VAR x, y, tr, tg, tb, ta : LONGINT;
  104. sum : LONGINT;
  105. hArray, vArray : ARRAY 2048 OF LONGINT;
  106. mode : Raster.Mode;
  107. pix : Raster.Pixel;
  108. BEGIN
  109. Raster.InitMode(mode, Raster.srcCopy);
  110. FOR y := 0 TO buffer.height - 1 DO
  111. FOR x := 0 TO buffer.width - 1 DO
  112. Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  113. sum := (tr + tg + tb);
  114. INC(hArray[x], sum);
  115. INC(vArray[y], sum);
  116. END
  117. END;
  118. FOR y := 0 TO buffer.height - 1 DO
  119. IF vArray[y] < threshold * buffer.width THEN
  120. rectified.canvas.Line(0, y, buffer.width, y, 0FF00FFH, WMGraphics.ModeCopy);
  121. END
  122. END;
  123. FOR x := 0 TO buffer.width - 1 DO
  124. IF hArray[x] < threshold * buffer.height THEN
  125. rectified.canvas.Line(x, 0, x, buffer.height, 0FF00FFH, WMGraphics.ModeCopy);
  126. END
  127. END
  128. END SearchHVLines;
  129. PROCEDURE IsEmptyField(buffer : Raster.Image; x, y , w, h : LONGINT) : BOOLEAN;
  130. VAR i, j, tr, tg, tb, ta : LONGINT;
  131. mode : Raster.Mode;
  132. pix : Raster.Pixel;
  133. nonEmpty : LONGINT;
  134. BEGIN
  135. Raster.InitMode(mode, Raster.srcCopy);
  136. nonEmpty := 0;
  137. FOR j := y TO y + h - 1 DO
  138. FOR i := x TO x + w - 1 DO
  139. Raster.Get(buffer,i,j, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  140. IF (tr + tg + tb) < threshold THEN
  141. Raster.SetRGBA(pix, 255, 0, 0, 255); Raster.Put(buffer, i, j, pix, mode);
  142. INC(nonEmpty)
  143. END
  144. END
  145. END;
  146. RETURN nonEmpty < 8*w*h DIV 100;
  147. END IsEmptyField;
  148. PROCEDURE Dist(buffer : Raster.Image; x0, y0, x1, y1, w, h : LONGINT) : LONGINT;
  149. VAR i, j, tr, tg, tb, ta, s0, s1 : LONGINT;
  150. mode : Raster.Mode;
  151. pix : Raster.Pixel;
  152. sum : LONGINT;
  153. BEGIN
  154. Raster.InitMode(mode, Raster.srcCopy);
  155. sum := 0;
  156. FOR j := 0 TO h - 1 DO
  157. FOR i := 0 TO w - 1 DO
  158. Raster.Get(buffer, x0 + i, y0 + j, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta); s0 := (tr + tg + tb);
  159. Raster.Get(buffer, x1 + i, y1 + j, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta); s1 := (tr + tg + tb);
  160. sum := sum + (threshold - s0) * (threshold - s1);
  161. END
  162. END;
  163. RETURN sum;
  164. END Dist;
  165. PROCEDURE CheckFields(buffer : Raster.Image);
  166. VAR i, j, x, y, w, h : LONGINT;
  167. empty : ARRAY 9, 9 OF BOOLEAN;
  168. nofNumbers : LONGINT;
  169. numbers : ARRAY 81 OF LONGINT;
  170. cluster: ARRAY 81 OF RECORD
  171. nofFields : SHORTINT;
  172. fields : ARRAY 81 OF SHORTINT;
  173. END;
  174. distance, dist : ARRAY 81, 81 OF LONGINT;
  175. PROCEDURE SetDist(a, b, d : LONGINT);
  176. BEGIN
  177. IF a < b THEN dist[a, b] := d
  178. ELSE dist[b, a] := d
  179. END
  180. END SetDist;
  181. PROCEDURE GetDist(a, b : LONGINT) : LONGINT;
  182. BEGIN
  183. IF a < b THEN RETURN dist[a, b]
  184. ELSE RETURN dist[b, a]
  185. END
  186. END GetDist;
  187. PROCEDURE GetSmallest(VAR maxi, maxj : LONGINT);
  188. VAR max : LONGINT;
  189. first : BOOLEAN;
  190. BEGIN
  191. first := TRUE;
  192. FOR j := 0 TO nofNumbers - 1 DO
  193. FOR i := 0 TO j - 1 DO
  194. IF first THEN
  195. max := GetDist(i, j);
  196. maxi := i; maxj := j;
  197. first := FALSE
  198. ELSE
  199. IF GetDist(i, j) > max THEN
  200. max := GetDist(i, j);
  201. maxi := i; maxj := j;
  202. END
  203. END
  204. END;
  205. END
  206. END GetSmallest;
  207. PROCEDURE Cluster;
  208. VAR i : LONGINT;
  209. BEGIN
  210. FOR i := 0 TO 81 - 1 DO cluster[i].nofFields := 0; cluster[i].fields[0] := SHORT(SHORT(i)) END;
  211. FOR i := 0 TO nofNumbers - 1 DO cluster[i].nofFields := 1 END;
  212. FOR i := 0 TO nofNumbers - 1 DO
  213. END;
  214. END Cluster;
  215. BEGIN
  216. w := buffer.width DIV 9 - 5;
  217. h := buffer.height DIV 9 - 5;
  218. nofNumbers := 0;
  219. FOR j := 0 TO 9 - 1 DO
  220. FOR i := 0 TO 9 - 1 DO
  221. x := (i * buffer.width DIV 9) + 5;
  222. y := (j * buffer.height DIV 9) + 5;
  223. IF IsEmptyField(buffer, x, y, w, h) THEN
  224. empty[j, i] := TRUE;
  225. rectified.canvas.Fill(WMRectangles.MakeRect(x, y, x + w, y + h), 00FF80H, WMGraphics.ModeSrcOverDst);
  226. ELSE empty[j, i] := FALSE;
  227. numbers[nofNumbers] := 9 * j + i;
  228. INC(nofNumbers)
  229. END
  230. END
  231. END;
  232. FOR j := 0 TO nofNumbers - 1 DO
  233. FOR i := 0 TO j - 1 DO
  234. distance[j, i] := Dist(buffer,
  235. (numbers[j] DIV 9) * buffer.width DIV 9 + 4, (numbers[j] MOD 9) * buffer.height DIV 9 + 4,
  236. (numbers[i] DIV 9) * buffer.width DIV 9 + 4, (numbers[i] MOD 9) * buffer.height DIV 9 + 4,
  237. w, h);
  238. SetDist(j, i, distance[j, i]);
  239. (* KernelLog.Int(distance[j, i], 0); KernelLog.String(" "); *)
  240. END;
  241. KernelLog.Ln;
  242. END;
  243. END CheckFields;
  244. (**
  245. Labels 8-way connected components in the image. Max components that can be found 32768.
  246. buffer : the image that should be labled
  247. labelBuffer : buffer with at least w * h integers for labels
  248. equivalenceBuffer : storage space for maxLabels label;
  249. colorThreshold : ...
  250. *)
  251. PROCEDURE BinaryLabler*(buffer : Raster.Image; VAR labelBuffer, equivalence : ARRAY OF INTEGER; colorThreshold, pixelThreshold, maxLabels : LONGINT;
  252. VAR labelInfo : ARRAY OF LabelInfo;
  253. unifyLabels : BOOLEAN; VAR nofFLabels : LONGINT; VAR res : LONGINT);
  254. VAR i, x, y, w , h, color: LONGINT;
  255. tr, tg, tb, ta : LONGINT;
  256. mode : Raster.Mode;
  257. pix : Raster.Pixel;
  258. nofLabels : INTEGER;
  259. lbufpos, lastLineLbufPos, minClass : LONGINT;
  260. lastsum, sum, cl, ctl, ct, ctr, tlabel : INTEGER;
  261. adr : ADDRESS;
  262. ch : CHAR;
  263. PROCEDURE Equivalence(x, y : LONGINT);
  264. BEGIN
  265. IF x > y THEN equivalence[x] := SHORT(y) ELSE equivalence[y] := SHORT(x) END
  266. END Equivalence;
  267. PROCEDURE NewLabel(lbufPos : LONGINT);
  268. BEGIN
  269. IF nofLabels < maxLabels THEN
  270. INC(nofLabels);
  271. labelBuffer[lbufpos] := nofLabels;
  272. labelInfo[nofLabels].firstPos := lbufPos;
  273. labelInfo[nofLabels].nofPixels := 1
  274. ELSE
  275. res := TooManyLabels;
  276. END
  277. END NewLabel;
  278. BEGIN
  279. ASSERT(maxLabels <= MAX(INTEGER));
  280. ASSERT(LEN(equivalence) >= maxLabels);
  281. ASSERT(LEN(labelBuffer) >= w*h);
  282. res := Ok;
  283. w := buffer.width; h := buffer.height;
  284. (* initialize equivalences *)
  285. FOR i := 0 TO SHORT(LEN( equivalence)) - 1 DO equivalence[i] := SHORT(i) END;
  286. Raster.InitMode(mode, Raster.srcCopy);
  287. nofLabels := 0;
  288. (* first line *)
  289. lbufpos := 0;
  290. FOR x := 0 TO w - 1 DO
  291. Raster.Get(buffer, x, 0, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  292. IF (tr + tg + tb < threshold) THEN
  293. IF (x > 0) & (labelBuffer[lbufpos - 1] > 0) THEN
  294. labelBuffer[lbufpos] := labelBuffer[lbufpos - 1]
  295. ELSE NewLabel(lbufpos)
  296. END;
  297. ELSE labelBuffer[lbufpos] := 0
  298. END;
  299. INC(lbufpos)
  300. END;
  301. lastLineLbufPos := 0;
  302. FOR y := 1 TO h - 1 DO
  303. adr := buffer.adr + y * buffer.bpr;
  304. SYSTEM.GET(adr, ch); lastsum := ORD(ch); INC(adr);
  305. SYSTEM.GET(adr, ch); lastsum := lastsum + ORD(ch); INC(adr);
  306. SYSTEM.GET(adr, ch); lastsum := lastsum + ORD(ch); INC(adr);
  307. INC(lbufpos); INC(lastLineLbufPos);
  308. FOR x := 1 TO w - 1 DO
  309. (*Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);*)
  310. SYSTEM.GET(adr, ch); sum := ORD(ch); INC(adr);
  311. SYSTEM.GET(adr, ch); sum := sum + ORD(ch); INC(adr);
  312. SYSTEM.GET(adr, ch); sum := sum + ORD(ch); INC(adr);
  313. lastsum := sum;
  314. IF ( sum (* tr + tg + tb*) < threshold) THEN
  315. IF (x > 0) THEN
  316. cl := labelBuffer[lbufpos - 1];
  317. ctl := labelBuffer[lastLineLbufPos - 1];
  318. ELSE cl := 0; ctl := 0
  319. END;
  320. ct := labelBuffer[lastLineLbufPos];
  321. IF x < w - 1 THEN ctr := labelBuffer[lastLineLbufPos + 1] ELSE ctr := 0 END;
  322. IF (cl + ctl + ct + ctr = 0)(*(cl = 0) & (ctl = 0) & (ct = 0) & (ctr = 0)*) THEN NewLabel(lbufpos)
  323. ELSE
  324. minClass := 0FFFFH;
  325. IF (cl # 0) & (cl < minClass) THEN minClass := cl END;
  326. IF (ctl # 0) & (ctl < minClass) THEN minClass := ctl END;
  327. IF (ct # 0) & (ct < minClass) THEN minClass := ct END;
  328. IF (ctr # 0) & (ctr < minClass) THEN minClass := ctr END;
  329. IF equivalence[minClass] < minClass THEN minClass := equivalence[minClass] END;
  330. labelBuffer[lbufpos] := SHORT(minClass);
  331. INC(labelInfo[minClass].nofPixels);
  332. IF (cl # 0) & (cl # minClass) THEN Equivalence(minClass, cl) END;
  333. IF (ctl # 0) & (ctl # minClass) THEN Equivalence(minClass, ctl) END;
  334. IF (ct # 0) & (ct # minClass) THEN Equivalence(minClass, ct) END;
  335. IF (ctr # 0) & (ctr # minClass) THEN Equivalence(minClass, ctr) END;
  336. END;
  337. ELSE labelBuffer[lbufpos] := 0
  338. END;
  339. INC(lbufpos);
  340. INC(lastLineLbufPos)
  341. END
  342. END;
  343. (* ensure all equivalences are pointing to the lowest numbered label id *)
  344. FOR i := 1 TO nofLabels - 1 DO
  345. IF equivalence[i] < i THEN WHILE equivalence[equivalence[i]] < equivalence[i] DO equivalence[i] := equivalence[equivalence[i]] END END;
  346. END;
  347. IF unifyLabels THEN
  348. FOR i := 0 TO w * h - 1 DO labelBuffer[i] := equivalence[labelBuffer[i]] END
  349. END;
  350. (* sum up the pixel sizes and adjust the first position of the region *)
  351. FOR i := 1 TO nofLabels - 1 DO
  352. IF equivalence[i] # i THEN
  353. labelInfo[equivalence[i]].firstPos := MIN(labelInfo[equivalence[i]].firstPos, labelInfo[i].firstPos);
  354. INC(labelInfo[equivalence[i]].nofPixels, labelInfo[i].nofPixels);
  355. labelInfo[i].nofPixels := 0;
  356. labelInfo[i].label := equivalence[i]
  357. END;
  358. END;
  359. IF DebugLabeler THEN
  360. lbufpos := 0;
  361. FOR y := 0 TO h - 1 DO
  362. FOR x := 0 TO w - 1 DO
  363. tlabel := equivalence[labelBuffer[lbufpos]];
  364. IF (tlabel>0)&(labelInfo[tlabel].nofPixels >= pixelThreshold) THEN color := labelColor[tlabel]
  365. ELSE color := LONGINT(0FFFFFFFFH);
  366. Raster.SetRGBA(pix, ((color DIV 65536) DIV 256) MOD 256, (color DIV 65536) MOD 256,
  367. (color DIV 256) MOD 256, 255);
  368. Raster.Put(buffer, x, y, pix, mode);
  369. END;
  370. INC(lbufpos);
  371. END
  372. END
  373. END;
  374. (* count and compress the labels *)
  375. nofFLabels := 0;
  376. FOR i := 1 TO nofLabels - 1 DO
  377. IF (equivalence[i] = i) & (labelInfo[i].nofPixels >= pixelThreshold) THEN
  378. labelInfo[nofFLabels] := labelInfo[i];
  379. INC(nofFLabels)
  380. END;
  381. END;
  382. END BinaryLabler;
  383. (* trace a region in the label buffer. The image buffer is used for the width and height and debug output.*)
  384. PROCEDURE Trace(buffer : Raster.Image; CONST labelBuffer : ARRAY OF INTEGER; VAR labelInfo : LabelInfo;
  385. VAR length : LONGINT; VAR path : ARRAY OF Point;
  386. VAR res : LONGINT);
  387. VAR x, y, tx, ty : LONGINT;
  388. w, h, i, j: LONGINT;
  389. dir, p, p2 : LONGINT;
  390. mode : Raster.Mode;
  391. pix : Raster.Pixel;
  392. deltaX, deltaY : ARRAY 8 OF LONGINT;
  393. BEGIN
  394. res := Ok;
  395. w := buffer.width; h := buffer.height;
  396. x := labelInfo.firstPos MOD w; y := labelInfo.firstPos DIV w;
  397. Raster.SetRGBA(pix, 255, 255, 0, 255);
  398. Raster.Put(buffer, x, y, pix, mode);
  399. deltaX[DirN] := 0; deltaY[DirN] := -w; (* N *)
  400. deltaX[DirNE] := 1; deltaY[DirNE] := -w; (* NE *)
  401. deltaX[DirE] := 1; deltaY[DirE] := 0; (* E *)
  402. deltaX[DirSE] := 1; deltaY[DirSE] := w; (* SE *)
  403. deltaX[DirS] := 0; deltaY[DirS] := w; (* S *)
  404. deltaX[DirSW] := -1; deltaY[DirSW] := w; (* SW *)
  405. deltaX[DirW] := -1; deltaY[DirW] := 0; (* W *)
  406. deltaX[DirNW] := -1; deltaY[DirNW] := -w; (* NW *)
  407. length := 0;
  408. p := labelInfo.firstPos;
  409. x := p MOD w; y := p DIV w;
  410. dir := 5;
  411. j := 0;
  412. LOOP
  413. IF length >= LEN(path) THEN res := PathTooLong; EXIT END;
  414. dir := (dir + 5) MOD 8;
  415. i := 0;
  416. LOOP
  417. INC(i);
  418. IF i > 8 THEN RETURN END;
  419. p2 := p + deltaX[dir] + deltaY[dir];
  420. tx := x + dirX[dir];
  421. ty := y + dirY[dir];
  422. IF (tx >= 0) & (tx < w) & (ty >= 0) & (ty < h) & (labelBuffer[p2] # 0) THEN EXIT END;
  423. dir := (dir + 1) MOD 8;
  424. END;
  425. p := p2;
  426. x := tx; y := ty;
  427. IF DebugTracer THEN
  428. IF g = NIL THEN NEW(g, buffer) END;
  429. g.Fill(WMRectangles.MakeRect(x-1, y-1, x+1, y+1), 0FFFFH, WMGraphics.ModeCopy);
  430. END;
  431. (* SLOW *)
  432. path[length].x := SHORT(p MOD w);
  433. path[length].y := SHORT(p DIV w);
  434. INC(length);
  435. IF p = labelInfo.firstPos THEN EXIT END;
  436. END;
  437. END Trace;
  438. PROCEDURE SimplifyPoly(VAR path : ARRAY OF Point; nofPoints, tolerance: LONGINT; VAR resultPoint: LONGINT);
  439. VAR i, j : LONGINT;
  440. dir0, dir1 : Vectors.TVector2d;
  441. BEGIN
  442. IF nofPoints > 2 THEN
  443. i := 2; j := 1;
  444. WHILE i < nofPoints DO
  445. dir0 := Vectors.VNormed2(Vectors.Vector2d(path[j].x - path[j - 1].x, path[j].y - path[j - 1].y));
  446. dir1 := Vectors.VNormed2(Vectors.Vector2d(path[i].x - path[i - 1].x, path[i].y - path[i - 1].y));
  447. IF Vectors.Scalar2(dir0, dir1) < 0.8 THEN INC(j) END;
  448. path[j] := path[i];
  449. INC(i);
  450. END
  451. END;
  452. resultPoint := j+ 1;
  453. END SimplifyPoly;
  454. PROCEDURE ExtractLines(buffer : Raster.Image; CONST path : ARRAY OF Point; pathLength : LONGINT; VAR poly : ARRAY OF Point; VAR nofPoints : LONGINT );
  455. VAR i, p, nofLines, straight, nonStraight : LONGINT;
  456. l: LONGINT;
  457. PROCEDURE IsLine(from, to, l : LONGINT) : BOOLEAN;
  458. VAR i, d : LONGINT;
  459. x0, x1, y0, y1, px, py : LONGINT;
  460. BEGIN
  461. i := from;
  462. x0 := path[from].x; y0 := path[from].y;
  463. x1 := path[to].x; y1 := path[to].y;
  464. INC(i);
  465. WHILE i < to DO
  466. px := path[i].x; py := path[i].y;
  467. d := ABS((x1 - x0) * (y0 - py) - (x0 - px) * (y1 - y0));
  468. (* / SQRT(SQR(x1-x0) + SQR(y1-y0)) *)
  469. IF d > l THEN RETURN FALSE END;
  470. INC(i);
  471. END;
  472. RETURN TRUE
  473. END IsLine;
  474. BEGIN
  475. ASSERT(LEN(poly) >= 3);
  476. nofLines := 0; nonStraight := 0; straight := 0;
  477. p := 3; i := 0;
  478. WHILE p < pathLength DO
  479. IF IsLine(i, p, 2) THEN
  480. l := 6;
  481. WHILE ((i + l) < pathLength) & IsLine(i, i + l, l) DO INC(l, 2) END;
  482. IF (i + l) >= pathLength THEN l := pathLength - i - 1 END;
  483. WHILE ~IsLine(i, i + l, l) DO DEC(l) END;
  484. p := i + l;
  485. IF DebugLiner THEN
  486. IF g = NIL THEN NEW(g, buffer) END;
  487. g.Fill(WMRectangles.MakeRect(path[p].x-2, path[p].y-2, path[p].x+2, path[p].y+2), 00FFH, WMGraphics.ModeCopy);
  488. g.Fill(WMRectangles.MakeRect(path[p].x-1, path[p].y-1, path[p].x+1, path[p].y+1), LONGINT(0FFFF00FFH), WMGraphics.ModeCopy);
  489. END;
  490. IF nofLines >= LEN(poly) THEN RETURN END;
  491. IF nofLines = 0 THEN poly[0] := path[i]; INC(nofLines) END;
  492. poly[nofLines] := path[p]; INC(nofLines);
  493. i := p;
  494. INC(straight);
  495. ELSE INC(i);
  496. INC(nonStraight)
  497. END;
  498. p := i + 3;
  499. END;
  500. (* IF nonStraight - straight > 30 THEN RETURN END; *)
  501. (* not general : assumes closed polygon *)
  502. IF nofLines > 0 THEN
  503. poly[nofLines-1] := poly[0];
  504. END;
  505. SimplifyPoly(poly, nofLines, 0, nofLines);
  506. IF DebugLiner THEN
  507. FOR i := 0 TO nofLines - 1 DO
  508. g.Fill(WMRectangles.MakeRect(poly[i].x-2, poly[i].y-2, poly[i].x+2, poly[i].y+2), 00FFH, WMGraphics.ModeCopy);
  509. g.Fill(WMRectangles.MakeRect(poly[i].x-1, poly[i].y-1, poly[i].x+1, poly[i].y+1), LONGINT(0FF0000FFH), WMGraphics.ModeCopy);
  510. END
  511. END;
  512. nofPoints := nofLines;
  513. END ExtractLines;
  514. PROCEDURE GetTimer():HUGEINT;
  515. VAR t : HUGEINT;
  516. res : Kernel32.BOOL;
  517. BEGIN
  518. res := Kernel32.QueryPerformanceCounter(SYSTEM.VAL(Kernel32.LargeInteger, t));
  519. RETURN t;
  520. END GetTimer;
  521. PROCEDURE GetFreq():HUGEINT;
  522. VAR t : HUGEINT;
  523. res : Kernel32.BOOL;
  524. BEGIN
  525. res := Kernel32.QueryPerformanceFrequency(SYSTEM.VAL(Kernel32.LargeInteger, t));
  526. RETURN t;
  527. END GetFreq;
  528. PROCEDURE Label2(buffer : Raster.Image);
  529. VAR nof, length, res, i, j : LONGINT; w, h: LONGINT;
  530. path : ARRAY 1024*4 OF Point;
  531. poly : ARRAY 40 OF Point;
  532. nofPoints : LONGINT;
  533. t0, t1, labeltime, tracetime, linetime : HUGEINT;
  534. f : LONGREAL;
  535. gp : ARRAY 50 OF WMGraphics.Point2d;
  536. PROCEDURE Sqr(x: LONGREAL):LONGREAL;
  537. BEGIN
  538. RETURN x * x
  539. END Sqr;
  540. BEGIN
  541. w := buffer.width; h := buffer.height;
  542. IF (labelBuffer = NIL) OR (LEN(labelBuffer^) < w*h) THEN NEW(labelBuffer, w*h) END;
  543. t0 := GetTimer();
  544. BinaryLabler(buffer, labelBuffer^, equivalence, threshold, pixThreshold, 32767, labelInfo, TRUE, nof, res);
  545. t1 := GetTimer();
  546. labeltime := t1 - t0;
  547. tracetime := 0; linetime := 0;
  548. IF g = NIL THEN NEW(g, buffer) END;
  549. IF res = 0 THEN
  550. FOR i := 0 TO nof - 1 DO
  551. t0 := GetTimer();
  552. Trace(buffer, labelBuffer^, labelInfo[i], length, path, res);
  553. t1 := GetTimer(); tracetime := tracetime + (t1 - t0);
  554. IF res = 0 THEN
  555. t0 := GetTimer();
  556. ExtractLines(buffer, path, length, poly, nofPoints);
  557. IF (nofPoints = 5) THEN
  558. FOR j := 0 TO nofPoints - 1 DO gp[j].x := poly[j].x; gp[j].y := poly[j].y END;
  559. IF g = NIL THEN NEW(g, buffer) END;
  560. IF (Math.sqrt(Sqr(poly[1].x - poly[0].x) + Sqr(poly[1].y - poly[0].y)) > 20) &
  561. (Math.sqrt(Sqr(poly[2].x - poly[1].x) + Sqr(poly[2].y - poly[1].y)) > 20) &
  562. (Math.sqrt(Sqr(poly[3].x - poly[2].x) + Sqr(poly[3].y - poly[2].y)) > 20) &
  563. (Math.sqrt(Sqr(poly[4].x - poly[3].x) + Sqr(poly[4].y - poly[3].y)) > 20) &
  564. (Math.sqrt(Sqr(poly[2].x - poly[0].x) + Sqr(poly[2].y - poly[0].y)) > 40) &
  565. (Math.sqrt(Sqr(poly[1].x - poly[3].x) + Sqr(poly[1].y - poly[3].y)) > 40) &
  566. (Math.sqrt(
  567. Sqr((poly[0].x + poly[1].x) / 2 - (poly[2].x + poly[3].x) / 2) +
  568. Sqr((poly[0].y + poly[1].y) / 2 - (poly[2].y + poly[3].y) / 2)) > 40) &
  569. (Math.sqrt(
  570. Sqr((poly[1].x + poly[2].x) / 2 - (poly[3].x + poly[4].x) / 2) +
  571. Sqr((poly[1].y + poly[2].y) / 2 - (poly[3].y + poly[4].y) / 2)) > 40) THEN
  572. Transform(buffer, rectified.img, poly);
  573. CheckFields(rectified.img);
  574. rectified.Invalidate(WMRectangles.MakeRect(0, 0, rectified.GetWidth(), rectified.GetHeight()));
  575. g.Line((poly[0].x + poly[1].x) DIV 2, (poly[0].y + poly[1].y) DIV 2 , (poly[2].x + poly[3].x) DIV 2, (poly[2].y + poly[3].y) DIV 2, LONGINT(0FF0000FFH), WMGraphics.ModeSrcOverDst);
  576. g.FillPolygonFlat(gp, nofPoints, 000FF0080H, WMGraphics.ModeSrcOverDst);
  577. g.Line(poly[0].x, poly[0].y, poly[2].x, poly[2].y, 000FFFFFFH, WMGraphics.ModeSrcOverDst);
  578. g.Line(poly[1].x, poly[1].y, poly[3].x, poly[3].y, 000FFFFFFH, WMGraphics.ModeSrcOverDst);
  579. END;
  580. (* g.FillPolygonFlat(gp, nofPoints, LONGINT(0FF00FF80H), WMGraphics.ModeSrcOverDst) *)
  581. ELSIF nofPoints = 6 THEN
  582. g.FillPolygonFlat(gp, nofPoints, LONGINT(0FF000020H), WMGraphics.ModeSrcOverDst);
  583. END;
  584. t1 := GetTimer(); linetime := linetime + (t1 - t0);
  585. END
  586. END
  587. END;
  588. f := GetFreq();
  589. f := f / 1000;
  590. (* KernelLog.String("nof= "); KernelLog.Int(nof, 0); KernelLog.Ln;
  591. KernelLog.String("labeltime = "); KernelLog.Int(ENTIER(labeltime / f), 0); KernelLog.Ln;
  592. KernelLog.String("tracetime = "); KernelLog.Int(ENTIER(tracetime / f), 0); KernelLog.Ln;
  593. KernelLog.String("linetime = "); KernelLog.Int(ENTIER(linetime / f), 0); KernelLog.Ln;
  594. *)
  595. END Label2;
  596. PROCEDURE YUVFilter(buffer : Raster.Image);
  597. VAR x, y, w , h : LONGINT;
  598. tr, tg, tb, ta, cy, cu, cv : LONGINT;
  599. mode : Raster.Mode;
  600. pix : Raster.Pixel;
  601. BEGIN
  602. Raster.InitMode(mode, Raster.srcCopy);
  603. w := buffer.width; h := buffer.height;
  604. (* rgb to yuv *)
  605. FOR y := 0 TO h - 1 DO
  606. FOR x := 0 TO w - 1 DO
  607. Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  608. RGBToYUVReal(tr, tg, tb, cy, cu, cv);
  609. Raster.SetRGBA(pix, cy, cu, cv, 255);
  610. Raster.Put(buffer, x, y, pix, mode);
  611. END
  612. END;
  613. END YUVFilter;
  614. PROCEDURE SetYUVFilter*;
  615. BEGIN
  616. VideoExample.InstallFrameHandler(YUVFilter)
  617. END SetYUVFilter;
  618. PROCEDURE BWFilter(buffer : Raster.Image);
  619. VAR x, y, w , h : LONGINT;
  620. tr, tg, tb, ta, cy, cu, cv : LONGINT;
  621. mode : Raster.Mode;
  622. pix : Raster.Pixel;
  623. BEGIN
  624. Raster.InitMode(mode, Raster.srcCopy);
  625. w := buffer.width; h := buffer.height;
  626. FOR y := 0 TO h - 1 DO
  627. FOR x := 0 TO w - 1 DO
  628. Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  629. RGBToYUVReal(tr, tg, tb, cy, cu, cv);
  630. Raster.SetRGBA(pix, cy, cy, cy, 255);
  631. Raster.Put(buffer, x, y, pix, mode);
  632. END
  633. END;
  634. END BWFilter;
  635. PROCEDURE SetBWFilter*;
  636. BEGIN
  637. VideoExample.InstallFrameHandler(BWFilter)
  638. END SetBWFilter;
  639. PROCEDURE RedDotFilter(buffer : Raster.Image);
  640. VAR x, y, w , h : LONGINT;
  641. tr, tg, tb, ta : LONGINT;
  642. mode : Raster.Mode;
  643. pix : Raster.Pixel;
  644. BEGIN
  645. Raster.InitMode(mode, Raster.srcCopy);
  646. w := buffer.width; h := buffer.height;
  647. FOR y := 0 TO h - 1 DO
  648. FOR x := 0 TO w - 1 DO
  649. Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta);
  650. IF (tr > 50) & (tg < 20) & (tb < 20) THEN
  651. Raster.SetRGBA(pix, 255, 255, 0, 255);
  652. Raster.Put(buffer, x, y, pix, mode);
  653. END
  654. END
  655. END;
  656. END RedDotFilter;
  657. PROCEDURE SetRedDotFilter*;
  658. BEGIN
  659. VideoExample.InstallFrameHandler(RedDotFilter)
  660. END SetRedDotFilter;
  661. PROCEDURE ThresholdFilter(buffer : Raster.Image);
  662. VAR x, y, w , h : LONGINT;
  663. sum, lastsum, tr, tg, tb, ta : LONGINT;
  664. mode : Raster.Mode;
  665. pix : Raster.Pixel;
  666. tresh : LONGINT;
  667. darkMode : BOOLEAN;
  668. BEGIN
  669. Raster.InitMode(mode, Raster.srcCopy);
  670. w := buffer.width; h := buffer.height;
  671. FOR y := 0 TO h - 1 DO
  672. Raster.Get(buffer, 0, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta); sum := tr + tg + tb;
  673. lastsum := sum;
  674. darkMode := sum < threshold;
  675. FOR x := 1 TO w - 1 DO
  676. Raster.Get(buffer, x, y, pix, mode); Raster.GetRGBA(pix, tr, tg, tb, ta); sum := tr + tg + tb;
  677. IF darkMode THEN
  678. IF (sum < tresh) THEN
  679. Raster.SetRGBA(pix, 255, 0, 0, 255);
  680. Raster.Put(buffer, x, y, pix, mode);
  681. ELSE darkMode := FALSE; tresh := threshold
  682. END;
  683. ELSE
  684. IF (sum < 3*lastsum DIV 4) OR (sum < tresh) THEN (*(sum > threshold) *)
  685. IF sum > tresh THEN tresh := 2*lastsum DIV 4 END;
  686. Raster.SetRGBA(pix, 255, 0, 0, 255);
  687. Raster.Put(buffer, x, y, pix, mode);
  688. darkMode := TRUE
  689. END
  690. END;
  691. lastsum := sum
  692. END
  693. END;
  694. END ThresholdFilter;
  695. PROCEDURE SetThresholdFilter*(context : Commands.Context);
  696. VAR
  697. options: Options.Options;
  698. BEGIN
  699. NEW(options);
  700. options.Add("t","threshold",Options.Integer);
  701. threshold := 50;
  702. IF options.Parse(context.arg, context.out) THEN
  703. IF options.GetInteger("threshold", threshold) THEN END;
  704. END;
  705. VideoExample.InstallFrameHandler(ThresholdFilter)
  706. END SetThresholdFilter;
  707. PROCEDURE AdaptiveThresholdFilter(buffer : Raster.Image);
  708. VAR x, y, w, h, p, t : LONGINT;
  709. sum : LONGINT;
  710. mode : Raster.Mode;
  711. pix : Raster.Pixel;
  712. ch : CHAR;
  713. adr : ADDRESS;
  714. total : LONGINT;
  715. BEGIN
  716. Raster.InitMode(mode, Raster.srcCopy);
  717. w := buffer.width; h := buffer.height;
  718. IF (intensityBuffer = NIL) OR (LEN(intensityBuffer^) < w*h) THEN NEW(intensityBuffer, w*h) END;
  719. p := 0; total := 0;
  720. FOR y := 0 TO h - 1 DO
  721. adr := buffer.adr + y * buffer.bpr;
  722. FOR x := 0 TO w - 1 DO
  723. INC(adr);
  724. SYSTEM.GET(adr, ch); sum := ORD(ch); INC(adr);
  725. SYSTEM.GET(adr, ch); sum := sum + ORD(ch); INC(adr);
  726. intensityBuffer[p] := CHR(sum DIV 2);
  727. total := total + (sum DIV 2);
  728. INC(p)
  729. END;
  730. END;
  731. t := 5* (total DIV (w * h)) DIV 8;
  732. p := 0;
  733. FOR y := 0 TO h - 1 DO
  734. FOR x := 0 TO w - 1 DO
  735. IF ORD(intensityBuffer[p]) < t THEN
  736. Raster.SetRGBA(pix, 255, 0, 0, 255)
  737. ELSE
  738. Raster.SetRGBA(pix, 0, 0, 0, 255)
  739. END;
  740. Raster.Put(buffer, x, y, pix, mode);
  741. INC(p);
  742. END;
  743. END;
  744. END AdaptiveThresholdFilter;
  745. PROCEDURE SetAdaptiveThresholdFilter*(context : Commands.Context);
  746. BEGIN
  747. VideoExample.InstallFrameHandler(AdaptiveThresholdFilter)
  748. END SetAdaptiveThresholdFilter;
  749. PROCEDURE FineAdaptiveThresholdFilter(buffer : Raster.Image);
  750. CONST WindowX = 32;
  751. VAR x, y, w, h, p, t : LONGINT;
  752. sum : LONGINT;
  753. mode : Raster.Mode;
  754. pix : Raster.Pixel;
  755. ch : CHAR;
  756. adr : ADDRESS;
  757. total : LONGINT;
  758. BEGIN
  759. Raster.InitMode(mode, Raster.srcCopy);
  760. w := buffer.width; h := buffer.height;
  761. IF (intensityBuffer = NIL) OR (LEN(intensityBuffer^) < w*h) THEN NEW(intensityBuffer, w*h) END;
  762. IF (thresholdBuffer = NIL) OR (LEN(thresholdBuffer^) < w*h) THEN NEW(thresholdBuffer, w*h) END;
  763. (* create intensity array *)
  764. p := 0; total := 0;
  765. FOR y := 0 TO h - 1 DO
  766. adr := buffer.adr + y * buffer.bpr;
  767. FOR x := 0 TO w - 1 DO
  768. INC(adr);
  769. SYSTEM.GET(adr, ch); sum := ORD(ch); INC(adr);
  770. SYSTEM.GET(adr, ch); sum := sum + ORD(ch); INC(adr);
  771. intensityBuffer[p] := CHR(sum DIV 2);
  772. total := total + (sum DIV 2);
  773. INC(p)
  774. END;
  775. END;
  776. p := 0;
  777. FOR y := 0 TO h - 1 DO
  778. total := 0;
  779. FOR x := 0 TO WindowX - 1 DO INC(total, ORD(intensityBuffer[p])); INC(p) END;
  780. t := y * w;
  781. FOR x := 0 TO WindowX DIV 2 - 1 DO thresholdBuffer[t] := CHR(total DIV WindowX); INC(t) END;
  782. FOR x := WindowX DIV 2 TO w - WindowX DIV 2 - 1 DO
  783. total := total - ORD(intensityBuffer[p- WindowX]) + ORD(intensityBuffer[p]);
  784. thresholdBuffer[t] := CHR(total DIV WindowX ); INC(t);
  785. INC(p)
  786. END;
  787. FOR x := w - WindowX DIV 2 TO w - 1 DO thresholdBuffer[t] := CHR(total DIV WindowX); INC(t) END;
  788. END;
  789. p := 0;
  790. FOR y := 0 TO (h-1) DIV 4 - 1 DO
  791. FOR x := 0 TO w - 1 DO
  792. (* total := ORD(thresholdBuffer[p]);
  793. total := total + ORD(thresholdBuffer[p + w]);
  794. total := total + ORD(thresholdBuffer[p + 2 * w]);
  795. total := total + ORD(thresholdBuffer[p + 3 * w]);
  796. total := 7*total DIV (4*8); *)
  797. total := ORD(thresholdBuffer[p]);
  798. total := total + ORD(thresholdBuffer[p + 1* w]);
  799. total := total + ORD(thresholdBuffer[p + 2 * w]);
  800. total := total + ORD(thresholdBuffer[p + 3 * w]);
  801. total := total + ORD(thresholdBuffer[p + 4 * w]);
  802. total := total + ORD(thresholdBuffer[p + 5 * w]);
  803. total := total + ORD(thresholdBuffer[p + 6 * w]);
  804. total := total + ORD(thresholdBuffer[p + 7 * w]);
  805. total := 14*total DIV (8*16);
  806. thresholdBuffer[p] := CHR(total); thresholdBuffer[p + w] := CHR(total); thresholdBuffer[p + 2 * w] := CHR(total); thresholdBuffer[p + 3 * w] := CHR(total);
  807. INC(p)
  808. END;
  809. INC(p, 3 * w);
  810. END;
  811. p := 0;
  812. FOR y := 0 TO h - 1 DO
  813. FOR x := 0 TO w - 1 DO
  814. IF ORD(intensityBuffer[p]) < ORD(thresholdBuffer[p]) THEN
  815. Raster.SetRGBA(pix, 255, 0, 0, 255)
  816. ELSE
  817. Raster.SetRGBA(pix, 0, 0, 0, 255)
  818. END;
  819. Raster.Put(buffer, x, y, pix, mode);
  820. INC(p);
  821. END;
  822. END;
  823. END FineAdaptiveThresholdFilter;
  824. PROCEDURE SetFineAdaptiveThresholdFilter*(context : Commands.Context);
  825. BEGIN
  826. VideoExample.InstallFrameHandler(FineAdaptiveThresholdFilter)
  827. END SetFineAdaptiveThresholdFilter;
  828. PROCEDURE SetLabelFilter*(context : Commands.Context);
  829. VAR
  830. options: Options.Options;
  831. BEGIN
  832. NEW(options);
  833. options.Add("t","threshold", Options.Integer);
  834. options.Add("p","pixelThreshold", Options.Integer);
  835. threshold := 50;
  836. pixThreshold := 50;
  837. IF options.Parse(context.arg, context.out) THEN
  838. IF options.GetInteger("threshold", threshold) THEN END;
  839. IF options.GetInteger("pixelThreshold", pixThreshold) THEN END;
  840. END;
  841. VideoExample.InstallFrameHandler(Label2)
  842. END SetLabelFilter;
  843. PROCEDURE Uninstall*;
  844. BEGIN
  845. VideoExample.InstallFrameHandler(NIL)
  846. END Uninstall;
  847. PROCEDURE Init;
  848. VAR i : LONGINT;
  849. gen : Random.Generator;
  850. BEGIN
  851. NEW(gen);
  852. FOR i := 1 TO LEN(labelColor) - 1 DO labelColor[i] := gen.Integer(); END;
  853. labelColor[0] := LONGINT(0FFFFFFFFH);
  854. dirX[DirN] := 0; dirY[DirN] := -1; (* N *)
  855. dirX[DirNE] := 1; dirY[DirNE] := -1; (* NE *)
  856. dirX[DirE] := 1; dirY[DirE] := 0; (* E *)
  857. dirX[DirSE] := 1; dirY[DirSE] := 1; (* SE *)
  858. dirX[DirS] := 0; dirY[DirS] := 1; (* S *)
  859. dirX[DirSW] := -1; dirY[DirSW] := 1; (* SW *)
  860. dirX[DirW] := -1; dirY[DirW] := 0; (* W *)
  861. dirX[DirNW] := -1; dirY[DirNW] := -1; (* NW *)
  862. END Init;
  863. PROCEDURE Cleanup;
  864. VAR timer : Kernel.Timer;
  865. BEGIN
  866. VideoExample.InstallFrameHandler(NIL);
  867. (* hack to not remove the module while a frame is still being filtered *)
  868. NEW(timer);
  869. timer.Sleep(1000);
  870. END Cleanup;
  871. BEGIN
  872. NEW(rectified, 256, 256);
  873. Init;
  874. SetYUVFilter();
  875. Modules.InstallTermHandler(Cleanup)
  876. END TestVideo.
  877. SystemTools.Free TestVideo ~
  878. TestVideo.SetLabelFilter -t=250 ~
  879. TestVideo.SetThresholdFilter -t=300 ~
  880. TestVideo.SetRedDotFilter ~
  881. TestVideo.SetYUVFilter ~
  882. TestVideo.SetBWFilter ~
  883. TestVideo.Uninstall ~
  884. VideoExample.Start ~
  885. VideoExample.Stop ~
  886. SystemTools.Free TestVideo ~
  887. TestVideo.SetLabelFilter -t=360 p=20 ~
  888. VideoExample.SimulateImage "sample0.jpg" ~