warp.c 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305
  1. // Copyright (C) 2004-2025 Artifex Software, Inc.
  2. //
  3. // This file is part of MuPDF.
  4. //
  5. // MuPDF is free software: you can redistribute it and/or modify it under the
  6. // terms of the GNU Affero General Public License as published by the Free
  7. // Software Foundation, either version 3 of the License, or (at your option)
  8. // any later version.
  9. //
  10. // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY
  11. // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  12. // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  13. // details.
  14. //
  15. // You should have received a copy of the GNU Affero General Public License
  16. // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>
  17. //
  18. // Alternative licensing terms are available from the licensor.
  19. // For commercial licensing, see <https://www.artifex.com/> or contact
  20. // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,
  21. // CA 94129, USA, for further information.
  22. #include "mupdf/fitz.h"
  23. #include "pixmap-imp.h"
  24. #include <string.h>
  25. /* Define TIMINGS to get timing information dumped to stdout. */
  26. #undef TIMINGS
  27. /* Define WARP_DEBUG to get debugging output (and PNGs saved). Note
  28. * that this will affect timings! */
  29. #undef WARP_DEBUG
  30. /* Define WARP_SPEW_DEBUG to get even more debug output (and PNGs). */
  31. #undef WARP_SPEW_DEBUG
  32. /* One reference suggested doing histogram equalisation. */
  33. #define DO_HISTEQ
  34. /* Define DETECT_DOCUMENT_RGB, and edge detection on RGB documents will
  35. * look for edges in just the R,G,B planes as well as the grey plane. */
  36. #undef DETECT_DOCUMENT_RGB
  37. #undef SLOW_INTERPOLATION
  38. #undef SLOW_WARPING
  39. #ifdef WARP_DEBUG
  40. static void
  41. debug_printf(fz_context *ctx, const char *fmt, ...)
  42. {
  43. char text[1024];
  44. va_list list;
  45. va_start(list, fmt);
  46. vsnprintf(text, sizeof(text), fmt, list);
  47. va_end(list);
  48. #ifdef _WIN32
  49. fz_write_string(ctx, fz_stdods(ctx), text);
  50. #endif
  51. fputs(text, stderr);
  52. }
  53. #else
  54. #define debug_printf(CTX, FMT, ...) do {} while (0)
  55. #endif
  56. #if defined(TIMINGS) && defined(_WIN32)
  57. #include "windows.h"
  58. #define MAX_TIMERS 256
  59. static struct {
  60. int started;
  61. int stackptr;
  62. int stack[MAX_TIMERS];
  63. const char *name[MAX_TIMERS];
  64. LARGE_INTEGER time[MAX_TIMERS];
  65. } timer;
  66. #define START_TIME() \
  67. do {\
  68. int i = timer.stack[timer.stackptr++] = timer.started++;\
  69. QueryPerformanceCounter(&timer.time[i]);\
  70. } while (0)
  71. #define END_TIME(NAME) \
  72. do {\
  73. LARGE_INTEGER end;\
  74. int i;\
  75. QueryPerformanceCounter(&end);\
  76. i = timer.stack[--timer.stackptr];\
  77. timer.time[i].QuadPart = end.QuadPart - timer.time[i].QuadPart;\
  78. timer.name[i] = NAME;\
  79. } while (0)
  80. #define DUMP_TIMES() \
  81. do {\
  82. int i;\
  83. LARGE_INTEGER freq;\
  84. QueryPerformanceFrequency(&freq);\
  85. float f = freq.QuadPart;\
  86. for (i = 0; i < timer.started; i++)\
  87. debug_printf(ctx, "%s: %g\n", timer.name[i], (int)1000*timer.time[i].QuadPart/f);\
  88. } while (0)
  89. #else
  90. #define START_TIME() do {} while(0)
  91. #define END_TIME(NAME) do {} while(0)
  92. #define DUMP_TIMES() do {} while(0)
  93. #endif
  94. typedef struct
  95. {
  96. int x;
  97. int y;
  98. } fz_ipoint;
  99. typedef struct
  100. {
  101. int i;
  102. int f;
  103. int di;
  104. int df;
  105. } fz_bresenham_core;
  106. typedef struct
  107. {
  108. fz_bresenham_core c;
  109. int n;
  110. } fz_bresenham;
  111. typedef struct
  112. {
  113. fz_bresenham_core x;
  114. fz_bresenham_core y;
  115. int n;
  116. } fz_ipoint_bresenham;
  117. typedef struct
  118. {
  119. fz_bresenham_core sx;
  120. fz_bresenham_core sy;
  121. fz_bresenham_core ex;
  122. fz_bresenham_core ey;
  123. int n;
  124. } fz_ipoint2_bresenham;
  125. static inline fz_bresenham_core
  126. init_bresenham_core(int start, int end, int n)
  127. {
  128. fz_bresenham_core b;
  129. int delta = end-start;
  130. b.di = n == 0 ? 0 : delta/n;
  131. b.df = delta - n*b.di; /* 0 <= b.df < n */
  132. if (b.df < 0)
  133. b.di--, b.df += n;
  134. /* Starts with bi.i = start, bi.f = n, and then does a half
  135. * step. */
  136. b.i = start + (b.di>>1);
  137. b.f = n - (((b.di & 1) * n + b.df)>>1);
  138. return b;
  139. }
  140. #ifdef CURRENTLY_UNUSED
  141. static inline fz_bresenham
  142. init_bresenham(int start, int end, int n)
  143. {
  144. fz_bresenham b;
  145. b.c = init_bresenham_core(start, end, n);
  146. b.n = n;
  147. return b;
  148. }
  149. static inline void
  150. step(fz_bresenham *b)
  151. {
  152. step_core(&b->c, b->n);
  153. }
  154. #endif
  155. static inline void
  156. step_core(fz_bresenham_core *b, int n)
  157. {
  158. b->i += b->di;
  159. b->f -= b->df;
  160. if (b->f <= 0)
  161. {
  162. b->f += n;
  163. b->i++;
  164. }
  165. }
  166. static inline fz_ipoint_bresenham
  167. init_ip_bresenham(fz_ipoint start, fz_ipoint end, int n)
  168. {
  169. fz_ipoint_bresenham b;
  170. b.x = init_bresenham_core(start.x, end.x, n);
  171. b.y = init_bresenham_core(start.y, end.y, n);
  172. b.n = n;
  173. return b;
  174. }
  175. static inline void
  176. step_ip(fz_ipoint_bresenham *b)
  177. {
  178. step_core(&b->x, b->n);
  179. step_core(&b->y, b->n);
  180. }
  181. static inline fz_ipoint
  182. current_ip(const fz_ipoint_bresenham *b)
  183. {
  184. fz_ipoint ip;
  185. ip.x = b->x.i;
  186. ip.y = b->y.i;
  187. return ip;
  188. }
  189. static inline fz_ipoint2_bresenham
  190. init_ip2_bresenham(fz_ipoint ss, fz_ipoint se, fz_ipoint es, fz_ipoint ee, int n)
  191. {
  192. fz_ipoint2_bresenham b;
  193. b.sx = init_bresenham_core(ss.x, se.x, n);
  194. b.sy = init_bresenham_core(ss.y, se.y, n);
  195. b.ex = init_bresenham_core(es.x, ee.x, n);
  196. b.ey = init_bresenham_core(es.y, ee.y, n);
  197. b.n = n;
  198. return b;
  199. }
  200. static inline void
  201. step_ip2(fz_ipoint2_bresenham *b)
  202. {
  203. step_core(&b->sx, b->n);
  204. step_core(&b->sy, b->n);
  205. step_core(&b->ex, b->n);
  206. step_core(&b->ey, b->n);
  207. }
  208. static inline fz_ipoint
  209. start_ip(const fz_ipoint2_bresenham *b)
  210. {
  211. fz_ipoint ip;
  212. ip.x = b->sx.i;
  213. ip.y = b->sy.i;
  214. return ip;
  215. }
  216. static fz_forceinline fz_ipoint
  217. end_ip(const fz_ipoint2_bresenham *b)
  218. {
  219. fz_ipoint ip;
  220. ip.x = b->ex.i;
  221. ip.y = b->ey.i;
  222. return ip;
  223. }
  224. static void
  225. interp_n(unsigned char *d, const unsigned char *s0,
  226. const unsigned char *s1, int f, int n)
  227. {
  228. do
  229. {
  230. int a = *s0++;
  231. int b = *s1++ - a;
  232. *d++ = ((a<<8) + b*f + 128)>>8;
  233. }
  234. while (--n);
  235. }
  236. static void
  237. interp2_n(unsigned char *d, const unsigned char *s0,
  238. const unsigned char *s1, const unsigned char *s2,
  239. int f0, int f1, int n)
  240. {
  241. do
  242. {
  243. int a = *s0++;
  244. int b = *s1++ - a;
  245. int c;
  246. a = (a<<8) + b*f0;
  247. c = (*s2++<<8) - a;
  248. *d++ = ((a<<8) + c*f1 + (1<<15))>>16;
  249. }
  250. while (--n);
  251. }
  252. static inline void
  253. copy_pixel(unsigned char *d, const fz_pixmap *src, fz_ipoint p)
  254. {
  255. int u = p.x>>8;
  256. int v = p.y>>8;
  257. int fu = p.x & 255;
  258. int fv = p.y & 255;
  259. int n = src->n;
  260. const unsigned char *s;
  261. ptrdiff_t stride = src->stride;
  262. if (u < 0)
  263. u = 0, fu = 0;
  264. else if (u >= src->w-1)
  265. u = src->w-1, fu = 0;
  266. if (v < 0)
  267. v = 0, fv = 0;
  268. else if (v >= src->h-1)
  269. v = src->h-1, fv = 0;
  270. s = &src->samples[u * n + v * stride];
  271. #ifdef SLOW_INTERPOLATION
  272. {
  273. int i;
  274. for (i = 0; i < n; i++)
  275. {
  276. int v0 = s[0];
  277. int v1 = s[n];
  278. int v2 = s[stride];
  279. int v3 = s[stride+n];
  280. int v01, v23, v;
  281. v01 = (v0<<8) + (v1-v0)*fu;
  282. v23 = (v2<<8) + (v3-v2)*fu;
  283. v = (v01<<8) + (v23-v01)*fv;
  284. assert(v >= 0 && v < (1<<24)-32768);
  285. *d++ = (v + 32768)>>16;
  286. s++;
  287. }
  288. return;
  289. }
  290. #else
  291. if (fu == 0)
  292. {
  293. if (fv == 0)
  294. {
  295. /* Copy single pixel */
  296. memcpy(d, s, n);
  297. return;
  298. }
  299. /* interpolate y pixels */
  300. interp_n(d, s, s + stride, fv, n);
  301. return;
  302. }
  303. if (fv == 0)
  304. {
  305. /* interpolate x pixels */
  306. interp_n(d, s, s+n, fu, n);
  307. return;
  308. }
  309. if (fu <= fv)
  310. {
  311. /* Top half of the trapezoid. */
  312. interp2_n(d, s, s+stride, s+stride+n, fv, fu, n);
  313. }
  314. else
  315. {
  316. /* Bottom half of the trapezoid. */
  317. interp2_n(d, s, s+n, s+stride+n, fu, fv, n);
  318. }
  319. #endif
  320. }
  321. static void
  322. warp_core(unsigned char *d, int n, int width, int height, int stride,
  323. const fz_ipoint corner[4], const fz_pixmap *src)
  324. {
  325. fz_ipoint2_bresenham row_bres;
  326. int x;
  327. /* We have a bresenham pair for how to move the start
  328. * and end of the row each y step. */
  329. row_bres = init_ip2_bresenham(corner[0], corner[3],
  330. corner[1], corner[2], height);
  331. stride -= width * n;
  332. #ifdef SLOW_WARPING
  333. {
  334. int h;
  335. for (h = 0 ; h < height ; h++)
  336. {
  337. int sx = corner[0].x + (corner[3].x - corner[0].x)*h/height;
  338. int sy = corner[0].y + (corner[3].y - corner[0].y)*h/height;
  339. int ex = corner[1].x + (corner[2].x - corner[1].x)*h/height;
  340. int ey = corner[1].y + (corner[2].y - corner[1].y)*h/height;
  341. for (x = 0; x < width; x++)
  342. {
  343. fz_ipoint p;
  344. p.x = sx + (ex-sx)*x/width;
  345. p.y = sy + (ey-sy)*x/width;
  346. copy_pixel(d, src, p);
  347. d += n;
  348. }
  349. d += stride;
  350. }
  351. }
  352. #else
  353. for (; height > 0; height--)
  354. {
  355. /* We have a bresenham for how to move the
  356. * current pixel across the row. */
  357. fz_ipoint_bresenham pix_bres;
  358. pix_bres = init_ip_bresenham(start_ip(&row_bres),
  359. end_ip(&row_bres),
  360. width);
  361. for (x = width; x > 0; x--)
  362. {
  363. /* Copy pixel */
  364. copy_pixel(d, src, current_ip(&pix_bres));
  365. d += n;
  366. step_ip(&pix_bres);
  367. }
  368. /* step to the next line. */
  369. step_ip2(&row_bres);
  370. d += stride;
  371. }
  372. #endif
  373. }
  374. /*
  375. points are clockwise from NW.
  376. This performs simple affine warping.
  377. */
  378. fz_pixmap *
  379. fz_warp_pixmap(fz_context *ctx, fz_pixmap *src, const fz_point points[4], int width, int height)
  380. {
  381. fz_pixmap *dst;
  382. if (src == NULL)
  383. return NULL;
  384. if (width >= (1<<24) || width < 0 || height >= (1<<24) || height < 0)
  385. fz_throw(ctx, FZ_ERROR_LIMIT, "Bad width/height");
  386. dst = fz_new_pixmap(ctx, src->colorspace, width, height,
  387. src->seps, src->alpha);
  388. dst->xres = src->xres;
  389. dst->yres = src->yres;
  390. fz_try(ctx)
  391. {
  392. unsigned char *d = dst->samples;
  393. int n = dst->n;
  394. fz_ipoint corner[4];
  395. /* Find the corner texture positions as fixed point */
  396. corner[0].x = (int)(points[0].x * 256 + 128);
  397. corner[0].y = (int)(points[0].y * 256 + 128);
  398. corner[1].x = (int)(points[1].x * 256 + 128);
  399. corner[1].y = (int)(points[1].y * 256 + 128);
  400. corner[2].x = (int)(points[2].x * 256 + 128);
  401. corner[2].y = (int)(points[2].y * 256 + 128);
  402. corner[3].x = (int)(points[3].x * 256 + 128);
  403. corner[3].y = (int)(points[3].y * 256 + 128);
  404. warp_core(d, n, width, height, width * n, corner, src);
  405. }
  406. fz_catch(ctx)
  407. {
  408. fz_drop_pixmap(ctx, dst);
  409. fz_rethrow(ctx);
  410. }
  411. return dst;
  412. }
  413. static float
  414. dist(fz_point a, fz_point b)
  415. {
  416. float x = a.x-b.x;
  417. float y = a.y-b.y;
  418. return sqrtf(x*x+y*y);
  419. }
  420. /* Again, affine warping, but this time where the destination width/height
  421. * are chosen automatically. */
  422. fz_pixmap *
  423. fz_autowarp_pixmap(fz_context *ctx, fz_pixmap *src, const fz_point points[4])
  424. {
  425. float w0 = dist(points[1], points[0]);
  426. float w1 = dist(points[2], points[3]);
  427. float h0 = dist(points[3], points[0]);
  428. float h1 = dist(points[2], points[1]);
  429. int w = (w0+w1+0.5)/2;
  430. int h = (h0+h1+0.5)/2;
  431. return fz_warp_pixmap(ctx, src, points, w, h);
  432. }
  433. /*
  434. Corner detection: We shall steal the algorithm from the Dropbox
  435. Document Scanner, as described here:
  436. https://dropbox.tech/machine-learning/fast-and-accurate-document-detection-for-scanning
  437. A good reference to the steps involved in the canny edge
  438. detection process can be found here:
  439. https://towardsdatascience.com/canny-edge-detection-step-by-step-in-python-computer-vision-b49c3a2d8123
  440. This involves:
  441. * Canny Edge Detection
  442. * * Greyscale conversion
  443. * * Noise reduction
  444. * * Gradient Calculation
  445. * * Non-maximum suppression
  446. * * Double threshold
  447. * * Edge tracking by Hysteresis
  448. * Hough Transform to fix possible edges
  449. * Computing intersections and scoring quads
  450. We modify the gradient calculation with a simple scale to ensure we fill the range.
  451. */
  452. #ifdef DO_HISTEQ
  453. static void
  454. histeq(fz_pixmap *im)
  455. {
  456. uint32_t count[256];
  457. unsigned char tbl[256];
  458. int i;
  459. unsigned char *s = im->samples;
  460. int n = im->w*im->h;
  461. int sigma;
  462. int den;
  463. memset(count, 0, sizeof(count));
  464. for (i = n; i > 0; i--)
  465. count[*s++]++;
  466. /* Rather than doing a pure histogram equalisation, we bend
  467. * the table so that 0 always stays as 0, and 255 always stays
  468. * as 255. */
  469. sigma = (count[0]>>1) - count[0];
  470. den = sigma + n - (count[255]>>1);
  471. for (i = 0; i < 256; i++)
  472. {
  473. int v = count[i];
  474. sigma += v - (v>>1);
  475. tbl[i] = (int)(255.0f * sigma / den + 0.5f);
  476. sigma += (v>>1);
  477. }
  478. s = im->samples;
  479. for (i = n; i > 0; i--)
  480. *s = tbl[*s], s++;
  481. }
  482. #endif
  483. /* The first functions apply a 5x5 gauss filter to blur the greyscale
  484. * image and remove noise. The gauss filter is a convolution with
  485. * weights:
  486. *
  487. * 2 4 5 4 2
  488. * 4 9 12 9 4
  489. * 5 12 15 12 5
  490. * 4 9 12 9 4
  491. * 2 4 5 4 2
  492. *
  493. * As you can see, there are 3 distinct lines of weights within that
  494. * matrix. We walk each row of source pixels once, calculating each of
  495. * those convolutions, storing the result in a rolling buffer of 5x3xw
  496. * entries. Then we sum columns from the buffer to give us the results.
  497. */
  498. /* Read across a row of pixels of width w, from s, performing
  499. * the horizontal portion of the convolutions, storing the results
  500. * in 3 lines of a buffer, starting at d, &d[w], &d[2*w].
  501. *
  502. * d[0*w] uses weights (5 12 15 12 5)
  503. * d[1*w] uses weights (4 9 12 9 4)
  504. * d[2*w] uses weights (2 4 5 4 2)
  505. */
  506. static void
  507. gauss5row(uint16_t *d, const unsigned char *s, int w)
  508. {
  509. int i;
  510. int s0 = s[0];
  511. int s1 = s[1];
  512. int s2 = s[2];
  513. int s3 = s[3];
  514. s += 4;
  515. d[2*w] = 11*s0 + 4*s1 + 2*s2;
  516. d[1*w] = 25*s0 + 9*s1 + 4*s2;
  517. *d++ = 32*s0 + 12*s1 + 5*s2;
  518. d[2*w] = 6*s0 + 5*s1 + 4*s2 + 2*s3;
  519. d[1*w] = 13*s0 + 12*s1 + 9*s2 + 4*s3;
  520. *d++ = 17*s0 + 15*s1 + 12*s2 + 5*s3;
  521. for (i = w - 4; i > 0; i--)
  522. {
  523. int d2 = 2*s0 + 4*s1 + 5*s2 + 4*s3;
  524. int d1 = 4*s0 + 9*s1 + 12*s2 + 9*s3;
  525. int d0 = 5*s0 + 12*s1 + 15*s2 + 12*s3;
  526. s0 = s1;
  527. s1 = s2;
  528. s2 = s3;
  529. s3 = *s++;
  530. d[2*w] = d2 + 2*s3;
  531. d[1*w] = d1 + 4*s3;
  532. *d++ = d0 + 5*s3;
  533. }
  534. d[2*w] = 2*s0 + 4*s1 + 5*s2 + 6*s3;
  535. d[1*w] = 4*s0 + 9*s1 + 12*s2 + 13*s3;
  536. *d++ = 5*s0 + 12*s1 + 15*s2 + 17*s3;
  537. d[2*w] = 2*s1 + 4*s2 + 11*s3;
  538. d[1*w] = 4*s1 + 9*s2 + 25*s3;
  539. *d = 5*s1 + 12*s2 + 32*s3;
  540. }
  541. /* Calculate the results for row y of the image, of width w, by
  542. * summing results from the temporary buffer s, and writing into the
  543. * original pixmap at d. */
  544. static void
  545. gauss5col(unsigned char *d, const uint16_t *s, int y, int w)
  546. {
  547. const uint16_t *s0, *s1, *s2, *s3, *s4;
  548. y *= 3;
  549. s0 = &s[((y+ 9+2)%15)*w];
  550. s1 = &s[((y+12+1)%15)*w];
  551. s2 = &s[( y %15)*w];
  552. s3 = &s[((y+ 3+1)%15)*w];
  553. s4 = &s[((y+ 6+2)%15)*w];
  554. for (; w > 0; w--)
  555. *d++ = (*s0++ + *s1++ + *s2++ + *s3++ + *s4++ + 79)/159;
  556. }
  557. static void
  558. gauss5x5(fz_context *ctx, fz_pixmap *src)
  559. {
  560. int w = src->w;
  561. int h = src->h;
  562. uint16_t *buf;
  563. unsigned char *s = src->samples;
  564. int y;
  565. if (w < 5 || h < 5)
  566. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Pixmap too small");
  567. buf = fz_malloc(ctx, w*3*5 * sizeof(uint16_t));
  568. gauss5row(&buf[0*3*w], &s[0*w], w);
  569. gauss5row(&buf[1*3*w], &s[1*w], w);
  570. memcpy(&buf[3*3*w], buf, w*3 * sizeof(uint16_t)); /* row -2 */
  571. memcpy(&buf[4*3*w], buf, w*3 * sizeof(uint16_t)); /* row -1 */
  572. for (y = 2; y < h; y++)
  573. {
  574. gauss5row(&buf[(y%5)*3*w], &s[2*w], w);
  575. gauss5col(s, buf, y-2, w);
  576. s += w;
  577. }
  578. for (; y < h+2; y++)
  579. {
  580. memcpy(&buf[(y%5)*3*w], &buf[((y+4)%5)*3*w], 3*w*sizeof(uint16_t));
  581. gauss5col(s, buf, y-2, w);
  582. s += w;
  583. }
  584. fz_free(ctx, buf);
  585. }
  586. #ifdef DETECT_DOCUMENT_RGB
  587. /* Variant of the above that works on a single plane from rgb data */
  588. static void
  589. gauss5row3(uint16_t *d, const unsigned char *s, int w)
  590. {
  591. int i;
  592. int s0 = s[0];
  593. int s1 = s[3];
  594. int s2 = s[6];
  595. int s3 = s[9];
  596. s += 4*3;
  597. d[2*w] = 11*s0 + 4*s1 + 2*s2;
  598. d[1*w] = 25*s0 + 9*s1 + 4*s2;
  599. *d++ = 32*s0 + 12*s1 + 5*s2;
  600. d[2*w] = 6*s0 + 5*s1 + 4*s2 + 2*s3;
  601. d[1*w] = 13*s0 + 12*s1 + 9*s2 + 4*s3;
  602. *d++ = 17*s0 + 15*s1 + 12*s2 + 5*s3;
  603. for (i = w - 4; i > 0; i--)
  604. {
  605. int d2 = 2*s0 + 4*s1 + 5*s2 + 4*s3;
  606. int d1 = 4*s0 + 9*s1 + 12*s2 + 9*s3;
  607. int d0 = 5*s0 + 12*s1 + 15*s2 + 12*s3;
  608. s0 = s1;
  609. s1 = s2;
  610. s2 = s3;
  611. s3 = *s; s += 3;
  612. d[2*w] = d2 + 2*s3;
  613. d[1*w] = d1 + 4*s3;
  614. *d++ = d0 + 5*s3;
  615. }
  616. d[2*w] = 2*s0 + 4*s1 + 5*s2 + 6*s3;
  617. d[1*w] = 4*s0 + 9*s1 + 12*s2 + 13*s3;
  618. *d++ = 5*s0 + 12*s1 + 15*s2 + 17*s3;
  619. d[2*w] = 2*s1 + 4*s2 + 11*s3;
  620. d[1*w] = 4*s1 + 9*s2 + 25*s3;
  621. *d = 5*s1 + 12*s2 + 32*s3;
  622. }
  623. static void
  624. gauss5x5_3(fz_context *ctx, fz_pixmap *dst, const fz_pixmap *src, int comp)
  625. {
  626. int w = src->w;
  627. int h = src->h;
  628. uint16_t *buf;
  629. unsigned char *s = src->samples + comp;
  630. unsigned char *d = dst->samples;
  631. int y;
  632. if (w < 5 || h < 5)
  633. fz_throw(ctx, FZ_ERROR_ARGUMENT, "Pixmap too small");
  634. buf = fz_malloc(ctx, w*3*5 * sizeof(uint16_t));
  635. gauss5row3(&buf[0*3*w], s, w);
  636. s += w*3;
  637. gauss5row3(&buf[1*3*w], s, w);
  638. s += w*3;
  639. memcpy(&buf[3*3*w], buf, w*3 * sizeof(uint16_t)); /* row -2 */
  640. memcpy(&buf[4*3*w], buf, w*3 * sizeof(uint16_t)); /* row -1 */
  641. for (y = 2; y < h; y++)
  642. {
  643. gauss5row3(&buf[((y*3)%15)*w], s, w);
  644. gauss5col(d, buf, y-2, w);
  645. s += w*3;
  646. d += w;
  647. }
  648. for (; y < h+2; y++)
  649. {
  650. memcpy(&buf[(y%5)*3*w], &buf[((y+4)%5)*3*w], 3*w*sizeof(uint16_t));
  651. gauss5col(d, buf, y-2, w);
  652. d += w;
  653. }
  654. fz_free(ctx, buf);
  655. }
  656. #endif
  657. /* The next set of functions perform the gradient calculation.
  658. * We convolve with Sobel kernels Kx and Ky respectively:
  659. *
  660. * Kx = -1 0 1 Ky = 1 2 1
  661. * -2 0 2 0 0 0
  662. * -1 0 1 -1 -2 -1
  663. *
  664. * We do this by using a rolling temporary buffer of int16_t's to hold
  665. * 3 pairs of lines of weights scaled by (1 0 1) and (1 2 1).
  666. *
  667. * We can then sum entries from those lines to calculate kx and ky for
  668. * each pixel in the image.
  669. *
  670. * Then by examining the values of x and y, we can figure out the
  671. * "direction" of the edge (horizontal, vertical, or either diagonal),
  672. * and the magnitude of the difference across that edge. These get
  673. * encoded back into the original image storage using the 2 bottom bits
  674. * for direction, and the top 6 bits for magnitude.
  675. */
  676. static void
  677. pregradrow(int16_t *d, const unsigned char *s, int w)
  678. {
  679. int i;
  680. unsigned char s0 = *s++;
  681. unsigned char s1 = *s++;
  682. d[w] = 3*s0 + s1;
  683. *d++ = s1 - s0;
  684. for (i = w-2; i > 0; i--)
  685. {
  686. int s2 = *s++;
  687. d[w] = s0 + 2*s1 + s2;
  688. *d++ = s2 - s0;
  689. s0 = s1;
  690. s1 = s2;
  691. }
  692. d[w] = s0 + 3*s1;
  693. *d = s1 - s0;
  694. }
  695. static void
  696. pregradcol(unsigned char *d, const int16_t *buf, int y, int w, uint32_t *max)
  697. {
  698. const int16_t *s0 = &buf[((y+2)%3)*w*2];
  699. const int16_t *s1 = &buf[((y )%3)*w*2];
  700. const int16_t *s2 = &buf[((y+1)%3)*w*2];
  701. int i;
  702. for (i = w; i > 0; i--)
  703. {
  704. uint32_t ax, ay, mag;
  705. int x;
  706. y = s0[w] - s2[w];
  707. x = *s0++ + 2 * *s1++ + *s2++;
  708. ax = x >= 0 ? x : -x;
  709. ay = y >= 0 ? y : -y;
  710. /* x and y are now both in the range -1020..1020 */
  711. /* Now we calculate slope and gradient.
  712. * angle = atan2(y, x);
  713. * intensity = hypot(x, y);
  714. * But wait, we don't need that accuracy. We only need
  715. * to distinguish 4 directions...
  716. *
  717. * -22.5 < angle <= 22.5 = 0
  718. * 22.5 < angle <= 67.5 = 1
  719. * 67.5 < angle <= 112.5 = 2
  720. * 115.5 < angle <= 157.5 = 3
  721. * (and the reflections)
  722. *
  723. * 7 0 1 (x positive right, y positive downwards)
  724. * 6 * 2
  725. * 5 4 3
  726. *
  727. * tan(22.5)*65536 = 27146.
  728. * And for magnitude, we consider the magnitude just
  729. * along the 8 directions we've picked. So
  730. * 65536/SQR(2) = 46341.
  731. * We want magnitude in the 0...63 range.
  732. */
  733. if (ax<<16 < 27146*ay)
  734. {
  735. /* angle = 0 */
  736. mag = ay<<16; /* 0 to 1020<<16 */
  737. }
  738. else if (ay<<16 < ax*27146)
  739. {
  740. /* angle = 2 */
  741. mag = ax<<16; /* 0 to 1020<<16 */
  742. }
  743. else
  744. {
  745. /* angle = 1 or 3 */
  746. mag = (46341*(ax+ay));
  747. }
  748. if (mag > *max)
  749. *max = mag;
  750. }
  751. }
  752. static uint32_t
  753. pregrad(fz_context *ctx, fz_pixmap *src)
  754. {
  755. int w = src->w;
  756. int h = src->h;
  757. unsigned char *s = src->samples;
  758. int16_t *buf = fz_malloc(ctx, w*2*3*sizeof(int16_t));
  759. int y;
  760. uint32_t max = 0;
  761. pregradrow(buf, s, w); /* Line 0 */
  762. memcpy(&buf[w*2*2], buf, w*2*sizeof(int16_t)); /* Line 1 */
  763. s += w;
  764. for (y = 1; y < h-1; y++)
  765. {
  766. pregradrow(&buf[(y%3)*w*2], s, w);
  767. pregradcol(s-w, buf, y-1, w, &max);
  768. s += w;
  769. }
  770. memcpy(&buf[((y+1)%3)*w*2], &buf[(y%3)*w*2], w*2*sizeof(int16_t)); /* Line h */
  771. pregradcol(s-w, buf, h-2, w, &max);
  772. pregradcol(s, buf, h-1, w, &max);
  773. fz_free(ctx, buf);
  774. if (max == 0)
  775. return 1;
  776. else
  777. return 0x7FFFFFFFU/max;
  778. }
  779. static void
  780. gradrow(int16_t *d, const unsigned char *s, int w)
  781. {
  782. int i;
  783. unsigned char s0 = *s++;
  784. unsigned char s1 = *s++;
  785. d[w] = 3*s0 + s1;
  786. *d++ = s1 - s0;
  787. for (i = w-2; i > 0; i--)
  788. {
  789. int s2 = *s++;
  790. d[w] = s0 + 2*s1 + s2;
  791. *d++ = s2 - s0;
  792. s0 = s1;
  793. s1 = s2;
  794. }
  795. d[w] = s0 + 3*s1;
  796. *d = s1 - s0;
  797. }
  798. static void
  799. gradcol(unsigned char *d, const int16_t *buf, int y, int w, int scale)
  800. {
  801. const int16_t *s0 = &buf[((y+2)%3)*w*2];
  802. const int16_t *s1 = &buf[((y )%3)*w*2];
  803. const int16_t *s2 = &buf[((y+1)%3)*w*2];
  804. int i;
  805. for (i = w; i > 0; i--)
  806. {
  807. uint32_t ax, ay, mag, scaled;
  808. int angle, x;
  809. y = s0[w] - s2[w];
  810. x = *s0++ + 2 * *s1++ + *s2++;
  811. ax = x >= 0 ? x : -x;
  812. ay = y >= 0 ? y : -y;
  813. /* x and y are now both in the range -1020..1020 */
  814. /* Now we calculate slope and gradient.
  815. * angle = atan2(y, x);
  816. * intensity = hypot(x, y);
  817. * But wait, we don't need that accuracy. We only need
  818. * to distinguish 4 directions...
  819. *
  820. * -22.5 < angle <= 22.5 = 0
  821. * 22.5 < angle <= 67.5 = 1
  822. * 67.5 < angle <= 112.5 = 2
  823. * 115.5 < angle <= 157.5 = 3
  824. * (and the reflections)
  825. *
  826. * 7 0 1 (x positive right, y positive downwards)
  827. * 6 * 2
  828. * 5 4 3
  829. *
  830. * tan(22.5)*65536 = 27146.
  831. * And for magnitude, we consider the magnitude just
  832. * along the 8 directions we've picked. So
  833. * 65536/SQR(2) = 46341.
  834. * We want magnitude in the 0...63 range.
  835. */
  836. if (ax<<16 < 27146*ay)
  837. {
  838. angle = 0;
  839. mag = ay<<16; /* 0 to 1020<<16 */
  840. }
  841. else if (ay<<16 < ax*27146)
  842. {
  843. angle = 2;
  844. mag = ax<<16; /* 0 to 1020<<16 */
  845. }
  846. else
  847. {
  848. /* 1 or 3 */
  849. angle = (x^y) >= 0 ? 3 : 1;
  850. mag = (46341*(ax+ay));
  851. }
  852. scaled = (mag * scale)>>25;
  853. assert(scaled >= 0 && scaled <= 63);
  854. *d++ = (scaled<<2) | angle;
  855. }
  856. }
  857. static void
  858. grad(fz_context *ctx, fz_pixmap *src, uint32_t scale)
  859. {
  860. int w = src->w;
  861. int h = src->h;
  862. unsigned char *s = src->samples;
  863. int16_t *buf = fz_malloc(ctx, w*2*3*sizeof(int16_t));
  864. int y;
  865. gradrow(buf, s, w); /* Line 0 */
  866. memcpy(&buf[w*2*2], buf, w*2*sizeof(int16_t)); /* Line 1 */
  867. s += w;
  868. for (y = 1; y < h-1; y++)
  869. {
  870. gradrow(&buf[(y%3)*w*2], s, w);
  871. gradcol(s-w, buf, y-1, w, scale);
  872. s += w;
  873. }
  874. memcpy(&buf[((y+1)%3)*w*2], &buf[(y%3)*w*2], w*2*sizeof(int16_t)); /* Line h */
  875. gradcol(s-w, buf, h-2, w, scale);
  876. gradcol(s, buf, h-1, w, scale);
  877. fz_free(ctx, buf);
  878. }
  879. #ifdef DETECT_DOCUMENT_RGB
  880. static void
  881. combine_grad(fz_pixmap *grey, const fz_pixmap *r, const fz_pixmap *g, const fz_pixmap *b)
  882. {
  883. int n;
  884. unsigned char *sd = grey->samples;
  885. const unsigned char *sr = r->samples;
  886. const unsigned char *sg = g->samples;
  887. const unsigned char *sb = b->samples;
  888. for (n = g->w * g->h; n > 0; n--)
  889. {
  890. unsigned char vg = *sg++;
  891. unsigned char vr = *sr++;
  892. unsigned char vb = *sb++;
  893. unsigned char vd = *sd++;
  894. if (vr > vg)
  895. vg = vr;
  896. if (vb > vg)
  897. vg = vb;
  898. if (vg > vd)
  899. sd[-1] = vg;
  900. }
  901. }
  902. #endif
  903. /* Next, we perform Non-Maximum Suppression and Double Thresholding,
  904. * both in the same phase.
  905. *
  906. * We walk the image, looking at the magnitude of the edges. Edges below
  907. * the 'weak' threshold are discarded. Otherwise, neighbouring pixels in
  908. * the direction of the edge are considered; if other pixels are stronger
  909. * then this pixel is discarded. If not, we classify ourself as either
  910. * 'strong' or 'weak'.
  911. */
  912. #define WEAK_EDGE 64
  913. #define STRONG_EDGE 128
  914. static void
  915. nonmax(fz_context *ctx, fz_pixmap *dst, const fz_pixmap *src, int pass)
  916. {
  917. int w = src->w;
  918. int h = src->h;
  919. const unsigned char *s0 = src->samples;
  920. const unsigned char *s1 = s0;
  921. const unsigned char *s2 = s0+w;
  922. unsigned char *d = dst->samples;
  923. int x, y;
  924. /* thresholds are in the 0 to 63 range.
  925. * WEAK is typically 0.1ish, STRONG 0.3ish
  926. */
  927. int weak = 6 - pass;
  928. int strong = 12 - pass*2;
  929. /* On entry, pixels have the angle in the bottom 2 bits and the magnitude in the rest. */
  930. /* On exit, strong pixels have bit 7 set, weak pixels have bit 6, others are 0.
  931. * strong and weak pixels have the angle in bits 4 and 5. */
  932. for (y = h-1; y >= 0;)
  933. {
  934. int lastmag;
  935. int ang = *s1++;
  936. int mag = ang>>2;
  937. int q, r;
  938. /* Pixel 0 */
  939. if (mag <= weak)
  940. {
  941. /* Not even a weak edge. We'll never keep it. */
  942. *d++ = 0;
  943. s0++;
  944. s2++;
  945. }
  946. else
  947. {
  948. ang &= 3;
  949. switch (ang)
  950. {
  951. default:
  952. case 0:
  953. q = (*s0++)>>2;
  954. r = (*s2++)>>2;
  955. break;
  956. case 1:
  957. q = (*++s0)>>2;
  958. r = 0;
  959. s2++;
  960. break;
  961. case 2:
  962. s0++;
  963. s2++;
  964. q = 0;
  965. r = *s1>>2;
  966. break;
  967. case 3:
  968. q = 0;
  969. s0++;
  970. r = (*++s2)>>2;
  971. break;
  972. }
  973. if (mag < q || mag < r)
  974. {
  975. /* Neighbouring edges are stronger.
  976. * Lose this one. */
  977. *d++ = 0;
  978. }
  979. else if (mag < strong)
  980. {
  981. /* Weak edge. */
  982. *d++ = WEAK_EDGE | (ang<<4);
  983. }
  984. else
  985. {
  986. /* Strong edge */
  987. *d++ = STRONG_EDGE | (ang<<4);
  988. }
  989. }
  990. lastmag = mag;
  991. for (x = w-2; x > 0; x--)
  992. {
  993. ang = *s1++;
  994. mag = ang>>2;
  995. if (mag <= weak)
  996. {
  997. /* Not even a weak edge. We'll never keep it. */
  998. *d++ = 0;
  999. s0++;
  1000. s2++;
  1001. }
  1002. else
  1003. {
  1004. ang &= 3;
  1005. switch (ang)
  1006. {
  1007. default:
  1008. case 0:
  1009. q = (*s0++)>>2;
  1010. r = (*s2++)>>2;
  1011. break;
  1012. case 1:
  1013. q = (*++s0)>>2;
  1014. r = ((s2++)[-1])>>2;
  1015. break;
  1016. case 2:
  1017. s0++;
  1018. s2++;
  1019. q = lastmag;
  1020. r = *s1>>2;
  1021. break;
  1022. case 3:
  1023. q = ((s0++)[-1])>>2;
  1024. r = (*++s2)>>2;
  1025. break;
  1026. }
  1027. if (mag < q || mag < r)
  1028. {
  1029. /* Neighbouring edges are stronger.
  1030. * Lose this one. */
  1031. *d++ = 0;
  1032. }
  1033. else if (mag < strong)
  1034. {
  1035. /* Weak edge. */
  1036. *d++ = WEAK_EDGE | (ang<<4);
  1037. }
  1038. else
  1039. {
  1040. /* Strong edge */
  1041. *d++ = STRONG_EDGE | (ang<<4);
  1042. }
  1043. }
  1044. lastmag = mag;
  1045. }
  1046. /* Pixel w-1 */
  1047. ang = *s1++;
  1048. mag = ang>>2;
  1049. if (mag <= weak)
  1050. {
  1051. /* Not even a weak edge. We'll never keep it. */
  1052. *d++ = 0;
  1053. s0++;
  1054. s2++;
  1055. lastmag = 0;
  1056. }
  1057. else
  1058. {
  1059. ang &= 3;
  1060. switch (ang)
  1061. {
  1062. default:
  1063. case 0:
  1064. q = (*s0++)>>2;
  1065. r = (*s2++)>>2;
  1066. break;
  1067. case 1:
  1068. q = 0;
  1069. s0++;
  1070. r = ((s2++)[-1])>>2;
  1071. break;
  1072. case 2:
  1073. s0++;
  1074. s2++;
  1075. q = 0;
  1076. r = *s1>>2;
  1077. break;
  1078. case 3:
  1079. q = ((s0++)[-1])>>2;
  1080. r = 0;
  1081. s2++;
  1082. break;
  1083. }
  1084. if (mag < q || mag < r)
  1085. {
  1086. /* Neighbouring edges are stronger.
  1087. * Lose this one. */
  1088. *d++ = 0;
  1089. }
  1090. else if (mag < strong)
  1091. {
  1092. /* Weak edge. */
  1093. *d++ = WEAK_EDGE | (ang<<4);
  1094. }
  1095. else
  1096. {
  1097. /* Strong edge */
  1098. *d++ = STRONG_EDGE | (ang<<4);
  1099. }
  1100. }
  1101. s0 = s1-w;
  1102. if (--y == 0)
  1103. s2 = s1;
  1104. }
  1105. }
  1106. /* Next, we have the hysteresis phase. Here we bump any 'weak' pixel
  1107. * that has at least one strong pixel around it up to being a 'strong'
  1108. * pixel.
  1109. *
  1110. * On entry, strong pixels have bit 7 set, weak pixels have bit 6 set,
  1111. * the angle is in bits 4 and 5, everything else is 0.
  1112. *
  1113. * We walk the rows of the image, and for each pixel we set bit 0 to be
  1114. * the logical OR of all bit 7's of itself, and its horizontally
  1115. * neighbouring pixels.
  1116. *
  1117. * Once we have done the first 2 rows like that, we can combine the
  1118. * operation of generating the bottom bits for row i, with the
  1119. * calculation of row i-1. Any given pixel on row i-1 should be promoted
  1120. * to 'strong' if it was 'weak', and if the logical OR of the matching
  1121. * pixels in row i, i-1 or i-2 has bit 0 set.
  1122. *
  1123. * At the end of this process any pixel with bit 7 set is 'strong'.
  1124. * Bits 4 and 5 still have the angle.
  1125. */
  1126. static void
  1127. hysteresis(fz_context *ctx, fz_pixmap *src)
  1128. {
  1129. int w = src->w;
  1130. int h = src->h;
  1131. unsigned char *s0 = src->samples;
  1132. unsigned char *s1 = s0;
  1133. unsigned char *s2 = s0;
  1134. unsigned char v0, v1, v2, r0, r1, r2;
  1135. int x, y;
  1136. /* On entry, strong pixels have bit 7 set, weak pixels have bit 6, others are 0.
  1137. * strong and weak pixels have the angle in bits 4 and 5. */
  1138. /* We make the bottom bit in every pixel be 1 iff the pixel
  1139. * or the ones to either side of it are 'strong'. */
  1140. /* First row - just do the bottom bit. */
  1141. /* Pixel 0 */
  1142. v0 = *s0++;
  1143. v1 = *s0++;
  1144. s0[-2] = v0 | ((v0 | v1)>>7);
  1145. /* Middle pixels */
  1146. for (x = w-2; x > 0; x--)
  1147. {
  1148. v2 = *s0++;
  1149. s0[-2] = v1 | ((v0 | v1 | v2)>>7);
  1150. v0 = v1;
  1151. v1 = v2;
  1152. }
  1153. /* Pixel w-1 */
  1154. s0[-1] = v1 | ((v0 | v1)>>7);
  1155. assert(s0 == src->samples + w);
  1156. /* Second row - do the "bottom bit" for the second row, and
  1157. * perform hysteresis on the top row. */
  1158. /* Pixel 0 */
  1159. v0 = *s0++;
  1160. v1 = *s0++;
  1161. r0 = v0 | ((v0 | v1)>>7);
  1162. s0[-2] = r0;
  1163. r1 = *s1++;
  1164. if ((r1>>6) & (r0 | r1))
  1165. s1[-1] |= 128;
  1166. /* Middle pixels */
  1167. for (x = w-2; x > 0; x--)
  1168. {
  1169. v2 = *s0++;
  1170. r0 = v1 | ((v0 | v1 | v2)>>7);
  1171. s0[-2] = r0;
  1172. r1 = *s1++;
  1173. if ((r1>>6) & (r0 | r1))
  1174. s1[-1] |= 128;
  1175. v0 = v1;
  1176. v1 = v2;
  1177. }
  1178. /* Pixel w-1 */
  1179. r0 = v1 | ((v0 | v1)>>7);
  1180. s0[-1] = r0;
  1181. r1 = *s1++;
  1182. if ((r1>>6) & (r0 | r1))
  1183. s1[-1] |= 128;
  1184. assert(s0 == s1 + w);
  1185. /* Now we get into the swing of things. We do the "bottom bit"
  1186. * for row n+1, and do the actual processing for row n. */
  1187. for (y = h-4; y > 0; y--)
  1188. {
  1189. /* Pixel 0 */
  1190. v0 = *s0++;
  1191. v1 = *s0++;
  1192. r0 = v0 | ((v0 | v1)>>7);
  1193. s0[-2] = r0;
  1194. r1 = *s1++;
  1195. r2 = *s2++;
  1196. if ((r1>>6) & (r0 | r1 | r2))
  1197. s1[-1] |= 128;
  1198. /* Middle pixels */
  1199. for (x = w-2; x > 0; x--)
  1200. {
  1201. v2 = *s0++;
  1202. r0 = v1 | ((v0 | v1 | v2)>>7);
  1203. s0[-2] = r0;
  1204. r1 = *s1++;
  1205. r2 = *s2++;
  1206. if ((r1>>6) & (r0 | r1 | r2))
  1207. s1[-1] |= 128;
  1208. v0 = v1;
  1209. v1 = v2;
  1210. }
  1211. /* Pixel w-1 */
  1212. r0 = v1 | ((v0 | v1)>>7);
  1213. s0[-1] = r0;
  1214. r1 = *s1++;
  1215. r2 = *s2++;
  1216. if ((r1>>6) & (r0 | r1 | r2))
  1217. s1[-1] |= 128;
  1218. assert(s0 == s1 + w);
  1219. assert(s1 == s2 + w);
  1220. }
  1221. /* Final 2 rows together */
  1222. /* Pixel 0 */
  1223. v0 = *s0++;
  1224. v1 = *s0++;
  1225. r0 = v0 | ((v0 | v1)>>7);
  1226. r1 = *s1++;
  1227. r2 = *s2++;
  1228. if ((r1>>6) & (r0 | r1 | r2))
  1229. s1[-1] |= 128;
  1230. if ((r0>>6) & (r0 | r1))
  1231. s0[-2] |= 128;
  1232. /* Middle pixels */
  1233. for (x = w-2; x > 0; x--)
  1234. {
  1235. v2 = *s0++;
  1236. r0 = v1 | ((v0 | v1 | v2)>>7);
  1237. r1 = *s1++;
  1238. r2 = *s2++;
  1239. if ((r1>>6) & (r0 | r1 | r2))
  1240. s1[-1] |= 128;
  1241. if ((r0>>6) & (r0 | r1))
  1242. s0[-2] |= 128;
  1243. v0 = v1;
  1244. v1 = v2;
  1245. }
  1246. /* Pixel w-1 */
  1247. r0 = v1 | ((v0 | v1)>>7);
  1248. r1 = *s1;
  1249. r2 = *s2;
  1250. if ((r1>>6) & (r0 | r1 | r2))
  1251. s1[0] |= 128;
  1252. if ((r0>>6) & (r0 | r1))
  1253. s0[-1] |= 128;
  1254. }
  1255. #ifdef WARP_DEBUG
  1256. /* A simple function to keep just bit 7 of the image. This 'cleans' the
  1257. * pixmap so that a grey version can be saved out for visual checking. */
  1258. static void
  1259. clean(fz_context *ctx, fz_pixmap *src)
  1260. {
  1261. int w = src->w;
  1262. int h = src->h;
  1263. unsigned char *s = src->samples;
  1264. for (w = w*h; w > 0; w--)
  1265. *s = *s & 128, s++;
  1266. }
  1267. #endif
  1268. #define SINTABLE_SHIFT 14
  1269. static int16_t sintable[270];
  1270. #define costable (&sintable[90])
  1271. /* We have collected an array of edge data.
  1272. * For each pixel, we know whether there is a 'strong' edge
  1273. * there, and if so, in which of 4 directions it runs.
  1274. *
  1275. * We want to convert this into hough space.
  1276. *
  1277. * The literature describes points in Hough space as having the
  1278. * form (r, theta). The value of any given point point in hough
  1279. * space is the "strength" of the line described by:
  1280. * x.cos(theta) + y.sin(theta) = r
  1281. *
  1282. * | \
  1283. * | /\
  1284. * | /\/\
  1285. * | r/ \
  1286. * | / \
  1287. * | / \
  1288. * |/theta \
  1289. * -+--------------
  1290. *
  1291. * i.e. r is the shortest distance from the origin to the line,
  1292. * and theta gives us the angle of that shortest line.
  1293. *
  1294. * But, we are using angles of theta from the vertical, so we need
  1295. * a different formulation:
  1296. *
  1297. * | \
  1298. * | /\
  1299. * | /\/\
  1300. * | r/ \ t = theta
  1301. * | / \
  1302. * |t/ \
  1303. * |/ \
  1304. * -+--------------
  1305. *
  1306. * So we're using 90-theta. cos(90-theta) = sin(theta),
  1307. * and sin(90-theta) = cos(theta).
  1308. *
  1309. * So: x.sin(theta) + y.cos(theta) = r (for theta measured
  1310. * clockwise from the y axis).
  1311. *
  1312. * We've been collecting angles according to their position in one
  1313. * of 4 octants:
  1314. *
  1315. * Ang 0 = close to a horizontal edge (-22.5 to 22.5 degrees)
  1316. * Ang 1 = close to diagonal edge (top left to bottom right) (22.5 to 67.5 degrees)
  1317. * Ang 2 = close to a vertical edge (67.5 to 112.5 degrees)
  1318. * Ang 3 = close to diagonal edge (bottom left to top right) (112.5 to 157.5 degrees)
  1319. *
  1320. * The other 4 octants mirror onto these.
  1321. *
  1322. * So, for each point in our (x,y) pixmap we whether we have a strong
  1323. * pixel or not. If we have such a pixel, then we know that an edge
  1324. * passes through that point, and which of those 4 octants it is in.
  1325. *
  1326. * We therefore consider all the possible angles within that octant,
  1327. * and add a 'vote' for each of those lines into our hough transformed
  1328. * space.
  1329. */
  1330. static void
  1331. mark_hough(uint32_t *d, int x, int y, int maxlen, int reduce, int ang)
  1332. {
  1333. int theta;
  1334. int stride = (maxlen*2)>>reduce;
  1335. int minang, maxang;
  1336. switch (ang)
  1337. {
  1338. /* The angles are really 22.5, 67.5 etc, but we are working in ints
  1339. * and specifying maxang as the first one greater than the one we
  1340. * want to mark. */
  1341. default:
  1342. case 0:
  1343. /* Vertical boundary. Lines through this boundary
  1344. * go horizontally. So the perpendicular to them
  1345. * is vertical. */
  1346. minang = 0; maxang = 23;
  1347. break;
  1348. case 1:
  1349. /* NE boundary */
  1350. minang = 23; maxang = 68;
  1351. break;
  1352. case 2:
  1353. /* Horizontal boundary. */
  1354. minang = 68; maxang = 113;
  1355. break;
  1356. case 3:
  1357. /* SE boundary */
  1358. minang = 113; maxang = 158;
  1359. break;
  1360. case 4:
  1361. /* For debugging: */
  1362. minang = 0; maxang = 180;
  1363. break;
  1364. }
  1365. d += minang * stride;
  1366. while (1)
  1367. {
  1368. for (theta = minang; theta < maxang; theta++)
  1369. {
  1370. int p = (x*sintable[theta] + y*costable[theta])>>SINTABLE_SHIFT;
  1371. int v = (maxlen + p)>>reduce;
  1372. d[v]++;
  1373. d += stride;
  1374. }
  1375. if (ang != 0)
  1376. break;
  1377. ang = 4;
  1378. minang = 158;
  1379. d += (minang - maxang) * stride;
  1380. maxang = 180;
  1381. }
  1382. }
  1383. #ifdef WARP_DEBUG
  1384. static void
  1385. save_hough_debug(fz_context *ctx, uint32_t *hough, int stride)
  1386. {
  1387. uint32_t scale;
  1388. uint32_t maxval;
  1389. uint32_t *p;
  1390. int y;
  1391. fz_pixmap *dst = fz_new_pixmap(ctx, NULL, stride, 180, NULL, 0);
  1392. unsigned char *d = dst->samples;
  1393. /* Make the image of the hough space (for debugging) */
  1394. maxval = 1; /* Avoid possible division by zero */
  1395. p = hough;
  1396. for (y = 180*stride; y > 0; y--)
  1397. {
  1398. uint32_t v = *p++;
  1399. if (v > maxval)
  1400. maxval = v;
  1401. }
  1402. scale = 0xFFFFFFFFU/maxval;
  1403. p = hough;
  1404. for (y = 180*stride; y > 0; y--)
  1405. {
  1406. *d++ = (scale * *p++)>>24;
  1407. }
  1408. fz_save_pixmap_as_png(ctx, dst, "hough.png");
  1409. fz_drop_pixmap(ctx, dst);
  1410. }
  1411. #endif
  1412. static uint32_t *do_hough(fz_context *ctx, const fz_pixmap *src, int stride, int maxlen, int reduce)
  1413. {
  1414. int w = src->w;
  1415. int h = src->h;
  1416. int x, y;
  1417. const unsigned char *s = src->samples;
  1418. uint32_t *hough = fz_calloc(ctx, sizeof(uint32_t), 180*stride);
  1419. START_TIME();
  1420. /* Construct the hough space representation. */
  1421. for (y = 0; y < h; y++)
  1422. {
  1423. for (x = 0; x < w; x++)
  1424. {
  1425. unsigned char v = *s++;
  1426. if (v & 128)
  1427. mark_hough(hough, x, y, maxlen, reduce, (v>>4)&3);
  1428. }
  1429. }
  1430. END_TIME("Building hough");
  1431. #ifdef WARP_DEBUG
  1432. save_hough_debug(ctx, hough, stride);
  1433. #endif
  1434. return hough;
  1435. }
  1436. typedef struct
  1437. {
  1438. int ang;
  1439. int dis;
  1440. int strength;
  1441. int x0;
  1442. int y0;
  1443. int x1;
  1444. int y1;
  1445. } hough_edge_t;
  1446. typedef struct
  1447. {
  1448. int e0;
  1449. int e1;
  1450. int score;
  1451. float x;
  1452. float y;
  1453. } hough_point_t;
  1454. static int
  1455. intersect(hough_point_t *pt, hough_edge_t *edges, int e0, int e1)
  1456. {
  1457. int x1 = edges[e0].x0;
  1458. int y1 = edges[e0].y0;
  1459. int x2 = edges[e0].x1;
  1460. int y2 = edges[e0].y1;
  1461. int x3 = edges[e1].x0;
  1462. int y3 = edges[e1].y0;
  1463. int x4 = edges[e1].x1;
  1464. int y4 = edges[e1].y1;
  1465. int d = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4);
  1466. int t = (x1-x3)*(y3-y4)-(y1-y3)*(x3-x4);
  1467. float ft;
  1468. if (d < 0)
  1469. {
  1470. if (t < d || t > 0)
  1471. return 0;
  1472. }
  1473. else
  1474. {
  1475. if (t < 0 || t > d)
  1476. return 0;
  1477. }
  1478. pt->e0 = e0;
  1479. pt->e1 = e1;
  1480. pt->score = edges[e0].strength + edges[e1].strength;
  1481. ft = t / (float)d;
  1482. pt->x = x1 + ft*(x2-x1);
  1483. pt->y = y1 + ft*(y2-y1);
  1484. return 1;
  1485. }
  1486. typedef struct
  1487. {
  1488. int w;
  1489. int h;
  1490. int edge[4];
  1491. int point[4];
  1492. int best_score;
  1493. int best_edge[4];
  1494. int best_point[4];
  1495. } hough_route_t;
  1496. /* To test convexity, we use the dot product:
  1497. * B
  1498. * / \
  1499. * / C
  1500. * A
  1501. *
  1502. * The dot product of vectors u and v is:
  1503. * dot(u,v) = |u|.|v|.cos(theta)
  1504. * Helpfully, cos(theta) > 0 for -90 < theta < 90.
  1505. * So if we can form perp(AB) = the vector given by rotating
  1506. * AB 90 degrees clockwise, we can then look at the sign of:
  1507. * dot(perp(AB),BC)
  1508. * If we do that for each corner of the polygon, and the signs
  1509. * of the results for all of them are the same, we have convexity.
  1510. *
  1511. * If any of the dot products are zero, the edges are parallel
  1512. * (i.e. the same edge). This should never happen.
  1513. *
  1514. * If AB = (x,y), then perp(AB) = (y,-x)
  1515. */
  1516. static void
  1517. score_corner(hough_point_t *points, hough_route_t *route, int p0, int *score, int *sign)
  1518. {
  1519. float x0, x1, x2, y0, y1, y2, ux, uy, vx, vy, dot;
  1520. int s, len;
  1521. float costheta;
  1522. /* If we've already decided this is duff, then bale. */
  1523. if (*score < 0)
  1524. return;
  1525. x0 = points[route->point[p0]].x;
  1526. y0 = points[route->point[p0]].y;
  1527. x1 = points[route->point[(p0+1)&3]].x;
  1528. y1 = points[route->point[(p0+1)&3]].y;
  1529. x2 = points[route->point[(p0+2)&3]].x;
  1530. y2 = points[route->point[(p0+2)&3]].y;
  1531. ux = y1-y0; /* u = Perp(p0 to p1)*/
  1532. uy = x0-x1;
  1533. vx = x2-x1; /* v = p1 to p2 */
  1534. vy = y2-y1;
  1535. dot = ux*vx + uy*vy;
  1536. if (dot == 0)
  1537. {
  1538. *score = -1;
  1539. return;
  1540. }
  1541. s = (dot > 0) ? 1 : -1;
  1542. if (*sign == 0)
  1543. *sign = s;
  1544. else if (*sign != s)
  1545. {
  1546. *score = -1;
  1547. return;
  1548. }
  1549. len = sqrt(ux*ux + uy*uy) * sqrt(vx*vx + vy*vy);
  1550. costheta = dot / (float)len;
  1551. if (costheta < 0)
  1552. costheta = -costheta;
  1553. if (costheta < 0.7)
  1554. {
  1555. *score = -1;
  1556. return;
  1557. }
  1558. costheta *= costheta;
  1559. *score += points[route->point[(p0+1)%3]].score * costheta;
  1560. }
  1561. /* route points to 8 ints:
  1562. * 2*i = edge number
  1563. * 2*i+1 = point number
  1564. */
  1565. static int
  1566. score_route(hough_point_t *points, hough_route_t *route)
  1567. {
  1568. int score = 0;
  1569. int sign = 0;
  1570. score_corner(points, route, 0, &score, &sign);
  1571. score_corner(points, route, 1, &score, &sign);
  1572. score_corner(points, route, 2, &score, &sign);
  1573. score_corner(points, route, 3, &score, &sign);
  1574. return score;
  1575. }
  1576. static float
  1577. score_by_area(const hough_point_t *points, const hough_route_t *route)
  1578. {
  1579. float double_area_of_quad =
  1580. points[route->point[0]].x * points[route->point[1]].y +
  1581. points[route->point[1]].x * points[route->point[2]].y +
  1582. points[route->point[2]].x * points[route->point[3]].y +
  1583. points[route->point[3]].x * points[route->point[0]].y -
  1584. points[route->point[1]].x * points[route->point[0]].y -
  1585. points[route->point[2]].x * points[route->point[1]].y -
  1586. points[route->point[3]].x * points[route->point[2]].y -
  1587. points[route->point[0]].x * points[route->point[3]].y;
  1588. float double_area = route->w * (float)route->h * 2;
  1589. if (double_area_of_quad < 0)
  1590. double_area_of_quad = -double_area_of_quad;
  1591. /* Anything larger than a quarter of the screen is acceptable. */
  1592. if (double_area_of_quad*4 > double_area)
  1593. return 1;
  1594. /* Anything smaller than a 16th of the screen is unacceptable in all circumstances. */
  1595. if (double_area_of_quad*16 < double_area)
  1596. return 0;
  1597. /* Otherwise, scale the score down by how much it's less than a quarter of the screen. */
  1598. return (double_area_of_quad*4)/double_area;
  1599. }
  1600. /* The first n+1 edges of the route are filled in, as are the first n
  1601. * points.
  1602. * 2*i = edge number
  1603. * 2*i+1 = point number
  1604. */
  1605. static void
  1606. find_route(fz_context *ctx, hough_point_t *points, int num_points, hough_route_t *route, int n)
  1607. {
  1608. int i;
  1609. for (i = 0; i < num_points; i++)
  1610. {
  1611. /* If this point continues our route (e0 == route->edge[n])
  1612. * then the next point in the route might be e1. */
  1613. int e0 = points[i].e0;
  1614. int e1 = points[i].e1;
  1615. if (e0 == route->edge[n])
  1616. {
  1617. }
  1618. else if (e1 == route->edge[n])
  1619. {
  1620. int t = e0; e0 = e1; e1 = t;
  1621. }
  1622. else
  1623. continue; /* Doesn't fit. Keep searching. */
  1624. /* If we've found 3 points already, then this is the
  1625. * fourth. */
  1626. if (n == 3)
  1627. {
  1628. int score = 0;
  1629. /* If we haven't looped back to our first edge,
  1630. * no good. Keep searching. */
  1631. if (route->edge[0] != e1)
  1632. continue;
  1633. route->point[3] = i;
  1634. score = score_route(points, route);
  1635. if (score > 0)
  1636. score *= score_by_area(points, route);
  1637. #ifdef WARP_DEBUG
  1638. debug_printf(ctx, "Found route: (point=%d %d %d %d) (edge %d %d %d %d) score=%d\n",
  1639. route->point[0], route->point[1], route->point[2], route->point[3],
  1640. route->edge[0], route->edge[1], route->edge[2], route->edge[3],
  1641. score);
  1642. #endif
  1643. /* We want our route to be convex */
  1644. if (score < 0)
  1645. continue;
  1646. /* Score the route */
  1647. if (route->best_score < score)
  1648. {
  1649. route->best_score = score;
  1650. memcpy(route->best_edge, route->edge, sizeof(*route->edge)*4);
  1651. memcpy(route->best_point, route->point, sizeof(*route->point)*4);
  1652. }
  1653. }
  1654. else
  1655. {
  1656. int j;
  1657. for (j = 0; j < n && route->edge[j] != e1; j++);
  1658. /* If we're about to loop back to any of the
  1659. * previous edges, keep searching. */
  1660. if (j != n)
  1661. continue;
  1662. /* Possible. Extend the route, and recurse. */
  1663. route->point[n] = i;
  1664. route->edge[n+1] = e1;
  1665. find_route(ctx, points, num_points, route, n+1);
  1666. }
  1667. }
  1668. }
  1669. #define MAX_EDGES 32
  1670. #define BLOT_ANG 10
  1671. #define BLOT_DIS 10
  1672. static int
  1673. make_hough(fz_context *ctx, const fz_pixmap *src, fz_point *corners)
  1674. {
  1675. int w = src->w;
  1676. int h = src->h;
  1677. int maxlen = (int)(sqrtf(w*w + h*h) + 0.5);
  1678. uint32_t *hough;
  1679. int x, y;
  1680. int reduce;
  1681. int stride;
  1682. hough_edge_t edge[MAX_EDGES];
  1683. hough_point_t points[MAX_EDGES * MAX_EDGES];
  1684. hough_route_t route;
  1685. int num_edges, num_points;
  1686. /* costable could (should) be statically inited. */
  1687. {
  1688. int i;
  1689. for (i = 0; i < 270; i++)
  1690. {
  1691. float theta = i*M_PI/180;
  1692. sintable[i] = (int16_t)((1<<SINTABLE_SHIFT)*sinf(theta) + 0.5f);
  1693. }
  1694. }
  1695. /* Figure out a suitable scale for the data. */
  1696. reduce = 0;
  1697. while ((maxlen*2>>reduce) > 720 && reduce < 16)
  1698. reduce++;
  1699. stride = (maxlen*2)>>reduce;
  1700. hough = do_hough(ctx, src, stride, maxlen, reduce);
  1701. /* We want to find the top n edges that aren't too close to
  1702. * one another. */
  1703. for (x = 0; x < MAX_EDGES; x++)
  1704. {
  1705. int ang, dis;
  1706. int minang, maxang, mindis, maxdis;
  1707. int where = 0;
  1708. uint32_t *p = hough;
  1709. uint32_t maxval = 0;
  1710. for (y = 180*stride; y > 0; y--)
  1711. {
  1712. uint32_t v = *p++;
  1713. if (v > maxval)
  1714. maxval = v, where = y;
  1715. }
  1716. if (where == 0)
  1717. break;
  1718. where = 180*stride - where;
  1719. ang = edge[x].ang = where/stride;
  1720. dis = edge[x].dis = where - edge[x].ang*stride;
  1721. edge[x].strength = hough[where];
  1722. /* We don't want to find any other maxima that are too
  1723. * close to this one, so we 'blot out' stuff around this
  1724. * maxima. */
  1725. #ifdef WARP_DEBUG
  1726. debug_printf(ctx, "Maxima %d: dist=%d ang=%d strength=%d\n",
  1727. x, (dis<<reduce)-maxlen, ang-90, edge[x].strength);
  1728. #endif
  1729. minang = ang - BLOT_ANG;
  1730. if (minang < 0)
  1731. minang = 0;
  1732. maxang = ang + BLOT_ANG;
  1733. if (maxang > 180)
  1734. maxang = 180;
  1735. mindis = dis - BLOT_DIS;
  1736. if (mindis < 0)
  1737. mindis = 0;
  1738. maxdis = dis + BLOT_DIS;
  1739. if (maxdis > stride)
  1740. maxdis = stride;
  1741. p = hough + minang*stride + mindis;
  1742. maxdis = (maxdis-mindis)*sizeof(uint32_t);
  1743. for (y = maxang-minang; y > 0; y--)
  1744. {
  1745. memset(p, 0, maxdis);
  1746. p += stride;
  1747. }
  1748. #ifdef WARP_DEBUG
  1749. //save_hough_debug(ctx, hough, stride);
  1750. #endif
  1751. }
  1752. num_edges = x;
  1753. if (num_edges == 0)
  1754. return 0;
  1755. /* Find edges in terms of lines. */
  1756. for (x = 0; x < num_edges; x++)
  1757. {
  1758. int ang = edge[x].ang;
  1759. int dis = edge[x].dis;
  1760. int p = (dis<<reduce) - maxlen;
  1761. if (ang < 45 || ang > 135)
  1762. {
  1763. /* Mostly horizontal line */
  1764. edge[x].x0 = 0;
  1765. edge[x].x1 = w;
  1766. edge[x].y0 = ((p<<SINTABLE_SHIFT) - edge[x].x0*sintable[ang])/costable[ang];
  1767. edge[x].y1 = ((p<<SINTABLE_SHIFT) - edge[x].x1*sintable[ang])/costable[ang];
  1768. }
  1769. else
  1770. {
  1771. /* Mostly vertical line */
  1772. edge[x].y0 = 0;
  1773. edge[x].y1 = h;
  1774. edge[x].x0 = ((p<<SINTABLE_SHIFT) - edge[x].y0*costable[ang])/sintable[ang];
  1775. edge[x].x1 = ((p<<SINTABLE_SHIFT) - edge[x].y1*costable[ang])/sintable[ang];
  1776. }
  1777. }
  1778. /* Find the points of intersection */
  1779. num_points = 0;
  1780. for (x = 0; x < num_edges-1; x++)
  1781. for (y = x+1; y < num_edges; y++)
  1782. num_points += intersect(&points[num_points],
  1783. edge, x, y);
  1784. #ifdef WARP_DEBUG
  1785. {
  1786. debug_printf(ctx, "%d edges, %d points\n", num_edges, num_points);
  1787. for (x = 0; x < num_points; x++)
  1788. {
  1789. debug_printf(ctx, "p%d: %d %d (score %d, %d+%d)\n", x,
  1790. (int)points[x].x, (int)points[x].y, points[x].score,
  1791. points[x].e0, points[x].e1);
  1792. }
  1793. }
  1794. #endif
  1795. /* Now, go looking for 'routes' A->B->C->D->A */
  1796. {
  1797. int i;
  1798. route.w = src->w;
  1799. route.h = src->h;
  1800. route.best_score = -1;
  1801. for (i = 0; i < num_points; i++)
  1802. {
  1803. route.edge[0] = points[i].e0;
  1804. route.point[0] = i;
  1805. route.edge[1] = points[i].e1;
  1806. find_route(ctx, points, num_points, &route, 1);
  1807. }
  1808. #ifdef WARP_DEBUG
  1809. if (route.best_score >= 0)
  1810. {
  1811. debug_printf(ctx, "Score: %d, Edges=%d->%d->%d->%d, Points=%d->%d->%d->%d\n",
  1812. route.best_score,
  1813. route.best_edge[0],
  1814. route.best_edge[1],
  1815. route.best_edge[2],
  1816. route.best_edge[3],
  1817. route.best_point[0],
  1818. route.best_point[1],
  1819. route.best_point[2],
  1820. route.best_point[3]);
  1821. debug_printf(ctx, "(%d,%d)->(%d,%d)->(%d,%d)->(%d,%d)\n",
  1822. (int)points[route.best_point[0]].x,
  1823. (int)points[route.best_point[0]].y,
  1824. (int)points[route.best_point[1]].x,
  1825. (int)points[route.best_point[1]].y,
  1826. (int)points[route.best_point[2]].x,
  1827. (int)points[route.best_point[2]].y,
  1828. (int)points[route.best_point[3]].x,
  1829. (int)points[route.best_point[3]].y);
  1830. }
  1831. #endif
  1832. }
  1833. #ifdef WARP_DEBUG
  1834. /* Mark up the src (again, for debugging) */
  1835. {
  1836. fz_device *dev = fz_new_draw_device(ctx, fz_identity, src);
  1837. fz_stroke_state *stroke = fz_new_stroke_state(ctx);
  1838. float col = 1;
  1839. fz_color_params params = { FZ_RI_PERCEPTUAL };
  1840. #ifdef WARP_SPEW_DEBUG
  1841. for (x = 0; x < num_edges; x++)
  1842. {
  1843. char text[64];
  1844. fz_path *path = fz_new_path(ctx);
  1845. fz_moveto(ctx, path, edge[x].x0, edge[x].y0);
  1846. fz_lineto(ctx, path, edge[x].x1, edge[x].y1);
  1847. fz_stroke_path(ctx, dev, path, stroke, fz_identity, fz_device_gray(ctx), &col, 1, params);
  1848. fz_drop_path(ctx, path);
  1849. debug_printf(ctx, "%d %d -> %d %d\n", edge[x].x0, edge[x].y0, edge[x].x1, edge[x].y1);
  1850. sprintf(text, "line%d.png", x);
  1851. fz_save_pixmap_as_png(ctx, src, text);
  1852. }
  1853. #endif
  1854. stroke->linewidth *= 4;
  1855. if (route.best_score >= 0)
  1856. {
  1857. fz_path *path = fz_new_path(ctx);
  1858. fz_moveto(ctx, path, points[route.best_point[0]].x, points[route.best_point[0]].y);
  1859. fz_lineto(ctx, path, points[route.best_point[1]].x, points[route.best_point[1]].y);
  1860. fz_lineto(ctx, path, points[route.best_point[2]].x, points[route.best_point[2]].y);
  1861. fz_lineto(ctx, path, points[route.best_point[3]].x, points[route.best_point[3]].y);
  1862. fz_closepath(ctx, path);
  1863. fz_stroke_path(ctx, dev, path, stroke, fz_identity, fz_device_gray(ctx), &col, 1, params);
  1864. fz_drop_path(ctx, path);
  1865. }
  1866. fz_drop_stroke_state(ctx, stroke);
  1867. fz_close_device(ctx, dev);
  1868. fz_drop_device(ctx, dev);
  1869. }
  1870. #endif
  1871. fz_free(ctx, hough);
  1872. if (route.best_score == -1)
  1873. return 0;
  1874. corners[0].x = points[route.best_point[0]].x;
  1875. corners[0].y = points[route.best_point[0]].y;
  1876. corners[1].x = points[route.best_point[1]].x;
  1877. corners[1].y = points[route.best_point[1]].y;
  1878. corners[2].x = points[route.best_point[2]].x;
  1879. corners[2].y = points[route.best_point[2]].y;
  1880. corners[3].x = points[route.best_point[3]].x;
  1881. corners[3].y = points[route.best_point[3]].y;
  1882. /* Discard any possible matches that aren't at least 1/8 of the pixmap. */
  1883. {
  1884. fz_rect r = fz_empty_rect;
  1885. r = fz_include_point_in_rect(r, corners[0]);
  1886. r = fz_include_point_in_rect(r, corners[1]);
  1887. r = fz_include_point_in_rect(r, corners[2]);
  1888. r = fz_include_point_in_rect(r, corners[3]);
  1889. if ((r.x1 - r.x0) * (r.y1 - r.y0) * 8 < (src->w * src->h))
  1890. return 0;
  1891. }
  1892. return 1;
  1893. }
  1894. #define DOC_DETECT_MAXDIM 500
  1895. int
  1896. fz_detect_document(fz_context *ctx, fz_point *points, fz_pixmap *orig_src)
  1897. {
  1898. fz_color_params p = {FZ_RI_PERCEPTUAL };
  1899. fz_pixmap *grey = NULL;
  1900. fz_pixmap *src = NULL;
  1901. #ifdef DETECT_DOCUMENT_RGB
  1902. fz_pixmap *r = NULL;
  1903. fz_pixmap *g = NULL;
  1904. fz_pixmap *b = NULL;
  1905. #endif
  1906. fz_pixmap *processed = NULL;
  1907. int i;
  1908. int found = 0;
  1909. /* Gauss function has std deviation of ~sqr(2), so a variance of
  1910. * 2. Apply it twice and we get twice that. So:
  1911. * n stddev variance
  1912. * 1 1.4 2
  1913. * 2 2 4
  1914. * 3 2.8 8
  1915. * 4 4 16
  1916. * 5 5.6 32
  1917. * 6 8 64
  1918. * 7 11.3 128
  1919. * 8 16 256
  1920. * 9 22.6 512
  1921. * 10 32 1024
  1922. * 11 45 2048
  1923. *
  1924. * The stddev is also known as the "width" by some sources.
  1925. *
  1926. * Our testing indicates that a width of 30ish works well for a
  1927. * image with it's major axis being ~3k pixels. So figure on a
  1928. * width of about 1% of the major axis dimension.
  1929. *
  1930. * By subsampling the incoming image, we can reduce the work we
  1931. * do in the gauss phase, as we get to use a smaller width.
  1932. */
  1933. int n = 10; /* Based on DOC_DETECT_MAXDIM */
  1934. int l2factor = 0;
  1935. fz_var(src);
  1936. fz_var(grey);
  1937. #ifdef DETECT_DOCUMENT_RGB
  1938. fz_var(r);
  1939. fz_var(g);
  1940. fz_var(b);
  1941. #endif
  1942. fz_var(processed);
  1943. fz_var(found);
  1944. fz_try(ctx)
  1945. {
  1946. START_TIME();
  1947. {
  1948. int maxdim = orig_src->w > orig_src->h ? orig_src->w : orig_src->h;
  1949. while (maxdim > DOC_DETECT_MAXDIM)
  1950. maxdim >>= 1, l2factor++;
  1951. START_TIME();
  1952. if (l2factor == 0)
  1953. src = fz_keep_pixmap(ctx, orig_src);
  1954. else
  1955. {
  1956. src = fz_clone_pixmap(ctx, orig_src);
  1957. fz_subsample_pixmap(ctx, src, l2factor);
  1958. }
  1959. END_TIME("subsample");
  1960. }
  1961. START_TIME();
  1962. if (src->n == 1 && src->alpha == 0)
  1963. {
  1964. if (src == orig_src)
  1965. grey = fz_clone_pixmap(ctx, src);
  1966. else
  1967. grey = fz_keep_pixmap(ctx, src);
  1968. }
  1969. else
  1970. {
  1971. grey = fz_convert_pixmap(ctx, src,
  1972. fz_default_gray(ctx, NULL), NULL, NULL, p, 0);
  1973. }
  1974. END_TIME("clone");
  1975. START_TIME();
  1976. for (i = 0; i < n; i++)
  1977. gauss5x5(ctx, grey);
  1978. END_TIME("gauss grey");
  1979. #ifdef WARP_DEBUG
  1980. fz_save_pixmap_as_png(ctx, grey, "gauss.png");
  1981. #endif
  1982. #ifdef DO_HISTEQ
  1983. START_TIME();
  1984. histeq(grey);
  1985. END_TIME("histeq grey");
  1986. #ifdef WARP_DEBUG
  1987. fz_save_pixmap_as_png(ctx, grey, "hist.png");
  1988. #endif
  1989. #endif
  1990. START_TIME();
  1991. grad(ctx, grey, pregrad(ctx, grey));
  1992. END_TIME("grad grey");
  1993. #ifdef WARP_DEBUG
  1994. fz_save_pixmap_as_png(ctx, grey, "grad.png");
  1995. #endif
  1996. #ifdef DETECT_DOCUMENT_RGB
  1997. if (src->n == 3 && src->alpha == 0)
  1998. {
  1999. START_TIME();
  2000. r = fz_new_pixmap(ctx, NULL, src->w, src->h, NULL, 0);
  2001. g = fz_new_pixmap(ctx, NULL, src->w, src->h, NULL, 0);
  2002. b = fz_new_pixmap(ctx, NULL, src->w, src->h, NULL, 0);
  2003. gauss5x5_3(ctx, r, src, 0);
  2004. for (i = 1; i < n; i++)
  2005. gauss5x5(ctx, r);
  2006. gauss5x5_3(ctx, g, src, 1);
  2007. for (i = 1; i < n; i++)
  2008. gauss5x5(ctx, g);
  2009. gauss5x5_3(ctx, b, src, 2);
  2010. for (i = 1; i < n; i++)
  2011. gauss5x5(ctx, b);
  2012. #ifdef DO_HISTEQ
  2013. histeq(r);
  2014. histeq(g);
  2015. histeq(b);
  2016. #endif
  2017. grad(ctx, r);
  2018. grad(ctx, g);
  2019. grad(ctx, b);
  2020. #ifdef WARP_DEBUG
  2021. fz_save_pixmap_as_png(ctx, r, "r.png");
  2022. fz_save_pixmap_as_png(ctx, g, "g.png");
  2023. fz_save_pixmap_as_png(ctx, b, "b.png");
  2024. #endif
  2025. combine_grad(grey, r, g, b);
  2026. END_TIME("rgb");
  2027. fz_drop_pixmap(ctx, r);
  2028. fz_drop_pixmap(ctx, g);
  2029. fz_drop_pixmap(ctx, b);
  2030. r = NULL;
  2031. g = NULL;
  2032. b = NULL;
  2033. }
  2034. #ifdef WARP_DEBUG
  2035. fz_save_pixmap_as_png(ctx, grey, "combined.png");
  2036. #endif
  2037. #endif
  2038. processed = fz_new_pixmap(ctx, fz_device_gray(ctx), grey->w, grey->h, NULL, 0);
  2039. /* Do multiple passes if required, dropping the thresholds for
  2040. * strong/weak pixels each time until we find a suitable result. */
  2041. for (i = 0; i < 6; i++)
  2042. {
  2043. START_TIME();
  2044. nonmax(ctx, processed, grey, i);
  2045. END_TIME("nonmax");
  2046. #ifdef WARP_DEBUG
  2047. fz_save_pixmap_as_png(ctx, processed, "nonmax.png");
  2048. #endif
  2049. START_TIME();
  2050. hysteresis(ctx, processed);
  2051. END_TIME("hysteresis");
  2052. #ifdef WARP_DEBUG
  2053. fz_save_pixmap_as_png(ctx, processed, "hysteresis.png");
  2054. #endif
  2055. START_TIME();
  2056. found = make_hough(ctx, processed, points);
  2057. END_TIME("total hough");
  2058. END_TIME("Total time");
  2059. DUMP_TIMES();
  2060. #ifdef WARP_DEBUG
  2061. clean(ctx, processed);
  2062. fz_save_pixmap_as_png(ctx, processed, "out.png");
  2063. #endif
  2064. if (found)
  2065. break;
  2066. }
  2067. }
  2068. fz_always(ctx)
  2069. {
  2070. fz_drop_pixmap(ctx, src);
  2071. #ifdef DETECT_DOCUMENT_RGB
  2072. fz_drop_pixmap(ctx, r);
  2073. fz_drop_pixmap(ctx, g);
  2074. fz_drop_pixmap(ctx, b);
  2075. #endif
  2076. fz_drop_pixmap(ctx, grey);
  2077. fz_drop_pixmap(ctx, processed);
  2078. }
  2079. fz_catch(ctx)
  2080. {
  2081. fz_rethrow(ctx);
  2082. }
  2083. if (found)
  2084. {
  2085. float f = (1<<l2factor);
  2086. float r = f/2;
  2087. for (i = 0; i < 4; i++)
  2088. {
  2089. points[i].x = points[i].x * f + r;
  2090. points[i].y = points[i].y * f + r;
  2091. }
  2092. }
  2093. return found;
  2094. }