1934: Make some cleaning, better makefiles, nicer tree.

https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Alexandre Abraham <abraham@lrde.epita.fr> Make some cleaning, better makefiles, nicer tree. * abraham/tests/morpho: New. * abraham/tests/morpho/ref: New Najman topological watershed for reference. * abraham/tests/morpho/ref/test: New. * abraham/tests/morpho/ref/test/UrOx.pgm: New. * abraham/tests/morpho/ref/include: New. * abraham/tests/morpho/ref/include/mcunionfind.h: New. * abraham/tests/morpho/ref/include/mclifo.h: New. * abraham/tests/morpho/ref/include/lattribheight.h: New. * abraham/tests/morpho/ref/include/mcutil.h: New. * abraham/tests/morpho/ref/include/mccomptree.h: New. * abraham/tests/morpho/ref/include/mcimage.h: New. * abraham/tests/morpho/ref/include/mcfahsalembier.h: New. * abraham/tests/morpho/ref/include/mcindic.h: New. * abraham/tests/morpho/ref/include/mccodimage.h: New. * abraham/tests/morpho/ref/include/lwshedtopo.h: New. * abraham/tests/morpho/ref/src: New. * abraham/tests/morpho/ref/src/lib: New. * abraham/tests/morpho/ref/src/lib/mccomptree.c: New. * abraham/tests/morpho/ref/src/lib/lattrib.c: New. * abraham/tests/morpho/ref/src/lib/mcimage.c: New. * abraham/tests/morpho/ref/src/lib/mcfahsalembier.c: New. * abraham/tests/morpho/ref/src/lib/mcindic.c: New. * abraham/tests/morpho/ref/src/lib/mccodimage.c: New. * abraham/tests/morpho/ref/src/lib/lwshedtopo.c: New. * abraham/tests/morpho/ref/src/lib/mcunionfind.c: New. * abraham/tests/morpho/ref/src/lib/mclifo.c: New. * abraham/tests/morpho/ref/src/lib/lattribheight.c: New. * abraham/tests/morpho/ref/src/com: New. * abraham/tests/morpho/ref/src/com/wshedtopo.c: New. * abraham/tests/morpho/ref/bin: New. * abraham/tests/morpho/ref/obj: New. * abraham/tests/morpho/ref/Makefile: New. * abraham/tests/morpho/Makefile: New. * abraham/tests/tikz.cc: Remove. * abraham/tests/io: New. * abraham/tests/io/tikz: New. * abraham/tests/io/tikz/tikz.cc: New. * abraham/tests/io/tikz/Makefile: New. * abraham/tests/Makefile: Remove. * abraham/mln: New. * abraham/mln/morpho: New. * abraham/mln/morpho/basic_najman.hh: . * abraham/mln/morpho/test.cc: Remove. * abraham/mln/morpho/test_component_tree.cc: . * abraham/mln/morpho/tikz.h: Remove. * abraham/mln/morpho/test_watershed.cc: . * abraham/mln/morpho/test_watershed_topo.cc: New. * abraham/mln/morpho/topo_wst.hh: Remove. * abraham/mln/morpho/Makefile: . * abraham/mln/io: New. * abraham/mln/io/tikz/save_header.hh: . * abraham/mln/io/tikz/save.hh: . * abraham/img/little_test.pgm: New. img/little_test.pgm | 5 mln/io/tikz/save.hh | 3 mln/io/tikz/save_header.hh | 2 mln/morpho/Makefile | 24 mln/morpho/basic_najman.hh | 472 ++++++ mln/morpho/test.cc | 46 mln/morpho/test_component_tree.cc | 5 mln/morpho/test_watershed.cc | 23 mln/morpho/test_watershed_topo.cc | 60 mln/morpho/tikz.h | 37 mln/morpho/topo_wst.hh | 130 - tests/Makefile | 9 tests/io/tikz/Makefile | 34 tests/io/tikz/tikz.cc | 49 tests/morpho/Makefile | 19 tests/morpho/ref/Makefile | 52 tests/morpho/ref/include/lattribheight.h | 4 tests/morpho/ref/include/lwshedtopo.h | 4 tests/morpho/ref/include/mccodimage.h | 100 + tests/morpho/ref/include/mccomptree.h | 79 + tests/morpho/ref/include/mcfahsalembier.h | 64 tests/morpho/ref/include/mcimage.h | 98 + tests/morpho/ref/include/mcindic.h | 27 tests/morpho/ref/include/mclifo.h | 48 tests/morpho/ref/include/mcunionfind.h | 24 tests/morpho/ref/include/mcutil.h | 31 tests/morpho/ref/src/com/wshedtopo.c | 97 + tests/morpho/ref/src/lib/lattrib.c | 1754 +++++++++++++++++++++++ tests/morpho/ref/src/lib/lattribheight.c | 717 +++++++++ tests/morpho/ref/src/lib/lwshedtopo.c | 1011 +++++++++++++ tests/morpho/ref/src/lib/mccodimage.c | 586 +++++++ tests/morpho/ref/src/lib/mccomptree.c | 805 ++++++++++ tests/morpho/ref/src/lib/mcfahsalembier.c | 236 +++ tests/morpho/ref/src/lib/mcimage.c | 2219 ++++++++++++++++++++++++++++++ tests/morpho/ref/src/lib/mcindic.c | 76 + tests/morpho/ref/src/lib/mclifo.c | 155 ++ tests/morpho/ref/src/lib/mcunionfind.c | 188 ++ tests/morpho/ref/test/UrOx.pgm | 6 tests/tikz.cc | 37 39 files changed, 9019 insertions(+), 317 deletions(-) Index: abraham/tests/morpho/ref/test/UrOx.pgm --- abraham/tests/morpho/ref/test/UrOx.pgm (revision 0) +++ abraham/tests/morpho/ref/test/UrOx.pgm (revision 0) @@ -0,0 +1,6 @@ +P5 +#xdim 1 +#ydim 1 +141 148 +255 +ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ?=;:853368>G^±ÎÓæZB4/+'#)--..--.00120.,--../048<;<>=;9AJRblnYE2/07GRXNHEHMT`n|§¸ÂÇÎÑÒÊ»¨pTH=63=UonQ=1.,,.12379:8754440,)()+,1:?=35=KGÿÿ:988741148=EY|¯ÏÙͱhJ81-)%,.-../-.11230.----,,,036899853=GQanxiXC70->Qgjkjmqx ¨¹ÇÔßååãßÙÅv\E?70,2Aeo^E60..024579<:974461.+*+.17@@<4<EQGÿÿ9:98610026;BUx«ÎÜÖ»uR<2-,.//,-/2-,.012/-.-,,*))-27998754?IRalusjZF6*5Lm¨¹ÏÞéñôóïåØÉªpYF985/-/4YkkN://0345656;;:83251.,+,/7>D>95ENQDÿÿ8998744436:?OmÇÞÜèaD41///.+.00./2111..0/..-,,/38:;;657GT__^]_]XOD7=Ld|°ÇÕÝàÝÕÊ·¤wcQD;6542001LcuWA03569:;9999974361.-/38BKSKFBQUL@ÿÿ89;:856656:@Mf¿Üâ˳pO9410/.-120/03221//10/.//.038:<<78>Q^g]UNPQRPJ?DN]r ~«µ¹¸²¨ucSF=865566421BZyaK579<ADEB>;98544510159@N\ib[U[VF;ÿÿ8:?<967889<CN`{´ØçÒ¼¦^A710/025410/0330001/-,01//27:;;:>I[fk\PIFFGIHDKRYirtib_is|~}xtk]TKD<745659;<9639PxlX=:=DMSTMG@;74553247;@G[pzmbS?6ÿÿ99=;986678;@IYp¥Ìä×Å®nL>520146655554211100/-/0//28;=<CM[ehd[TOIGIFFINWdoqjZQNQUYUTTURJDA@:64566=@?<985GnvjJIQaq{vhWI?7764678?GPp£t_M>7ÿÿ;:::::8789;>ERc»ÝØË´[F9301467888853233010/000149?CENZhif^YUQLJLGHOVarytaOD@ABD@?ACC@==?964567=@?=;93@`{z^_n§«£z_J;:869:9ALZ§Æ´sZG<7ÿÿ<:7;=<==<;<>DLV}§Ô×͸¬nP<3//257987853465100012147:DMT]gqg_XUROOOPNQXcpyZG;68;?>>@?>>?@@;75457:;<<:72:Ozw|»ÎרÕŪ}Y>=;8;;:AOd·ÑµhSC93ÿÿ?<8<>>>>==>ADHOl½ÈȽ´ ]D51//13677853344310./027>GS^iqrl\PHFFFLOQQV_pYD859<==<<>>>?><:85444788;;837Ct©ÎÕÕÎÐÍÅoIB;7899@Pi¶Ä¤_L?64ÿÿ?<9<>?>=<<=@ADI_~¦¸¿½·ªmM82/.-/356753234531..04=IYfq{yrcQC;;<>DINQYg¤¡^F969;;;;:==;<<::843224569:945;l§¤²ÓÓÎÂÇÍÓTE<889;CSj°µtVG<56ÿÿ<:9:=@<:9:;;<?EUn¦´ºµ°¬Z=3./))0356531247641/05FZo| wfVE803579>EL[p¤µ®hM=:769::;;968:;:7310/245899547b´§¯ÊɳºÅÕ¼^I>=::>GUg¦¥fMC;69ÿÿ@>>?AA?=<;:7;?AM_y¨µ´µ¶sJ;32--36776533465305=J_sn\L?755569<AL^vºÊÁ¦zZF?;:<<=?<:;:;<;94323346:=?>==^½ºÁÒÐËÂÆÌÔ¼aJ><<=>JYlv[G?:9:ÿÿBBBCCBB@=<;8<?@HUg²·ºª^G94004799874445444@ObwtaRE=:;9769<@L_x§ÈÚзhN@<;>>>@<;=;;==:4456558?FKJHD_ÃÉÏÕÕÒÌÌÌ˰\I><>@BM\qnTC;8:8ÿÿCDEDCBDB=>>=>@CGO[t£¯¶¹¸£yWA74458:;:8533547=Pe}rZQH@?@A>;7:=BM^u¨ÍåÚÆ¨wS>9:?@?><;<::==:566768<HS^ZTMfÄÓØÓØØÒÍĸtOE?<?CIP_vlRA8586ÿÿBBDCBABB@@?<<>BHMRf}§²¸½´qO8545:;:9989:<AJWk~~jYLHEBAABA>;=@DKYlÉèÞηaB;9<>>:9:<:9:;:7888>FO\eib[TpÆÙÞÖÓÌÁ´£u\C>;;=AHSh§ªkO>8667ÿÿCCECBBBBBA?;;=AFJN[n¬¸¾¿»dB955:;89:;>AFSarweUJCBBAABDB@=>AFLVdÀçã×ÄoI>9:=<97798789:879=JWbimlea`}ÃÎÏÅ¿·®¢~gS?;9:=BHWs¸µmP>8557ÿÿHGGEDEDCB@><<=@BGNS_t¤·¼ÃÌ©UA767879;<BJSh|lYLGC>??=?BFDA<<@IOU\³äéáͧ~SC:9;<;85346789859F\kspkfdhq¥»´« nXC;8;@DI]®Å½qU@8446ÿÿJHGGGGDDEB@>>>=>BINXeµÀÈÍ¿£wUA::9779;DQbz o\NGDA>A@:<>?@@>>@FLRWx¡ÓäåÕ¶eM?<:::7789998;AGRcu~~xsoz ¥© s^TKDGMVtÆÖÍ«hQG@<;ÿÿJIHHHHEEGEC@?>;:=DIQ[v²ÂËÎÊ·iM>;:879=I[rp[OGDC@>A@:;<<>@@@ADIOUj¼ÛæßÄ¢y]MID@?<;===;;ANZkxtrpw}vph_ahu»ÝåÛÀi^UNLÿÿJJIHGHGGHHFB@=:9:>CJUj®ÁÌÏÊ¿¬}ZA<9:8;BQgiWJFDCB@>??<<<;>@ABCCFKT\u ÎçêÒ´uebXOHDA@AA>AL]m¢·ÄÇ»´±®§ylmnorqmmlju§ÉâóòèÕ¹ |rkhÿÿHHGGHIGFEFD??<9:;<@GQcz«·»»µªgKC=9<CNatwcVMFCBBA@>?@A>====@>=>BHPUf·ÜîÜŪ~wpida_^_ago¡ÄØáà˹ª¥r`^^^cglonikpw¯¼ÊÚêôøñåÕ¾©|wtÿÿFFGGGGEDBCB?><8:;;>DN\m¢§¨§z^PF@EO]o{p_LHEDABDB@>?AC@?><;><<<?ELOYj Ëìà̱¡ ¡¾àêèÚ¿« kWTRQV]eijiijm ¢ÄØéõùöíÜ˺«{ywÿÿEFIGEBAAA@@A><9:;<=BLU^foy ¢¡{dUNS_p}|nWG>?@CBCHEA>@BCBA?;:;>???BGJP[¶ãÞʦ¦©³®ª§ÂÜõíØ¶£~ePLJJMRX[ajmonÉàðøöéг}zqnqqÿÿFGHCABA@>???><:=>=@DINRWZcr¢°°£xzu]I><>AEHHEA?>?@AA@>=<;=?@@ADIQ^ ¬ÐDzwtx}¤±¾ÂÇÎÜãåÇ©xs{ nYGGHIMPSUY_cgk¡Ì×àçÝÆ¢vifdc\\bdÿÿEFGCABBA>??>=<=@@?BDGGHJKUg{ª½Â¹§vTC;<@CFJID@???@ABA>?>;=?A??AHRa¡½¯~ofbejpw~¤µÂÑáçáΣj`_grtn^PDEGIKMMPRUZ_e|ÊÓÙÜÆ§k]WUSRKLUYÿÿDEGHFAEEA?>=;<@CC@ACDA?@ANe¹ÇȽ©©TE>=BEFHGCBAABCCDCA?=<>?@==@GSd¨ o`VSSTW`hoz¯ÇàäÔ¯bSPPSXYTNIEFHIIIHLMLRW\qÄÕÜײkZOLMKH=>KNÿÿDDEEDACCA@?>=>ACCAAAA=;;ARm¡¶Â¿®snvcMA>DFGFFDCB?BCDEC@=;:<?A<<?ERfwfUOMNSY^cis ³Å¾uYKIILNOMKHDEEFIIIHHHNU]lÃØÝÓ©[OHEGGEBCIIÿÿCCCCBAAAAA@??@BA@?>==;::F[y£³¸µ©k]_qvXF@CFFEDCCB?BDDDC@<;:<=?==@HVk¦vWMIJLOSTVYew¬®pVGFFGIIHIHEEEEGHHEDDKRZjÆÙÛÍ wSIC@ABCDFGDÿÿ@@A@@A@@A@?>?AB=;<878;<=Qj£°«ª®¬rXNTygNABCDDB?@ABDDBBA@=<=<;<?BEQat °Ä«ZMHIJKLOOMQ]r¤tXGFEDHIGGGGHGEFFEDB@GMTkÌÙ×ÅpRG@=<=ADEFAÿÿ==@@@@AA@@@@>>B<:;99:?FPj¡µÆ»iQLiv]HEBAA@>@BCCCBA@@=;;:::>CKZj|}w¦·WKDBACILNNRZez^JHFEIJHHGFHGDEFFECAFLSnÏÜ×ÂoSGA@??@ABDBÿÿ@@CBAABB@ABB?>A<:;=?BN\k~ ³ÒÒ±|YI\upVKD@?>>@AABBA@??<:::::>FQbs{tkoQIC@>@GKNOQUZvfOKGEIKKJHFHGDFGHFEDHMSrÒÞ×¾oTICBA@>@ACBÿÿIHJECDFEABCEB@>;;>BHOh}vu©ÐÜÍfKSikVHA==@??>?@@@?<:99:;;?IXjy vj_gmqdVGFDA@AFLONMNQc|pTMHEILNKIGFFEGIJGFGLPUv¡×àÖ¹nUKDAA@=@BC@ÿÿpmjb^\ZVQOPVRKC??BN`x¤«~rkhl{¸ÈÆuWYimVE@>?>??@@@?=;988:<<ERewl[PVXVPICBABABCHKKHGJPfzZNGCFHKKJGGHJKJIFEFHMTx¥ØÝϯjRHB@BA=?@@?ÿÿ{voggni^MHHOf¥»Ä¾£qb[]cn¦«v]^l¨¤jOE?>>??>>?><:876;>?L^szbQGJJFDBA@ACBBBFHHECCBV|aQGBDFHJIFFGJKJHFEDFKSz¥ÖÖÅ¥hQHB?A@<=>?@ÿÿ®µ¼·²¯©£y]UWd±ÔßÛɦbWRTY_fpwzrh]bp§¸»£^K@=>?>;;=<<;865<ADWloXJDEC@@@@ACEBBEFFFEA:9IjiTHCDEFGFEBBEFGGHFBEKTy£Ñ̹hSJB<>=::<AAÿÿ©²ººº¼¸´°£¡©Á×ÔŪkTMJKNQUY\^[YWarÃ̺sXG@?>=<=>=;96557>IefTIEDB?@ACAADAADDFID?:8B[sXGAABDFGGDCDCCCCCBFMWw¹±¢wdRHA=?>;=?@?ÿÿ¦®°³°¯¯ª¦£¥££¨µ¿Å¸£mYJFDDEGJJKLLOS^pÈÙʰjRC@>>>>?=;96568BSq {\OGEC@=?BFCAB@?ABEIC>:7>Ny}]JBABEEFHGFECABAAAFMYt~qcTIB?@?<?@@?ÿÿ ¤ª°¬ t`VMEDB?@ADCBCFKQYh~¦ÇâÕÁ§aFA?@??@=;:878AN`z¥rQIEEB>;>CIFC@=<=@CHB=99=EpfPGDEJFEHLLHEDCA@@EN[r{vsneWME@?>>ABAAÿÿipuy|}{|¢¨¨¤xgZQKFBA?=>>=@A@EJQYco»ßÙͺxUJB?@A?<::;<=FTg hKGEHEC@CFGEB?=<=@BEC?;:<@dqWGFFGFFJJIFECB@??DN\jqpjhllg_ULB?>>@BBCÿÿTX]bfiims¤«¯®¥}jZPJHDAA?>?@?<>?>BHNU]fªÑØÕÈ®kVG>@@>;9:>ACMZkx^HEEIGDAEFFDBA><=>@CCB>=<<Yxz`JHFEEGJHFDCA@?>?DMZbd^\^egge]RE@===?ACÿÿHJNORX[du¼Äĸy`OFCCE@>@>@FEDA>=<?DINWbuºÑÙÑÀ¨eL?=<;::;BHLU`nkTGCDIGD@CEFEDDA><;=@CDC@=9NnjPGCCFHIFCA?>?>=>DLU[YORW^aejcWH@;:78=BÿÿCBCBDKP\q¦¾Êʽ¢dSHCBCDCBBABGFD@=<>>@FKR[h|ºÏÕɶ|`HB=::;?IT]clx~`MDDEHIGCCDEDC@>=<99=BDC>:6KktTICADFFEDC?=>;;=BFJOPMRW]]dsujTKB:327>ÿÿ?=<;>FM]v®ÅÎǰmVJDBABDEDBBDFFDB>>@=>CHNV^j{ ¾ÔÐîwYJ@;;?ESdxqWGBCDFHGECBEDC??=;99;@BA=:8Ih}YKC@CDEEDD?<<::<AEJLNQW[]Ybx{cVJ?979>ÿÿ;:9:?GRf°ÂǺrXOEAB@AEDB?BDCDEFB@A>>AFLRV]g¦ÍÔϾ«rTC??CL`z©²µ©dOC@@ABDEE@@DEDAA?::;<>?>==>Jg _NDAABDDDC>;:88;BKWSU\aa\V`ytaSIHEBBÿÿ88:<AJ]v «µ¹«hTMGDEDDFEDDEDADECBA@@@@DGIRY`q¬ÂËŸ§nUHKPYwºÀÇα]LCCDCBABDBCEFEB?<9789=?ACFIWu¤¦lVIDBAA>=>>=:88<DMX[dqmcSJO`qvocXPNKGDÿÿ779>FSn¢§¯®y`QLIGFFGHFFHGEBED@BCBBAACEFOVZcs¨¸¼µ¥nX[bl²ÓÔØÝ´YJCDECA??BBBDDC@=;8668=BEKQXl·´ zaPHD@=:9:<=;:;@JT]dpxgMCBIYbea]YXSJFÿÿ887@Nc¤ ¤±¦jXNMJHGHIJHHKHFGGD>ADFCBBCEHORSZcn £¢¥¢ppx¨Èçåãâ´ VIDECA?>>>>?@?>;<:7668@GLT^jªÎ¬oZMG@88758;>?BIV_fn{lK?86AMX]bfe\LHÿÿ79<Lc¨¥¤§®~]QKJGFHHHGHIIGHJKHAABCBBCBDGJLNU[`ny ¢¢®ÀÔêéäÛ»[KB@??>=<<==;;:88769;<DO]l~µÌÙʵjXMC;6348?GO[iuzw| oR?407BQ^hokaSIÿÿ;>E^| ¯±¦©©¥mRLHHEFHGFGHHGFGKLICBABABCABEFHINRUZ_eely¨°·¾ÇÆÍÝãáÖ¼]LA====<;:<;8877679=ADN^s¥ÁÒÙ×Ë»§|iZND:7;DP_kwy]E6/1:IZgpjaTIÿÿCHRvÁ¿¶¥¨v\IHGGFEFEEHIHFCEJJHEDCAAAB@@CDEDEGLHJQRXb~ÅÔÙÒ»´¿ÔÜÕ¶]LA<<<<:999875568;>CHO^s³ÒîáÔÇľ´ o_RECJ\pmR>2/3?P^ic[QJÿÿ^gz¾ØË¿µ¯fSFGGGFEECBAFHFFFIJIFEEEBAA??AABCBCFEEHLS]xÎÝßÔÀ¹ÀÕÚÎ`M@98887777667:?BDGMWdsÐèóäØÏÍǼ yuroryupotv~lQ900:JV^WPHCÿÿ¤ÅÛèÖÈ»¨mZMDFHIGFEC?;CHHHHJJIGFFFCBB@@@ABDBABBBCHOYy£×æçÚËÇÎ򯂤iRC:75666679<AGNRUW\fs ÃÞéæÓƽ»´©}ru| zma_ahhmxfG728GRYRKD@ÿÿ©»Ñèóñâϸy[RJDGJMJHGB=8AHLJKNKJIFDCDEEEDABDGCA@@@@EKT¯áðñãÛÝêåÖ¾¦v]J=8656669@IR[cjmnptz°ÑÚÖÅ® {nbWbt~pga\\\\YZ_t}[C89FPYSLC?ÿÿ¥ÃåôùöÞÁfRNJFGILMNNHC?EIJHIMJIHEDEEEFEFHFEFBABCDCHNVyÂÝëîÞÖ×Ôȵ¢mYF?;9=BGNWbmtxzzyw{¥°«~tljgb[TLR_q~ ysld]VQOOPRezxYD:DNXUOHCÿÿ¥ËóúúñϪiVLKJHGIKMNOJHFIKJHHJIIIFEFGGHFGKFEFCBBDEFKOSk¡ÄÞðÙȼ¾¹~lXNIGNU]dmv~qb]YUTSRPLGKTbr{~wrnf_XOIEGHJXjqXCGMUVTOJÿÿ¨Òûüôä¶eUKGIJIHHIIIJIJMNNKHFEHJJIHGJKKFEHEDEDCABEINOLVf|¦Êç㣩¨qfa`gox~zk[UOIKLKJIJKJHLS]trg_XRMID?BDFLYm~tUNLQWYXSÿÿ¥Íô÷ìÓ£zYLEEEECDFHHHFHKNNMLLKHHHIJIFJLKGFGCBBCCBCEHMMJO[n³Ð¶~ ¢{of^ULJHFEEEBCFHJMSZaruj_XRONNJE>?BGJQ[nr_SNORUVÿÿÄíòæÇqQHDEDCCDFGHFDFIMMMKLKHGGIJIFJKKHEDB@@BDCDEILKFHRc³~hr~ }tfZRMHDCCBAAC??CFKSY^bnm^VQPNMNLG??AFHLQ_so\MHHKPÿÿ¶åîãÂnMIGFEFHIIFGFDEFILLGFFFEGJKIFGILHD@@@@BCDEGKKG@AJZyr`W[fwtogw n`UNKKFDCA?<?ADA@AEMZ^`ahf\VTWROMNJC@AEFIOTaw}gPB;<Bÿÿ ®ßêàÃsRLHFGHGIHDEFGHIHHGDDEHHGGHHHHHHDBA@@ABDGGILHA8<GXz}_NINWbnqju|qg^XQLKJIGECA?=???==@FQa_]YadcditmbTOJEDEFHJLNUaxpWF;56ÿÿ©ÚâÛÄxVMGEFFFHGDEFIJJIGFEDEHIGDFGHHGGDBBAABCDFGIJE>49F[~ qSB>CIQjtnv~unhcWNIJIFHIHHFA@??>>=<<?GSc_\Ybjq{gWMHGGHJKKKMRbp|weP@40ÿÿ~§Ö×ÑÅ }ZMECBCDEFGEFIJKLIIJFEGHFCFGGHIHFDCA@ADDBEFFC=39IcjN<58=Dhxtx l_VPMLFB?DFEGHGHD=>?@>=<=>@ITa^^`iu®¹º©fRKIIKMMLKJJLUfv}|`J92ÿÿ}¤ÏËÆÁ¢]OHFDBADFHGGHIJKIGGFEEFGIGEDFFDDDDDC@@@@DGHA90<Oj^F845=LitmwydWOLJHIECDFGEECACA=;;=<;9:<?JSYY^gr ªª¡ªª¡tWJGGJLMNOMGCDM\k{q_H;ÿÿ~¦ÏÄ¿¿¤`QHFDB@CFHGFEFHIGGHGFDGJMIEBEECCDEGEA?>>CGJA80?Us zR?535@ThnfvyeQJFEFFGEDFFFECB@@?=::;;979;>JPQT\jw¯¢¦°^KFEIJLOQNG?;=HZryr]Lÿÿ¬Õ»¾§cPFCDCBDFHECBCDEFHMJGDIMPKFBCEFEEFHGB@><AGLC:2B\tG8238E\fg`tmWGGEBEGHFEEDDECBCA?<<<;9878;>GKJOZky²§}´gLFDGGJPQOI@96<J`xzcÿÿ ³ÞÉÀ«iVJEDCBDFHGECCCCDEGGGEHIIHGEEEEDEHGEBBA>AEIA;9E^mG947@Oe`[WtgTFEDBEGHHGDEEFDCCB@>>>>?=9;>BGIGR`qw£ª¦¢¨¬dKFEFEGKPQNB:6;DP`mxsÿÿ·æÓÈÆ®kXLEDDCEFGGFBCCBCCDFGFHHFGHHGGGFFIGDCBA?ADF@==Ib~hF;8=L[iZSVw~dQEEEDFGHIHFEEFDCCCB@>?@A?;=?BFHGUdss}¢«ª«¦w]IFEGEFKPRPD;59>DJUdqÿÿ¸ëÞÓʲjWIBEGFFEDEDABBCCDEGHGJJGIJJIIJHHIGED?>?BDCB@?Oj~eD>>D]iiTP\}~cODGHGIIGJKJFEGCBCDCB?>A@><>>=CGHWernpy¤³ª|cRHEEHFHNQRQF<36:=89?`ÿÿªÚãáÓµnYKDDDEEEDEEFEDDDEFIIEFGHHHGHHHFFGFEC@=<?ADCA@Tp|bEBIXr}yljs|aOGGGGIIHIJLHGIFEEEDA><<?@?ACEEEF\jphcblw{p`UKDEFHFGKMOOG>556:534Sÿÿ}ÃàçÚ¸q[LECCDEEDDFHEEFFFGKKFEEGFFEFGGEDEDC@=;:=AFCBBWry_FGSju]NHGGFGGGGIKIILJHFEC@=;:?A@BEIFFH_lmaWPSX_ZTNKGBFGGEEGIKLE>6348310Lÿÿ|¦Óæß»s\MEDCBEECDEGDEHGFGMNJECDDCBCEHECBA?<77;=AHBAEXrt[EJ\z ¹Æ½µ°iWLGHGEDDEFGHGIONKFEB>=<<@A>BFIHIMajhZNEFGIHGFGFCHHEB@AFHGC=6239533JÿÿuÂÙÚ¶zfXPMIEEEEGGHHGGGGGJKKGEDDDDEFGCBC@?A:9<AFKFEH[su\FOf²ÆÆ³¬±eUKGFFEFFGGHIGINTURKE?<;<AB?BFJIKPbifXLCABGGFEFFEGFDCA>BEFGD=88=@CFZÿÿls ¯ÆÌ}od\XRKHFGGGGIJGHHGHIJHGEDDFFFEA@B@@B=<?EKSNKK]st]IVq¿È¹¥¢¯~bTKGGFFFFGFGHHLSclm]NC=;=AB@DINMOUdieVJA?@EDDEFEDDCBA@=?AEKKG?<?FLQ_ÿÿ`gw®·¡}wqke^VMHHEDDIKJIIHHHIHHHFFGFEC>=@A@??ADIS`XSPasr`P_±ÆÀ ªz_SKGIIHDCFEDEHQ^|x_JB>>@BCHOVRT[hkfSG@??BACFFD@@@@>==;=CNSSF?@HOT[ÿÿX_l yjilpqkaVOKIHEGHGEEEDEHHHGEDFCA@><;>><=AGSbtyvmlrsdUh¾Ê¾£u\PIFIJHEEGEDDJYr²¼tPGA?CGJR^nnoquqeVKCBBCCDFB@@@?>>>>>BJUYUJEEIP\mÿÿMT`s ufVX_irsmcZQNKFEDDCCDBBEFFECCB@>><;9<=;=BL^txs|qfYlÁÍÀ¡qWMGEHIIFFGDCEK]z§ÃΨUIBAELSbu~p_SJGEEDDE@>??>=>>>BIRZ[VMKNPXgyÿÿ>FQfsxeSBDJThu|uiZSMGDBBCDE@?@BCCB@====:99;<;>EQi®Åè uznd[mºÏÆ¡ ¡¢kQHDDFHJGFFBBFM]v¤ÁÌ©XIBBGP^v³Á¿®¡ n^UNIFEDC?=<==>=>?HPY\ZUPQY]gv~ÿÿ5<G_rjUA=<?L\mrpi^TJGEDBA@>>>BCC@><==<;;<>ACJUf ¨ÏÞ׺z|}zrz¥Ç˰¯«£hPIDCEFHFECBCDHSe ¤mRHFKYj ½ØÜÚÏÀ±¢}tkbWQLGC?;==;@DHRX[WVVWYZY^giÿÿ49BZq s]E;53:GZhoph]PLHDA><<==@BB>=>??=?ACEJP\m¥ÆçìâÇ~{ ~½Í¿·§oXPJFFFGEDCCBACIUhu|k]POT`t£ÂÚìéæãÖʾªsg]SKD?@@?GPZ_^YUUY^]XUV\[ÿÿ;<CXomM@7127BXgpogZRJA><;;<=>>?<>CDC>EJNPWct¨ÉâôïãÐ x {~±Ì×Ðð~j^UNIFFDDEB@>=@GLPSRRS^m°ËÝéïèæéãÝ×ǽ¸¯¥vgYNFEFHUcsncTSW`b^UPPUUÿÿCGNaoxw`OA8434ES`fgbXND@==:;@BDDEIPQQOU[bkw¸ÓáèèâÞݶ|tsz¹Òʹ {tldZSNJGEA=;;>CGLRYcp¨·ÁÅÃÁ¾¸¶¸¼¾¾¾ÂÉÊÇÁ²¡zhXQRYk~w][]da\WVUTPÿÿNWctxqzzp[K?83/8DQ\be^ULFDECEJNQT[bjihfiox°ÆØèéçâàãêϲ|pkn³©xtwxwumf^WPJD?;<>CIR^n¤³ÀÁ¼°¢¥²ÂÍÕÚÖÊ·£ymlw£·©ib`c_\YZWQLÿÿZmprv|eTH?8239BOYbb_XRPRUX\`fo~ ¤¾ÝéíèáÞáéñøêÓ´oebks{peZUW^iu~wk_TLE>?AFSdyªÀËÏ˸¢yld_ahkns|£ºÏäððãÔÀ©¡¼ÑàÌ©xia^]]\]XKHÿÿ]y²© vs}l\OG?759AKUacb__`cehms{©®wqt¦ÉéêåÙÑÏÔêøüòäдwbXZafh]VSMLOT[cmtwyvpg^WUW]q ³ÂÍȾ®jb\ZVVY\^`eo|¢·ÐâíëäØÏÏØåíîϦscZX[]\XQHBÿÿZx§Â¾vtfUME=9;CNZfiigfffimrwª·¹e_cq ÃÛÑŶ±µÃçúýöíâ¾kVOT^b`VPOJHHHJPZbipttqnmmqw¡¹ÄÉÇ´¡veXUTSQPPSTTVZ`o~©ÂÚêóôòó÷ûøïÆk]VWZ[XPIC?ÿÿQlÄ˱~q\SKF??GXfqtspic]aeinz¨´±nNKRd¬³°Þ÷ûöðê½\LHQbhcYRNMKIDCGHJLRY`ju¡±ÄŽyi\TSTSOOOOPPOMNQZcl{©Ðìýþÿÿþôâ³bYWZ[XQF@==ÿÿI[z£·¶¡ui`[UWazraTSUYblxlXIHPb~won}Éëüþûñá¬{PECJakh[SOOOMIGGFFGGIMT[alw©º¬pbWTRPPNJKJIMMLIJNTY]gr¡¿ÚëôôêØ¿zaYTSRME=:;<ÿÿEOa ¬©¥~|x{ ¡¸Çĸ£mXQORY_chgbULGJTdrsheit²âõÿÿûìÐmKDBG`lk]UQPPPMKJGEFCBBFIKUan¡«ze[SNPQPOMIJIGKLKHIMOQSX^e}³ÊÔÑò wg]UPLF<879>ÿÿCIPi§¯¬£¨¥©³ÎàêãÖĤi\TSRPONNNJIJQ[jlh_hy³Öûþÿÿøà¶cLGEH]il_VSPPSPOQKHGECA>==BL[ v_ROMMNPSRPLLKIJKLKKMLLNNQXdt~vfZQI@6678Aÿÿ@ITp¢°±¥|£´ÃÐ××Ï·uj_WQLGFGHKPT\grxz¤¿ÚïþÿÿÿðÐy\IHHLYbf]UOOPQNMNLLLJHFC@>@K^nYMNMMLMPQPMLKLLKIKLLKJJLOS\gr}|pdbhv r`OD<757=Mÿÿ>K^²µ®qhlptw~¨ºÄÆ·¤{pg^ULGGKPUV[ct±ËãóüÿÿÿþèÂoWHILPY^`ZTNNNOLKMNOPOMJHD@CPhgULNONLLNONKJKNNMJLLLKIHJLOW^ekg[PP[m~}iSF>;;AK^ÿÿ=Nm°Ã·¦zi\YWW[_cejs¨£yk\RLSWZWY_s°ÓìûýþÿÿþüÞ¶iUHKOU[]ZVSPLKMKKNOQRSROMICI[z{aRMPQPMLMLJFGJPQPMNMKJIHHILSZac`WLN[izv]MDCITduÿÿJe£¯°£qaUPMKMOPRV[kxxpgkosvxwsme_^addah¨ÏèòõùþýûøÚ³hTIJOX_`ZUROKJLKMQRRQRRPPMIQfs]RPPPNMLLLLJKLMPQQOMJIIIHHKNRW\adem|¡xia_ekqoÿÿ`~¥¥wgYMIEBCDDGJOX_d\VPTZagmt~wkgknkcdwÇáëðöþýû÷ݹnXLKOYbbZTPMJIKKNRVWUUUUUSR]sn\SSRPNMLKMMMMNNOQSPMJJJIHHIKMQYdt ª°·¿»°zyvqiÿÿ§ ~ui]QEB>;=?ABGNQRQOJCCGPTZa}vrxuofgtºØåíõýýüúçÈy`QORYdeZTOJIHILNQZ^^[[^\\]k¤¡k^WVUSPMLKNONOPQOPSPMKKKJIHGHKOYk¬ËäèéèàÖÉ´¢ vfbÿÿ¢ti^SKCA?;>ADFIOQQNLHD??CNW`~wpjegs¯ÄÇÈÎÚæñùðذlVRSZaaYQMKJJLNPRZ`aabebbcw¯l`YWVTQPMKMNMNONOPPNMMNMJHFDFIN\tÆäóððñðéÚÂub]ÿÿ¯¨{wi]SLFBA?<?CFFINOONKHE@>=GQ[v¤yohcam¢¥¡®ÂÖëðãÄy]VU[_^YQMLLNQRSV]befhkijo ·oc\ZXUSQOLMMMNMMNOMMMMOMIFEDDHNaÚó÷ööøóçÔº¥s_Xÿÿ¼ªth[QJGDBA@?BDFDFKKLOKHFFC>AITg}}tj_Xbon{¬ÎéëÕ®f[W\^^[SNMORWVY^cfhknqotª¼vg_^ZWUSPMMMNLKLLKJNNKMKFFFFDGOhÈêøò÷ûýéÒ¸ ~q^Tÿÿ½§xgYNGDDEEDDDDDDEGIIKPOMIHEA@BFO`yn_TQUblng__gx§ÊÚÖ³l]UUZ]^WQNNQVVZaglprsvu| ¯¸xme_[XVTSTPNNLLOPOLMNMKIGGFDBGRs ÚïùùúïÚºqffrsj[ÿÿ¹m[MFBACEHFEDDDDEFGHJNONJIFC@?>BOdkWLKKMPRTSU[i{¸Ñܽq\PMTZ]ZUPORWX]elrwwy}yªµ´{sjc]YWTSTQOOMMOPPNNMMJHGFECBIX}¬æôûüôݺ{gZTWkuubÿÿ¯r`PCAABDFIFDAACFCCEGIKLKIIGDA?=?HW}kREDCB?@FKQVct²ÑçË¥uYIDMSV[[TRSX]cipv|}zµ¼°woha[VSPNOPQPOLOPPOMJGFFECBCM_´ëøþýæÅ~h[WVWiv~jÿÿ{cTIABCCDFHFEDABFFEDEFGGFEFECA?<CLX{¢{]GCAA?<9>FQe}ÅäôÖ¬vYF=DLV^^VQQV\cjt{°Á±¡zpgb]VTQNORVQMLMNPNLIHGEBACFP`®ãôøîÆ¡|maXWY^jxzÿÿ{gUKDBCDEEFGFEDBCFFFEDDDDCABCCC@;DNZ{°lKC@A?;58@Ke®ÙóûÚ®w[H>AHR\`\USUZajt|«·ÃÊŲ¤}qhc]VUSOOQVQONNNONLHGEC@@BHR_zÏåè×§f_YUVX^ht{ÿÿ`SJDBEDEHGFFFDABDGFEFEDCDC>?AEFC;CO^{º£QE?@><::>EcËíýûجw_PIDDIXaf^XUW^iqy£¶ÆÕÐı¦tme]UXVPMNQRRSQOMNLHEB@@@AJS[m¯ÊκhWRQRQSXbjqoÿÿQIECCGGGFIIGGEBCEGEEGEDBBB@ACFFD@>Ia~À´iQC>=;89=DgÐìõëÂp`TNHEDP[gc_ZZ_how¤»ËÒɽ°£ {sle^VWVSPPPQRSSQNMKGECA@@BIOS]q±µqYOJHIMRXbjqsÿÿGCBCEHHGEHIGGECDEFEEFEEDCBBBCEEDB<E^y¼¼©`H=<;8:?HmËàâÓªh^VQJD?GRcfe`^`eks|§¿ËÌ¿´ªyqjc]WWVSRQPPQRRQNMJEDCBBCEIKLSd¢¢`OIECDIPXetÿÿCBADGHGEDFGHGEBCDEFFCFGGEDDBAABBA<CVnºµoO>;:;;BPt¾ÈIJr`YUSKC:<GZglib`agox ¬ÁÉô©¡yoe_[XWURSRONNONNOLHCBBCFHHIHGM`lWJEBABELWn«¿ÿÿCDDEGIGGGHIIGECDEFGFDFFDCCCBA>?>>@FP]r§©dHDDHP^t·±zcWTRQJB96<L^inhb^emw±¹¸¤ }xphb\WTUSOPOMOOOMLLMJEEFFGHIGECMd_PGCCBADKVwÎáÿÿCEFEFHFFHIIJIGDFFFGGFFECCCDDB=>>=AEKS_q£|\XZcr¢§¦¯§kVNLKLGA946@Tdpnjdhoy±®¥yroga]XTPQPONNLMNNKJKLKGGGGGGHECAOk{UKEBCCABIU°æõÿÿBEHCCFDDFGHKLKGGGGHHHFDBDFGGD>??>>AGNRU^pzv|¡±ºµ°©²¦ bLCAACB?9546I[nuvqpu~§®~ypjf_ZUTRMKLPONLJJKJJKKJIHGFEFGDBBTu¤nOIDACC@@FS¼òùÿÿEFGBADEEFFGJIIHGFEGHHDB@BCEB?=AA=<>AFJLQZj¥²¿ÆÅÅÁ¼»¨cOFEDEGE>868GZs¡¯¯¡{xtpmh`\WRPONOQSPNLJHHIJLJHHGFEFGHCAAX{ªjJFCAAA?@GS ºñôÿÿFFEBACEGGGHIHIJGFGHHHDB?@AB<99?@<;<>BFHIMRq§µÂÎÕ×ÓÓÏȼ¤~fTHGGGKJDA@CPeµÂ»»ÀĹ}rokgfbZWSNMMNQSUROJHGGIKKIGHEEEGHIB?>W|«gHC@@@@?AGR¯áßÿÿDCBCCCFHJJJJJKMHHMHFGFD@A@>4029<::;=BFHGFEXv¡¾ÒÝâäãàÙζ}jYKIHHNPMNQVe{ºÕèßÚÚÖŧwlgc`]XSROKJKOQSVUPGEEGLLHHHGCCGHIJA;9Sw¦ fG@=>@A@CHOtüÿÿEEFGFCDFHHHGGILIHJHHKIFDCB?;9;<<989<CIMKJHTl´ÏàãåäÚÎÁ«sj`TOMNXajorsy¡ÂÙåÚÏÄÀ»²mbZWVUSPMIJKLMNQROHEEHKKIHFDDEHKLI?96Ot¤iFAAEEDBEIOcvÿÿFGIIHDDEGHGFFGIHHJHILJIHECA>>?=;889=FLQOMLQb~¢¾ÐÎËȼ²«¡sle_[Y[dn{~~{}·ÇÌ¿°£¯¢veYSQPPNLHJKKJKNPNHEEIJKJGECEFHMMH?82Kq¤tLFEIIHFKPT\bgoÿÿGGKIGFCDHJJGFEFGHKJJKKKKFDD?=><:89;?IQVTROPZk¯¢~nhkmnorx|ulox~kl}¥q`UOKJLLIKLKJKNNLGDDIJKKFDCDFHMLG@8/Fm¦YOJILMLU\_^^^gÿÿHILGEDDEFHHFFFEGIJHHJIIIFDDB?<:9:9<AJOOONLLQ\sxnh_^dqfdb`adhgd`djrvupjcZZg£ q[RKGIJJKJHJKMMJFABHIJJGFEGHHIJJD=4Hn¥³§oedgknvyvohckÿÿHIKGEDFFEGGDEEEGHJGGIIIHECBCA<99;;>DKMILLHFIQcnrbWRIFIf~e]XTUX]`aa``a^ZTUTRPXj «i\QHIJKKJHKKJKJGDDHJKJIHFGGFGIKHC<Or¦¿¿¤ |oe]eÿÿHIHGGFGGFGEBDEDFHIHHJLLIDA>CC?<;<?CHKJDKKC@BJ[fm^SLD=8OngXNKNT]gmod\UNJINRTPQWl§¦m\MMLJKKKLKGIKLLLKMMJKIFCABGJJJIGYz©Å̾¢o_TMTÿÿGFFFGIHHKIFCEEDEEFFGHIGBA?=?@>;:;AFIJIFHF>;=EOX_XQJE>6AXzxcUNVcuhVKHGHIJMMNR]p¡ xaWPJJIIJKJJKLNONMKGHFC?>AIOSTUVi¬·´£qe[NGDLÿÿEDDEFIHILHECEFCCCCEFFFDBA?<>>><;<CHJJHDEB=:<BHNTROJE@9;Ibyj`ercNCDEGFGIKMOVap ª¢xfWLJIJIJKLLLNNNLIEEC?<=ALU\_ady¥¡ ztqpmh^VPFA@FÿÿCCCCCDGHIECCFFBBBBCDDCDGD@;>?>==>EIIJF?@?>=?CFILNNKFCA>BNy¥}qVE=BEFGHHILPW[[g}«¨ycPKJMJIJMNKJJJHFDDA:;?DQ\cjoqqd]WTQQTTRNGCABÿÿDEBDEEFHIFDBFHHFEFDBBCCBB@<?>9:=AFIIGC===?ABBCCCCEHFDCCDHh§¬«¤ xukYLB=ADGGHKJLPTVVZg{¤hYOKIHHJKKJIGGECB>9@EJVcnwuf\WRMJKNSSSRLIHFÿÿEFDEEEGIKIFDFHHDCFDBACB>>=;>>9;?EHIIEA<<>ADDCA><<?EEEEHKNe«»Â¿©j^SIFC?ACFFHJIJMOQSSXbw kYNJGEGHHHGEDCBA?=DJO[hv~m]SONJGDGJNNPRPMJFÿÿFFHEDDHLOLIHGFC==CCB@B@;:98;=>@CHIIHE@;=AFGGF?:58=CDEFLT_p°ÇÒÒ¿fRFAFFCBBCDFGHIHGJPQRQZk¥iVLEBEEBDEDA@AABEINS_lzjWMKJKFCBEFFEHOSPGCÿÿHEEDCEGIKJIGDCB@@BBBA@?;987:<=CKU[`c]XTNKKLLI?968;>@DIZiu¥Ä×Þѱ`MHJJGEDCDFGFEEEHNOPQU\hq`RHGEBEFDBABEHLORVap o]QJIIJGFEFECAEOQOICÿÿLGEDDEFGIIHGDBABCCBA@?=:767;?BO_q}ztjb\\WMA9557:?GRl}´ÐäÜÄoUMMLKHFDEEEDCDEGLMNPQTYhyygTLHGLNLJJJMPTSUZgx u[SMIHHHHGGFECAENOMJEÿÿQLGFFFFGHGFGECBCDDCA>=<9448=DMd±½À³§yuhRE;3237@M` zs¼ãáÒ¶]NNNNKHFFEBCDEFGILMNPSVW^i ¡gSLRZ][ZYXZ[[WX]pw`KLKIHFDGHGFEDEHKKJIHÿÿRNJIHGHHGEEEDDEDBA?>?=;768<I[p«ÆÙâáÍ·xmTA656:GXozj`{¡ÓÞÛÉlONMLKJHFCADEDCEHIKKJLQRTXgy~h\Zaedikkheb``bz fRGGHHGFGGHHEDDDEGGHHFÿÿROJIHGHHEEEEEEFC@><<>;979?I`y³ÌàíïçͰzmk}gR@;;@Tj m]Th»ÔÞØ©~UPMLJHFD@9BFDBBDGHHFHNMMMQ^tzkbeggnqqlhffjppXJEEFHGGHGHIFDCCCDEFFFÿÿQNIGFFEDCFHGFFEA>=::;879>K`¡¿ÒáëëãÒ±p[PPcxlQDAGgt_SO\vÄÛá¾`UONID@@9,=FGB@?CEDDFKIHHCHVlzifcbjmjecfkv v[NGEFGIIIIGHLIEBCCCEEDEÿÿLJJFCABBACEFDB@><97789=DSh¹ÑÛßÞн¥q\QLMS`rrb_h|dWOMUg¥¾ÌÁ¢p]ROMHA?:3@GIEB@ACECDGIJJJMU^jx|zrib^`_]WVWlnUKFDEFFIJJHHKIGEEDBCDECÿÿKFIFC@@AABDFC@=;97667=HVm¡·ÉØØÐÁª}j[PKIIJPZq nWQMMQ\m¢³½fVQPLGD@=DHIGEBBCFCCFIJJKNSV\dntumd[XVTPOPo±mRJECEEDGIJHHLJIGFECBCFCÿÿNDGHFB@ADCCEB?<866568EXp¤¸ÉÒÕÉ´zf[TOMIGFGGFWn ©¨r_LMNOPV`u´´q[UQPQNKHIHGHGEFFFEEGGGGHKRUWV_hspgXTQOPPOv¾rRJECFFCEGHGINKJIFEFBCHEÿÿ`OLMLJFCCDDA=:9878:?H_u ²ÂÈô l^UQMJHHGECAAL[p s`RIIJLMQVeu ¢®©cURQQOMMMMJJIHIIJJIJGEDGJMRTT\ciif`[WUZcp±É®aOECEFGEEGEFJHHJFDDABFHÿÿwaTSSRNJGIHA>;99:<EQ`x¸¿·§xcQMKJGFGGFDA?=DOa~zcTKHHIIKMOZfv¤µnWRPQPONONKIHIIIKKKKHFDHJINQRY]_`acba`gu©À̾£yZICDEGEFHFEHGGHDBAACFLÿÿx_[YZWTPQNFDA<=?BWl©´µ®~gZNDGGFCCHGFEB?<?J^x oRKHIIIHIJLQ[i|ºz[QMPQPMNMJEDGFGHHIJKJGJJHJLOTVTSWajoox¸ÇÇȹkODBBCDGLGFGFEBB@<AFIPÿÿga\ZVSPSRMLKINWex ¦¡rdXQJEFFGEEHGD@A@?COc§lOIGIIIHHIKOWbt¯¢bVQQPPROLJHGFGGGEEGJLLLKIJKNONMOT\hmjny¥®©©¨©lULFDEGIFDDFFEEDAEGHSÿÿ j`YUQNKMNMPSVcr uc[TNKIFEEEEFHFC?ABBGUl¤¯mQKHIJJHIJKMRZl¡¨o]SRQQTOKJKJHHHGEEGJLMLKIIKMJIGKR[dfafs¡paWPNLJGEBEFFFFEGIJXÿÿ}gXNJIF@?BHOYd}¢¢¤§xeWNOMIJIGECBCEHFC@BDGM]w³ºqXQKHKKIJKJKNQf{«¦fVSTTSMJJMMKIHIIIJIJKLJFIKLHDAHR]\YS`rzqtsf^VNKGBDFGEEHHKPaÿÿ}p\NFCEECACHRat «ª£m]XRKLLJIIJGEEFFEDDEDEFL\v¤ÀËvVNJKLLJJKKKLL^q ¥«r[RQQQLJKLKFFFGGGGFIMKKKMNNGCALTYZ^g{{mdbgzypga`_[XVVX]gtÿÿtiTG@=BDDDFJ[o §¦iXMPOJKKJIJLHGHGFDCDHFEFL[s§ÉÙ¬XNJKLLIJJJIIIXi}©¨bRQPOKIKJHEEEFEEFFIMJJLNOOHEFRY^dmzsh_ZYdo{ ~zvrpqw|ÿÿqfOC<:?BCGKOi ¦ª~dVMILMJIIIJKMJIIFEGDDGGFEN\p§Îæ½^PIJLKHIHEEFHTdx ´kTSPMHFHEDGFFEDEGIKLIHJLMNJKQZbk{|vpkaZVUW\fs¢¥ª±²²±¬¥xÿÿlg`QGADGIS]iy}kYPKIJJJIIJIIJJJJGGIHGHFEDKXl£ÎïÌ iWMJJIEGGFEDEN^u¯wWRONJHHFEFEEFHIJKLMIJOQRPQU\enwvwy{{{sld`_`___^aflqu{zÿÿmkqg_XY\`is~wttwl_QMKJIIJJKKJIHIJLIHIHHHEDEJVfËôØ®w_PKJHEGGEEDBGVow¨^VRQMKIHGFFHJORRTUUPPU[]]^_ahovpoqssphaZZ\_```][[]^^bhpv} ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file Index: abraham/tests/morpho/ref/include/mcunionfind.h --- abraham/tests/morpho/ref/include/mcunionfind.h (revision 0) +++ abraham/tests/morpho/ref/include/mcunionfind.h (revision 0) @@ -0,0 +1,24 @@ +/* $Id: mcunionfind.h,v 1.3 2006/02/28 07:49:12 michel Exp $ */ +/* ============== */ +/* types publics */ +/* ============== */ + +typedef struct { + int32_t Size; + int32_t *Fth; + int32_t *Rank; +} Tarjan; + +/* ============== */ +/* prototypes */ +/* ============== */ + +extern Tarjan * CreeTarjan(int32_t taille); +extern void TarjanTermine(Tarjan * T); +extern void TarjanInit(Tarjan * T); +extern void TarjanPrint(Tarjan * T); +extern void TarjanMakeSet(Tarjan * T, int32_t x); +extern int32_t TarjanFind(Tarjan * T, int32_t x); +extern int32_t TarjanLink(Tarjan * T, int32_t x, int32_t y); +extern int32_t TarjanLinkSafe(Tarjan * T, int32_t x, int32_t y); + Index: abraham/tests/morpho/ref/include/mclifo.h --- abraham/tests/morpho/ref/include/mclifo.h (revision 0) +++ abraham/tests/morpho/ref/include/mclifo.h (revision 0) @@ -0,0 +1,48 @@ +/* $Id: mclifo.h,v 1.4 2006/02/28 07:49:12 michel Exp $ */ + +typedef struct { + int32_t Max; /* taille max de la Lifo */ + int32_t Sp; /* index de pile (pointe la 1ere case libre) */ + int32_t Pts[1]; +} Lifo; + +/* ============== */ +/* prototypes */ +/* ============== */ + +extern Lifo * CreeLifoVide( + int32_t taillemax +); + +extern void LifoFlush( + Lifo * L +); + +extern int32_t LifoVide( + Lifo * L +); + +extern int32_t LifoPop( + Lifo * L +); + +extern int32_t LifoHead( + Lifo * L +); + +extern void LifoPush( + Lifo * L, + int32_t V +); + +extern void LifoPrint( + Lifo * L +); + +extern void LifoPrintLine( + Lifo * L +); + +extern void LifoTermine( + Lifo * L +); Index: abraham/tests/morpho/ref/include/lattribheight.h --- abraham/tests/morpho/ref/include/lattribheight.h (revision 0) +++ abraham/tests/morpho/ref/include/lattribheight.h (revision 0) @@ -0,0 +1,4 @@ +/* $Id: lattribheight.h,v 1.3 2006/02/28 07:49:12 michel Exp $ */ +extern int32_t lsegmentheight(struct xvimage *image, int32_t connex, int32_t param, int32_t max); +extern int32_t lheightmaxima(struct xvimage *image, int32_t connex, int32_t param); +extern int32_t lheightselnb(struct xvimage *image, int32_t connex, int32_t param, int32_t mode); Index: abraham/tests/morpho/ref/include/mcutil.h --- abraham/tests/morpho/ref/include/mcutil.h (revision 0) +++ abraham/tests/morpho/ref/include/mcutil.h (revision 0) @@ -0,0 +1,31 @@ +/* $Id: mcutil.h,v 1.7 2006/02/28 07:49:12 michel Exp $ */ +#define mcabs(X) ((X)>=0?(X):-(X)) +#define max(X,Y) ((X)>=(Y)?(X):(Y)) +#define min(X,Y) ((X)<=(Y)?(X):(Y)) +#define odd(X) ((X)&1) +#define even(X) (((X)&1)==0) +#define arrondi(z) (((z)-(double)((int32_t)(z)))<=0.5?((int32_t)(z)):((int32_t)(z+1))) +#define signe(z) (((z)>0.0)?1.0:-1.0) +#define sqr(x) ((x)*(x)) + +/* retourne VRAI si Z est plus proche de A que de B */ +#define PlusProche(Z,A,B) (abs((Z)-(A))<abs((Z)-(B))) + +#define TestNonNul(P) {if((P)==NULL){\ +perror("Erreur fatale : memoire insuffisante (malloc)\n");exit(0);}} + +#ifndef M_PI +# define M_E 2.7182818284590452354 /* e */ +# define M_LOG2E 1.4426950408889634074 /* log_2 e */ +# define M_LOG10E 0.43429448190325182765 /* log_10 e */ +# define M_LN2 0.69314718055994530942 /* log_e 2 */ +# define M_LN10 2.30258509299404568402 /* log_e 10 */ +# define M_PI 3.14159265358979323846 /* pi */ +# define M_PI_2 1.57079632679489661923 /* pi/2 */ +# define M_PI_4 0.78539816339744830962 /* pi/4 */ +# define M_1_PI 0.31830988618379067154 /* 1/pi */ +# define M_2_PI 0.63661977236758134308 /* 2/pi */ +# define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */ +# define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +# define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif Index: abraham/tests/morpho/ref/include/mccomptree.h --- abraham/tests/morpho/ref/include/mccomptree.h (revision 0) +++ abraham/tests/morpho/ref/include/mccomptree.h (revision 0) @@ -0,0 +1,79 @@ +/* ============================================================================== */ +/* + Structure de donnees pour la construction de l'arbre des composantes. + + Les sommets de cet arbre representent les composantes des coupes de F, + a l'exception de celles qui sont egales a une composante d'un niveau inferieur. + Il y a donc moins de N sommets (N = nombre de pixels) et de N-1 arcs. + + Une composante (sommet) est representee par une structure ctreenode. +*/ +/* ============================================================================== */ + +#define ATTRIB_AREA +#define ATTRIB_VOL + +typedef struct soncell // cell structure for the lists of sons +{ + int32_t son; // index of the son in table tabnodes [struct ctree] + struct soncell *next; // points to next cell +} soncell; + +typedef struct // structure for one node in the component tree +{ + u_int8_t data; // node's level + int32_t father; // index of the father node. value -1 indicates the root + int32_t nbsons; // number or sons. value -1 indicates a deleted node +#ifdef ATTRIB_AREA + int32_t area; // number of pixels in the component +#endif +#ifdef ATTRIB_VOL + int32_t vol; // volume of the component +#endif + soncell *sonlist; // list of sons (points to the first son cell) + soncell *lastson; // direct pointer to the last son cell +} ctreenode; + +typedef struct // structure for a component tree +{ + int32_t nbnodes; // total number of nodes + int32_t nbleafs; // total number of leafs + int32_t nbsoncells; // number of avaliable son cells + int32_t root; // index of the root node in table tabnodes + ctreenode * tabnodes; // table which contains all the nodes + soncell * tabsoncells; // table which contains all the son cells + u_int8_t *flags; // each flag is associated to the node with the same index +} ctree; + +/* ==================================== */ +/* PROTOTYPES */ +/* ==================================== */ +#define IMGCHAR +//#define IMGLONG + +#ifdef IMGCHAR +#define MAXGREY 256 +#else +#define MAXGREY 65536 +#endif + +extern ctree * ComponentTreeAlloc(int32_t N); +extern void ComponentTreeFree(ctree * CT); +#ifdef IMGCHAR +extern int32_t ComponentTree( u_int8_t *F, int32_t rs, int32_t N, int32_t connex, // inputs +#endif +#ifdef IMGLONG +extern int32_t ComponentTree( u_int32_t *F, int32_t rs, int32_t N, int32_t connex, // inputs +#endif + ctree **CompTree, // output + int32_t **CompMap // output + ); +#ifdef IMGCHAR +extern int32_t ComponentTree3d( u_int8_t *F, int32_t rs, int32_t ps, int32_t N, int32_t connex, // inputs +#endif +#ifdef IMGLONG +extern int32_t ComponentTree3d( u_int32_t *F, int32_t rs, int32_t ps, int32_t N, int32_t connex, // inputs +#endif + ctree **CompTree, // output + int32_t **CompMap // output + ); Index: abraham/tests/morpho/ref/include/mcimage.h --- abraham/tests/morpho/ref/include/mcimage.h (revision 0) +++ abraham/tests/morpho/ref/include/mcimage.h (revision 0) @@ -0,0 +1,98 @@ +/* $Id: mcimage.h,v 1.9 2006/02/28 07:49:12 michel Exp $ */ +/* ============== */ +/* prototypes for mcimage.c */ +/* ============== */ + +extern struct xvimage *allocimage(char * name, int32_t rs, int32_t cs, int32_t d, int32_t t); +extern void razimage(struct xvimage *f); +extern struct xvimage *allocheader(char * name, int32_t rs, int32_t cs, int32_t d, int32_t t); +extern int32_t showheader(char * name); +extern void freeimage(struct xvimage *image); +extern struct xvimage *copyimage(struct xvimage *f); +extern int32_t copy2image(struct xvimage *dest, struct xvimage *source); +extern int32_t equalimages(struct xvimage *im1, struct xvimage *im2); +extern void list2image(struct xvimage * image, double *P, int32_t n); +extern double * image2list(struct xvimage * image, int32_t *n); + +extern void writeimage( + struct xvimage * image, + char *filename +); + +extern void writese( + struct xvimage * image, + char *filename, + int32_t x, int32_t y, int32_t z +); + +extern void writelongimage( + struct xvimage * image, + char *filename +); + +extern void writerawimage( + struct xvimage * image, + char *filename +); + +extern void writeascimage( + struct xvimage * image, + char *filename +); + +extern void printimage( + struct xvimage * image +); + +extern void writergbimage( + struct xvimage * redimage, + struct xvimage * greenimage, + struct xvimage * blueimage, + char *filename +); + +extern struct xvimage * readimage( + char *filename +); + +extern struct xvimage * readheader( + char *filename +); + +extern struct xvimage * readse(char *filename, int32_t *x, int32_t *y, int32_t*z); + +extern struct xvimage * readlongimage( + char *filename +); + +extern int32_t readrgbimage( + char *filename, + struct xvimage ** r, + struct xvimage ** g, + struct xvimage ** b +); + +extern int32_t readbmp( + char *filename, + struct xvimage ** r, + struct xvimage ** g, + struct xvimage ** b +); + +extern void writebmp( + struct xvimage * redimage, + struct xvimage * greenimage, + struct xvimage * blueimage, + char *filename +); + +extern int32_t readrgb( + char *filename, + struct xvimage ** r, + struct xvimage ** g, + struct xvimage ** b +); + +extern int32_t convertgen(struct xvimage **f1, struct xvimage **f2); +extern int32_t convertlong(struct xvimage **f1); +extern int32_t convertfloat(struct xvimage **f1); Index: abraham/tests/morpho/ref/include/mcfahsalembier.h --- abraham/tests/morpho/ref/include/mcfahsalembier.h (revision 0) +++ abraham/tests/morpho/ref/include/mcfahsalembier.h (revision 0) @@ -0,0 +1,64 @@ +/* $Id: mcfahsalembier.h,v 1.4 2006/02/28 07:49:12 michel Exp $ */ +typedef struct FAHELT { + int32_t Point; + struct FAHELT * Next; + struct FAHELT * Prev; +} FahElt; + +//#define NPRIO 256 +#define NPRIO 65536 + +typedef struct { + int32_t Max; /* taille max de la fah (en nombre de points) */ + int32_t Niv; /* niveau a partir duquel des listes existent */ + int32_t Util; /* nombre de points courant dans la fah */ + int32_t Maxutil; /* nombre de points utilises max (au cours du temps) */ + FahElt *Tete[NPRIO]; /* tableau des tetes de liste (la ou l'on insere) */ + FahElt *Queue[NPRIO];/* tableau des queues de liste (la ou l'on preleve) */ + FahElt *Libre; /* pile des cellules libres */ + FahElt Elts[1]; /* tableau des elements physiques */ +} Fah; + +/* ============== */ +/* prototypes */ +/* ============== */ + +extern Fah * CreeFahVide( + int32_t taillemax +); + +extern void FahFlush( + Fah * L +); + +extern int32_t FahVide( + Fah * L +); + +extern int32_t FahVideNiveau( + Fah * L, + int32_t niv +); + +extern int32_t FahPop( + Fah * L +); + +extern int32_t FahPopNiveau( + Fah * L, + int32_t niv +); + +extern void FahPush( + Fah * L, + int32_t Po, + int32_t Ni +); + +extern void FahTermine( + Fah * L +); + +extern void FahPrint( + Fah * L +); Index: abraham/tests/morpho/ref/include/mcindic.h --- abraham/tests/morpho/ref/include/mcindic.h (revision 0) +++ abraham/tests/morpho/ref/include/mcindic.h (revision 0) @@ -0,0 +1,27 @@ +/* $Id: mcindic.h,v 1.3 2006/02/28 07:49:12 michel Exp $ */ + +typedef u_int8_t Indicstype; + +extern Indicstype *Indics; /* en global pour etre efficace */ + +#define Set(x,INDIC) Indics[x]|=(1<<INDIC) +#define UnSet(x,INDIC) Indics[x]&=~(1<<INDIC) +#define UnSetAll(x) Indics[x]=0 +#define IsSet(x,INDIC) (Indics[x]&(1<<INDIC)) +#define IsSetAny(x) (Indics[x]) + +#define Set1(x) Indics[x/8]|=(1<<(x%8)) +#define UnSet1(x) Indics[x/8]&=~(1<<(x%8)) +#define IsSet1(x) (Indics[x/8]&(1<<(x%8))) + +/* ============== */ +/* prototypes */ +/* ============== */ + +extern void IndicsInit(int32_t Size); + +extern void Indics1bitInit(int32_t Size); + +extern void IndicsTermine(); + + Index: abraham/tests/morpho/ref/include/mccodimage.h --- abraham/tests/morpho/ref/include/mccodimage.h (revision 0) +++ abraham/tests/morpho/ref/include/mccodimage.h (revision 0) @@ -0,0 +1,100 @@ +/* $Id: mccodimage.h,v 1.10 2006/04/24 15:07:28 michel Exp $ */ +#define SHRT_MIN -32767 +#define SHRT_MAX +32767 +#define USHRT_MAX 65535 +#define INT_MIN -32767 +#define INT_MAX +32767 +#define UINT_MAX 65535 +#define LONG_MIN -2147483647 +#define LONG_MAX +2147483647 +#define ULONG_MAX 4294967295 +#define NDG_MAX 255 /* niveau de gris max */ +#define NDG_MIN 0 /* niveau de gris min */ + +/* definitions for data storage type, + u_int32_t data_storage_type; */ +#define VFF_TYP_BIT 0 /* pixels are on or off (binary image)*/ + /* Note: This is an X11 XBitmap + with bits packed into a byte and + padded to a byte */ +#define VFF_TYP_1_BYTE 1 /* pixels are byte (u_int8_t) */ +#define VFF_TYP_2_BYTE 2 /* pixels are two byte (int16_t) */ +#define VFF_TYP_4_BYTE 4 /* pixels are four byte (integer) */ +#define VFF_TYP_FLOAT 5 /* pixels are float (single precision)*/ +#define VFF_TYP_DOUBLE 9 /* pixels are float (double precision)*/ +#define VFF_TYP_COMPLEX 10 /* pixels are complex float */ +#define VFF_TYP_DCOMPLEX 11 /* double complex */ + +#ifndef KHOROS +struct xvimage { + char *name; + u_int32_t row_size; + u_int32_t col_size; + u_int32_t num_data_bands; /* Number of bands per data pixel, + or number of bands per image, or + dimension of vector data, or + number of elements in a vector */ + + u_int32_t data_storage_type; /* storage type for disk data */ + double xdim, ydim, zdim; /* voxel dimensions in real world */ + u_int8_t imagedata[1]; +}; +#endif + +#define UCHARDATA(I) ((u_int8_t *)((I)->imagedata)) +#define USHORTDATA(I) ((u_int16_t *)((I)->imagedata)) +#define ULONGDATA(I) ((u_int32_t *)((I)->imagedata)) +#define FLOATDATA(I) ((float *)((I)->imagedata)) +#define DOUBLEDATA(I) ((double *)((I)->imagedata)) +#define colsize(I) ((I)->col_size) +#define rowsize(I) ((I)->row_size) +#define depth(I) ((I)->num_data_bands) +#define datatype(I) ((I)->data_storage_type) + +/* + Codage du voisinage + + + 3 2 1 + 4 X 0 + 5 6 7 +*/ +#define EST 0 +#define NORD 2 +#define OUEST 4 +#define SUD 6 +#define NORD_EST 1 +#define NORD_OUEST 3 +#define SUD_OUEST 5 +#define SUD_EST 7 +#define DEVANT 8 +#define DERRIERE 10 + +#define nonbord(p,rs,N) ((p%rs!=rs-1)&&(p>=rs)&&(p%rs!=0)&&(p<N-rs)) +#define nonbord3d(p,rs,ps,N) ((p>=ps)&&(p<N-ps)&&(p%ps>=rs)&&(p%ps<ps-rs)&&(p%rs!=0)&&(p%rs!=rs-1)) + +/* ============== */ +/* prototypes */ +/* ============== */ + +extern int32_t voisin(int32_t i, int32_t k, int32_t rs, int32_t nb); +extern int32_t voisin2(int32_t i, int32_t k, int32_t rs, int32_t nb); +extern int32_t voisin6(int32_t i, int32_t k, int32_t rs, int32_t n, int32_t nb); +extern int32_t bord(int32_t i, int32_t rs, int32_t nb); +extern int32_t bord3d(int32_t i, int32_t rs, int32_t ps, int32_t nb); +extern int32_t voisin26(int32_t i, int32_t k, int32_t rs, int32_t n, int32_t nb); +extern int32_t voisin18(int32_t i, int32_t k, int32_t rs, int32_t n, int32_t nb); +extern int32_t voisins4(int32_t i, int32_t j, int32_t rs); +extern int32_t voisins8(int32_t i, int32_t j, int32_t rs); +extern int32_t voisins6(int32_t i, int32_t j, int32_t rs, int32_t ps); +extern int32_t voisins26(int32_t i, int32_t j, int32_t rs, int32_t ps); +extern int32_t voisin5(int32_t i, int32_t k, int32_t rs, int32_t nb); +extern int32_t voisin6b(int32_t i, int32_t k, int32_t rs, int32_t nb, int32_t par); +extern int32_t voisinNESO(int32_t i, int32_t k, int32_t rs, int32_t nb); +extern int32_t voisinNOSE(int32_t i, int32_t k, int32_t rs, int32_t nb); +extern int32_t voisin14b(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N); +extern int32_t voisinONAV(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ); +extern int32_t voisinENAR(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ); +extern int32_t voisinENAV(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ); +extern int32_t voisinONAR(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ); +extern u_int32_t maskvois26(u_int8_t *F, u_int32_t bitmask, int32_t i, int32_t rs, int32_t ps, int32_t N); Index: abraham/tests/morpho/ref/include/lwshedtopo.h --- abraham/tests/morpho/ref/include/lwshedtopo.h (revision 0) +++ abraham/tests/morpho/ref/include/lwshedtopo.h (revision 0) @@ -0,0 +1,4 @@ +extern int32_t lwshedtopo(struct xvimage *image, int32_t connex); +extern int32_t lreconsdilat(struct xvimage *g, struct xvimage *f, int32_t connex); +extern int32_t lreconseros(struct xvimage *g, struct xvimage *f, int32_t connex); +extern int32_t lwshedtopobin(struct xvimage *image, struct xvimage *marqueur, int32_t connex); Index: abraham/tests/morpho/ref/src/lib/mccomptree.c --- abraham/tests/morpho/ref/src/lib/mccomptree.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mccomptree.c (revision 0) @@ -0,0 +1,805 @@ +/* $Id: mccomptree.c,v 1.8 2006/02/28 07:49:16 michel Exp $ */ +/* + Arbre des composantes (nouvelle version) + + Ref: NC04 + + Michel Couprie - septembre 2003 + Michel Couprie - aout 2004 : 3D + Michel Couprie - septembre 2005 : area +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mcunionfind.h> +#include <mccomptree.h> + +#define MAXTREE +#define PARANO +//#define VERBOSE + +//#define DEBUG + +/* ==================================== */ +int32_t * linsortimageup(u_int8_t *F, int32_t N) +/* ==================================== */ +/* + Tri par denombrement - cf. Cormen & al., "Introduction a l'algorithmique" + version pour une image sur 8 bits + F: l'image + N: le nombre de pixels + retourne: un tableau d'indices de pixels (taille N) + dans l'ordre croissant des valeurs +*/ +#undef F_NAME +#define F_NAME "linsortimageup" +{ + int32_t i, j, k, H[256]; + int32_t *T = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (T == NULL) + { fprintf(stderr, "%s() : malloc failed for T\n", F_NAME); + return NULL; + } + for (i = 0; i < 256; i++) H[i] = 0; // initialise l'histogramme + for (i = 0; i < N; i++) H[F[i]] += 1; // calcule l'histogramme + j = H[0]; H[0] = 0; // calcule l'histogramme cumule + for (i = 1; i < 256; i++) { k = H[i]; H[i] = j; j += k; } + for (i = 0; i < N; i++) // tri lineaire + { + k = F[i]; j = H[k]; T[j] = i; H[k] += 1; + } + return T; +} /* linsortimageup() */ + +/* ==================================== */ +int32_t * linsortimagedown(u_int8_t *F, int32_t N) +/* ==================================== */ +/* + Tri par denombrement - cf. Cormen & al., "Introduction a l'algorithmique" + version pour une image sur 8 bits + F: l'image + N: le nombre de pixels + retourne: un tableau d'indices de pixels (taille N) + dans l'ordre decroissant des valeurs +*/ +#undef F_NAME +#define F_NAME "linsortimagedown" +{ + int32_t i, j, k, H[256]; + int32_t *T = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (T == NULL) + { fprintf(stderr, "%s() : malloc failed for T\n", F_NAME); + return NULL; + } + for (i = 0; i < 256; i++) H[i] = 0; // initialise l'histogramme + for (i = 0; i < N; i++) H[F[i]] += 1; // calcule l'histogramme + j = H[255]; H[255] = 0; // calcule l'histogramme cumule + for (i = 254; i >= 0; i--) { k = H[i]; H[i] = j; j += k; } + for (i = 0; i < N; i++) // tri lineaire + { + k = F[i]; j = H[k]; T[j] = i; H[k] += 1; + } + return T; +} /* linsortimagedown() */ + +/* ==================================== */ +void addson(ctree *CT, int32_t node, int32_t nodeaux) +/* ==================================== */ +// add nodeaux to the lists of sons of node +// operation done in constant time +#undef F_NAME +#define F_NAME "addson" +{ + soncell * newson; +#ifdef DEBUGADDSON + printf("addson: %d %d\n", node, nodeaux); +#endif + if (CT->nbsoncells >= CT->nbnodes) + { + fprintf(stderr, "%s : fatal error : maximum nb of cells exceeded\n", F_NAME); + // ComponentTreePrint(CT); + exit(1); + } +#ifdef PARANO + if (CT->tabnodes[node].nbsons > 0) + for (newson = CT->tabnodes[node].sonlist; newson != NULL; newson = newson->next) + if (newson->son == nodeaux) + { + fprintf(stderr, "%s : error : son already in list\n", F_NAME); + return; + } +#endif + newson = &(CT->tabsoncells[CT->nbsoncells]); + CT->nbsoncells += 1; + newson->son = nodeaux; + if (CT->tabnodes[node].nbsons == 0) + { + newson->next = NULL; + CT->tabnodes[node].sonlist = CT->tabnodes[node].lastson = newson; + } + else + { + newson->next = CT->tabnodes[node].sonlist; + CT->tabnodes[node].sonlist = newson; + } + CT->tabnodes[node].nbsons += 1; + CT->tabnodes[nodeaux].father = node; +} // addson() + +/* ==================================== */ +void mergenodes(ctree *CT, int32_t node, int32_t nodeaux) +/* ==================================== */ +// add the sons of nodeaux to the lists of sons of node, +// and mark nodeaux as deleted - operation done in constant time +#undef F_NAME +#define F_NAME "mergenodes" +{ +#ifdef PARANO + soncell * nodeson, * nodeauxson; + if ((CT->tabnodes[node].nbsons > 0) && (CT->tabnodes[nodeaux].nbsons > 0)) + for (nodeson = CT->tabnodes[node].sonlist; nodeson != NULL; nodeson = nodeson->next) + for (nodeauxson = CT->tabnodes[nodeaux].sonlist; nodeauxson != NULL; nodeauxson = nodeauxson->next) + if (nodeson->son == nodeauxson->son) + { + fprintf(stderr, "%s : error : son already in list (%d %d)\n", F_NAME); + return; + } +#endif + if (CT->tabnodes[nodeaux].nbsons <= 0) + { + CT->tabnodes[nodeaux].nbsons = -1; + return; + } + if (CT->tabnodes[node].nbsons > 0) + { + soncell *lson = CT->tabnodes[node].lastson; + lson->next = CT->tabnodes[nodeaux].sonlist; + CT->tabnodes[node].lastson = CT->tabnodes[nodeaux].lastson; + CT->tabnodes[node].nbsons += CT->tabnodes[nodeaux].nbsons; + } + else + { + CT->tabnodes[node].sonlist = CT->tabnodes[nodeaux].sonlist; + CT->tabnodes[node].lastson = CT->tabnodes[nodeaux].lastson; + CT->tabnodes[node].nbsons = CT->tabnodes[nodeaux].nbsons; + } + CT->tabnodes[nodeaux].nbsons = -1; +} // mergenodes() + +/* ==================================== */ +ctree * ComponentTreeAlloc(int32_t N) +/* ==================================== */ +#undef F_NAME +#define F_NAME "ComponentTreeAlloc" +{ + ctree *CT; + CT = (ctree *)calloc(1,sizeof(ctree)); + CT->tabnodes = (ctreenode *)calloc(1,N * sizeof(ctreenode)); + CT->tabsoncells = (soncell *)calloc(1,N * sizeof(soncell)); + CT->flags = (u_int8_t *)calloc(N, sizeof(char)); + if ((CT == NULL) || (CT->tabnodes == NULL) || (CT->tabsoncells == NULL) || (CT->flags == NULL)) + { + fprintf(stderr, "%s : malloc failed\n", F_NAME); + return NULL; + } + CT->nbnodes = N; + CT->nbleafs = 0; + CT->nbsoncells = 0; + return CT; +} // ComponentTreeAlloc() + +/* ==================================== */ +void ComponentTreeFree(ctree * CT) +/* ==================================== */ +{ + free(CT->tabnodes); + free(CT->tabsoncells); + free(CT->flags); + free(CT); +} // ComponentTreeFree() + +/* ==================================== */ +void ComponentTreePrint(ctree * CT) +/* ==================================== */ +{ + int32_t i; + soncell *s; + printf("root = %d ; nbnodes: %d ; nbleafs: %d ; nbsoncells: %d\n", CT->root, CT->nbnodes, CT->nbleafs, CT->nbsoncells); + for (i = 0; i < CT->nbnodes; i++) if (CT->tabnodes[i].nbsons != -1) + { +#ifdef ATTRIB_VOL + printf("node: %d ; level %d ; nbsons: %d ; father: %d ; area: %d ; vol: %d ; ", + i, CT->tabnodes[i].data, CT->tabnodes[i].nbsons, CT->tabnodes[i].father, CT->tabnodes[i].area, CT->tabnodes[i].vol); +#else + printf("node: %d ; level %d ; nbsons: %d ; father: %d ; ", + i, CT->tabnodes[i].data, CT->tabnodes[i].nbsons, CT->tabnodes[i].father); +#endif + if (CT->tabnodes[i].nbsons > 0) + { + printf("sons: "); + for (s = CT->tabnodes[i].sonlist; s != NULL; s = s->next) + printf("%d ", s->son); + } + printf("\n"); + } +} // ComponentTreePrint() + +#ifdef ATTRIB_AREA +/* ==================================== */ +int32_t ComputeArea(ctree * CT, int32_t node, int32_t *na1) +/* ==================================== */ +/* + Calcule la surface de chacune des composantes, a partir de + l'information stockee dans CT->tabnode[i].area, qui correspond a la + difference de surface entre la composante i et ses filles. + Le resultat est provisoirement stocke dans le tableau na1 (indexe par + le numero de composante i), pour etre ensuite recopie dans CT. +*/ +#undef F_NAME +#define F_NAME "ComputeArea" +{ + soncell * s; + int32_t son; + na1[node] = CT->tabnodes[node].area; + if (CT->tabnodes[node].nbsons == 0) return na1[node]; + if (CT->tabnodes[node].nbsons > 0) + { + for (s = CT->tabnodes[node].sonlist; s != NULL; s = s->next) + { + son = s->son; + na1[node] += ComputeArea(CT, son, na1); + } + return na1[node]; + } +#ifdef PARANO + printf("%s : structure arbre pervertie", F_NAME); + exit(0); +#endif +} /* ComputeArea() */ + +#ifdef ATTRIB_VOL +/* ==================================== */ +int32_t ComputeVol(ctree * CT, int32_t node, int32_t *na1) +/* ==================================== */ +/* + Calcule la surface de chacune des composantes, a partir de + l'information stockee dans CT->tabnode[i].area, qui correspond a la + surface de la composante i. + Le resultat est provisoirement stocke dans le tableau na1 (indexe par + le numero de composante i), pour etre ensuite recopie dans CT. +*/ +#undef F_NAME +#define F_NAME "ComputeVol" +{ + soncell * s; + int32_t son, fth; + na1[node] = CT->tabnodes[node].area; + fth = CT->tabnodes[node].father; + if (fth != -1) + na1[node] = na1[node] * (CT->tabnodes[node].data - CT->tabnodes[fth].data); + if (CT->tabnodes[node].nbsons == 0) return na1[node]; + if (CT->tabnodes[node].nbsons > 0) + { + for (s = CT->tabnodes[node].sonlist; s != NULL; s = s->next) + { + son = s->son; + na1[node] += ComputeVol(CT, son, na1); + } + return na1[node]; + } +#ifdef PARANO + printf("%s : structure arbre pervertie", F_NAME); + exit(0); +#endif +} /* ComputeVol() */ +#endif +#endif + +/* ==================================== */ +int32_t ComponentTree( u_int8_t *F, int32_t rs, int32_t N, int32_t connex, // inputs + ctree **CompTree, // output + int32_t **CompMap // output + ) +/* ==================================== */ +#undef F_NAME +#define F_NAME "ComponentTree" +{ + ctree *CT; + int32_t *CM; + int32_t *S; + int32_t i, k, p, q, incr_vois, tmp; + int32_t numbernodes = N; + int32_t *SubtreeRoot; + int32_t currentSubtree; + int32_t currentNode; + int32_t neighbSubtree; + int32_t neighbNode; + Tarjan *T1, *T2; + soncell *sc; int32_t son; + + CT = ComponentTreeAlloc(N); + if (CT == NULL) + { fprintf(stderr, "%s() : ComponentTreeAlloc failed\n", F_NAME); + return 0; + } + CM = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (CM == NULL) + { fprintf(stderr, "%s() : malloc failed for CM\n", F_NAME); + return 0; + } + SubtreeRoot = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (SubtreeRoot == NULL) + { fprintf(stderr, "%s() : malloc failed for SubtreeRoot\n", F_NAME); + return 0; + } +#ifdef MAXTREE + S = linsortimagedown(F, N); +#else + S = linsortimageup(F, N); +#endif + if (S == NULL) + { fprintf(stderr, "%s() : linsortimage failed\n", F_NAME); + return 0; + } + T1 = CreeTarjan(N); + T2 = CreeTarjan(N); + if ((T1 == NULL) || (T2 == NULL)) + { fprintf(stderr, "%s() : CreeTarjan failed\n", F_NAME); + return 0; + } + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; + } /* switch (connex) */ + + for (i = 0; i < N; i++) + { + TarjanMakeSet(T1, i); + TarjanMakeSet(T2, i); + SubtreeRoot[i] = i; + CT->tabnodes[i].nbsons = 0; + CT->tabnodes[i].data = F[i]; + CT->tabnodes[i].father = -1; +#ifdef ATTRIB_AREA + CT->tabnodes[i].area = 1; +#endif + } + + for (i = 0; i < N; i++) + { + p = S[i]; // pixel courant, dans l'ordre croissant +#ifdef DEBUG +printf("pixel %d ; valeur %d\n", p, F[p]); +#endif + currentSubtree = TarjanFind(T1, p); + currentNode = TarjanFind(T2, SubtreeRoot[currentSubtree]); +#ifdef DEBUG +printf("currentSubtree %d ; currentNode %d\n", currentSubtree, currentNode); +#endif + + for (k = 0; k < 8; k += incr_vois) + { + q = voisin(p, k, rs, N); +#ifdef MAXTREE + if ((q != -1) && (F[q] >= F[p])) +#else + if ((q != -1) && (F[q] <= F[p])) +#endif + { +#ifdef DEBUG +printf(" neighbor %d ; valeur %d\n", q, F[q]); +#endif + neighbSubtree = TarjanFind(T1, q); + neighbNode = TarjanFind(T2, SubtreeRoot[neighbSubtree]); +#ifdef DEBUG +printf(" neighbSubtree %d ; neighbNode %d\n", neighbSubtree, neighbNode); +#endif + if (currentNode != neighbNode) + { + if (CT->tabnodes[currentNode].data == CT->tabnodes[neighbNode].data) + { // merge the nodes + numbernodes -= 1; + tmp = TarjanLink(T2, neighbNode, currentNode); +#ifdef PARANO + if ((tmp != currentNode) && (tmp != neighbNode)) + printf("%s : choix inattendu pour le representant", F_NAME); +#endif + if (tmp == currentNode) mergenodes(CT, currentNode, neighbNode); + else mergenodes(CT, neighbNode, currentNode); +#ifdef DEBUG + printf(" mergenodes: %d %d\n", currentNode, neighbNode); +#endif +#ifdef ATTRIB_AREA + CT->tabnodes[tmp].area = CT->tabnodes[currentNode].area + CT->tabnodes[neighbNode].area; +#endif + currentNode = tmp; + } + else + { // add neighbNode as a new son of currentNode + addson(CT, currentNode, neighbNode); +#ifdef DEBUG +printf(" addson: %d %d\n", currentNode, neighbNode); +#endif + } + currentSubtree = TarjanLink(T1, neighbSubtree, currentSubtree); + SubtreeRoot[currentSubtree] = currentNode; + } // endif + } // if ((q != -1) && (F[q] <= F[p])) + } // for (k = 0; k < 8; k += incr_vois) + } // for (i = 0; i < N; i++) + + CT->root = SubtreeRoot[TarjanFind(T1, TarjanFind(T2, 0))]; + for (i = 0; i < N; i++) CM[i] = TarjanFind(T2, i); + for (i = 0; i < N; i++) // construction de la relation "father" + if (CT->tabnodes[i].nbsons > 0) + for (sc = CT->tabnodes[i].sonlist; sc != NULL; sc = sc->next) + { + son = sc->son; + CT->tabnodes[son].father = i; + } + + k = 0; + for (i = 0; i < N; i++) + if (CT->tabnodes[i].nbsons == 0) + k++; + CT->nbleafs = k; +#ifdef VERBOSE + printf("nombre de feuilles = %d\n", CT->nbleafs); +#endif + + TarjanTermine(T1); + TarjanTermine(T2); + +#ifdef ATTRIB_AREA +{ + int32_t *area = (int32_t *)malloc(N * sizeof(int32_t)); + if (area == NULL) + { fprintf(stderr, "%s() : malloc failed\n", F_NAME); + return 0; + } + ComputeArea(CT, CT->root, area); + for (i = 0; i < N; i++) + CT->tabnodes[i].area = area[i]; + +#ifdef ATTRIB_VOL + ComputeVol(CT, CT->root, area); + + for (i = 0; i < N; i++) + CT->tabnodes[i].vol = area[i]; +#endif + + free(area); +} +#endif + + *CompTree = CT; + *CompMap = CM; + return 1; +} // ComponentTree() + +/* ==================================== */ +int32_t ComponentTree3d( u_int8_t *F, int32_t rs, int32_t ps, int32_t N, int32_t connex, // inputs + ctree **CompTree, // output + int32_t **CompMap // output + ) +/* ==================================== */ +#undef F_NAME +#define F_NAME "ComponentTree3d" +{ + ctree *CT; + int32_t *CM; + int32_t *S; + int32_t i, k, p, q, tmp; + int32_t numbernodes = N; + int32_t *SubtreeRoot; + int32_t currentSubtree; + int32_t currentNode; + int32_t neighbSubtree; + int32_t neighbNode; + Tarjan *T1, *T2; + soncell *sc; int32_t son; + + CT = ComponentTreeAlloc(N); + if (CT == NULL) + { fprintf(stderr, "%s() : ComponentTreeAlloc failed\n", F_NAME); + return 0; + } + CM = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (CM == NULL) + { fprintf(stderr, "%s() : malloc failed for CM\n", F_NAME); + return 0; + } + SubtreeRoot = (int32_t *)calloc(1,N * sizeof(int32_t)); + if (SubtreeRoot == NULL) + { fprintf(stderr, "%s() : malloc failed for SubtreeRoot\n", F_NAME); + return 0; + } +#ifdef MAXTREE + S = linsortimagedown(F, N); +#else + S = linsortimageup(F, N); +#endif + if (S == NULL) + { fprintf(stderr, "%s() : linsortimage failed\n", F_NAME); + return 0; + } + T1 = CreeTarjan(N); + T2 = CreeTarjan(N); + if ((T1 == NULL) || (T2 == NULL)) + { fprintf(stderr, "%s() : CreeTarjan failed\n", F_NAME); + return 0; + } + + for (i = 0; i < N; i++) + { + TarjanMakeSet(T1, i); + TarjanMakeSet(T2, i); + SubtreeRoot[i] = i; + CT->tabnodes[i].nbsons = 0; + CT->tabnodes[i].data = F[i]; + CT->tabnodes[i].father = -1; +#ifdef ATTRIB_AREA + CT->tabnodes[i].area = 1; +#endif + } + + if (connex == 6) + { + for (i = 0; i < N; i++) + { + p = S[i]; // pixel courant, dans l'ordre croissant + currentSubtree = TarjanFind(T1, p); + currentNode = TarjanFind(T2, SubtreeRoot[currentSubtree]); + for (k = 0; k <= 10; k += 2) + { + q = voisin6(p, k, rs, ps, N); +#ifdef MAXTREE + if ((q != -1) && (F[q] >= F[p])) +#else + if ((q != -1) && (F[q] <= F[p])) +#endif + { + neighbSubtree = TarjanFind(T1, q); + neighbNode = TarjanFind(T2, SubtreeRoot[neighbSubtree]); + if (currentNode != neighbNode) + { + if (CT->tabnodes[currentNode].data == CT->tabnodes[neighbNode].data) + { // merge the nodes + numbernodes -= 1; + tmp = TarjanLink(T2, neighbNode, currentNode); +#ifdef PARANO + if ((tmp != currentNode) && (tmp != neighbNode)) + printf("%s : choix inattendu pour le representant", F_NAME); +#endif + if (tmp == currentNode) mergenodes(CT, currentNode, neighbNode); + else mergenodes(CT, neighbNode, currentNode); +#ifdef ATTRIB_AREA + CT->tabnodes[tmp].area = CT->tabnodes[currentNode].area + CT->tabnodes[neighbNode].area; +#endif + currentNode = tmp; + } + else + { // add neighbNode as a new son of currentNode + addson(CT, currentNode, neighbNode); + } + currentSubtree = TarjanLink(T1, neighbSubtree, currentSubtree); + SubtreeRoot[currentSubtree] = currentNode; + } // endif + } // if ((q != -1) && (F[q] <= F[p])) + } // for (k = 0; k < 8; k += incr_vois) + } // for (i = 0; i < N; i++) + } // if (connex == 6) + else if (connex == 18) + { + for (i = 0; i < N; i++) + { + p = S[i]; // pixel courant, dans l'ordre croissant + currentSubtree = TarjanFind(T1, p); + currentNode = TarjanFind(T2, SubtreeRoot[currentSubtree]); + for (k = 0; k < 18; k++) + { + q = voisin18(p, k, rs, ps, N); +#ifdef MAXTREE + if ((q != -1) && (F[q] >= F[p])) +#else + if ((q != -1) && (F[q] <= F[p])) +#endif + { + neighbSubtree = TarjanFind(T1, q); + neighbNode = TarjanFind(T2, SubtreeRoot[neighbSubtree]); + if (currentNode != neighbNode) + { + if (CT->tabnodes[currentNode].data == CT->tabnodes[neighbNode].data) + { // merge the nodes + numbernodes -= 1; + tmp = TarjanLink(T2, neighbNode, currentNode); +#ifdef PARANO + if ((tmp != currentNode) && (tmp != neighbNode)) + printf("%s : choix inattendu pour le representant", F_NAME); +#endif + if (tmp == currentNode) mergenodes(CT, currentNode, neighbNode); + else mergenodes(CT, neighbNode, currentNode); +#ifdef ATTRIB_AREA + CT->tabnodes[tmp].area = CT->tabnodes[currentNode].area + CT->tabnodes[neighbNode].area; +#endif + currentNode = tmp; + } + else + { // add neighbNode as a new son of currentNode + addson(CT, currentNode, neighbNode); + } + currentSubtree = TarjanLink(T1, neighbSubtree, currentSubtree); + SubtreeRoot[currentSubtree] = currentNode; + } // endif + } // if ((q != -1) && (F[q] <= F[p])) + } // for (k = 0; k < 8; k += incr_vois) + } // for (i = 0; i < N; i++) + } // if (connex == 18) + else if (connex == 26) + { + for (i = 0; i < N; i++) + { + p = S[i]; // pixel courant, dans l'ordre croissant + currentSubtree = TarjanFind(T1, p); + currentNode = TarjanFind(T2, SubtreeRoot[currentSubtree]); + for (k = 0; k < 26; k++) + { + q = voisin26(p, k, rs, ps, N); +#ifdef MAXTREE + if ((q != -1) && (F[q] >= F[p])) +#else + if ((q != -1) && (F[q] <= F[p])) +#endif + { + neighbSubtree = TarjanFind(T1, q); + neighbNode = TarjanFind(T2, SubtreeRoot[neighbSubtree]); + if (currentNode != neighbNode) + { + if (CT->tabnodes[currentNode].data == CT->tabnodes[neighbNode].data) + { // merge the nodes + numbernodes -= 1; + tmp = TarjanLink(T2, neighbNode, currentNode); +#ifdef PARANO + if ((tmp != currentNode) && (tmp != neighbNode)) + printf("%s : choix inattendu pour le representant", F_NAME); +#endif + if (tmp == currentNode) mergenodes(CT, currentNode, neighbNode); + else mergenodes(CT, neighbNode, currentNode); +#ifdef ATTRIB_AREA + CT->tabnodes[tmp].area = CT->tabnodes[currentNode].area + CT->tabnodes[neighbNode].area; +#endif + currentNode = tmp; + } + else + { // add neighbNode as a new son of currentNode + addson(CT, currentNode, neighbNode); + } + currentSubtree = TarjanLink(T1, neighbSubtree, currentSubtree); + SubtreeRoot[currentSubtree] = currentNode; + } // endif + } // if ((q != -1) && (F[q] <= F[p])) + } // for (k = 0; k < 8; k += incr_vois) + } // for (i = 0; i < N; i++) + } // if (connex == 26) + else + { fprintf(stderr, "%s() : bad value for connex : %d\n", F_NAME, connex); + return 0; + } + + CT->root = SubtreeRoot[TarjanFind(T1, TarjanFind(T2, 0))]; + for (i = 0; i < N; i++) CM[i] = TarjanFind(T2, i); + for (i = 0; i < N; i++) // construction de la relation "father" + if (CT->tabnodes[i].nbsons > 0) + for (sc = CT->tabnodes[i].sonlist; sc != NULL; sc = sc->next) + { + son = sc->son; + CT->tabnodes[son].father = i; + } + + k = 0; + for (i = 0; i < N; i++) + if (CT->tabnodes[i].nbsons == 0) + k++; + CT->nbleafs = k; +#ifdef VERBOSE + printf("nombre de feuilles = %d\n", CT->nbleafs); +#endif + + TarjanTermine(T1); + TarjanTermine(T2); + +#ifdef ATTRIB_AREA +{ + int32_t *area = (int32_t *)malloc(N * sizeof(int32_t)); + if (area == NULL) + { fprintf(stderr, "%s() : malloc failed\n", F_NAME); + return 0; + } + ComputeArea(CT, CT->root, area); + for (i = 0; i < N; i++) + CT->tabnodes[i].area = area[i]; + +#ifdef ATTRIB_VOL + ComputeVol(CT, CT->root, area); + for (i = 0; i < N; i++) + CT->tabnodes[i].vol = area[i]; +#endif + + free(area); +} +#endif + + *CompTree = CT; + *CompMap = CM; + return 1; +} // ComponentTree3d() + +#ifdef TESTSORT +int32_t main() { + u_int8_t F[20] = {25, 10, 1, 1, 0, 0, 1, 3, 5, 3, 2, 3, 4, 5, 7, 10, 11, 6, 3, 3}; + int32_t i; + int32_t *T = linsortimagedown((u_int8_t *)F, 20); + for (i = 0; i < 20; i++) printf("F[T[%d]] = %d\n", i, F[T[i]]); + free(T); + T = linsortimageup((u_int8_t *)F, 20); + for (i = 0; i < 20; i++) printf("F[T[%d]] = %d\n", i, F[T[i]]); + free(T); +} +#endif + +#ifdef TESTCOMPTREE +int32_t main() { +/* + u_int8_t F[15] = { + 110, 90, 100, 10, 40, + 50, 50, 50, 10, 20, + 80, 60, 70, 10, 30 + }; + int32_t i, rs = 5, cs = 3; + u_int8_t F[60] = { + 110, 110, 90, 90, 100, 100, 10, 10, 40, 40, + 110, 110, 90, 90, 100, 100, 10, 10, 40, 40, + 50, 50, 50, 50, 50, 50, 10, 10, 20, 20, + 50, 50, 50, 50, 50, 50, 10, 10, 20, 20, + 80, 80, 60, 60, 70, 70, 10, 10, 30, 30, + 80, 80, 60, 60, 70, 70, 10, 10, 30, 30 + }; + int32_t i, rs = 10, cs = 6; + u_int8_t F[60] = { + 110, 110, 90, 90, 100, 100, 75, 75, 140, 140, + 110, 110, 90, 90, 100, 100, 75, 75, 140, 140, + 60, 60, 50, 50, 50, 50, 50, 50, 85, 85, + 60, 60, 50, 50, 50, 50, 50, 50, 85, 85, + 80, 80, 60, 60, 70, 70, 55, 55, 130, 130, + 80, 80, 60, 60, 70, 70, 55, 55, 130, 130 + }; + int32_t i, rs = 10, cs = 6; +*/ + u_int8_t F[15] = { + 110, 90, 100, + 50, 50, 50, + 40, 20, 50, + 50, 50, 50, + 120, 70, 80 + }; + int32_t i, rs = 3, cs = 5; + ctree *CT; + int32_t *CM; + + ComponentTree(F, rs, rs*cs, 4, &CT, &CM); + printf("component tree:\n"); + ComponentTreePrint(CT); + printf("component mapping:\n"); + for (i = 0; i < rs*cs; i++) + { + if (i % rs == 0) printf("\n"); + printf("%3d ", CM[i]); + } /* for i */ + printf("\n"); + + ComponentTreeFree(CT); + free(CM); +} +#endif Index: abraham/tests/morpho/ref/src/lib/lattrib.c --- abraham/tests/morpho/ref/src/lib/lattrib.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/lattrib.c (revision 0) @@ -0,0 +1,1754 @@ +/* $Id: lattrib.c,v 1.9 2006/02/28 07:49:14 michel Exp $ */ +/* + Common code for files: + lattribarea.c + lattribheight.c + lattribvol.c + lsegreconsheight.c +*/ + +//#define DEBUG + +#define FILTERED_OUT 0x01 +#define LEAFMIN 0x02 +#define LEAFMAX 0x04 +#define LEAF (LEAFMIN|LEAFMAX) +#define LCA1 0x08 +#define LCA2 0x10 +#define LCA (LCA1|LCA2) + +#define NOT_ANALYZED 2000000000 +#define IN_THE_QUEUE 2000000001 + +/* + principe de l'encodage des composantes: + le niveau est code dans les bits 24 a 31 + il reste donc 24 bits pour coder le numero de la composante, + 24 + soit 2 = 16 megacomposantes par niveau. +*/ + +#define ENCODE(y,h) (y|(h<<24)) +#define DECODENUM(y) (y&0x00ffffff) +#define DECODENIV(y) (y>>24) + +/* + macros pour l'acces aux donnees de la structure CompactTree +*/ + +#define NBCOMP(h) ((h==0)?(cpct->hc[0]):(cpct->hc[h]-cpct->hc[h-1])) +#define INDEXCOMP(h,j) ((h==0)?(j):(cpct->hc[h-1]+j)) +#define NBFILS(c) ((c==0)?(cpct->dfils[0]):(cpct->dfils[c]-cpct->dfils[c-1])) +#define INDEXFILS(c,j) ((c==0)?(j):(cpct->dfils[c-1]+j)) + +/* ============================================================================== */ +/* + Structure de donnees pour la construction de l'arbre des composantes. + + Les sommets de cet arbre sont les composantes des coupes >=, + a l'exception de celles qui sont egales a une composante d'un niveau inferieur. + Il y a donc moins de N sommets (N = nombre de pixels) et de N-1 arcs. + + Une composante (sommet) est representee par deux donnees : + son niveau (sur 8 bits) et son numero dans le niveau (sur 24 bits), + le tout encode dans un entier 32 bits. + + L'arbre est represente par + une liste d'arcs (tableaux tete et queue), fleches de la racine vers les feuilles. +*/ +/* ============================================================================== */ +typedef struct { + u_int32_t nbmaxarcs; /* nombre maximum d'arcs */ + u_int32_t nbarcs; /* nombre effectif d'arcs */ + u_int32_t racine; /* racine de l'arbre */ + u_int32_t *tete; /* sommets initiaux des arcs de l'arbre */ + u_int32_t *queue; /* sommets terminaux des arcs de l'arbre */ +#ifdef ATTR_SURF + int32_t surf_racine; /* attribut surface pour la racine */ + int32_t *surf; /* attributs des sommets terminaux des arcs */ +#endif +#ifdef ATTR_PERIM + int32_t *perim; +#endif +#ifdef ATTR_HBORD + int32_t *hbord; +#endif +#ifdef ATTR_VOL + int32_t *vol; +#endif +} CompTree; +/* ============================================================================== */ + +/* ============================================================================== */ +/* + Structure de donnees compacte pour l'arbre des composantes. + + L'arbre est represente par cinq tableaux: + - le tableau 'hc' qui au niveau de gris h, associe le nombre de composantes de + niveau <= h (histogramme cumule). On a donc: + nombre de composantes de niveau 0 = hc[0] + nombre de composantes de niveau h > 0 = hc[h] - hc[h-1] + index derniere composante de niveau h s'il en existe = hc[h] - 1 + - le tableau 'comp' qui, a l'index i d'une composante, associe le code de la + composante (represente dans 32 bits comme dans la structure CompTree) + - le tableau 'pere' qui, a l'index i d'une composante, associe l'index du pere de i + (sauf pour la racine qui a pour index 0 et a laquelle est associee 0) + - le tableau 'dfils' qui, a l'index i d'une composante, associe l'index(+1) + du dernier fils de i (sauf pour les feuilles) + - le tableau 'fils' qui contient les listes de fils +*/ +/* ============================================================================== */ +#define CPCT_ROOT 0 +typedef struct { + u_int32_t nbcomp; /* nombre de composantes */ + u_int32_t *comp; /* tableau des composantes */ + u_int32_t *pere; /* tableau representant la relation 'pere' */ + u_int32_t *dfils; /* tableau donnant l'index+1 du dernier fils dans le tableau 'fils' */ + u_int32_t *fils; /* tableau representant, avec le precedent, la relation 'fils' */ + u_int32_t *hc; /* histogramme cumule des composantes */ +#ifdef ATTR_SURF + int32_t *surf; +#endif +#ifdef ATTR_HEIGHT + int32_t *height; +#endif +#ifdef ATTR_PERIM + int32_t *perim; +#endif +#ifdef ATTR_HBORD + int32_t *hbord; +#endif +#ifdef ATTR_CONTRAST + double *contrast; /* attribut flottant */ +#endif +#ifdef ATTR_VOL + int32_t *vol; +#endif +#ifdef ATTR_DYN + int32_t *dyn; +#endif + char *flags; /* 8 booleens pour des usages divers */ +} CompactTree; +/* ============================================================================== */ + +/* ======================================================================== */ +/* ======================================================================== */ +/* FONCTIONS POUR LE TRI */ +/* ======================================================================== */ +/* ======================================================================== */ + +// cle DOUBLE + +/* =============================================================== */ +static int32_t d_Partitionner(int32_t *A, double *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + partitionne les elements de A entre l'indice p (compris) et l'indice r (compris) + en deux groupes : les elements q tq T[A[q]] <= T[A[p]] et les autres. +*/ +{ + int32_t t; + double x = T[A[p]]; + int32_t i = p - 1; + int32_t j = r + 1; + while (1) + { + do j--; while (T[A[j]] > x); + do i++; while (T[A[i]] < x); + if (i < j) { t = A[i]; A[i] = A[j]; A[j] = t; } + else return j; + } /* while (1) */ +} /* d_Partitionner() */ + +/* =============================================================== */ +static int32_t d_PartitionStochastique(int32_t *A, double *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + partitionne les elements de A entre l'indice p (compris) et l'indice r (compris) + en deux groupes : les elements k tels que T[A[k]] <= T[A[q]] et les autres, + avec q tire au hasard dans [p,r]. +*/ +{ + int32_t t, q; + + q = p + (rand() % (r - p + 1)); + t = A[p]; /* echange A[p] et A[q] */ + A[p] = A[q]; + A[q] = t; + return d_Partitionner(A, T, p, r); +} /* d_PartitionStochastique() */ + +/* =============================================================== */ +static void d_TriRapideStochastique (int32_t * A, double *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + trie les valeurs du tableau A de l'indice p (compris) a l'indice r (compris) + par ordre croissant +*/ +{ + int32_t q; + if (p < r) + { + q = d_PartitionStochastique(A, T, p, r); + d_TriRapideStochastique (A, T, p, q) ; + d_TriRapideStochastique (A, T, q+1, r) ; + } +} /* d_TriRapideStochastique() */ + +// cle INT + +/* =============================================================== */ +static int32_t i_Partitionner(int32_t *A, int32_t *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + partitionne les elements de A entre l'indice p (compris) et l'indice r (compris) + en deux groupes : les elements q tq T[A[q]] <= T[A[p]] et les autres. +*/ +{ + int32_t t; + int32_t x = T[A[p]]; + int32_t i = p - 1; + int32_t j = r + 1; + while (1) + { + do j--; while (T[A[j]] > x); + do i++; while (T[A[i]] < x); + if (i < j) { t = A[i]; A[i] = A[j]; A[j] = t; } + else return j; + } /* while (1) */ +} /* i_Partitionner() */ + +/* =============================================================== */ +static int32_t i_PartitionStochastique(int32_t *A, int32_t *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + partitionne les elements de A entre l'indice p (compris) et l'indice r (compris) + en deux groupes : les elements k tels que T[A[k]] <= T[A[q]] et les autres, + avec q tire au hasard dans [p,r]. +*/ +{ + int32_t t, q; + + q = p + (rand() % (r - p + 1)); + t = A[p]; /* echange A[p] et A[q] */ + A[p] = A[q]; + A[q] = t; + return i_Partitionner(A, T, p, r); +} /* i_PartitionStochastique() */ + +/* =============================================================== */ +static void i_TriRapideStochastique (int32_t * A, int32_t *T, int32_t p, int32_t r) +/* =============================================================== */ +/* + trie les valeurs du tableau A de l'indice p (compris) a l'indice r (compris) + par ordre croissant +*/ +{ + int32_t q; + if (p < r) + { + q = i_PartitionStochastique(A, T, p, r); + i_TriRapideStochastique (A, T, p, q) ; + i_TriRapideStochastique (A, T, q+1, r) ; + } +} /* i_TriRapideStochastique() */ + +/* ======================================================================== */ +/* ======================================================================== */ +/* CONSTRUCTION ET GESTION DE L'ARBRE DES COMPOSANTES */ +/* ======================================================================== */ +/* ======================================================================== */ + +/* ==================================== */ +static CompTree * InitCompTree(int32_t nbmaxarcs) +/* ==================================== */ +{ + CompTree *ct; + ct = (CompTree *)malloc(sizeof(CompTree)); + if (ct == NULL) return NULL; + ct->tete = (u_int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->tete == NULL) return NULL; + ct->queue = (u_int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->queue == NULL) return NULL; +#ifdef ATTR_SURF + ct->surf = (int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->surf == NULL) return NULL; +#endif +#ifdef ATTR_PERIM + ct->perim = (int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->perim == NULL) return NULL; +#endif +#ifdef ATTR_HBORD + ct->hbord = (int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->hbord == NULL) return NULL; +#endif +#ifdef ATTR_VOL + ct->vol = (int32_t *)malloc(nbmaxarcs * sizeof(int32_t)); + if (ct->vol == NULL) return NULL; +#endif + ct->nbmaxarcs = nbmaxarcs; + ct->nbarcs = 0; + ct->racine = CPCT_ROOT; + return ct; +} /* InitCompTree() */ + +/* ==================================== */ +static void TermineCompTree(CompTree *ct) +/* ==================================== */ +{ + free(ct->tete); + free(ct->queue); +#ifdef ATTR_SURF + free(ct->surf); +#endif +#ifdef ATTR_PERIM + free(ct->perim); +#endif +#ifdef ATTR_HBORD + free(ct->hbord); +#endif +#ifdef ATTR_VOL + free(ct->vol); +#endif + free(ct); +} /* TermineCompTree() */ + +/* ==================================== */ +static CompactTree * CompTree2CompactTree(CompTree *ct, u_int32_t *number_nodes) +/* ==================================== */ +/* ATTENTION EFFET DE BORD : DETRUIT LA RELATION number_nodes + (number_nodes represente le nombre de composantes par niveau, calcule par flood()) +*/ +{ + CompactTree *cpct; + u_int32_t i, n, h, t, th, tn, q, qh, qn; + u_int32_t nbcomp = ct->nbarcs + 1; + u_int32_t *nfils; + + cpct = (CompactTree *)malloc(sizeof(CompactTree)); + if (cpct == NULL) return NULL; + cpct->nbcomp = nbcomp; + cpct->comp = (u_int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->comp == NULL) return NULL; + cpct->pere = (u_int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->pere == NULL) return NULL; + cpct->dfils = (u_int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->dfils == NULL) return NULL; + cpct->fils = (u_int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->fils == NULL) return NULL; + cpct->hc = (u_int32_t *)malloc(256 * sizeof(int32_t)); + if (cpct->hc == NULL) return NULL; +#ifdef ATTR_SURF + cpct->surf = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->surf == NULL) return NULL; +#endif +#ifdef ATTR_HEIGHT + cpct->height = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->height == NULL) return NULL; +#endif +#ifdef ATTR_PERIM + cpct->perim = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->perim == NULL) return NULL; +#endif +#ifdef ATTR_HBORD + cpct->hbord = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->hbord == NULL) return NULL; +#endif +#ifdef ATTR_CONTRAST + cpct->contrast = (double *)malloc(nbcomp * sizeof(double)); + if (cpct->contrast == NULL) return NULL; +#endif +#ifdef ATTR_VOL + cpct->vol = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->vol == NULL) return NULL; +#endif +#ifdef ATTR_DYN + cpct->dyn = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (cpct->dyn == NULL) return NULL; +#endif + cpct->flags = (char *)calloc(nbcomp, sizeof(char)); + if (cpct->flags == NULL) return NULL; + + /* calcule l'histogramme cumule hc */ + n = cpct->hc[0] = number_nodes[0]; + for (i = 1; i < 256; i++) { n += number_nodes[i]; cpct->hc[i] = n; } + + /* construit le tableau des composantes comp */ + n = 0; h = 0; while (!number_nodes[h]) h++; /* ATTENTION CODE FRAGILE */ + for (i = 0; i < nbcomp; i++) /* SUPPOSE CORRECTES LES DONNEES D'ENTREE */ + { /* PAS DE VERIFICATION */ + cpct->comp[i] = ENCODE(n,h); + number_nodes[h]--; n++; + if (!number_nodes[h]) { n = 0; while (!number_nodes[h]) h++; } + } /* for i */ + + /* construit la relation pere */ + for (i = 0; i < nbcomp-1; i++) + { + t = ct->tete[i]; q = ct->queue[i]; + th = DECODENIV(t); tn = DECODENUM(t); + qh = DECODENIV(q); qn = DECODENUM(q); + cpct->pere[INDEXCOMP(qh,qn)] = INDEXCOMP(th,tn); + } + q = ct->racine; qh = DECODENIV(q); qn = DECODENUM(q); + cpct->pere[INDEXCOMP(qh,qn)] = INDEXCOMP(qh,qn); + + /* construit la relation dfils et fils */ + nfils = (u_int32_t *)calloc(nbcomp, sizeof(int32_t)); + if (nfils == NULL) return NULL; + for (i = 1; i < nbcomp; i++) nfils[cpct->pere[i]] += 1; + /* exception : la racine (0) est fille d'elle-meme, cette relation n'est pas comptee */ + cpct->dfils[CPCT_ROOT] = nfils[CPCT_ROOT]; + for (i = 1; i < nbcomp; i++) cpct->dfils[i] = cpct->dfils[i - 1] + nfils[i]; + for (i = 1; i < nbcomp; i++) + { + t = cpct->pere[i]; /* i est fils de t */ + nfils[t] -= 1; + cpct->fils[INDEXFILS(t,nfils[t])] = i; + } + free(nfils); + + /* transfere les attributs (cas particulier pour la racine) */ + for (i = 0; i < nbcomp-1; i++) + { + q = ct->queue[i]; qh = DECODENIV(q); qn = DECODENUM(q); +#ifdef ATTR_SURF + cpct->surf[INDEXCOMP(qh,qn)] = ct->surf[i]; +#endif +#ifdef ATTR_PERIM + cpct->perim[INDEXCOMP(qh,qn)] = ct->perim[i]; +#endif +#ifdef ATTR_HBORD + cpct->hbord[INDEXCOMP(qh,qn)] = ct->hbord[i]; +#endif +#ifdef ATTR_VOL + cpct->vol[INDEXCOMP(qh,qn)] = ct->vol[i]; +#endif + } +#ifdef ATTR_SURF + cpct->surf[CPCT_ROOT] = ct->surf_racine; +#endif +#ifdef ATTR_PERIM + cpct->perim[CPCT_ROOT] = 0; +#endif +#ifdef ATTR_HBORD + cpct->hbord[CPCT_ROOT] = 0; +#endif +#ifdef ATTR_VOL + cpct->vol[CPCT_ROOT] = 0; +#endif + return cpct; +} /* CompTree2CompactTree() */ + +/* ==================================== */ +static void ReInitFlags(CompactTree * cpct) +/* ==================================== */ +{ + u_int32_t nbcomp = cpct->nbcomp; + memset(cpct->flags,0,nbcomp); +} /* ReInitFlags() */ + +#ifdef ATTR_SURF +/* ==================================== */ +static int32_t surfrec(CompactTree * cpct, u_int32_t som, int32_t *na1) +/* ==================================== */ +/* + Calcule la surface de chacune des composantes, a partir de + l'information stockee dans cpct->surf[i], qui correspond a la + difference de surface entre la composante i et ses filles. + Le resultat est provisoirement stocke dans le tableau na1 (indexe par + le numero de composante i), pour etre ensuite recopie dans cpct->surf[i]. +*/ +{ + int32_t i, n, j; + n = NBFILS(som); + if (n == 0) return na1[som] = cpct->surf[som]; + na1[som] = cpct->surf[som]; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + na1[som] += surfrec(cpct, j, na1); + } + return na1[som]; +} /* surfrec() */ +#endif + +#ifdef ATTR_VOL +/* ==================================== */ +static int32_t volrec(CompactTree * cpct, u_int32_t som, int32_t *na1) +/* ==================================== */ +/* + Attention: pour utiliser cette fonction, il faut avoir + prealablement calcule la surface des composantes (cf. surfrec()) + et avoir stocke cette information dans cpct->surf[]. + + Calcule le volume de chacune des composantes, a partir de + l'information stockee dans cpct->surf[i], qui correspond a la + surface de la composante. + Le resultat est provisoirement stocke dans le tableau na1 (indexe par + le numero de composante i), pour etre ensuite recopie dans cpct->vol[i]. +*/ +{ + int32_t i, n, j, nb_coupes_eq; + n = NBFILS(som); + if (n == 0) return na1[som] = cpct->surf[som]; + na1[som] = cpct->surf[som]; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + nb_coupes_eq = DECODENIV(cpct->comp[j]) - DECODENIV(cpct->comp[som]) - 1; + na1[som] += volrec(cpct, j, na1) + (cpct->surf[j] * nb_coupes_eq); + } + return na1[som]; +} /* volrec() */ + +/* ==================================== */ +static int32_t volrec_old(CompactTree * cpct, u_int32_t som, int32_t *na1) +/* ==================================== */ +{ + int32_t i, n, j; + n = NBFILS(som); + if (n == 0) return na1[som] = cpct->surf[som]; + na1[som] = cpct->surf[som]; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + na1[som] += volrec_old(cpct, j, na1); + } + return na1[som]; +} /* volrec_old() */ +#endif + +#ifdef ATTR_HEIGHT +/* ==================================== */ +static int32_t heightrec(CompactTree * cpct, u_int32_t som, int32_t *na1) +/* ==================================== */ +/* retourne le niveau max des descendants de som (ou le niveau de som pour une feuille) */ +{ + int32_t i, n, j, h; + n = NBFILS(som); + if (n == 0) return na1[som] = DECODENIV(cpct->comp[som]); + na1[som] = 0; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + h = heightrec(cpct, j, na1); + na1[som] = max(na1[som], h); + } + return na1[som]; +} /* heightrec() */ +#endif + +#ifdef ATTR_PERIM +/* ==================================== */ +static int32_t perimrec(CompactTree * cpct, u_int32_t som, int32_t *nperim) +/* ==================================== */ +{ + int32_t i, n, j; + n = NBFILS(som); + if (n == 0) return nperim[som] = cpct->perim[som]; + nperim[som] = cpct->perim[som]; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + nperim[som] += perimrec(cpct, j, nperim); + } + return nperim[som]; +} /* perimrec() */ +#endif + +#ifdef ATTR_HBORD +/* ==================================== */ +static int32_t hbordrec(CompactTree * cpct, u_int32_t som, int32_t *nhbord) +/* ==================================== */ +{ + int32_t i, n, j; + n = NBFILS(som); + if (n == 0) return nhbord[som] = cpct->hbord[som]; + nhbord[som] = cpct->hbord[som]; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + nhbord[som] += hbordrec(cpct, j, nhbord); + } + return nhbord[som]; +} /* hbordrec() */ +#endif + +/* ==================================== */ +static void CalculeAttributs(CompactTree * cpct) +/* ==================================== */ +{ + int32_t *na1, *na2, i; + u_int32_t nbcomp = cpct->nbcomp; + + na1 = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + na2 = (int32_t *)malloc(nbcomp * sizeof(int32_t)); +#ifdef ATTR_SURF + (void)surfrec(cpct, 0, na1); + for (i = 0; i < nbcomp; i++) cpct->surf[i] = na1[i]; +#endif +#ifdef ATTR_VOL + if (cpct->surf == NULL) + { + fprintf(stderr, "CalculeAttributs: VOL ne peut etre calcule dans SURF\n"); + exit(0); + } + (void)volrec(cpct, 0, na1); + for (i = 0; i < nbcomp; i++) cpct->vol[i] = na1[i]; +#endif +#ifdef ATTR_HEIGHT + + (void)heightrec(cpct, 0, na1); + /* pour la mesure de la hauteur, il faut rajouter la difference de niveau avec le pere */ + for (i = 1; i < nbcomp; i++) cpct->height[i] = na1[i] + /* - DECODENIV(cpct->comp[i]) + DECODENIV(cpct->comp[i]) */ /* inutile */ + - DECODENIV(cpct->comp[cpct->pere[i]]) - 1; + + cpct->height[0] = NDG_MAX - NDG_MIN; +#endif +#ifdef ATTR_PERIM + (void)perimrec(cpct, 0, na1); + for (i = 0; i < nbcomp; i++) cpct->perim[i] = na1[i]; +#endif +#ifdef ATTR_HBORD + (void)hbordrec(cpct, 0, na2); + for (i = 0; i < nbcomp; i++) cpct->hbord[i] = na2[i]; +#endif +#ifdef ATTR_CONTRAST + for (i = 0; i < nbcomp; i++) cpct->contrast[i] = ((double)(na2[i]))/na1[i]; +#endif + free(na1); + free(na2); +} /* CalculeAttributs() */ + +#ifdef ATTR_HEIGHT +/* ==================================== */ +static int32_t FiltreHeightRec(CompactTree * cpct, int32_t som, int32_t h) +/* ==================================== */ +/* + Filtre les sommets de l'arbre selon un critere de hauteur : + + height(som) >= h + + Un sommet 'som' ne satisfaisant pas le critere est marque FILTERED_OUT. + La fonction traite recursivement les fils, et retourne le nombre NNM de sommets non marques dans + la descendance (inclus le sommet lui-meme). + Un sommet non filtre et dont le NNM de la descendance vaut 0 est marque LEAFMIN. +*/ +{ + int32_t i, n, j, NNM = 0; + n = NBFILS(som); + if (cpct->height[som] < h) cpct->flags[som] |= FILTERED_OUT; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + NNM += FiltreHeightRec(cpct, j, h); + } + if (cpct->height[som] >= h) /* sommet non filtre */ + { + if (NNM == 0) cpct->flags[som] |= LEAFMIN; + NNM++; + } + return NNM; +} /* FiltreHeightRec() */ +#endif + +#ifdef ATTR_SURF +/* ==================================== */ +static int32_t FiltreSurfRec(CompactTree * cpct, int32_t som, int32_t h) +/* ==================================== */ +/* + Filtre les sommets de l'arbre selon un critere de surface : + + surf(som) >= h + + Un sommet 'som' ne satisfaisant pas le critere est marque FILTERED_OUT. + La fonction traite recursivement les fils, et retourne le nombre NNM de sommets non marques dans + la descendance (inclus le sommet lui-meme). + Un sommet non filtre et dont le NNM de la descendance vaut 0 est marque LEAFMIN. +*/ +{ + int32_t i, n, j, NNM = 0; + n = NBFILS(som); + if (cpct->surf[som] < h) cpct->flags[som] |= FILTERED_OUT; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + NNM += FiltreSurfRec(cpct, j, h); + } + if (cpct->surf[som] >= h) /* sommet non filtre */ + { + if (NNM == 0) cpct->flags[som] |= LEAFMIN; + NNM++; + } + return NNM; +} /* FiltreSurfRec() */ +#endif + +#ifdef ATTR_VOL +/* ==================================== */ +static int32_t FiltreVolRec(CompactTree * cpct, int32_t som, int32_t h) +/* ==================================== */ +/* + Filtre les sommets de l'arbre selon un critere de volume : + + vol(som) >= h + + Un sommet 'som' ne satisfaisant pas le critere est marque FILTERED_OUT. + La fonction traite recursivement les fils, et retourne le nombre NNM de sommets non marques dans + la descendance (inclus le sommet lui-meme). + Un sommet non filtre et dont le NNM de la descendance vaut 0 est marque LEAFMIN. +*/ +{ + int32_t i, n, j, NNM = 0; + n = NBFILS(som); + if (cpct->vol[som] < h) cpct->flags[som] |= FILTERED_OUT; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + NNM += FiltreVolRec(cpct, j, h); + } + if (cpct->vol[som] >= h) /* sommet non filtre */ + { + if (NNM == 0) cpct->flags[som] |= LEAFMIN; + NNM++; + } + return NNM; +} /* FiltreVolRec() */ +#endif + +/* ==================================== */ +static int32_t MaximiseSegmentation(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + +*/ +{ + int32_t i, n, j, f, nf, NF = 0; + if (cpct->flags[som] & FILTERED_OUT) return 0; + n = NBFILS(som); + if (n == 0) return 1; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + if (nf = MaximiseSegmentation(cpct, j)) { f = j; NF += nf; } + } + if (NF == 0) return 1; + if (NF == 1) + { + cpct->flags[f] |= FILTERED_OUT; + cpct->flags[som] |= LEAFMAX; + return 1; + } + return 1 + NF; +} /* MaximiseSegmentation() */ + +#ifdef ATTR_CONTRAST +/* ==================================== */ +static void Reconstruction(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + Recherche a partir de la racine, les sommets marques LEAF. + A partir de chacun de ces sommets : + - remonte en suivant les etiquettes LEAFMAX jusqu'a trouver un sommet marque LEAFMIN, + - stocke dans 'branche' le chemin (liste de sommets), dans 'contrast' l'attribut contrast associe a chaque sommet, + et dans 'index' les index des sommets (initialises a 0,1,2,3,...) + - trie le tableau index sur la cle contraste, + - selectionne un sommet M maximum (si plusieurs, ...), + - a partir de M, on "redescend" en demarquant les sommets +*/ +{ + int32_t i, n, m, j, k, M; + double contrast[256]; + int32_t branche[256]; + int32_t index[256]; + + if (!(cpct->flags[som] & LEAF)) /* remonte l'arbre pour trouver une LEAF */ + { + n = NBFILS(som); + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + Reconstruction(cpct, j); + } + } + else /* on a trouve une LEAF */ + { + m = 0; /* m indexe le tableau contrast */ + k = som; + while (!(cpct->flags[k] & LEAFMIN)) + { + contrast[m] = cpct->contrast[k]; + branche[m] = k; + m++; + n = NBFILS(k); /* on va chercher le fils qui est marque LEAF */ + for (i = 0; i < n; i++) + { + j = INDEXFILS(k, i); + j = cpct->fils[j]; + if (cpct->flags[j] & LEAF) break; + } + k = j; +#ifdef PARANO + if (i >= n) fprintf(stderr, "Reconstruction : ERREUR INATTENDUE\n"); +#endif + } + contrast[m] = cpct->contrast[k]; + branche[m] = k; + m++; + +#ifdef DEBUGRECONS + printf("Reconstruction Sommet %d\n", som); + for (i = 0; i < m; i++) printf("%d %d %g\n", i, branche[i], contrast[i]); +#endif + + /* trie le tableau index sur la cle contraste */ + for (i = 0; i < m; i++) index[i] = i; + d_TriRapideStochastique (index, contrast, 0, m-1); + +#ifdef DEBUGRECONS + printf("Apres tri : \n"); + for (i = 0; i < m; i++) printf("%d %d %g\n", index[i], branche[index[i]], contrast[index[i]]); +#endif + + /* selectionne un sommet M maximum (SI PLUSIEURS, ... CHOIX ARBITRAIRE), */ + M = branche[index[m-1]]; + + /* a partir de M, on "redescend" en demarquant les sommets */ + cpct->flags[M] &= ~FILTERED_OUT; + cpct->flags[M] |= LEAFMAX; + k = cpct->pere[M]; + while (cpct->flags[k] & LEAFMAX) + { + cpct->flags[k] &= ~LEAFMAX; + cpct->flags[k] &= ~FILTERED_OUT; + k = cpct->pere[k]; + } + } /* else (on a trouve une LEAF) */ +} /* Reconstruction() */ +#endif + +/* ==================================== */ +static int32_t NbLeafs(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + Recherche a partir du sommet som, les sommets marques LEAF. + Retourne le nombre de ces sommets. +*/ +{ + int32_t i, j, k, n; + + if (!(cpct->flags[som] & LEAF)) /* remonte l'arbre pour trouver une LEAF */ + { + n = NBFILS(som); + k = 0; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + k += NbLeafs(cpct, j); + } + return k; + } + else /* (on a trouve une LEAF) */ + return 1; +} /* NbLeafs() */ + +/* ==================================== */ +static void RecupereImageFiltree(CompactTree * cpct, + u_int32_t *STATUS, + int32_t rs, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t i, h; + u_int32_t c, comp; + for (i = 0; i < N; i++) + { + h = ORI[i]; + c = STATUS[i]; + comp = INDEXCOMP(h,c); + while (cpct->flags[comp] == FILTERED_OUT) comp = cpct->pere[comp]; + ORI[i] = DECODENIV(cpct->comp[comp]); + } +} /* RecupereImageFiltree() */ + +/* ==================================== */ +static void RecupereSegmentation(CompactTree * cpct, + u_int32_t *STATUS, + int32_t rs, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t i, h; + u_int32_t c, comp; + for (i = 0; i < N; i++) + { + h = ORI[i]; + c = STATUS[i]; + comp = INDEXCOMP(h,c); + while (cpct->flags[comp] & FILTERED_OUT) + { +#ifdef PARANO + if (comp == cpct->pere[comp]) + fprintf(stderr, "RecupereSegmentation: la racine a ete eliminee\n"); +#endif + comp = cpct->pere[comp]; + } + if (cpct->flags[comp] & LEAF) ORI[i] = NDG_MAX; else ORI[i] = NDG_MIN; + } +} /* RecupereSegmentation() */ + +/* ==================================== */ +static void TermineCompactTree(CompactTree *cpct) +/* ==================================== */ +{ + free(cpct->comp); + free(cpct->pere); + free(cpct->dfils); + free(cpct->fils); + free(cpct->hc); +#ifdef ATTR_SURF + free(cpct->surf); +#endif +#ifdef ATTR_HEIGHT + free(cpct->height); +#endif +#ifdef ATTR_PERIM + free(cpct->perim); +#endif +#ifdef ATTR_HBORD + free(cpct->hbord); +#endif +#ifdef ATTR_CONTRAST + free(cpct->contrast); +#endif +#ifdef ATTR_VOL + free(cpct->vol); +#endif +#ifdef ATTR_DYN + free(cpct->dyn); +#endif + + free(cpct->flags); + free(cpct); +} /* TermineCompactTree() */ + +/* ==================================== */ +static void AfficheCompTree(CompTree *ct) +/* ==================================== */ +{ + int32_t i; + printf("===========================\n"); + printf("nombre max arcs = %d\n", ct->nbmaxarcs); + printf("nombre arcs = %d\n", ct->nbarcs); + printf("racine = C%d,%d\n", DECODENIV(ct->racine), DECODENUM(ct->racine)); + printf("===========================\n"); + for (i = 0; i < ct->nbarcs; i++) + printf("C%d,%d --> C%d,%d\n", + DECODENIV(ct->tete[i]), DECODENUM(ct->tete[i]), + DECODENIV(ct->queue[i]), DECODENUM(ct->queue[i])); + printf("===========================\n"); +} /* AfficheCompTree() */ + +/* ==================================== */ +static void AfficheCompactTree(CompactTree *cpct) +/* ==================================== */ +{ + u_int32_t i, j, n, f; + printf("===========================\n"); + printf("nombre composantes = %d\n", cpct->nbcomp); + printf("===========================\n"); + for (i = 0; i < cpct->nbcomp; i++) + { + printf("comp[%d] = C%d,%d ", i, DECODENIV(cpct->comp[i]), DECODENUM(cpct->comp[i])); +#ifdef ATTR_SURF + printf("surf = %d ", cpct->surf[i]); +#endif +#ifdef ATTR_HEIGHT + printf("height = %d ", cpct->height[i]); +#endif +#ifdef ATTR_VOL + printf("vol = %d ", cpct->vol[i]); +#endif +#ifdef ATTR_PERIM + printf("perim = %d ", cpct->perim[i]); +#endif +#ifdef ATTR_HBORD + printf("hbord = %d ", cpct->hbord[i]); +#endif +#ifdef ATTR_CONTRAST + printf("contrast = %g ",cpct->contrast[i]); +#endif +#ifdef ATTR_DYN + printf("dynamique = %d ",cpct->dyn[i]); +#endif + printf("fils = [ "); + n = NBFILS(i); + for (j = 0; j < n; j++) + { + f = INDEXFILS(i,j); + f = cpct->fils[f]; + printf("C%d,%d ", DECODENIV(cpct->comp[f]), DECODENUM(cpct->comp[f]), f); + } + printf("] "); + if (cpct->flags[i] & FILTERED_OUT) printf(" - OUT"); + if (cpct->flags[i] & LEAFMIN) printf(" - LEAFMIN"); + if (cpct->flags[i] & LEAFMAX) printf(" - LEAFMAX"); + printf("\n"); + } + printf("===========================\n"); + for (i = 0; i < cpct->nbcomp; i++) + printf("pere[%d] = %d\n", i, cpct->pere[i]); + printf("===========================\n"); +} /* AfficheCompactTree() */ + +/* ==================================== */ +static void AfficheImaComp(CompactTree * cpct, + u_int32_t *STATUS, + int32_t rs, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t i, h; + u_int32_t c, comp; + for (i = 0; i < N; i++) + { + h = ORI[i]; + c = STATUS[i]; + printf("C%d,%d\t", h, c); + if ((i % rs) == (rs - 1)) printf("\n"); + } +} /* AfficheImaComp() */ + +/* ==================================== */ +static void WriteCompactTree(CompactTree *cpct, char * filename) +/* ==================================== */ +{ + u_int32_t i, j, n, f; + FILE * fd = NULL; + char buf[256]; + + fd = fopen(filename,"w"); + if (!fd) + { + fprintf(stderr, "WriteCompactTree: cannot open file: %s\n", filename); + exit(0); + } + + fprintf(fd, "%d %d\n", cpct->nbcomp, cpct->nbcomp-1); + fprintf(fd, "noms sommets\n"); + for (i = 0; i < cpct->nbcomp; i++) + { + sprintf(buf, "C%d,%d", DECODENIV(cpct->comp[i]), DECODENUM(cpct->comp[i])); + fprintf(fd, "%d %s\n", i, buf); + } + fprintf(fd, "arcs\n"); + for (i = 1; i < cpct->nbcomp; i++) + fprintf(fd, "%d %d\n", cpct->pere[i], i); + fclose(fd); +} /* WriteCompactTree() */ + +/* ==================================== */ +static int32_t LeafCount(CompactTree *cpct) +/* ==================================== */ +{ + u_int32_t i, f = 0; + for (i = 0; i < cpct->nbcomp; i++) + if ((NBFILS(i)) == 0) f++; + return f; +} /* LeafCount() */ + +/* ==================================== */ +static int32_t LeafMark(CompactTree *cpct) +/* ==================================== */ +{ + u_int32_t i, f = 0; + for (i = 0; i < cpct->nbcomp; i++) + if ((NBFILS(i)) == 0) { f++; cpct->flags[i] |= LEAF; } + return f; +} /* LeafMark() */ + +/* ==================================== */ +static int32_t NbFilsNonFiltres(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + retourne le nombre de fils de 'som' non marques FILTERED_OUT. +*/ +{ + int32_t i, n, j, NNM = 0; + n = NBFILS(som); + if (n == 0) + return 0; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + if (!(cpct->flags[j] & FILTERED_OUT)) NNM++; + else if (NbFilsNonFiltres(cpct, j)>=1) NNM++; + } + return NNM; +} /* NbFilsNonFiltres() */ + +/* ==================================== */ +static void AjouteArc(CompTree *ct, u_int32_t i, u_int32_t j +#ifdef ATTR_SURF + , int32_t surf +#endif +#ifdef ATTR_PERIM + , int32_t perim +#endif +#ifdef ATTR_HBORD + , int32_t hbord +#endif + ) +/* ==================================== */ +{ + if (ct->nbarcs >= ct->nbmaxarcs) + { + fprintf(stderr, "AjouteArc : structure CompTree saturee (%d arcs)\n", ct->nbarcs); + exit(0); + } + ct->tete[ct->nbarcs] = i; + ct->queue[ct->nbarcs] = j; +#ifdef ATTR_SURF + ct->surf[ct->nbarcs] = surf; +#endif +#ifdef ATTR_PERIM + ct->perim[ct->nbarcs] = perim; +#endif +#ifdef ATTR_HBORD + ct->hbord[ct->nbarcs] = hbord; +#endif + ct->nbarcs += 1; +} /* AjouteArc() */ + +/* ==================================== */ +static int32_t contrib_perim(int32_t p, u_int8_t *ORI, u_int32_t *STATUS, int32_t rs, int32_t N, int32_t incr_vois) +/* ==================================== */ +{ /* calcule la contribution du point p au perimetre de la composante */ + int32_t q, k, nv = 0; + + for (k = 0; k < 8; k += incr_vois) /* compte le nombre nv de voisins deja traites */ + { + q = voisin(p, k, rs, N); + if ((q != -1) && (ORI[q] >= ORI[p]) && (STATUS[q] < NOT_ANALYZED)) nv++; + } /* for (k = 0; k < 8; k += incr_vois) */ + + return 4 - 2 * nv; +} + + +/* ==================================== */ +static int32_t contrib_perimb(int32_t p, u_int8_t *ORI, u_int32_t *STATUS, int32_t rs, int32_t N, int32_t connex) +/* ==================================== */ +{ /* calcule la contribution du point p au perimetre de la composante */ + int32_t q, k, nv = 0; + + for (k = 0; k < 6; k ++) /* compte le nombre nv de voisins deja traites */ + { + q = voisin6b(p, k, rs, N, connex); + if ((q != -1) && (ORI[q] >= ORI[p]) && (STATUS[q] < NOT_ANALYZED)) nv++; + } /* for (k = 0; k < 8; k += incr_vois) */ + + return 4 - 2 * nv; +} + + +/* ==================================== */ +static int32_t contrib_hbord(int32_t p, u_int8_t *ORI, u_int32_t *STATUS, int32_t rs, int32_t N, int32_t incr_vois) +/* ==================================== */ +{ /* calcule la contribution du point p au hbord de la composante */ + int32_t q, k, h = 0; + + for (k = 0; k < 8; k += incr_vois) + { + q = voisin(p, k, rs, N); + if (q != -1) h += (ORI[p] - ORI[q]); + } /* for (k = 0; k < 8; k += incr_vois) */ + + return h; +} + + +/* ==================================== */ +static int32_t contrib_hbordb(int32_t p, u_int8_t *ORI, u_int32_t *STATUS, int32_t rs, int32_t N, int32_t connex) +/* ==================================== */ +{ /* calcule la contribution du point p au hbord de la composante */ + int32_t q, k, h = 0; + + for (k = 0; k < 6; k ++) + { + q = voisin6b(p, k, rs, N, connex); + if (q != -1) h += (ORI[p] - ORI[q]); + } /* for (k = 0; k < 8; k += incr_vois) */ + + return h; +} + + + +/* ==================================== */ +static int32_t flood(int32_t h, /* niveau a inonder */ + Fah *FAH, + u_int32_t *STATUS, /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la comp. de niveau h */ + /* qui contient le pixel */ + u_int32_t *number_nodes, /* nombre de composantes par niveau */ + u_int8_t *node_at_level, /* tableau de booleens */ + CompTree * tree, /* l'arbre en construction */ + int32_t incr_vois, /* = 1 pour la 8-connexite, + = 2 pour la 4-connexite */ + int32_t rs, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t p, q, k, m, i, j; +#ifdef ATTR_SURF + int32_t surf = 0; +#endif +#ifdef ATTR_PERIM + int32_t perim = 0; +#endif +#ifdef ATTR_HBORD + int32_t hbord = 0; +#endif + +#ifdef DEBUGFLOOD + printf("debut flood niveau %d\n", h); +#endif + + node_at_level[h] = 1; /* CORRECTION BUG: LIGNE AJOUTEE LE 02/08/00 */ + while (!FahVideNiveau(FAH, h)) /* first step : propagation */ + { /* ======================== */ + p = FahPopNiveau(FAH, h); + STATUS[p] = number_nodes[h]; +#ifdef DEBUGFLOOD + printf("STATUS[p] %d\n", STATUS[p]); +#endif + for (k = 0; k < 8; k += incr_vois) + { + q = voisin(p, k, rs, N); + if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) + { + FahPush(FAH, q, ORI[q]); + STATUS[q] = IN_THE_QUEUE; + node_at_level[ORI[q]] = 1; + if (ORI[q] > ORI[p]) + { + m = ORI[q]; + do + { +#ifdef PARANO + if ((m < 0) || (m > 255)) + { + fprintf(stderr, "flood: mauvais niveau : %d ; ORI[q] = %d\n", m, ORI[q]); + exit(0); + } +#endif + m = flood(m, FAH, STATUS, number_nodes, node_at_level, tree, incr_vois, rs, N, ORI); + } while ((m != h) && (m >= 0)); + } /* if (ORI[q] > ORI[p]) */ + } /* if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) */ + } /* for (k = 0; k < 8; k += incr_vois) */ +#ifdef ATTR_SURF + surf += 1; +#endif +#ifdef ATTR_PERIM + perim += contrib_perim(p, ORI, STATUS, rs, N, incr_vois); +#endif +#ifdef ATTR_HBORD + hbord += contrib_hbord(p, ORI, STATUS, rs, N, incr_vois); +#endif + } /* while (!FahVideNiveau(FAH, h)) */ +#ifdef DEBUGFLOOD + printf("retour flood niveau %d\n", h); +#endif + number_nodes[h] += 1; + + m = h - 1; /* second step : define the father */ + while ((m >= 0) && (!node_at_level[m])) m--; /* =============================== */ + i = number_nodes[h] - 1; + if (m >= 0) + { + j = number_nodes[m]; +#ifdef DEBUGFLOOD + printf("AjouteArc (%d %d) (%d %d)\n", m, j, h, i); +#endif + AjouteArc(tree, ENCODE(j,m), ENCODE(i,h) /* definit Cm,j comme le pere de Ch,i */ +#ifdef ATTR_SURF + , surf +#endif +#ifdef ATTR_PERIM + , perim +#endif +#ifdef ATTR_HBORD + , hbord +#endif + ); + } /* if (m >= 0) */ + else + { +#ifdef DEBUGFLOOD + printf("DefinitRacine (%d %d)\n", h, i); +#endif + tree->racine = ENCODE(i,h); /* Ch,i est racine */ +#ifdef ATTR_SURF + tree->surf_racine = surf; +#endif + + } + node_at_level[h] = 0; +#ifdef DEBUGFLOOD + printf("fin flood niveau %d, retourne %d\n", h, m); +#endif + return m; +} /* flood() */ + + +/* ==================================== */ +static int32_t floodb(int32_t h, /* niveau a inonder */ + Fah *FAH, + u_int32_t *STATUS, /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la comp. de niveau h */ + /* qui contient le pixel */ + u_int32_t *number_nodes, /* nombre de composantes par niveau */ + u_int8_t *node_at_level, /* tableau de booleens */ + CompTree * tree, /* l'arbre en construction */ + int32_t connex, /* = 0 pour première case vide, + = 1 pour la translation */ + int32_t rs, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t p, q, k, m, i, j; + const int32_t incr_voisin = 1; +#ifdef ATTR_SURF + int32_t surf = 0; +#endif +#ifdef ATTR_PERIM + int32_t perim = 0; +#endif +#ifdef ATTR_HBORD + int32_t hbord = 0; +#endif + +#ifdef DEBUGFLOOD + printf("debut flood niveau %d\n", h); +#endif + + node_at_level[h] = 1; /* CORRECTION BUG: LIGNE AJOUTEE LE 02/08/00 */ + while (!FahVideNiveau(FAH, h)) /* first step : propagation */ + { /* ======================== */ + p = FahPopNiveau(FAH, h); + STATUS[p] = number_nodes[h]; +#ifdef DEBUGFLOOD + printf("STATUS[p] %d\n", STATUS[p]); +#endif + for (k = 0; k < 6; k ++) + { + q = voisin6b(p, k, rs, N, connex); + if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) + { + FahPush(FAH, q, ORI[q]); + STATUS[q] = IN_THE_QUEUE; + node_at_level[ORI[q]] = 1; + if (ORI[q] > ORI[p]) + { + m = ORI[q]; + do + { +#ifdef PARANO + if ((m < 0) || (m > 255)) + { + fprintf(stderr, "flood: mauvais niveau : %d ; ORI[q] = %d\n", m, ORI[q]); + exit(0); + } +#endif + m = floodb(m, FAH, STATUS, number_nodes, node_at_level, tree, connex, rs, N, ORI); + } while ((m != h) && (m >= 0)); + } /* if (ORI[q] > ORI[p]) */ + } /* if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) */ + } /* for (k = 0; k < 6; k++) */ +#ifdef ATTR_SURF + surf += 1; +#endif +#ifdef ATTR_PERIM + perim += contrib_perimb(p, ORI, STATUS, rs, N, connex); +#endif +#ifdef ATTR_HBORD + hbord += contrib_hbordb(p, ORI, STATUS, rs, N, connex); +#endif + } /* while (!FahVideNiveau(FAH, h)) */ +#ifdef DEBUGFLOOD + printf("retour flood niveau %d\n", h); +#endif + number_nodes[h] += 1; + + m = h - 1; /* second step : define the father */ + while ((m >= 0) && (!node_at_level[m])) m--; /* =============================== */ + i = number_nodes[h] - 1; + if (m >= 0) + { + j = number_nodes[m]; +#ifdef DEBUGFLOOD + printf("AjouteArc (%d %d) (%d %d)\n", m, j, h, i); +#endif + AjouteArc(tree, ENCODE(j,m), ENCODE(i,h) /* definit Cm,j comme le pere de Ch,i */ +#ifdef ATTR_SURF + , surf +#endif +#ifdef ATTR_PERIM + , perim +#endif +#ifdef ATTR_HBORD + , hbord +#endif + ); + } /* if (m >= 0) */ + else + { +#ifdef DEBUGFLOOD + printf("DefinitRacine (%d %d)\n", h, i); +#endif + tree->racine = ENCODE(i,h); /* Ch,i est racine */ +#ifdef ATTR_SURF + tree->surf_racine = surf; +#endif + + } + node_at_level[h] = 0; +#ifdef DEBUGFLOOD + printf("fin flood niveau %d, retourne %d\n", h, m); +#endif + return m; +} /* floodb() */ + + + +/* ==================================== */ +static int32_t flood3d( + int32_t h, /* niveau a inonder */ + Fah *FAH, + u_int32_t *STATUS, /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la comp. de niveau h */ + /* qui contient le pixel */ + u_int32_t *number_nodes, /* nombre de composantes par niveau */ + u_int8_t *node_at_level, /* tableau de booleens */ + CompTree * tree, /* l'arbre en construction */ + int32_t connex, + int32_t rs, int32_t ps, int32_t N, + u_int8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t p, q, k, m, i, j; +#ifdef ATTR_SURF + int32_t surf = 0; +#endif +#ifdef ATTR_PERIM + int32_t perim = 0; +#endif +#ifdef ATTR_HBORD + int32_t hbord = 0; +#endif + +#ifdef DEBUGFLOOD + printf("debut flood3d niveau %d\n", h); +#endif + + node_at_level[h] = 1; /* CORRECTION BUG: LIGNE AJOUTEE LE 02/08/00 */ + while (!FahVideNiveau(FAH, h)) /* first step : propagation */ + { /* ======================== */ + p = FahPopNiveau(FAH, h); + STATUS[p] = number_nodes[h]; +#ifdef DEBUGFLOOD + printf("STATUS[p] %d\n", STATUS[p]); +#endif + + switch (connex) + { + case 6: + for (k = 0; k <= 10; k += 2) /* parcourt les 6 voisins */ + { + q = voisin6(p, k, rs, ps, N); + if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) + { + FahPush(FAH, q, ORI[q]); + STATUS[q] = IN_THE_QUEUE; + node_at_level[ORI[q]] = 1; + if (ORI[q] > ORI[p]) + { + m = ORI[q]; + do + { +#ifdef PARANO + if ((m < 0) || (m > 255)) + { + fprintf(stderr, "flood3d: mauvais niveau : %d ; ORI[q] = %d\n", m, ORI[q]); + exit(0); + } +#endif + m = flood3d(m, FAH, STATUS, number_nodes, node_at_level, tree, connex, rs, ps, N, ORI); + } while ((m != h) && (m >= 0)); + } /* if (ORI[q] > ORI[p]) */ + } /* if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) */ + } /* for (...) */ + break; + case 18: + for (k = 0; k < 18; k++) /* parcourt les 18 voisins */ + { + q = voisin18(p, k, rs, ps, N); + if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) + { + FahPush(FAH, q, ORI[q]); + STATUS[q] = IN_THE_QUEUE; + node_at_level[ORI[q]] = 1; + if (ORI[q] > ORI[p]) + { + m = ORI[q]; + do + { +#ifdef PARANO + if ((m < 0) || (m > 255)) + { + fprintf(stderr, "flood3d: mauvais niveau : %d ; ORI[q] = %d\n", m, ORI[q]); + exit(0); + } +#endif + m = flood3d(m, FAH, STATUS, number_nodes, node_at_level, tree, connex, rs, ps, N, ORI); + } while ((m != h) && (m >= 0)); + } /* if (ORI[q] > ORI[p]) */ + } /* if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) */ + } /* for (...) */ + break; + case 26: + for (k = 0; k < 26; k++) /* parcourt les 26 voisins */ + { + q = voisin26(p, k, rs, ps, N); + if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) + { + FahPush(FAH, q, ORI[q]); + STATUS[q] = IN_THE_QUEUE; + node_at_level[ORI[q]] = 1; + if (ORI[q] > ORI[p]) + { + m = ORI[q]; + do + { +#ifdef PARANO + if ((m < 0) || (m > 255)) + { + fprintf(stderr, "flood3d: mauvais niveau : %d ; ORI[q] = %d\n", m, ORI[q]); + exit(0); + } +#endif + m = flood3d(m, FAH, STATUS, number_nodes, node_at_level, tree, connex, rs, ps, N, ORI); + } while ((m != h) && (m >= 0)); + } /* if (ORI[q] > ORI[p]) */ + } /* if ((q != -1) && (STATUS[q] == NOT_ANALYZED)) */ + } /* for (...) */ + break; + default: + fprintf(stderr, "flood3d: mauvaise connexite: %d\n", connex); + exit(0); + } /* switch (connex) */ + +#ifdef ATTR_SURF + surf += 1; +#endif + } /* while (!FahVideNiveau(FAH, h)) */ +#ifdef DEBUGFLOOD + printf("retour flood3d niveau %d\n", h); +#endif + number_nodes[h] += 1; + + m = h - 1; /* second step : define the father */ + while ((m >= 0) && (!node_at_level[m])) m--; /* =============================== */ + i = number_nodes[h] - 1; + if (m >= 0) + { + j = number_nodes[m]; +#ifdef DEBUGFLOOD + printf("AjouteArc (%d %d) (%d %d)\n", m, j, h, i); +#endif + AjouteArc(tree, ENCODE(j,m), ENCODE(i,h) /* definit Cm,j comme le pere de Ch,i */ +#ifdef ATTR_SURF + , surf +#endif +#ifdef ATTR_PERIM + , perim +#endif +#ifdef ATTR_HBORD + , hbord +#endif + ); + } /* if (m >= 0) */ + else + { +#ifdef DEBUGFLOOD + printf("DefinitRacine (%d %d)\n", h, i); +#endif + tree->racine = ENCODE(i,h); /* Ch,i est racine */ +#ifdef ATTR_SURF + tree->surf_racine = surf; +#endif + } + node_at_level[h] = 0; +#ifdef DEBUGFLOOD + printf("fin flood3d niveau %d, retourne %d\n", h, m); +#endif + return m; +} /* flood3d() */ + +/* ==================================== */ +static int32_t LowestCommonAncestor( + CompactTree * cpct, + int32_t argc, + int32_t *argv, + u_int8_t d) +/* Retourne le plus proche commun ancetre des cellules de la liste (argc, argv) + dont le niveau est > d, ou -1 s'il n'existe pas. + Utilise le champ "flags". + +*/ +/* ==================================== */ +#undef F_NAME +#define F_NAME "LowestCommonAncestor" +{ + int32_t x, i, lca, NoComAnc; + if (argc <= 0) return -1; + if (argc == 1) return argv[0]; + + x = argv[0]; /* index de la premiere cellule */ + do + { + cpct->flags[x] |= LCA1; /* marque LCA1 tous les ancetres de x plus hauts que d */ + x = cpct->pere[x]; + } while ((x != CPCT_ROOT) && (DECODENIV(cpct->comp[x]) > d)); + + for (i = 1; i < argc; i++) /* boucle pour les autres cellules */ + { + x = argv[i]; + NoComAnc = 1; /* pas d'ancetre commun trouve */ + do + { /* remonte les ancetres de x sans depasser d */ + if (cpct->flags[x] & LCA1) /* on a un ancetre commun */ + { + NoComAnc = 0; + cpct->flags[x] |= LCA2; /* on le marque LCA2 */ + break; /* on arrete la remontee (sort du do while) */ + } + else + x = cpct->pere[x]; /* on continue la remontee */ + } while ((x != CPCT_ROOT) && (DECODENIV(cpct->comp[x]) > d)); + if (NoComAnc) break; /* pas d'AC: on sort aussi du for */ + } /* for (i = 1; i < argc; i++) */ + + x = argv[0]; /* index de la premiere cellule */ + do + { /* derniere remontee: demarque et repere le lca */ + if (cpct->flags[x] & LCA2) lca = x; + cpct->flags[x] &= ~LCA; + x = cpct->pere[x]; + } while ((x != CPCT_ROOT) && (DECODENIV(cpct->comp[x]) > d)); + + for (i = 1; i < argc; i++) /* boucle pour les autres cellules */ + { + x = argv[i]; + do + { cpct->flags[x] &= ~LCA; + x = cpct->pere[x]; /* on continue la remontee */ + } while ((x != CPCT_ROOT) && (DECODENIV(cpct->comp[x]) > d)); + } /* for (i = 1; i < argc; i++) */ + +#ifdef DEBUGLCA +printf("%s(", F_NAME); +for (i = 0; i < argc; i++) printf(" %d ", argv[i]); +printf(") -> "); +if (NoComAnc) printf("NIL\n"); else printf("%d\n", lca); +#endif + + if (NoComAnc) /* pas d'ancetre commun */ + return -1; + else + return lca; +} /* LowestCommonAncestor() */ + +/* ==================================== */ +static int32_t LowComAnc( + CompactTree * cpct, + int32_t c1, + int32_t c2) +/* Retourne le plus proche commun ancetre des cellules c1,c2 + Utilise le champ "flags". +*/ +/* ==================================== */ +#undef F_NAME +#define F_NAME "LowComAnc" +{ + int32_t x, i, lca = -1; + + x = c1; do + { + cpct->flags[x] |= LCA1; /* marque LCA1 tous les ancetres de x */ + x = cpct->pere[x]; + } while (x != CPCT_ROOT); + cpct->flags[x] |= LCA1; /* marque aussi la racine */ + + x = c2; do + { /* remonte les ancetres de x */ + if (cpct->flags[x] & LCA1) { lca = x; break; } + x = cpct->pere[x]; + } while (x != CPCT_ROOT); + if ((lca == -1) && (cpct->flags[x] & LCA1)) lca = x; + + x = c1; do + { /* derniere remontee: demarque */ + cpct->flags[x] &= ~LCA1; + x = cpct->pere[x]; + } while (x != CPCT_ROOT); + cpct->flags[x] &= ~LCA1; /* demarque aussi la racine */ +#ifdef PARANO + if (lca == -1) + { + fprintf(stderr, "%s: lca not found\n", F_NAME); + exit(0); + } +#endif + return lca; +} /* LowComAnc() */ + +/* ==================================== */ +static int32_t Ancestor(CompactTree * cpct, int32_t c1, int32_t c2) +/* Teste si la composante c1 est ancetre de la composante c2 +*/ +/* ==================================== */ +{ + do + { + if (c1 == c2) return 1; + c2 = cpct->pere[c2]; + } while (c2 != CPCT_ROOT); + return 0; +} /* Ancestor() */ +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> Index: abraham/tests/morpho/ref/src/lib/mcimage.c --- abraham/tests/morpho/ref/src/lib/mcimage.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mcimage.c (revision 0) @@ -0,0 +1,2219 @@ +/* $Id: mcimage.c,v 1.22 2006/02/28 07:49:16 michel Exp $ */ +/* + Librairie mcimage : + + fonctions pour les entrees/sorties fichiers et l'allocation de structures + image en memoire. + + Michel Couprie 1996 + + Avertissement: la lecture des fichiers PGM en 65535 ndg (ascii) provoque un sous-echantillonage + a 256 ndg. A MODIFIER. + + Update septembre 2000 : lecture de fichiers BMP truecolor + Update octobre 2000 : ecriture de fichiers BMP truecolor + Update janvier 2002 : lecture d'elements structurants (readse) + Update mars 2002 : nettoie la gestion des noms + Update decembre 2002 : type FLOAT + Update decembre 2002 : convertgen + Update avril 2003 : convertfloat + Update janvier 2006 : adoption des nouveaux "magic numbers" pour + les formats byte 3d, idem 2d (P2 et P5) + P7 (raw 3d) est conservé pour la compatibilité +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <mcutil.h> +#include <mcimage.h> +#include <mccodimage.h> + +#define BUFFERSIZE 10000 + +/* +#define VERBOSE +*/ + +/* ==================================== */ +struct xvimage *allocimage( + char * name, + int32_t rs, /* row size */ + int32_t cs, /* col size */ + int32_t d, /* depth */ + int32_t t) /* data type */ +/* ==================================== */ +#undef F_NAME +#define F_NAME "allocimage" +{ + int32_t N = rs * cs * d; /* taille image */ + struct xvimage *g; + int32_t ts; /* type size */ + + switch (t) + { + case VFF_TYP_BIT: ts = 1; break; + case VFF_TYP_1_BYTE: ts = 1; break; + case VFF_TYP_2_BYTE: ts = 2; break; + case VFF_TYP_4_BYTE: ts = 4; break; + case VFF_TYP_FLOAT: ts = sizeof(float); break; + case VFF_TYP_COMPLEX: ts = 2 * sizeof(float); break; + case VFF_TYP_DOUBLE: ts = sizeof(double); break; + case VFF_TYP_DCOMPLEX: ts = 2 * sizeof(double); break; + default: fprintf(stderr,"%s() : bad data type %d\n", F_NAME, t); + return NULL; + } /* switch (t) */ + + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1 + (N * ts)); + if (g == NULL) + { fprintf(stderr,"%s() : malloc failed (%d bytes)\n", F_NAME, sizeof(struct xvimage) - 1 + (N * ts)); + return NULL; + } + if (name != NULL) + { + g->name = (char *)calloc(1,strlen(name)+1); + if (g->name == NULL) + { fprintf(stderr,"%s() : malloc failed for name\n", F_NAME); + return NULL; + } + strcpy((char *)(g->name), name); + } + else + g->name = NULL; + + rowsize(g) = rs; + colsize(g) = cs; + depth(g) = d; + datatype(g) = t; + g->xdim = g->ydim = g->zdim = 0.0; + + return g; +} /* allocimage() */ + +/* ==================================== */ +void razimage(struct xvimage *f) +/* ==================================== */ +#undef F_NAME +#define F_NAME "razimage" +{ + int32_t rs = rowsize(f); /* taille ligne */ + int32_t cs = colsize(f); /* taille colonne */ + int32_t ds = depth(f); /* nb plans */ + int32_t N = rs * cs * ds; /* taille image */ + int32_t ts; + u_int8_t *F = UCHARDATA(f); + + switch(datatype(f)) + { + case VFF_TYP_BIT: ts = 1; break; + case VFF_TYP_1_BYTE: ts = 1; break; + case VFF_TYP_2_BYTE: ts = 2; break; + case VFF_TYP_4_BYTE: ts = 4; break; + case VFF_TYP_FLOAT: ts = sizeof(float); break; + case VFF_TYP_COMPLEX: ts = 2 * sizeof(float); break; + case VFF_TYP_DOUBLE: ts = sizeof(double); break; + case VFF_TYP_DCOMPLEX: ts = 2 * sizeof(double); break; + default: fprintf(stderr,"%s() : bad data type %d\n", F_NAME, datatype(f)); + return; + } /* switch (t) */ + memset(F, 0, N*ts); +} /* razimage() */ + +/* ==================================== */ +struct xvimage *allocheader( + char * name, + int32_t rs, /* row size */ + int32_t cs, /* col size */ + int32_t d, /* depth */ + int32_t t) /* data type */ +/* ==================================== */ +#undef F_NAME +#define F_NAME "allocheader" +{ + struct xvimage *g; + + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1); + if (g == NULL) + { fprintf(stderr,"%s() : malloc failed\n", F_NAME); + return NULL; + } + if (name != NULL) + { + g->name = (char *)calloc(1,strlen(name)+1); + if (g->name == NULL) + { fprintf(stderr,"%s() : malloc failed for name\n", F_NAME); + return NULL; + } + strcpy((char *)(g->name), name); + } + else + g->name = NULL; + + rowsize(g) = rs; + colsize(g) = cs; + depth(g) = d; + datatype(g) = t; + g->xdim = g->ydim = g->zdim = 0.0; + + return g; +} /* allocheader() */ + +/* ==================================== */ +int32_t showheader(char * name) +/* ==================================== */ +#undef F_NAME +#define F_NAME "showheader" +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, d, c; + char *read; +#ifdef UNIXIO + fd = fopen(name,"r"); +#endif +#ifdef DOSIO + fd = fopen(name,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, name); + return 0; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (buffer[0] != 'P') + { + fprintf(stderr,"%s : invalid image format : %c%c\n", F_NAME, buffer[0], buffer[1]); + return 0; + } + switch (buffer[1]) + { + case '2': printf("type : P%c (ascii byte)\n", buffer[1]); break; + case '3': printf("type : P%c (ascii byte rgb)\n", buffer[1]); break; + case '5': printf("type : P%c (raw byte)\n", buffer[1]); break; + case '6': printf("type : P%c (raw byte rgb)\n", buffer[1]); break; + case '7': printf("type : P%c (raw byte 3d - ext. MC [OBSOLETE - USE P5])\n", buffer[1]); break; + case '8': printf("type : P%c (raw int32_t - ext. MC)\n", buffer[1]); break; + case '9': printf("type : P%c (raw float - ext. MC)\n", buffer[1]); break; + case 'A': printf("type : P%c (ascii float - ext. LN)\n", buffer[1]); break; + case 'B': printf("type : P%c (ascii int32_t - ext. MC)\n", buffer[1]); break; + break; + default: + fprintf(stderr,"%s : invalid image format : P%c\n", F_NAME, buffer[1]); + return 0; + } /* switch */ + + do + { + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (buffer[0] == '#') /* commentaire */ + printf("comment : %s", buffer+1); + } while (!isdigit(buffer[0])); + + c = sscanf(buffer, "%d %d %d", &rs, &cs, &d); + if (c == 2) printf("size : rowsize = %d ; colsize = %d\n", rs, cs); + else if (c == 3) printf("size : rowsize = %d ; colsize = %d ; depth = %d\n", rs, cs, d); + else + { + fprintf(stderr,"%s : invalid image format : cannot find image size\n", F_NAME); + return 0; + } + + fclose(fd); + return 1; +} // showheader() + +/* ==================================== */ +void freeimage(struct xvimage *image) +/* ==================================== */ +{ + free(image); +} + +/* ==================================== */ +struct xvimage *copyimage(struct xvimage *f) +/* ==================================== */ +#undef F_NAME +#define F_NAME "copyimage" +{ + int32_t rs = rowsize(f); /* taille ligne */ + int32_t cs = colsize(f); /* taille colonne */ + int32_t d = depth(f); /* nb plans */ + int32_t N = rs * cs * d; /* taille image */ + struct xvimage *g; + + switch(datatype(f)) + { + case VFF_TYP_1_BYTE: + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1 + (N*sizeof(char))); + if (g == NULL) + { + fprintf(stderr,"%s() : malloc failed (%d bytes)\n", F_NAME, sizeof(struct xvimage) - 1 + (N*sizeof(char))); + return NULL; + } + memcpy((void *)g, (void *)f, sizeof(struct xvimage) - 1 + (N*sizeof(char))); + break; + case VFF_TYP_4_BYTE: + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1 + (N*sizeof(int32_t))); + if (g == NULL) + { + fprintf(stderr,"%s() : malloc failed (%d bytes)\n", F_NAME, sizeof(struct xvimage) - 1 + (N*sizeof(int32_t))); + return NULL; + } + memcpy((void *)g, (void *)f, sizeof(struct xvimage) - 1 + (N*sizeof(int32_t))); + break; + case VFF_TYP_FLOAT: + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1 + (N*sizeof(float))); + if (g == NULL) + { + fprintf(stderr,"%s() : malloc failed (%d bytes)\n", F_NAME, sizeof(struct xvimage) - 1 + (N*sizeof(float))); + return NULL; + } + memcpy((void *)g, (void *)f, sizeof(struct xvimage) - 1 + (N*sizeof(float))); + break; + case VFF_TYP_DOUBLE: + g = (struct xvimage *)calloc(1,sizeof(struct xvimage) - 1 + (N*sizeof(double))); + if (g == NULL) + { + fprintf(stderr,"%s() : malloc failed (%d bytes)\n", F_NAME, sizeof(struct xvimage) - 1 + (N*sizeof(double))); + return NULL; + } + memcpy((void *)g, (void *)f, sizeof(struct xvimage) - 1 + (N*sizeof(double))); + break; + default: + fprintf(stderr,"%s() : bad data type %d\n", F_NAME, datatype(f)); + return NULL; + } /* switch(f->datatype) */ + + if (f->name != NULL) + { + g->name = (char *)calloc(1,strlen(f->name) + 1); + if (g->name == NULL) + { fprintf(stderr,"%s() : malloc failed for name\n", F_NAME); + return NULL; + } + strcpy(g->name, f->name); + } + return g; +} // copyimage() + +/* ==================================== */ +int32_t copy2image(struct xvimage *dest, struct xvimage *source) +/* ==================================== */ +#undef F_NAME +#define F_NAME "copy2image" +{ + int32_t rs = rowsize(source); /* taille ligne */ + int32_t cs = colsize(source); /* taille colonne */ + int32_t ds = depth(source); /* nb plans */ + int32_t N = rs * cs * ds; /* taille image */ + if ((rowsize(dest) != rs) || (colsize(dest) != cs) || (depth(dest) != ds)) + { + fprintf(stderr, "%s: incompatible image sizes\n", F_NAME); + return 0; + } + if (datatype(dest) != datatype(source)) + { + fprintf(stderr, "%s: incompatible image types\n", F_NAME); + return 0; + } + switch(datatype(source)) + { + case VFF_TYP_1_BYTE: + { + u_int8_t *S = UCHARDATA(source); + u_int8_t *D = UCHARDATA(dest); + memcpy(D, S, N*sizeof(char)); + break; + } + case VFF_TYP_4_BYTE: + { + u_int32_t *S = ULONGDATA(source); + u_int32_t *D = ULONGDATA(dest); + memcpy(D, S, N*sizeof(int32_t)); + break; + } + case VFF_TYP_FLOAT: + { + float *S = FLOATDATA(source); + float *D = FLOATDATA(dest); + memcpy(D, S, N*sizeof(float)); + break; + } + case VFF_TYP_DOUBLE: + { + double *S = DOUBLEDATA(source); + double *D = DOUBLEDATA(dest); + memcpy(D, S, N*sizeof(double)); + break; + } + default: + fprintf(stderr,"%s() : bad data type %d\n", F_NAME, datatype(source)); + return 0; + } /* switch(f->datatype) */ + return 1; +} // copy2image() + +/* ==================================== */ +int32_t equalimages(struct xvimage *im1, struct xvimage *im2) +/* ==================================== */ +// checks whether the two images are equal +#undef F_NAME +#define F_NAME "equalimages" +{ + int32_t rs = rowsize(im1); /* taille ligne */ + int32_t cs = colsize(im1); /* taille colonne */ + int32_t ds = depth(im1); /* nb plans */ + int32_t N = rs * cs * ds; /* taille image */ + if ((rowsize(im2) != rs) || (colsize(im2) != cs) || (depth(im2) != ds)) return 0; + if (datatype(im2) != datatype(im1)) return 0; + switch(datatype(im1)) + { + case VFF_TYP_1_BYTE: + { + u_int8_t *I1 = UCHARDATA(im1); + u_int8_t *I2 = UCHARDATA(im2); + if (memcmp(I1, I2, N*sizeof(char)) != 0) return 0; + break; + } + case VFF_TYP_4_BYTE: + { + u_int32_t *I1 = ULONGDATA(im1); + u_int32_t *I2 = ULONGDATA(im2); + if (memcmp(I1, I2, N*sizeof(int32_t)) != 0) return 0; + break; + } + case VFF_TYP_FLOAT: + { + float *I1 = FLOATDATA(im1); + float *I2 = FLOATDATA(im2); + if (memcmp(I1, I2, N*sizeof(float)) != 0) return 0; + break; + } + case VFF_TYP_DOUBLE: + { + double *I1 = DOUBLEDATA(im1); + double *I2 = DOUBLEDATA(im2); + if (memcmp(I1, I2, N*sizeof(double)) != 0) return 0; + break; + } + } /* switch(f->datatype) */ + return 1; +} // equalimages() + +/* ==================================== */ +int32_t convertgen(struct xvimage **f1, struct xvimage **f2) +/* ==================================== */ +// Converts the images f1, f2 to the type of the most general one. +// Returns the code of the chosen type. +#undef F_NAME +#define F_NAME "convertgen" +{ + struct xvimage *im1 = *f1; + struct xvimage *im2 = *f2; + struct xvimage *im3; + int32_t type1 = datatype(im1); + int32_t type2 = datatype(im2); + int32_t type, typemax = max(type1,type2); + + if (type1 == type2) return type1; + if (type1 < type2) { im1 = *f2; im2 = *f1; } // im1 : rien a changer + // il faut convertir 'im2' a 'typemax' + type = datatype(im2); + if (type == VFF_TYP_1_BYTE) + { + int32_t i, rs=rowsize(im2), cs=colsize(im2), ds=depth(im2), N=rs*cs*ds; + u_int8_t *F = UCHARDATA(im2); + im3 = allocimage(NULL, rs, cs, ds, typemax); + if (im3 == NULL) + { + fprintf(stderr,"%s() : allocimage failed\n", F_NAME); + return 0; + } + if (typemax == VFF_TYP_4_BYTE) + { + u_int32_t *L = ULONGDATA(im3); + for (i = 0; i < N; i++) L[i] = (u_int32_t)F[i]; + } + else if (typemax == VFF_TYP_FLOAT) + { + float *FL = FLOATDATA(im3); + for (i = 0; i < N; i++) FL[i] = (float)F[i]; + } + else + { + fprintf(stderr,"%s() : bad data type\n", F_NAME); + return 0; + } + } + else if (type == VFF_TYP_4_BYTE) + { + int32_t i, rs=rowsize(im2), cs=colsize(im2), ds=depth(im2), N=rs*cs*ds; + u_int32_t *L = ULONGDATA(im2); + im3 = allocimage(NULL, rs, cs, ds, typemax); + if (im3 == NULL) + { + fprintf(stderr,"%s() : allocimage failed\n", F_NAME); + return 0; + } + if (typemax == VFF_TYP_FLOAT) + { + float *FL = FLOATDATA(im3); + for (i = 0; i < N; i++) FL[i] = (float)L[i]; + } + else + { + fprintf(stderr,"%s() : bad data type\n", F_NAME); + return 0; + } + } + else + { + fprintf(stderr,"%s() : bad data type\n", F_NAME); + return 0; + } + + if (type1 < type2) *f1 = im3; else *f2 = im3; + freeimage(im2); + return typemax; +} // convertgen() + +/* ==================================== */ +int32_t convertlong(struct xvimage **f1) +/* ==================================== */ +// Converts the image f1 to int32_t. +#undef F_NAME +#define F_NAME "convertlong" +{ + struct xvimage *im1 = *f1; + struct xvimage *im3; + int32_t type = datatype(im1); + int32_t i, rs=rowsize(im1), cs=colsize(im1), ds=depth(im1), N=rs*cs*ds; + u_int32_t *FL; + + if (type == VFF_TYP_4_BYTE) return 1; + + im3 = allocimage(NULL, rs, cs, ds, VFF_TYP_4_BYTE); + if (im3 == NULL) + { + fprintf(stderr,"%s() : allocimage failed\n", F_NAME); + return 0; + } + FL = ULONGDATA(im3); + + if (type == VFF_TYP_1_BYTE) + { + u_int8_t *F = UCHARDATA(im1); + for (i = 0; i < N; i++) FL[i] = (u_int32_t)F[i]; + } + else if (type == VFF_TYP_FLOAT) + { + float *F = FLOATDATA(im1); + for (i = 0; i < N; i++) FL[i] = (u_int32_t)F[i]; + } + else + { + fprintf(stderr,"%s() : bad data type\n", F_NAME); + return 0; + } + + *f1 = im3; + return 1; +} // convertlong() + +/* ==================================== */ +int32_t convertfloat(struct xvimage **f1) +/* ==================================== */ +// Converts the image f1 to float. +#undef F_NAME +#define F_NAME "convertfloat" +{ + struct xvimage *im1 = *f1; + struct xvimage *im3; + int32_t type = datatype(im1); + int32_t i, rs=rowsize(im1), cs=colsize(im1), ds=depth(im1), N=rs*cs*ds; + float *FL; + + if (type == VFF_TYP_FLOAT) return 1; + + im3 = allocimage(NULL, rs, cs, ds, VFF_TYP_FLOAT); + if (im3 == NULL) + { + fprintf(stderr,"%s() : allocimage failed\n", F_NAME); + return 0; + } + FL = FLOATDATA(im3); + + if (type == VFF_TYP_1_BYTE) + { + u_int8_t *F = UCHARDATA(im1); + for (i = 0; i < N; i++) FL[i] = (float)F[i]; + } + else if (type == VFF_TYP_4_BYTE) + { + u_int32_t *F = ULONGDATA(im1); + for (i = 0; i < N; i++) FL[i] = (float)F[i]; + } + else + { + fprintf(stderr,"%s() : bad data type\n", F_NAME); + return 0; + } + + *f1 = im3; + return 1; +} // convertfloat() + +/* ==================================== */ +void list2image(struct xvimage * image, double *P, int32_t n) +/* ==================================== */ +#undef F_NAME +#define F_NAME "list2image" +{ + int32_t rs, cs, ds, ps, N, x, y, z, i; + u_int8_t *F; + + rs = rowsize(image); + cs = colsize(image); + ds = depth(image); + ps = rs * cs; + N = ps * ds; + F = UCHARDATA(image); + if (ds == 1) // 2D + { + for (i = 0; i < n; i++) + { + x = arrondi(P[2*i]); y = arrondi(P[2*i + 1]); + if ((x >= 0) && (x < rs) && (y >= 0) && (y < cs)) + F[y * rs + x] = NDG_MAX; + } + } + else // 3D + { + for (i = 0; i < n; i++) + { + x = arrondi(P[3*i]); + y = arrondi(P[3*i + 1]); + z = arrondi(P[3*i + 2]); + if ((x >= 0) && (x < rs) && (y >= 0) && (y < cs) && (z >= 0) && (z < ds)) + F[z*ps + y*rs + x] = NDG_MAX; + } + } +} // list2image() + +/* ==================================== */ +double * image2list(struct xvimage * image, int32_t *n) +/* ==================================== */ +#undef F_NAME +#define F_NAME "image2list" +{ + int32_t rs, cs, ds, ps, N, x, y, z; + u_int8_t *F; + int32_t n1; + double * P1; + + rs = rowsize(image); + cs = colsize(image); + ds = depth(image); + ps = rs * cs; + N = ps * ds; + F = UCHARDATA(image); + n1 = 0; /* compte le nombre de points non nuls pour image1 */ + for (x = 0; x < N; x++) if (F[x]) n1++; + if (ds == 1) // 2D + { + P1 = (double *)calloc(1, n1 * 2 * sizeof(double)); + if (P1 == NULL) + { + fprintf(stderr,"%s() : malloc failed for P1\n", F_NAME); + return NULL; + } + n1 = 0; + for (y = 0; y < cs; y++) + for (x = 0; x < rs; x++) + if (F[y * rs + x]) { P1[2*n1] = (double)x; P1[2*n1 + 1] = (double)y; n1++; } + } + else // 3D + { + P1 = (double *)calloc(1, n1 * 3 * sizeof(double)); + if (P1 == NULL) + { + fprintf(stderr,"%s() : malloc failed for P1\n", F_NAME); + return NULL; + } + n1 = 0; + for (z = 0; z < ds; z++) + for (y = 0; y < cs; y++) + for (x = 0; x < rs; x++) + if (F[z*ps + y*rs + x]) + { + P1[3*n1] = (double)x; + P1[3*n1 + 1] = (double)y; + P1[3*n1 + 2] = (double)z; + n1++; + } + } + *n = n1; + return P1; +} // image2list() + +/* ==================================== */ +void writeimage(struct xvimage * image, char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writeimage" +{ + int32_t rs, cs, ds; + rs = rowsize(image); + cs = colsize(image); + ds = depth(image); + if ((rs<=25) && (cs<=25) && (ds<=25) && + ((datatype(image) == VFF_TYP_1_BYTE) || (datatype(image) == VFF_TYP_4_BYTE) || + (datatype(image) == VFF_TYP_FLOAT))) + writeascimage(image, filename); + else + writerawimage(image, filename); +} /* writeimage() */ + +/* ==================================== */ +void writerawimage(struct xvimage * image, char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writerawimage" +{ + FILE *fd = NULL; + int32_t rs, cs, d, N, i, ret; + + rs = rowsize(image); + cs = colsize(image); + d = depth(image); + N = rs * cs * d; + +#ifdef UNIXIO + fd = fopen(filename,"w"); +#endif +#ifdef DOSIO + fd = fopen(filename,"wb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + if (datatype(image) == VFF_TYP_1_BYTE) + { + fputs("P5\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if ((image->xdim != 0.0) && (d == 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n", image->xdim, image->ydim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "255\n"); + + ret = fwrite(UCHARDATA(image), sizeof(char), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + } + else if (datatype(image) == VFF_TYP_2_BYTE) + { + fputs("P5\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if ((image->xdim != 0.0) && (d == 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n", image->xdim, image->ydim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "65535\n"); + + ret = fwrite(USHORTDATA(image), 2*sizeof(char), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + } + else if (datatype(image) == VFF_TYP_4_BYTE) + { + fputs("P8\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if ((image->xdim != 0.0) && (d == 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n", image->xdim, image->ydim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "4294967295\n"); + + ret = fwrite(ULONGDATA(image), sizeof(int32_t), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + } + else if (datatype(image) == VFF_TYP_FLOAT) + { + fputs("P9\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if ((image->xdim != 0.0) && (d == 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n", image->xdim, image->ydim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "0\n"); + + ret = fwrite(FLOATDATA(image), sizeof(float), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + } + else + { fprintf(stderr,"%s() : bad datatype : %d\n", F_NAME, datatype(image)); + exit(0); + } + + fclose(fd); +} /* writerawimage() */ + +/* ==================================== */ +void writese(struct xvimage * image, char *filename, int32_t x, int32_t y, int32_t z) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writese" +{ + FILE *fd = NULL; + int32_t rs, cs, d, ps, N, i, ret; + + rs = rowsize(image); + cs = colsize(image); + d = depth(image); + ps = rs * cs; + N = ps * d; + +#ifdef UNIXIO + fd = fopen(filename,"w"); +#endif +#ifdef DOSIO + fd = fopen(filename,"wb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + if (datatype(image) == VFF_TYP_1_BYTE) + { + if (d > 1) + { + if ((rs<=25) && (cs<=25) && (d<=25)) fputs("P2\n", fd); else fputs("P5\n", fd); + fprintf(fd, "#origin %d %d %d\n", x, y, z); + } + else + { + if ((rs<=25) && (cs<=25) && (d<=25)) fputs("P2\n", fd); else fputs("P5\n", fd); + fprintf(fd, "#origin %d %d\n", x, y); + } + /* fputs("# CREATOR: writese by MC - 07/1996\n", fd); */ + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "255\n"); + + if ((rs<=25) && (cs<=25) && (d<=25)) + { + for (i = 0; i < N; i++) + { + if (i % rs == 0) fprintf(fd, "\n"); + if (i % ps == 0) fprintf(fd, "\n"); + fprintf(fd, "%3d ", (int32_t)(image->imagedata[i])); + } /* for i */ + fprintf(fd, "\n"); + } + else + { + ret = fwrite(UCHARDATA(image), sizeof(char), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + } + } + else + { fprintf(stderr,"%s() : bad datatype : %d\n", F_NAME, datatype(image)); + exit(0); + } + + fclose(fd); +} /* writese() */ + +/* ==================================== */ +void writeascimage(struct xvimage * image, char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writeascimage" +{ + FILE *fd = NULL; + int32_t rs, cs, ps, d, nndg, N, i; + + fd = fopen(filename,"w"); + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + rs = rowsize(image); + cs = colsize(image); + d = depth(image); + ps = rs * cs; + N = ps * d; + + if (datatype(image) == VFF_TYP_1_BYTE) + { + fputs("P2\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "255\n"); + + for (i = 0; i < N; i++) + { + if (i % rs == 0) fprintf(fd, "\n"); + if (i % ps == 0) fprintf(fd, "\n"); + fprintf(fd, "%3d ", (int32_t)(image->imagedata[i])); + } /* for i */ + fprintf(fd, "\n"); + } + else if (datatype(image) == VFF_TYP_4_BYTE) + { + fputs("PB\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "4294967295\n"); + + for (i = 0; i < N; i++) + { + if (i % rs == 0) fprintf(fd, "\n"); + if (i % ps == 0) fprintf(fd, "\n"); + fprintf(fd, "%ld ", ULONGDATA(image)[i]); + } /* for i */ + fprintf(fd, "\n"); + } + else if (datatype(image) == VFF_TYP_FLOAT) + { + fputs("PA\n", fd); + if ((image->xdim != 0.0) && (d > 1)) + fprintf(fd, "#xdim %g\n#ydim %g\n#zdim %g\n", image->xdim, image->ydim, image->zdim); + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "1\n"); + + for (i = 0; i < N; i++) + { + if (i % rs == 0) fprintf(fd, "\n"); + if (i % ps == 0) fprintf(fd, "\n"); + fprintf(fd, "%8g ", FLOATDATA(image)[i]); + } /* for i */ + fprintf(fd, "\n"); + } + fclose(fd); +} + +/* ==================================== */ +void printimage(struct xvimage * image) +/* ==================================== */ +#undef F_NAME +#define F_NAME "printimage" +{ + int32_t rs, cs, d, ps, N, i; + + rs = rowsize(image); + cs = colsize(image); + d = depth(image); + ps = rs * cs; + N = ps * d; + + for (i = 0; i < N; i++) + { + if (i % rs == 0) printf("\n"); + if (i % ps == 0) printf("\n"); + printf("%3d ", (int32_t)(image->imagedata[i])); + } /* for i */ + printf("\n"); +} + +/* ==================================== */ +void writergbimage( + struct xvimage * redimage, + struct xvimage * greenimage, + struct xvimage * blueimage, + char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writergbimage" +{ + FILE *fd = NULL; + int32_t rs, cs, nndg, N, i; + +#ifdef UNIXIO + fd = fopen(filename,"w"); +#endif +#ifdef DOSIO + fd = fopen(filename,"wb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + rs = redimage->row_size; + cs = redimage->col_size; + if ((greenimage->row_size != rs) || (greenimage->col_size != cs) || + (blueimage->row_size != rs) || (blueimage->col_size != cs)) + { + fprintf(stderr, "%s: incompatible image sizes\n", F_NAME); + exit(0); + } + + N = rs * cs; + nndg = 255; + + fputs("P6\n", fd); + /* fputs("# CREATOR: writeimage by MC - 07/1996\n", fd); */ + fprintf(fd, "##rgb\n"); + fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "%d\n", nndg); + + for (i = 0; i < N; i++) + { + fputc((int32_t)(redimage->imagedata[i]), fd); + fputc((int32_t)(greenimage->imagedata[i]), fd); + fputc((int32_t)(blueimage->imagedata[i]), fd); + } /* for i */ + + fclose(fd); +} + +/* ==================================== */ +void writelongimage(struct xvimage * image, char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "writelongimage" +/* + obsolete - utiliser maintenant writeimage +*/ +{ + FILE *fd = NULL; + int32_t rs, cs, d, nndg, N, i; + int32_t ret; + +#ifdef UNIXIO + fd = fopen(filename,"w"); +#endif +#ifdef DOSIO + fd = fopen(filename,"wb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + rs = rowsize(image); + cs = colsize(image); + d = depth(image); + N = rs * cs * d; + nndg = 255; + + fputs("P8\n", fd); + /* fputs("# CREATOR: writelongimage by MC - 07/1996\n", fd); */ + if (d > 1) fprintf(fd, "%d %d %d\n", rs, cs, d); else fprintf(fd, "%d %d\n", rs, cs); + fprintf(fd, "%d\n", nndg); + + ret = fwrite(ULONGDATA(image), sizeof(int32_t), N, fd); + if (ret != N) + { + fprintf(stderr, "%s: only %d items written\n", F_NAME, ret); + exit(0); + } + + fclose(fd); +} /* writelongimage() */ + +/* ==================================== */ +struct xvimage * readimage(char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "readimage" +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, d, ndgmax, N, i; + struct xvimage * image; + int32_t ascii; + int32_t typepixel; + int32_t c; + double xdim=1.0, ydim=1.0, zdim=1.0; + char *read; + +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, filename); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); /* P5: raw byte bw ; P2: ascii bw */ + /* P6: raw byte rgb ; P3: ascii rgb */ + /* P8: raw int32_t 2d-3d == extension MC */ + /* P9: raw float 2d-3d == extension MC */ + /* PA: ascii float 2d-3d == extension LN */ + /* PB: ascii int32_t 2d-3d == extension MC */ + + /* P7: raw byte 3d : OBSOLETE - left for compatibility */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + if (buffer[0] != 'P') + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + switch (buffer[1]) + { + case '2': ascii = 1; typepixel = VFF_TYP_1_BYTE; break; + case '5': + case '7': ascii = 0; typepixel = VFF_TYP_1_BYTE; break; + case '8': ascii = 0; typepixel = VFF_TYP_4_BYTE; break; + case '9': ascii = 0; typepixel = VFF_TYP_FLOAT; break; + case 'A': ascii = 1; typepixel = VFF_TYP_FLOAT; break; + case 'B': ascii = 1; typepixel = VFF_TYP_4_BYTE; break; + default: + fprintf(stderr,"%s : invalid image format : P%c\n", F_NAME, buffer[1]); + return NULL; + } /* switch */ + + do + { + read = fgets(buffer, BUFFERSIZE, fd); /* commentaire */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (strncmp(buffer, "#xdim", 5) == 0) + sscanf(buffer+5, "%lf", &xdim); + else if (strncmp(buffer, "#ydim", 5) == 0) + sscanf(buffer+5, "%lf", &ydim); + else if (strncmp(buffer, "#zdim", 5) == 0) + sscanf(buffer+5, "%lf", &zdim); + } while (!isdigit(buffer[0])); + + c = sscanf(buffer, "%d %d %d", &rs, &cs, &d); + if (c == 2) d = 1; + else if (c != 3) + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + sscanf(buffer, "%d", &ndgmax); + N = rs * cs * d; + + image = allocimage(NULL, rs, cs, d, typepixel); + if (image == NULL) + { fprintf(stderr,"%s : alloc failed\n", F_NAME); + return(NULL); + } + image->xdim = xdim; + image->ydim = ydim; + image->zdim = zdim; + + if (typepixel == VFF_TYP_1_BYTE) + { + if (ascii) + { + if (ndgmax == 255) + for (i = 0; i < N; i++) + { + fscanf(fd, "%d", &c); + image->imagedata[i] = (u_int8_t)c; + } /* for i */ + else if (ndgmax == 65535) + for (i = 0; i < N; i++) + { + fscanf(fd, "%d", &c); + image->imagedata[i] = (u_int8_t)(c/256); + } /* for i */ + else + { + fprintf(stderr,"%s : wrong ndgmax = %d\n", F_NAME, ndgmax); + return(NULL); + } + } + else + { + int32_t ret = fread(UCHARDATA(image), sizeof(char), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + } + } /* if (typepixel == VFF_TYP_1_BYTE) */ + else + if (typepixel == VFF_TYP_4_BYTE) + { + if (ascii) + { + for (i = 0; i < N; i++) + { + fscanf(fd, "%ld", &(ULONGDATA(image)[i])); + } /* for i */ + } + else + { + int32_t ret = fread(ULONGDATA(image), sizeof(int32_t), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + } + } /* if (typepixel == VFF_TYP_4_BYTE) */ + else + if (typepixel == VFF_TYP_FLOAT) + { + if (ascii) + { + for (i = 0; i < N; i++) + { + fscanf(fd, "%f", &(FLOATDATA(image)[i])); + } /* for i */ + } + else + { + int32_t ret = fread(FLOATDATA(image), sizeof(float), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + } + } /* if (typepixel == VFF_TYP_FLOAT) */ + + fclose(fd); + + return image; +} /* readimage() */ + +/* ==================================== */ +struct xvimage * readheader(char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "readheader" +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, d, ndgmax, N, i; + struct xvimage * image; + int32_t ascii; + int32_t typepixel; + int32_t c; + double xdim=1.0, ydim=1.0, zdim=1.0; + char *read; + +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, filename); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (buffer[0] != 'P') + { + fprintf(stderr,"%s : invalid image format: %c%c\n", F_NAME, buffer[0], buffer[1]); + return NULL; + } + switch (buffer[1]) + { + case '2': ascii = 1; typepixel = VFF_TYP_1_BYTE; break; + case '5': + case '7': ascii = 0; typepixel = VFF_TYP_1_BYTE; break; + case '8': ascii = 0; typepixel = VFF_TYP_4_BYTE; break; + case '9': ascii = 0; typepixel = VFF_TYP_FLOAT; break; + case 'A': ascii = 1; typepixel = VFF_TYP_FLOAT; break; + case 'B': ascii = 1; typepixel = VFF_TYP_4_BYTE; break; + default: + fprintf(stderr,"%s : invalid image format: %c%c\n", F_NAME, buffer[0], buffer[1]); + return NULL; + } /* switch */ + + do + { + read = fgets(buffer, BUFFERSIZE, fd); /* commentaire */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (strncmp(buffer, "#xdim", 5) == 0) + sscanf(buffer+5, "%lf", &xdim); + else if (strncmp(buffer, "#ydim", 5) == 0) + sscanf(buffer+5, "%lf", &ydim); + else if (strncmp(buffer, "#zdim", 5) == 0) + sscanf(buffer+5, "%lf", &zdim); + } while (!isdigit(buffer[0])); + + c = sscanf(buffer, "%d %d %d", &rs, &cs, &d); + if (c == 2) d = 1; + else if (c != 3) + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + sscanf(buffer, "%d", &ndgmax); + + image = allocheader(NULL, rs, cs, d, typepixel); + if (image == NULL) + { fprintf(stderr,"%s : alloc failed\n", F_NAME); + return(NULL); + } + image->xdim = xdim; + image->ydim = ydim; + image->zdim = zdim; + + fclose(fd); + + return image; +} /* readheader() */ + +/* ==================================== */ +struct xvimage * readse(char *filename, int32_t *x, int32_t *y, int32_t*z) +/* ==================================== */ +#undef F_NAME +#define F_NAME "readse" +/* +Specialisation de readimage pour les elements structurants. +L'origine est donnee dans le fichier pgm par une ligne de commentaire +de la forme : +#origin x y [z] +*/ +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, d, ndgmax, N, i; + struct xvimage * image; + int32_t ascii; + int32_t typepixel; + int32_t c; + int32_t dimorigin = 0; + char *read; + +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, filename); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (buffer[0] != 'P') + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + switch (buffer[1]) + { + case '2': ascii = 1; typepixel = VFF_TYP_1_BYTE; break; + case '5': + case '7': ascii = 0; typepixel = VFF_TYP_1_BYTE; break; + default: + fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } /* switch */ + + do + { + read = fgets(buffer, BUFFERSIZE, fd); /* commentaire */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (strncmp(buffer, "#origin", 7) == 0) + { + dimorigin = sscanf(buffer+7, "%d %d %d", x, y, z); +#ifdef VERBOSE + if (dimorigin == 2) fprintf(stderr, "%s: origin %d %d\n", F_NAME, *x, *y); + if (dimorigin == 3) fprintf(stderr, "%s: origin %d %d %d\n", F_NAME, *x, *y, *z); +#endif + } + } while (buffer[0] == '#'); + + if (!dimorigin) + { fprintf(stderr,"%s : origin missing for structuring element\n", F_NAME); + return NULL; + } + + c = sscanf(buffer, "%d %d %d", &rs, &cs, &d); + if (c != dimorigin) + { fprintf(stderr,"%s : incompatible origin and image dimensions\n", F_NAME); + return NULL; + } + if (c == 2) d = 1; + else if (c != 3) + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + sscanf(buffer, "%d", &ndgmax); + N = rs * cs * d; + + image = allocimage(NULL, rs, cs, d, typepixel); + if (image == NULL) + { fprintf(stderr,"%s : alloc failed\n", F_NAME); + return(NULL); + } + + if (typepixel == VFF_TYP_1_BYTE) + { + if (ascii) + { + if (ndgmax == 255) + for (i = 0; i < N; i++) + { + fscanf(fd, "%d", &c); + image->imagedata[i] = (u_int8_t)c; + } /* for i */ + else if (ndgmax == 65535) + for (i = 0; i < N; i++) + { + fscanf(fd, "%d", &c); + image->imagedata[i] = (u_int8_t)(c/256); + } /* for i */ + else + { fprintf(stderr,"%s : wrong ndgmax = %d\n", F_NAME, ndgmax); + return(NULL); + } + } + else + { + int32_t ret = fread(UCHARDATA(image), sizeof(char), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + } + } /* if (typepixel == VFF_TYP_1_BYTE) */ + else + if (typepixel == VFF_TYP_4_BYTE) + { + int32_t ret = fread(ULONGDATA(image), sizeof(int32_t), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + } /* if (typepixel == VFF_TYP_4_BYTE) */ + + fclose(fd); + + return image; +} /* readse() */ + +/* ==================================== */ +int32_t readrgbimage( + char *filename, + struct xvimage ** r, + struct xvimage ** g, + struct xvimage ** b) +/* ==================================== */ +#undef F_NAME +#define F_NAME "readrgbimage" +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, nndg, N, i; + int32_t ascii = 0; + int32_t c; + char *read; + +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, filename); + return 0; + } + + read = fgets(buffer, BUFFERSIZE, fd); /* P5: raw int32_t bw ; P2: ascii bw */ + /* P6: raw int32_t rgb ; P3: ascii rgb */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + if (buffer[0] != 'P') + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return 0; + } + + switch (buffer[1]) + { + case '3': ascii = 1; break; + case '6': ascii = 0; break; + default: + fprintf(stderr,"%s : invalid image format\n", F_NAME); + return 0; + } /* switch */ + + do + { + read = fgets(buffer, BUFFERSIZE, fd); /* commentaire */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + } while (!isdigit(buffer[0])); + + c = sscanf(buffer, "%d %d", &rs, &cs); + if (c != 2) + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return 0; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + sscanf(buffer, "%d", &nndg); + N = rs * cs; + + *r = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *g = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *b = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + if ((*r == NULL) && (*g == NULL) && (*b == NULL)) + { fprintf(stderr,"%s : allocimage failed\n", F_NAME); + return(0); + } + + if (ascii) + for (i = 0; i < N; i++) + { + fscanf(fd, "%d", &c); + (*r)->imagedata[i] = (u_int8_t)c; + fscanf(fd, "%d", &c); + (*g)->imagedata[i] = (u_int8_t)c; + fscanf(fd, "%d", &c); + (*b)->imagedata[i] = (u_int8_t)c; + } /* for i */ + else + for (i = 0; i < N; i++) + { + (*r)->imagedata[i] = fgetc(fd); + (*g)->imagedata[i] = fgetc(fd); + (*b)->imagedata[i] = fgetc(fd); + } /* for i */ + + fclose(fd); + return 1; +} /* readrgbimage() */ + +/* ==================================== */ +struct xvimage * readlongimage(char *filename) +/* ==================================== */ +#undef F_NAME +#define F_NAME "readlongimage" +/* + obsolete - utiliser maintenant readimage +*/ +{ + char buffer[BUFFERSIZE]; + FILE *fd = NULL; + int32_t rs, cs, d, nndg, N, i; + struct xvimage * image; + int32_t c, ret; + char *read; + +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif + if (!fd) + { + fprintf(stderr, "%s: file not found: %s\n", F_NAME, filename); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); /* P8: raw int32_t 3d == extension MC */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + if ((buffer[0] != 'P') || (buffer[1] != '8')) + { fprintf(stderr,"%s : invalid image format\n", F_NAME); + return NULL; + } + + do + { + read = fgets(buffer, BUFFERSIZE, fd); /* commentaire */ + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + } while (buffer[0] == '#'); + + c = sscanf(buffer, "%d %d %d", &rs, &cs, &d); + if (c == 2) d = 1; + else if (c != 3) + { fprintf(stderr,"%s : invalid image format - c = %d \n", F_NAME, c); + return NULL; + } + + read = fgets(buffer, BUFFERSIZE, fd); + if (!read) + { + fprintf(stderr, "%s: fgets returned without reading\n", F_NAME); + return 0; + } + + sscanf(buffer, "%d", &nndg); + N = rs * cs * d; + + image = allocimage(NULL, rs, cs, d, VFF_TYP_4_BYTE); + if (image == NULL) + { fprintf(stderr,"%s : alloc failed\n", F_NAME); + return(NULL); + } + + ret = fread(ULONGDATA(image), sizeof(int32_t), N, fd); + if (ret != N) + { + fprintf(stderr,"%s : fread failed : %d asked ; %d read\n", F_NAME, N, ret); + return(NULL); + } + + fclose(fd); + return image; +} /* readlongimage() */ + +/* =========================================================================== */ +/* =========================================================================== */ +/* BMP files */ +/* =========================================================================== */ +/* =========================================================================== */ + +struct BITMAPFILEHEADER { /* size 14 bytes */ + char Signature[2]; /* size 2 bytes : 'BM' */ + u_int32_t FileSize; /* size 4 bytes : File size in bytes */ + u_int32_t reserved; /* size 4 bytes : unused (=0) */ + u_int32_t DataOffset; /* size 4 bytes : File offset to Raster Data */ +}; + +struct BITMAPINFOHEADER { /* size 40 bytes */ + u_int32_t Size; /* size 4 bytes : Size of InfoHeader =40 */ + u_int32_t Width; /* size 4 bytes : Bitmap Width */ + u_int32_t Height; /* size 4 bytes : Bitmap Height */ + u_int16_t Planes; /* size 2 bytes : Number of Planes (=1) */ + u_int16_t BitCount; /* size 2 bytes : Bits per Pixel */ + /* 1 = monochrome palette. NumColors = 1 + 4 = 4bit palletized. NumColors = 16 + 8 = 8bit palletized. NumColors = 256 + 16 = 16bit RGB. NumColors = 65536 (?) + 24 = 24bit RGB. NumColors = 16M + */ + u_int32_t Compression; /* size 4 bytes : Type of Compression */ + /* + 0 = BI_RGB no compression + 1 = BI_RLE8 8bit RLE encoding + 2 = BI_RLE4 4bit RLE encoding + */ + u_int32_t ImageSize; /* size 4 bytes : (compressed) Size of Image */ + /* It is valid to set this =0 if Compression = 0 */ + u_int32_t XpixelsPerM; /* size 4 bytes : horizontal resolution: Pixels/meter */ + u_int32_t YpixelsPerM; /* size 4 bytes : vertical resolution: Pixels/meter */ + u_int32_t ColorsUsed; /* size 4 bytes : Number of actually used colors */ + u_int32_t ColorsImportant; /* size 4 bytes : Number of important colors (0 = all) */ +}; + +/* + ColorTable + 4 * NumColors bytes + present only if Info.BitsPerPixel <= 8 + colors should be ordered by importance + + Red + 1 byte + Red intensity + Green + 1 byte + Green intensity + Blue + 1 byte + Blue intensity + reserved + 1 byte + unused (=0) + repeated NumColors times + + Raster Data + Info.ImageSize bytes + The pixel data + +Raster Data encoding + + Depending on the image's BitCount and on the Compression flag + there are 6 different encoding schemes. All of them share the + following: + + Pixels are stored bottom-up, left-to-right. Pixel lines are + padded with zeros to end on a 32bit (4byte) boundary. For + uncompressed formats every line will have the same number of bytes. + Color indices are zero based, meaning a pixel color of 0 + represents the first color table entry, a pixel color of 255 + (if there are that many) represents the 256th entry. For images with more + than 256 colors there is no color table. + + + Raster Data encoding for 1bit / black & white images + + BitCount = 1 Compression = 0 + Every byte holds 8 pixels, its highest order bit representing + the leftmost pixel of those. There are 2 color table entries. Some + readers will ignore them though, and assume that 0 is black and 1 is white. + If you are storing black and white pictures you should + stick to this, with any other 2 colors this is not an issue. + Remember padding with zeros up to a 32bit boundary (This can be up to + 31 zeros/pixels!) + + + Raster Data encoding for 4bit / 16 color images + + BitCount = 4 Compression = 0 + Every byte holds 2 pixels, its high order 4 bits representing the left of those. + There are 16 color table entries. These colors do not + have to be the 16 MS-Windows standard colors. Padding each line with + zeros up to a 32bit boundary will result in up to 28 zeros + = 7 'wasted pixels'. + + + Raster Data encoding for 8bit / 256 color images + + BitCount = 8 Compression = 0 + Every byte holds 1 pixel. There are 256 color table entries. + Padding each line with zeros up to a 32bit boundary will result in up to + 3 bytes of zeros = 3 'wasted pixels'. + + + Raster Data encoding for 16bit / hicolor images + + BitCount = 16 Compression = 0 + Every 2bytes / 16bit holds 1 pixel. + <information missing: the 16 bit was introduced together with + Video For Windows? Is it a memory-only-format?> + The pixels are no color table pointers. There are no color table entries. + Padding each line with zeros up to a 16bit boundary will + result in up to 2 zero bytes. + + + Raster Data encoding for 24bit / truecolor images + + BitCount = 24 Compression = 0 + Every 4bytes / 32bit holds 1 pixel. The first holds its red, + the second its green, and the third its blue intensity. The fourth byte is + reserved and should be zero. There are no color table entries. + The pixels are no color table pointers. No zero padding necessary. + + + Raster Data compression for 4bit / 16 color images + + BitCount = 4 Compression = 2 + The pixel data is stored in 2bytes / 16bit chunks. The first of these + specifies the number of consecutive pixels with the same pair + of color. The second byte defines two color indices. The resulting + pixel pattern will be interleaved high-order 4bits and low order 4 + bits (ABABA...). If the first byte is zero, the second defines an escape code. + The End-of-Bitmap is zero padded to end on a 32bit boundary. + Due to the 16bit-ness of this structure this will always be either + two zero bytes or none. + + n (byte 1) + c (Byte 2) + Description + >0 + any + n pixels are to be drawn. The 1st, 3rd, 5th, ... pixels' + color is in c's high-order 4 bits, the even pixels' color + is in c's low-order 4 bits. If both color indices are the same, + it results in just n pixels of color c + 0 + 0 + End-of-line + 0 + 1 + End-of-Bitmap + 0 + 2 + Delta. The following 2 bytes define an unsigned offset + in x and y direction (y being up) The skipped pixels + should get a color zero. + 0 + >=3 + The following c bytes will be read as single pixel colors + just as in uncompressed files. up to 12 bits of zeros + follow, to put the file/memory pointer on a 16bit boundary again. + + + Example for 4bit RLE + Compressed Data + Expanded data + 03 04 + 0 4 0 + 05 06 + 0 6 0 6 0 + 00 06 45 56 67 00 + 4 5 5 6 6 7 + 04 78 + 7 8 7 8 + 00 02 05 01 + Move 5 right and 1 up. (Windows docs say down, which is wrong) + 00 00 + End-of-line + 09 1E + 1 E 1 E 1 E 1 E 1 + 00 01 + EndofBitmap + 00 00 + Zero padding for 32bit boundary + + + + + Raster Data compression for 8bit / 256 color images + + BitCount = 8 Compression = 1 + The pixel data is stored in 2bytes / 16bit chunks. The first of these + specifies the number of consecutive pixels with the same + color. The second byte defines their color index. If the first byte + is zero, the second defines an escape code. The End-of-Bitmap + is zero padded to end on a 32bit boundary. Due to the 16bit-ness of + this structure this will always be either two zero bytes or none. + + n (byte 1) + c (Byte 2) + Description + >0 + any + n pixels of color number c + 0 + 0 + End-of-line + 0 + 1 + EndOfBitmap + 0 + 2 + Delta. The following 2 bytes define an unsigned offset + in x and y direction (y being up) The skipped pixels + should get a color zero. + 0 + >=3 + The following c bytes will be read as single pixel colors + just as in uncompressed files. A zero follows, if c is + odd, putting the file/memory pointer on a 16bit boundary again. + + + Example for 8bit RLE + Compressed Data + Expanded data + 03 04 + 04 04 04 + 05 06 + 06 06 06 06 06 + 00 03 45 56 67 00 + 45 56 67 + 02 78 + 78 78 + 00 02 05 01 + Move 5 right and 1 up. (Windows docs say down, which is wrong) + 00 00 + End-of-line + 09 1E + 1E 1E 1E 1E 1E 1E 1E 1E 1E + 00 01 + End-of-bitmap + 00 00 + Zero padding for 32bit boundary + +*/ + +void freadushort(u_int16_t *ptr, FILE* fd) +{ + u_int16_t tmp; u_int8_t t1, t2; + t1 = getc(fd); t2 = getc(fd); + tmp = t2; + tmp = tmp*256+t1; + *ptr = tmp; +} + +void freadulong(u_int32_t *ptr, FILE* fd) +{ + u_int32_t tmp; u_int8_t t1, t2, t3, t4; + t1 = getc(fd); t2 = getc(fd); t3 = getc(fd); t4 = getc(fd); + tmp = t4; + tmp = tmp*256+t3; + tmp = tmp*256+t2; + tmp = tmp*256+t1; + *ptr = tmp; +} + +/* =============================================================== */ +int32_t readbmp(char *filename, struct xvimage ** r, struct xvimage ** g, struct xvimage ** b) +/* =============================================================== */ +#undef F_NAME +#define F_NAME "readbmp" +{ + FILE *fd; + struct BITMAPFILEHEADER FileHeader; + struct BITMAPINFOHEADER InfoHeader; + u_int8_t *R, *G, *B; + int32_t i, j, rs, cs; + +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + return 0; + } + + fread(&(FileHeader.Signature), sizeof(char), 2, fd); + freadulong(&(FileHeader.FileSize), fd); + freadulong(&(FileHeader.reserved), fd); + freadulong(&(FileHeader.DataOffset), fd); +#ifdef VERBOSE + printf("signature = %c%c\n", FileHeader.Signature[0], FileHeader.Signature[1]); + printf("file size = %ld\n", FileHeader.FileSize); + printf("reserved = %ld\n", FileHeader.reserved); + printf("data offset = %ld\n", FileHeader.DataOffset); +#endif + freadulong(&(InfoHeader.Size), fd); + freadulong(&(InfoHeader.Width), fd); + freadulong(&(InfoHeader.Height), fd); + freadushort(&(InfoHeader.Planes), fd); + freadushort(&(InfoHeader.BitCount), fd); + freadulong(&(InfoHeader.Compression), fd); + freadulong(&(InfoHeader.ImageSize), fd); + freadulong(&(InfoHeader.XpixelsPerM), fd); + freadulong(&(InfoHeader.YpixelsPerM), fd); + freadulong(&(InfoHeader.ColorsUsed), fd); + freadulong(&(InfoHeader.ColorsImportant), fd); +#ifdef VERBOSE + printf("Size = %d\n", InfoHeader.Size); + printf("Width = %d\n", InfoHeader.Width); + printf("Height = %d\n", InfoHeader.Height); + printf("Planes = %d\n", InfoHeader.Planes); + printf("BitCount = %d\n", InfoHeader.BitCount); + printf("Compression = %d\n", InfoHeader.Compression); + printf("ImageSize = %d\n", InfoHeader.ImageSize); + printf("XpixelsPerM = %d\n", InfoHeader.XpixelsPerM); + printf("YpixelsPerM = %d\n", InfoHeader.YpixelsPerM); + printf("ColorsUsed = %d\n", InfoHeader.ColorsUsed); + printf("ColorsImportant = %d\n", InfoHeader.ColorsImportant); +#endif + if ((InfoHeader.Compression != 0) && (InfoHeader.BitCount != 24)) + { + fprintf(stderr, "restricted bmp format conversion:\n"); + fprintf(stderr, "compression tag must be 0 (No compression), found: %d\n", InfoHeader.Compression); + fprintf(stderr, "bitcount/pixel must be 24 (True color), found: %d\n", InfoHeader.BitCount); + fprintf(stderr, "cannot process file\n"); + return 0; + } + rs = InfoHeader.Width; + cs = InfoHeader.Height; + *r = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *g = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *b = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + if ((*r == NULL) || (*g == NULL) || (*b == NULL)) + { + fprintf(stderr, "%s: allocimage failed\n", F_NAME); + return 0; + } + R = (u_int8_t *)((*r)->imagedata); + G = (u_int8_t *)((*g)->imagedata); + B = (u_int8_t *)((*b)->imagedata); + for (j = cs-1; j >= 0 ; j--) + for (i = 0; i < rs; i++) + { + B[(j*rs)+i] = (u_int8_t)getc(fd); + G[(j*rs)+i] = (u_int8_t)getc(fd); + R[(j*rs)+i] = (u_int8_t)getc(fd); + /* (void)getc(fd); */ + } + fclose(fd); + return 1; +} /* readbmp() */ + +void fwriteushort(u_int16_t us, FILE* fd) +{ + putc((u_int8_t)(us & 0xff), fd); us = us >> 8; + putc((u_int8_t)(us & 0xff), fd); us = us >> 8; +} + +void fwriteulong(u_int32_t ul, FILE* fd) +{ + putc((u_int8_t)(ul & 0xff), fd); ul = ul >> 8; + putc((u_int8_t)(ul & 0xff), fd); ul = ul >> 8; + putc((u_int8_t)(ul & 0xff), fd); ul = ul >> 8; + putc((u_int8_t)(ul & 0xff), fd); ul = ul >> 8; +} + +/* =============================================================== */ +void writebmp( + struct xvimage * redimage, + struct xvimage * greenimage, + struct xvimage * blueimage, + char *filename) +/* =============================================================== */ +#undef F_NAME +#define F_NAME "writebmp" +{ + FILE *fd; + u_int8_t *R, *G, *B; + int32_t i, j, rs, cs, N; + + rs = rowsize(redimage); + cs = colsize(redimage); + N = rs * cs; + + if ((rs != rowsize(greenimage)) || (cs != colsize(greenimage)) || + (rs != rowsize(blueimage)) || (cs != colsize(blueimage))) + { + fprintf(stderr, "%s: incompatible image sizes\n", F_NAME); + exit(0); + } + + R = UCHARDATA(redimage); + G = UCHARDATA(greenimage); + B = UCHARDATA(blueimage); + +#ifdef DOSIO + fd = fopen(filename,"wb"); +#endif +#ifdef UNIXIO + fd = fopen(filename,"w"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + exit(0); + } + + putc('B', fd); putc('M', fd); + fwriteulong(N + 54, fd); + fwriteulong(0, fd); + fwriteulong(54, fd); + fwriteulong(40, fd); + fwriteulong(rs, fd); + fwriteulong(cs, fd); + fwriteushort(1, fd); + fwriteushort(24, fd); + fwriteulong(0, fd); + fwriteulong(N, fd); + fwriteulong(0, fd); + fwriteulong(0, fd); + fwriteulong(0, fd); + fwriteulong(0, fd); + + for (j = cs-1; j >= 0 ; j--) + for (i = 0; i < rs; i++) + { + putc(B[(j*rs)+i], fd); + putc(G[(j*rs)+i], fd); + putc(R[(j*rs)+i], fd); + } + + fclose(fd); +} /* writebmp() */ + +/* =========================================================================== */ +/* =========================================================================== */ +/* RGB files */ +/* =========================================================================== */ +/* =========================================================================== */ + +/* RGB file format is documented on: + +http://reality.sgi.com/grafica/sgiimage.html + +*/ + +struct RGBFILEHEADER { /* size 108 bytes */ + u_int16_t magic; /* size 2 bytes : magic number = 474 */ + u_int8_t compression; /* size 1 byte : 0 for no compression */ + u_int8_t bytespercha; /* size 1 byte : nb. bytes per channel */ + u_int16_t dim; /* size 2 bytes : nb. channels */ + u_int16_t width; /* size 2 bytes : image row size */ + u_int16_t height; /* size 2 bytes : image col size */ + u_int16_t components; /* size 2 bytes : components */ + u_int32_t mincol; /* size 4 bytes : 0 */ + u_int32_t maxcol; /* size 4 bytes : 255 */ + u_int32_t dummy; /* size 4 bytes : dummy */ + char name[80]; /* size 80 bytes : image name or comment */ + u_int32_t cmaptype; /* size 4 bytes : 0 for NORMAL RGB */ +}; /** plus 404 bytes dummy padding to make header 512 bytes **/ + +/* =============================================================== */ +int32_t readrgb(char *filename, struct xvimage ** r, struct xvimage ** g, struct xvimage ** b) +/* =============================================================== */ +#undef F_NAME +#define F_NAME "readrgb" +{ + FILE *fd; + struct RGBFILEHEADER FileHeader; + u_int8_t *R, *G, *B; + int32_t i, j, rs, cs, N; + +#ifdef DOSIO + fd = fopen(filename,"rb"); +#endif +#ifdef UNIXIO + fd = fopen(filename,"r"); +#endif + if (!fd) + { + fprintf(stderr, "%s: cannot open file: %s\n", F_NAME, filename); + return 0; + } + + freadushort(&(FileHeader.magic), fd); + FileHeader.compression = (u_int8_t)getc(fd); + FileHeader.bytespercha = (u_int8_t)getc(fd); + freadushort(&(FileHeader.dim), fd); + freadushort(&(FileHeader.width), fd); + freadushort(&(FileHeader.height), fd); + + if (FileHeader.magic != 474) + { + fprintf(stderr, "bad rgb format magic number: 474 expected, %d found\n", + FileHeader.magic); + return 0; + } + + if (FileHeader.compression != 0) + { + fprintf(stderr, "restricted rgb format conversion:\n"); + fprintf(stderr, "compression tag must be 0 (No compression), found: %d\n", FileHeader.compression); + return 0; + } + rs = FileHeader.width; + cs = FileHeader.height; + N = rs * cs; + *r = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *g = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + *b = allocimage(NULL, rs, cs, 1, VFF_TYP_1_BYTE); + if ((*r == NULL) || (*g == NULL) || (*b == NULL)) + { + fprintf(stderr, "%s: allocimage failed\n", F_NAME); + return 0; + } + R = (u_int8_t *)((*r)->imagedata); + G = (u_int8_t *)((*g)->imagedata); + B = (u_int8_t *)((*b)->imagedata); + + for (i = 0; i < 502; i++) /** padding bytes **/ + (void)getc(fd); + + for (j = cs-1; j >= 0 ; j--) + for (i = 0; i < rs; i++) /** red bytes **/ + R[(j*rs)+i] = (u_int8_t)getc(fd); + for (j = cs-1; j >= 0 ; j--) + for (i = 0; i < rs; i++) /** green bytes **/ + G[(j*rs)+i] = (u_int8_t)getc(fd); + for (j = cs-1; j >= 0 ; j--) + for (i = 0; i < rs; i++) /** blue bytes **/ + B[(j*rs)+i] = (u_int8_t)getc(fd); + fclose(fd); + return 1; +} /* readrgb() */ Index: abraham/tests/morpho/ref/src/lib/mcfahsalembier.c --- abraham/tests/morpho/ref/src/lib/mcfahsalembier.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mcfahsalembier.c (revision 0) @@ -0,0 +1,236 @@ +/* $Id: mcfahsalembier.c,v 1.5 2006/02/28 07:49:16 michel Exp $ */ +/* structure de file d'attente hierarchique de points d'image */ +/* Michel Couprie */ + +/* un point d'une image F est reperee par son index */ +/* dans le tableau mono-dimension ou les valeurs sont rangees */ +/* par ligne, puis par colonne */ + +/* d'apres F. Meyer: "Un Algorithme Optimal de Ligne de Partage des Eaux" */ +/* version "salembier" (un point insere sous le niveau courant recree une file a ce niveau, + de plus on peut retirer un point de n'importe quel niveau a tout moment) */ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mcfahsalembier.h> + +/* +#define TESTFah +#define VERBOSE +*/ + +/* ==================================== */ +Fah * CreeFahVide( + int32_t taillemax) +/* ==================================== */ +{ + int32_t i; + Fah * L = (Fah *)calloc(1,sizeof(Fah) + (taillemax - 1) * sizeof(FahElt)); + if (L == NULL) + { + fprintf(stderr, "erreur allocation Fah\n"); + exit(1); + } + L->Max = taillemax; + L->Util = 0; + L->Maxutil = 0; + L->Niv = 0; + for (i = 0; i < taillemax - 1; i++) L->Elts[i].Next = &(L->Elts[i+1]); + L->Elts[taillemax - 1].Next = NULL; + L->Libre = &(L->Elts[0]); + for (i = 0; i < NPRIO; i++) L->Tete[i]= NULL; + for (i = 0; i < NPRIO; i++) L->Queue[i]= NULL; + return L; +} /* CreeFahVide() */ + +/* ==================================== */ +void FahFlush( + Fah * L) +/* ==================================== */ +{ + int32_t i; + L->Niv = 0; + L->Util = 0; + for (i = 0; i < L->Max - 1; i++) L->Elts[i].Next = &(L->Elts[i+1]); + L->Elts[L->Max - 1].Next = NULL; + L->Libre = &(L->Elts[0]); + for (i = 0; i < NPRIO; i++) L->Tete[i]= NULL; + for (i = 0; i < NPRIO; i++) L->Queue[i]= NULL; +} /* FahFlush() */ + +/* ==================================== */ +int32_t FahVide( + Fah * L) +/* ==================================== */ +{ + if (L->Util == 0) return 1; + return 0; +} /* FahVide() */ + +/* ==================================== */ +int32_t FahVideNiveau( + Fah * L, + int32_t niv) +/* ==================================== */ +{ + if (L->Queue[niv] == NULL) return 1; + return 0; +} /* FahVideNiveau() */ + +/* ==================================== */ +int32_t FahPopNiveau( + Fah * L, + int32_t niv) +/* ==================================== */ +{ + int32_t V; + FahElt * FE; + if (L->Queue[niv] == NULL) + { + fprintf(stderr, "erreur Fah vide au niveau %d\n", niv); + exit(1); + } + + L->Util--; + V = L->Queue[niv]->Point; + FE = L->Queue[niv]->Prev; + + L->Queue[niv]->Next = L->Libre; /* recupere la cellule dans la liste libre */ + L->Libre = L->Queue[niv]; + L->Queue[niv] = FE; + + if (FE == NULL) /* plus aucun element dans la liste */ + { + L->Tete[niv] = NULL; + if (niv == L->Niv) + do (L->Niv)++; /* incrementer le niveau */ + while ((L->Niv < NPRIO) + && (L->Tete[L->Niv] == NULL)); + } + else if (L->Tete[niv] == L->Queue[niv]) /* seul un element reste dans la liste */ + { + L->Tete[niv]->Next = L->Tete[niv]->Prev = NULL; + } + + return V; +} /* FahPopNiveau() */ + +/* ==================================== */ +int32_t FahPop( + Fah * L) +/* ==================================== */ +{ + if (L->Util == 0) + { + fprintf(stderr, "erreur Fah vide\n"); + exit(1); + } + return FahPopNiveau(L, L->Niv); +} /* FahPop() */ + +/* ==================================== */ +void FahPush( + Fah * L, + int32_t Po, + int32_t Ni) +/* ==================================== */ +{ + if (L->Libre == NULL) + { + fprintf(stderr, "erreur Fah pleine\n"); + exit(1); + } + if (Ni >= NPRIO) + { + fprintf(stderr, "erreur niveau = %d; max autorise = %d\n", Ni, NPRIO-1); + exit(1); + } + + if ((L->Util == 0) || (Ni < L->Niv)) L->Niv = Ni; + + L->Util++; + if (L->Util > L->Maxutil) L->Maxutil = L->Util; + if (L->Tete[Ni] != NULL) /* insertion dans la liste de niveau Ni non vide */ + { + FahElt * FE = L->Tete[Ni]; + L->Tete[Ni] = L->Libre; + L->Libre = L->Libre->Next; + L->Tete[Ni]->Next = FE; + L->Tete[Ni]->Prev = NULL; + L->Tete[Ni]->Point = Po; + FE->Prev = L->Tete[Ni]; + } + else /* (L->Tete[Ni] == NULL) */ + { + L->Tete[Ni] = L->Queue[Ni] = L->Libre; + L->Libre = L->Libre->Next; + L->Tete[Ni]->Next = NULL; + L->Tete[Ni]->Prev = NULL; + L->Tete[Ni]->Point = Po; + } +} /* FahPush() */ + +/* ==================================== */ +void FahTermine( + Fah * L) +/* ==================================== */ +{ +#ifdef VERBOSE + printf("Fah: taux d'utilisation: %g\n", (double)L->Maxutil / (double)L->Max); +#endif + free(L); +} /* FahTermine() */ + +/* ==================================== */ +void FahPrint( + Fah * L) +/* ==================================== */ +{ + int32_t i; + FahElt * FE; + if (FahVide(L)) {printf("[]\n"); return;} + printf("niveau courant = %d\n", L->Niv); + for (i = 0; i < NPRIO; i++) + if (L->Tete[i] != NULL) + { + printf("%d [ ", i); + for (FE = L->Tete[i]; FE != NULL; FE = FE->Next) + printf("%d ", FE->Point); + printf("]\n"); + } +} /* FahPrint() */ + +#ifdef TESTFAH +void main() +{ + Fah * L = CreeFahVide(5); + char r[80]; + int32_t p, n; + + do + { + printf("commande (qUIT, PuSH, PoP, pRINT, TESTvIDE) > "); + scanf("%s", r); + switch (r[0]) + { + case 'u': + printf("niveau > "); + scanf("%d", &n); + printf("valeur > "); + scanf("%d", &p); + FahPush(L, p, n); + break; + case 'o': + printf("pop: %d\n", FahPop(L)); + break; + case 'p': FahPrint(L); break; + case 'v': + printf("vide: %d\n", FahVide(L)); + break; + case 'q': break; + } + } while (r[0] != 'q'); + FahTermine(L); +} +#endif Index: abraham/tests/morpho/ref/src/lib/mcindic.c --- abraham/tests/morpho/ref/src/lib/mcindic.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mcindic.c (revision 0) @@ -0,0 +1,76 @@ +/* $Id: mcindic.c,v 1.4 2006/02/28 07:49:16 michel Exp $ */ +/* gestion d'indicateurs binaires (jusqu'a 8) */ +/* les indicateurs sont numerotes de 0 a 7 */ +/* M. Couprie juillet 1996 */ + +/* gestion d'un indicateur binaire compact */ +/* M. Couprie novembre 1999 */ + +/* +#define TESTINDIC +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mcindic.h> + +Indicstype *Indics = NULL; /* en global pour etre efficace */ + +/* ==================================== */ +void IndicsInit(int32_t Size) +/* ==================================== */ +{ + int32_t i; + Indics = (Indicstype *)calloc(Size, sizeof(Indicstype)); + if (Indics == NULL) + { + fprintf(stderr, "erreur allocation Indics\n"); + exit(1); + } +} + +/* ==================================== */ +void Indics1bitInit(int32_t Size) +/* ==================================== */ +{ + int32_t i; + Indics = (Indicstype *)calloc((Size-1)/8 + 1, sizeof(Indicstype)); + if (Indics == NULL) + { + fprintf(stderr, "erreur allocation Indics\n"); + exit(1); + } +} + +/* ==================================== */ +void Indics1bitReInit(int32_t Size) +/* ==================================== */ +{ + memset(Indics, 0, ((Size-1)/8 + 1) * sizeof(Indicstype)); +} + +/* ==================================== */ +void IndicsTermine() +/* ==================================== */ +{ + free(Indics); +} + +#ifdef TESTINDIC +void main() +{ + IndicsInit(3); + Set(0, 0); if (IsSet(0, 0)) printf("test1 ok\n"); +printf("->%d\n", Indics[0]); + Set(0, 1); if (IsSet(0, 1)) printf("test2 ok\n"); +printf("->%d\n", Indics[0]); + UnSet(0, 1); if (!IsSet(0, 1)) printf("test3 ok\n"); +printf("->%d\n", Indics[0]); + if (IsSet(0, 0)) printf("test4 ok\n"); + UnSetAll(0); if (!IsSet(0, 0)) printf("test5 ok\n"); +printf("->%d\n", Indics[0]); + + IndicsTermine(); +} +#endif Index: abraham/tests/morpho/ref/src/lib/mccodimage.c --- abraham/tests/morpho/ref/src/lib/mccodimage.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mccodimage.c (revision 0) @@ -0,0 +1,586 @@ +/* $Id: mccodimage.c,v 1.12 2006/04/24 15:07:28 michel Exp $ */ +/* + Librairie mccodimage : + + fonctions pour l'acces aux voisins d'un point et pour la detection de bord + + Michel Couprie 1996 + +*/ +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mccodimage.h> +#include <mcutil.h> + +/* + Codage du voisinage en 2D + + 3 2 1 + 4 X 0 + 5 6 7 + + pour le voisinage étendu + + 14 13 12 11 10 + 15 3 2 1 9 + 16 4 X 0 8 + 17 5 6 7 23 + 18 19 20 21 22 + + Traduction index <-> coordonnées (2D) + + i = y*rs + x + + x = i % rs + y = i / rs; + + Traduction index <-> coordonnées (3D) + + i = z*ps + y*rs + x + + x = i % rs + y = (i % ps) / rs; + z = i / ps; +*/ + +/* ==================================== */ +int32_t voisin(int32_t i, int32_t k, int32_t rs, int32_t nb) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* nb : taille de l'image */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +#undef F_NAME +#define F_NAME "voisin" +{ + switch(k) + { + case EST: if (i%rs!=rs-1) return i+1; else return -1; + case NORD_EST: if ((i%rs!=rs-1)&&(i>=rs)) return i+1-rs; else return -1; + case NORD: if (i>=rs) return i-rs; else return -1; + case NORD_OUEST: if ((i>=rs)&&(i%rs!=0)) return i-rs-1; else return -1; + case OUEST: if (i%rs!=0) return i-1; else return -1; + case SUD_OUEST: if ((i%rs!=0)&&(i<nb-rs)) return i-1+rs; else return -1; + case SUD: if (i<nb-rs) return i+rs; else return -1; + case SUD_EST: if ((i<nb-rs)&&(i%rs!=rs-1)) return i+rs+1; else return -1; + default: + fprintf(stderr, "%s: bad index value %d\n", F_NAME, k); + exit(0); + } +} // voisin() + +/* ==================================== */ +int32_t voisin2(int32_t i, int32_t k, int32_t rs, int32_t nb) +/* i : index du point dans l'image */ +/* k : index du voisin (24 possibilités - voisinage étendu) */ +/* rs : taille d'une rangee */ +/* nb : taille de l'image */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +#undef F_NAME +#define F_NAME "voisin2" +{ + switch(k) + { + case EST: if (i%rs!=rs-1) return i+1; else return -1; + case NORD_EST: if ((i%rs!=rs-1)&&(i>=rs)) return i+1-rs; else return -1; + case NORD: if (i>=rs) return i-rs; else return -1; + case NORD_OUEST: if ((i>=rs)&&(i%rs!=0)) return i-rs-1; else return -1; + case OUEST: if (i%rs!=0) return i-1; else return -1; + case SUD_OUEST: if ((i%rs!=0)&&(i<nb-rs)) return i-1+rs; else return -1; + case SUD: if (i<nb-rs) return i+rs; else return -1; + case SUD_EST: if ((i<nb-rs)&&(i%rs!=rs-1)) return i+rs+1; else return -1; + case 8: if (i%rs<rs-2) return i+2; else return -1; + case 9: if ((i%rs<rs-2)&&(i>=rs)) return i+2-rs; else return -1; + case 10: if ((i%rs<rs-2)&&(i>=2*rs)) return i+2-2*rs; else return -1; + case 11: if ((i%rs<rs-1)&&(i>=2*rs)) return i+1-2*rs; else return -1; + case 12: if (i>=2*rs) return i-2*rs; else return -1; + case 13: if ((i%rs>0)&&(i>=2*rs)) return i-1-2*rs; else return -1; + case 14: if ((i%rs>1)&&(i>=2*rs)) return i-2-2*rs; else return -1; + case 15: if ((i%rs>1)&&(i>=rs)) return i-2-rs; else return -1; + case 16: if (i%rs>1) return i-2; else return -1; + case 17: if ((i%rs>1)&&(i<nb-rs)) return i-2+rs; else return -1; + case 18: if ((i%rs>1)&&(i<nb-2*rs)) return i-2+2*rs; else return -1; + case 19: if ((i%rs>0)&&(i<nb-2*rs)) return i-1+2*rs; else return -1; + case 20: if (i<nb-2*rs) return i+2*rs; else return -1; + case 21: if ((i%rs<rs-1)&&(i<nb-2*rs)) return i+1+2*rs; else return -1; + case 22: if ((i%rs<rs-2)&&(i<nb-2*rs)) return i+2+2*rs; else return -1; + case 23: if ((i%rs<rs-2)&&(i<nb-rs)) return i+2+rs; else return -1; + default: + fprintf(stderr, "%s: bad index value %d\n", F_NAME, k); + exit(0); + } +} // voisin2() + +/* Cette fonction indique a quel bord appartient le point */ +/* ==================================== */ +int32_t bord(int32_t i, int32_t rs, int32_t nb) +/* ==================================== */ +{ + /* valeurs renvoyees : + 4 3 2 + 5 0 1 + 6 7 8 + */ + + if (i==0) return (4); + if (i==(nb-rs)) return (6); + if (i==rs-1) return (2); + if (i==nb-1) return (8); + if (i%rs==0) return (5); + if (i%rs==rs-1) return (1); + if (i<rs) return (3); + if (i>nb-rs) return (7); + return (0); +} + +/* + Codage d'une image en 3D niveaux de gris + + L'image 3d est sockee sous forme de plans (images planes verticales) + Le premier plan constitue l'avant + Chaque image a pour dimensions rs (taille rangee) et cs (taille colonne) + L'image est constituee de d plans, chacun de taille n = rs*cs pixels. + +*/ + +/* Cette fonction indique a quel bord appartient le point */ +/* ==================================== */ +int32_t bord3d(int32_t i, int32_t rs, int32_t ps, int32_t nb) +/* ==================================== */ +{ + if (i%rs == rs-1) return 1; + if (i%rs == 0) return 1; + if ((i%ps) < rs) return 1; + if ((i%ps) >= ps-rs) return 1; + if (i < ps) return 1; + if (i >= nb-ps) return 1; + return (0); +} + +/* ==================================== */ +int32_t voisin6(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* N : taille de l'image 3D */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +{ + switch(k) + { + case EST: if (i%rs!=rs-1) return i+1; else return -1; + case NORD: if ((i%ps)>=rs) return i-rs; else return -1; + case OUEST: if (i%rs!=0) return i-1; else return -1; + case SUD: if ((i%ps)<ps-rs) return i+rs; else return -1; + case DEVANT: if (i>=ps) return i-ps; else return -1; + case DERRIERE: if (i<N-ps) return i+ps; else return -1; + } +} + +/* ==================================== */ +int32_t voisin26(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* N : taille de l'image 3D */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +{ + switch(k) + { + /* les 9 premiers (0 a 8) sont les 9 pixels du plan "ARRIERE" (+ps) */ + case 0: if ((i<N-ps)&&(i%rs!=rs-1)) return ps+i+1; else return -1; /* 1 0 1 */ + case 1: if ((i<N-ps)&&(i%rs!=rs-1)&&(i%ps>=rs)) return ps+i+1-rs; else return -1; /* 1 -1 1 */ + case 2: if ((i<N-ps)&&(i%ps>=rs)) return ps+i-rs; else return -1; /* 0 -1 1 */ + case 3: if ((i<N-ps)&&(i%ps>=rs)&&(i%rs!=0)) return ps+i-rs-1; else return -1; /* -1 -1 1 */ + case 4: if ((i<N-ps)&&(i%rs!=0)) return ps+i-1; else return -1; /* -1 0 1 */ + case 5: if ((i<N-ps)&&(i%rs!=0)&&(i%ps<ps-rs)) return ps+i-1+rs; else return -1; /* -1 1 1 */ + case 6: if ((i<N-ps)&&(i%ps<ps-rs)) return ps+i+rs; else return -1; /* 0 1 1 */ + case 7: if ((i<N-ps)&&(i%ps<ps-rs)&&(i%rs!=rs-1)) return ps+i+rs+1; else return -1;/* 1 1 1 */ + case 8: if ((i<N-ps)) return ps+i; else return -1; /* 0 0 1 */ + /* les 8 suivants (9 a 16) sont les 8 pixels du plan "COURANT" () */ + case 9: if ((i%rs!=rs-1)) return i+1; else return -1; + case 10: if ((i%rs!=rs-1)&&(i%ps>=rs)) return i+1-rs; else return -1; + case 11: if ((i%ps>=rs)) return i-rs; else return -1; + case 12: if ((i%ps>=rs)&&(i%rs!=0)) return i-rs-1; else return -1; + case 13: if ((i%rs!=0)) return i-1; else return -1; + case 14: if ((i%rs!=0)&&(i%ps<ps-rs)) return i-1+rs; else return -1; + case 15: if ((i%ps<ps-rs)) return i+rs; else return -1; + case 16: if ((i%ps<ps-rs)&&(i%rs!=rs-1)) return i+rs+1; else return -1; + /* les 9 derniers (17 a 25) sont les 9 pixels du plan "AVANT" (-ps) */ + case 17: if ((i>=ps)&&(i%rs!=rs-1)) return -ps+i+1; else return -1; + case 18: if ((i>=ps)&&(i%rs!=rs-1)&&(i%ps>=rs)) return -ps+i+1-rs; else return -1; + case 19: if ((i>=ps)&&(i%ps>=rs)) return -ps+i-rs; else return -1; + case 20: if ((i>=ps)&&(i%ps>=rs)&&(i%rs!=0)) return -ps+i-rs-1; else return -1; + case 21: if ((i>=ps)&&(i%rs!=0)) return -ps+i-1; else return -1; + case 22: if ((i>=ps)&&(i%rs!=0)&&(i%ps<ps-rs)) return -ps+i-1+rs; else return -1; + case 23: if ((i>=ps)&&(i%ps<ps-rs)) return -ps+i+rs; else return -1; + case 24: if ((i>=ps)&&(i%ps<ps-rs)&&(i%rs!=rs-1)) return -ps+i+rs+1; else return -1; + case 25: if ((i>=ps)) return -ps+i; else return -1; + } +} + +/* ==================================== */ +int32_t voisin18(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* N : taille de l'image 3D */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +{ + switch(k) + { + /* les 5 premiers (0 a 4) sont les 5 pixels du plan "ARRIERE" (+ps) */ + case 0: if ((i<N-ps)&&(i%rs!=rs-1)) return ps+i+1; else return -1; + case 1: if ((i<N-ps)&&(i%ps>=rs)) return ps+i-rs; else return -1; + case 2: if ((i<N-ps)&&(i%rs!=0)) return ps+i-1; else return -1; + case 3: if ((i<N-ps)&&(i%ps<ps-rs)) return ps+i+rs; else return -1; + case 4: if ((i<N-ps)) return ps+i; else return -1; + /* les 8 suivants (5 a 12) sont les 8 pixels du plan "COURANT" () */ + case 5: if ((i%rs!=rs-1)) return i+1; else return -1; + case 6: if ((i%rs!=rs-1)&&(i%ps>=rs)) return i+1-rs; else return -1; + case 7: if ((i%ps>=rs)) return i-rs; else return -1; + case 8: if ((i%ps>=rs)&&(i%rs!=0)) return i-rs-1; else return -1; + case 9: if ((i%rs!=0)) return i-1; else return -1; + case 10: if ((i%rs!=0)&&(i%ps<ps-rs)) return i-1+rs; else return -1; + case 11: if ((i%ps<ps-rs)) return i+rs; else return -1; + case 12: if ((i%ps<ps-rs)&&(i%rs!=rs-1)) return i+rs+1; else return -1; + /* les 5 derniers (13 a 17) sont les 5 pixels du plan "AVANT" (-ps) */ + case 13: if ((i>=ps)&&(i%rs!=rs-1)) return -ps+i+1; else return -1; + case 14: if ((i>=ps)&&(i%ps>=rs)) return -ps+i-rs; else return -1; + case 15: if ((i>=ps)&&(i%rs!=0)) return -ps+i-1; else return -1; + case 16: if ((i>=ps)&&(i%ps<ps-rs)) return -ps+i+rs; else return -1; + case 17: if ((i>=ps)) return -ps+i; else return -1; + } +} + +/* ==================================== */ +int32_t voisins4(int32_t i, int32_t j, int32_t rs) +/* i, j : index des deux points dans l'image */ +/* rs : taille d'une rangee */ +/* retourne 1 si les points i et j sont 4-voisins */ +/* ==================================== */ +{ + int32_t xi = i % rs; + int32_t xj = j % rs; + int32_t yi = i / rs; + int32_t yj = j / rs; + if (abs(xi-xj) + abs(yi-yj) != 1) return 0; + return 1; +} // voisins4() + +/* ==================================== */ +int32_t voisins8(int32_t i, int32_t j, int32_t rs) +/* i, j : index des deux points dans l'image */ +/* rs : taille d'une rangee */ +/* retourne 1 si les points i et j sont 8-voisins */ +/* ==================================== */ +{ + int32_t xi = i % rs; + int32_t xj = j % rs; + int32_t yi = i / rs; + int32_t yj = j / rs; + if (abs(xi-xj) > 1) return 0; + if (abs(yi-yj) > 1) return 0; + return 1; +} // voisins8() + +/* ==================================== */ +int32_t voisins6(int32_t i, int32_t j, int32_t rs, int32_t ps) +/* i, j : index des deux points dans l'image */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* retourne 1 si les points i et j sont 6-voisins (en 3D) */ +/* ==================================== */ +{ + int32_t xi = i % rs; + int32_t xj = j % rs; + int32_t yi = (i%ps) / rs; + int32_t yj = (j%ps) / rs; + int32_t zi = i / ps; + int32_t zj = j / ps; + if (abs(xi-xj) + abs(yi-yj) + abs(zi-zj) != 1) return 0; + return 1; +} // voisins6() + +/* ==================================== */ +int32_t voisins18(int32_t i, int32_t j, int32_t rs, int32_t ps) +/* i, j : index des deux points dans l'image */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* retourne 1 si les points i et j sont 18-voisins (en 3D) */ +/* ==================================== */ +{ + int32_t xi = i % rs; + int32_t xj = j % rs; + int32_t yi = (i%ps) / rs; + int32_t yj = (j%ps) / rs; + int32_t zi = i / ps; + int32_t zj = j / ps; + if (abs(xi-xj) > 1) return 0; + if (abs(yi-yj) > 1) return 0; + if (abs(zi-zj) > 1) return 0; + if ((abs(xi-xj) == 1) && (abs(yi-yj) == 1) && (abs(zi-zj) == 1)) return 0; + return 1; +} // voisins18() + +/* ==================================== */ +int32_t voisins26(int32_t i, int32_t j, int32_t rs, int32_t ps) +/* i, j : index des deux points dans l'image */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* retourne 1 si les points i et j sont 26-voisins (en 3D) */ +/* ==================================== */ +{ + int32_t xi = i % rs; + int32_t xj = j % rs; + int32_t yi = (i%ps) / rs; + int32_t yj = (j%ps) / rs; + int32_t zi = i / ps; + int32_t zj = j / ps; + if (abs(xi-xj) > 1) return 0; + if (abs(yi-yj) > 1) return 0; + if (abs(zi-zj) > 1) return 0; + return 1; +} // voisins26() + +/* ==================================== */ +int32_t voisin5(int32_t i, int32_t k, int32_t rs, int32_t nb) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* nb : taille de l'image */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +/* + + 2 + 1 + + 3 + + + 0 + + + i + + + 4 + + + 7 + + 5 + 6 + +*/ +{ + int32_t rs2; + switch(k) + { + case 0: if ((i%rs<rs-2)&&(i>=rs)) return i -rs +2; else return -1; + case 1: rs2 = rs+rs; if ((i%rs<rs-1)&&(i>=rs2)) return i -rs2 +1; else return -1; + case 2: rs2 = rs+rs; if ((i%rs>0)&&(i>=rs2)) return i -rs2 -1; else return -1; + case 3: if ((i%rs>1)&&(i>=rs)) return i -rs -2; else return -1; + case 4: if ((i%rs>1)&&(i<nb-rs)) return i +rs -2; else return -1; + case 5: rs2 = rs+rs; if ((i%rs>0)&&(i<nb-rs2)) return i +rs2 -1; else return -1; + case 6: rs2 = rs+rs; if ((i%rs<rs-1)&&(i<nb-rs2)) return i +rs2 +1; else return -1; + case 7: if ((i%rs<rs-2)&&(i<nb-rs)) return i +rs +2; else return -1; + } +} + +/* ==================================== */ +/* renvoie l'index du voisin si il */ +/* appartient a gamma b sinon renvoie */ +/* -1 */ +int32_t voisin6b(int32_t i, int32_t k, int32_t rs, int32_t nb, int32_t par) +/* i : index du point dans l'image */ +/* k : direction du voisin */ +/* rs : taille d'une rangee */ +/* nb : taille de l'image */ +/* retourne -1 si le voisin n'existe pas */ +/* ==================================== */ +{ + if (par==0) { + if( ((i%rs)%2) == ((i/rs)%2) ) + return voisinNOSE(i, k, rs, nb); + else + return voisinNESO(i, k, rs, nb); + } else { + if( ((i%rs)%2) == ((i/rs)%2) ) + return voisinNESO(i, k, rs, nb); + else + return voisinNOSE(i, k, rs, nb); + } +} + +/* 1 0 * */ +/* 2 X 5 */ +/* * 3 4 */ + +int32_t voisinNOSE(int32_t i, int32_t k, int32_t rs, int32_t nb) +{ + switch(k) + { + case 0: if (i>=rs) return i-rs; else return -1; + case 1: if ((i>=rs)&&(i%rs!=0)) return i-rs-1; else return -1; + case 2: if (i%rs!=0) return i-1; else return -1; + case 5: if (i%rs!=rs-1) return i+1; else return -1; + case 3: if (i<nb-rs) return i+rs; else return -1; + case 4: if ((i<nb-rs)&&(i%rs!=rs-1)) return i+rs+1; else return -1; + default: return -1; + } +} + +/* * 0 5 */ +/* 1 X 4 */ +/* 2 3 * */ +int32_t voisinNESO(int32_t i, int32_t k, int32_t rs, int32_t nb) +{ + switch(k) + { + case 4: if (i%rs!=rs-1) return i+1; else return -1; + case 5: if ((i%rs!=rs-1)&&(i>=rs)) return i+1-rs; else return -1; + case 0: if (i>=rs) return i-rs; else return -1; + case 1: if (i%rs!=0) return i-1; else return -1; + case 2: if ((i%rs!=0)&&(i<nb-rs)) return i-1+rs; else return -1; + case 3: if (i<nb-rs) return i+rs; else return -1; + default: return -1; + } +} + +/* ==================================== */ +/* renvoie l'index du voisin si il */ +/* appartient a gamma b sinon renvoie */ +/* */ +/* les différents cas sont traites */ +/* directement dans la fonction pour */ +/* eviter de recalculer les coords du */ +/* point courannt */ + +int32_t voisin14b(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N) +{ + int32_t px, py, pz, ix, iy, iz; + px = (i%rs)%2; + py = (i/ps)%2; + pz = ((i%ps)/rs)%2; + if( (px && py && pz) || (!px && !py && !pz)) + return voisinONAV(i, k, rs, ps, N ); + if( (px && !py && pz) || (!px && py && !pz)) + return voisinENAR( i, k, rs, ps, N ); + if( (!px && py && pz) || (px && !py && !pz)) + return voisinENAV(i, k, rs, ps, N ); + else + return voisinONAR( i, k, rs, ps, N ); +} + +/* Soit l'ordre suivant + d'OUEST en EST, + de NORD à SUD, + d'AVANT vers l'ARRIERE. + les voisin sont numérotés suivant cet ordre +*/ +int32_t voisinONAV(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ) +{ + switch(k) + { + /* Premiere clique */ + case 0: if ((i/ps != 0) && (i%rs !=0) && ((i%ps)/rs != 0)) return (i-ps-rs-1); else return -1; + case 1: if ((i/ps != 0) && ((i%ps)/rs != 0)) return i-ps-rs; else return -1; + case 2: if ((i/ps != 0) && (i%rs !=0)) return i-ps -1; else return -1; + case 3: if ( (i/ps != 0) ) return i-ps; else return -1; + case 4: if ((i%rs !=0) && ((i%ps)/rs != 0)) return i-rs-1; else return -1; + case 5: if ((i%ps)/rs != 0) return i-rs; else return -1; + case 6: if ((i%rs !=0)) return i-1; else return -1; + /* Deuxième clique */ + case 7: if ((i%rs < rs-1) ) return i+1; else return -1; + case 8: if (i%ps < ps-rs) return i+rs; else return -1; + case 9: if ( (i%rs < rs-1) && (i%ps < ps-rs) ) return i+rs+1; else return -1; + case 10: if (i < N-ps ) return i+ps; else return-1; + case 11: if ( (i < N-ps ) && (i%rs < rs-1)) return i+ps+1; else return -1; + case 12: if ( (i < N-ps) && (i%ps < ps-rs)) return i+ps+rs; else return -1; + case 13: if ((i < N-ps ) && (i%rs < rs-1) && (i%ps < ps-rs)) return i+ps+rs+1; else return -1; + } +} + +int32_t voisinENAR(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ) +{ + switch(k) + { + /* Premiere clique */ + case 0: if((i%rs !=0) && (i/ps != 0)) return i-ps-1; else return -1; + case 1: if( (i/ps != 0)) return i-ps; else return -1; + case 2: if ((i%rs !=0) && ( i%ps<ps-rs) && (i/ps != 0)) return i-ps+rs-1; else return -1; + case 3: if ( ( i%ps<ps-rs) && (i/ps != 0) ) return i-ps+rs; else return -1; + case 4: if (i%rs !=0) return i-1; else return -1; + case 5: if ( (i%rs !=0) && (i%ps<ps-rs) ) return i+rs-1; else return -1; + case 6: if ( (i%ps<ps-rs) ) return i+rs; else return -1; + /* Deuxième clique */ + case 7: if ((i%ps)/rs != 0) return i-rs; else return -1; + case 8: if ( (i%rs < rs-1) && ((i%ps)/rs != 0) ) return i-rs+1; else return -1; + case 9: if (i%rs < rs-1) return i+1; else return -1; + case 10: if ( ((i%ps)/rs != 0) && (i < N-ps ) ) return i+ps-rs; else return -1; + case 11: if ( (i%rs < rs-1) && ((i%ps)/rs != 0) && (i < N-ps )) return i+ps-rs+1; else return -1; + case 12: if (i < N-ps ) return i+ps; else return -1; + case 13: if ((i%rs < rs-1) && (i < N-ps )) return i+ps+1; else return -1; + } +} + +int32_t voisinENAV(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ) +{ + switch(k) + { + /* Premiere clique */ + case 0: if ( (i%rs < rs-1) && (i/ps != 0)) return i-ps-rs; else return -1; + case 1: if ( (i%rs < rs-1) && ((i%ps)/rs != 0) && (i/ps != 0) ) return i-ps-rs+1; else return -1; + case 2: if (i/ps != 0) return i-ps; else return -1; + case 3: if ( (i%rs < rs-1) && (i/ps != 0) ) return i-ps+1; else return -1; + case 4: if ((i%ps)/rs != 0) return i-rs; else return -1; + case 5: if ( (i%rs < rs-1) && ((i%ps)/rs != 0)) return i-rs+1; else return -1; + case 6: if (i%rs < rs-1) return i+1; else return -1; + /* Deuxième clique */ + case 7: if (i%rs !=0) return i-1; else return -1; + case 8: if ( (i%rs !=0) && (i%ps<ps-rs) ) return i+rs-1; else return -1; + case 9: if ( i%ps<ps-rs ) return i+rs; else return -1; + case 10: if ( (i%rs !=0) && (i < N-ps ) ) return i+ps-1; else return -1; + case 11: if (i < N-ps) return i+ps; else return -1; + case 12: if ( (i%rs !=0) && (i%ps<ps-rs) && (i < N-ps )) return i+ps+rs-1; else return -1; + case 13: if ( (i%ps<ps-rs) && (i < N-ps ) ) return i+ps+rs; else return -1; + } +} + +int32_t voisinONAR(int32_t i, int32_t k, int32_t rs, int32_t ps, int32_t N ) +{ + switch(k) + { + /* Premiere clique */ + case 0: if (i/ps != 0) return i-ps; else return -1; + case 1: if ( (i%rs < rs-1) && (i/ps != 0) ) return i-ps+1; else return -1; + case 2: if ( (i%ps<ps-rs) && (i/ps != 0) ) return i-ps+rs; else return -1; + case 3: if ( (i%rs < rs-1) && (i%ps<ps-rs) && (i/ps != 0) ) return i-ps+rs+1; else return -1; + case 4: if (i%rs < rs-1) return i+1; else return -1; + case 5: if (i%ps<ps-rs) return i+rs; else return -1; + case 6: if ( (i%rs < rs-1) && (i%ps<ps-rs)) return i+rs+1; else return -1; + /* Deuxième clique */ + case 7: if ((i%rs !=0) && ((i%ps)/rs != 0)) return i-rs-1; else return -1; + case 8: if ((i%ps)/rs != 0) return i-rs;else return -1; + case 9: if (i%rs !=0) return i-1; else return -1; + case 10: if ((i%rs !=0) && ((i%ps)/rs != 0) && (i < N-ps )) return i+ps-rs-1; else return -1; + case 11: if (((i%ps)/rs != 0) && (i < N-ps )) return i+ps-rs; else return -1; + case 12: if ((i%rs !=0) && (i < N-ps )) return i+ps-1; else return -1; + case 13: if (i < N-ps ) return i+ps; else return -1; + } +} + +/* ==================================== */ +u_int32_t maskvois26(u_int8_t *F, u_int32_t bitmask, int32_t i, int32_t rs, int32_t ps, int32_t N) +/* F : pointeur de base de l'image */ +/* bitmask : masque du bit à tester */ +/* i : index du point dans l'image */ +/* rs : taille d'une rangee */ +/* ps : taille d'un plan */ +/* N : taille de l'image 3D */ +/* ==================================== */ +{ + u_int32_t mask = 0; + int32_t k, v; + for (k = 0; k < 26; k++) + { + v = voisin26(i, k, rs, ps, N); + if ((v != -1) && (F[v] & bitmask)) + mask = mask | (1<<k); + } + return mask; +} Index: abraham/tests/morpho/ref/src/lib/lwshedtopo.c --- abraham/tests/morpho/ref/src/lib/lwshedtopo.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/lwshedtopo.c (revision 0) @@ -0,0 +1,1011 @@ +/* $Id: lwshedtopo.c,v 1.14 2006/02/28 07:49:16 michel Exp $ */ +/* + Ligne de partage des eaux topologique (nouvelle version) + + Ref: CBN04 + + Michel Couprie - septembre 2003 + Laurent Najman - mai 2005 + +Updates: + MC - cor. bug mem. alloc. - 12 juillet 2005 +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <math.h> +#include <mcimage.h> +#include <mccodimage.h> +#include <mcfahsalembier.h> +#include <mccomptree.h> +#include <mcutil.h> +#include <mcindic.h> +#include <lwshedtopo.h> +#include <assert.h> + +static void compressTree(ctree *CT, int32_t *CM, int32_t *newCM, int32_t N); +static void reconsTree(ctree *CT, int32_t *CM, int32_t *newCM, int32_t N, u_int8_t *G); + +#define EN_FAH 0 +#define WATERSHED 1 +#define MASSIF 2 +#define MODIFIE 4 +#define LCA1 0x08 + +//#define VERBOSE +//#define _DEBUG_ +//#define PARANO + +// If you want the first version (slower), +// uncomment the following line +//#define OLDVERSION +// If you want the first version of lwshedtopobin (slower, BUT WHICH WORKS), +// uncomment the following line +//#define OLDVERSIONBIN + +// If you want to compute slowly the LCA in the watershed, uncomment the following line +//#define LCASLOW + +/* ==================================== */ +static int32_t TrouveComposantes(int32_t x, u_int8_t *F, int32_t rs, int32_t ps, int32_t N, int32_t connex, + int32_t *CM, int32_t *tabcomp) +/* ==================================== */ +// variante sans simplification +// place la plus haute composante (ou l'une des plus hautes) en premier +{ + int32_t k, y, n = 1, maxval = F[x], first = 1; + + switch (connex) + { + case 4: + for (k = 0; k < 8; k += 2) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin(x, k, rs, N); + if ((y != -1) && (F[y] > maxval)) maxval = F[y]; + } /* for (k = 0; k < 8; k += 2) */ + if (maxval == F[x]) return 0; + for (k = 0; k < 8; k += 2) // parcourt les c-voisins y de x d'un niveau > F[x] + + { y = voisin(x, k, rs, N); + if ((y != -1) && (F[y] > F[x])) + { if (first && (F[y] == maxval)) { tabcomp[0] = CM[y]; first = 0; } + else { tabcomp[n] = CM[y]; n++; } + } + } break; + case 8: + for (k = 0; k < 8; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin(x, k, rs, N); + if ((y != -1) && (F[y] > maxval)) maxval = F[y]; + } /* for (k = 0; k < 8; k += 1) */ + if (maxval == F[x]) return 0; + for (k = 0; k < 8; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin(x, k, rs, N); + if ((y != -1) && (F[y] > F[x])) + { if (first && (F[y] == maxval)) { tabcomp[0] = CM[y]; first = 0; } + else { tabcomp[n] = CM[y]; n++; } + } + } break; + case 6: + for (k = 0; k <= 10; k += 2) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin6(x, k, rs, ps, N); + if ((y != -1) && (F[y] > maxval)) maxval = F[y]; + } + if (maxval == F[x]) return 0; + for (k = 0; k <= 10; k += 2) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin6(x, k, rs, ps, N); + if ((y != -1) && (F[y] > F[x])) + { if (first && (F[y] == maxval)) { tabcomp[0] = CM[y]; first = 0; } + else { tabcomp[n] = CM[y]; n++; } + } + } break; + case 18: + for (k = 0; k < 18; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin18(x, k, rs, ps, N); + if ((y != -1) && (F[y] > maxval)) maxval = F[y]; + } + if (maxval == F[x]) return 0; + for (k = 0; k < 18; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin18(x, k, rs, ps, N); + if ((y != -1) && (F[y] > F[x])) + { if (first && (F[y] == maxval)) { tabcomp[0] = CM[y]; first = 0; } + else { tabcomp[n] = CM[y]; n++; } + } + } break; + case 26: + for (k = 0; k < 26; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin26(x, k, rs, ps, N); + if ((y != -1) && (F[y] > maxval)) maxval = F[y]; + } + if (maxval == F[x]) return 0; + for (k = 0; k < 26; k += 1) // parcourt les c-voisins y de x d'un niveau > F[x] + { y = voisin26(x, k, rs, ps, N); + if ((y != -1) && (F[y] > F[x])) + { if (first && (F[y] == maxval)) { tabcomp[0] = CM[y]; first = 0; } + else { tabcomp[n] = CM[y]; n++; } + } + } break; + } // switch (connex) + return n; +} // TrouveComposantes() + + +/* ==================================== */ +static int32_t LowComAncSlow( + ctree * CT, + int32_t c1, + int32_t c2) +/* Retourne le plus proche commun ancetre des cellules c1,c2 + Utilise le champ "flags". +*/ +/* ==================================== */ +#undef F_NAME +#define F_NAME "LowComAncSlow" +{ + int32_t x, i, lca = -1; + + x = c1; do + { + CT->flags[x] |= LCA1; /* marque LCA1 tous les ancetres de x */ + x = CT->tabnodes[x].father; + } while (x != -1); + + x = c2; do + { /* remonte les ancetres de x */ + if (CT->flags[x] & LCA1) { lca = x; break; } + x = CT->tabnodes[x].father; + } while (x != -1); + + x = c1; do + { /* derniere remontee: demarque */ + CT->flags[x] &= ~LCA1; + x = CT->tabnodes[x].father; + } while (x != -1); +#ifdef PARANO + if (lca == -1) + { + fprintf(stderr, "%s: lca not found\n", F_NAME); + exit(0); + } +#endif + return lca; +} // LowComAncSlow() + +///////////////////////////////////////// +// lca : Nearest (Lowest) Common Ancestor +// +// From: The LCA Problem Revisited +// M.A. Bender - M. Farach-Colton +// + +// Depth-first preprocessing +int32_t LCApreprocessDepthFirst(ctree *CT, int32_t node, int32_t depth, int32_t *nbr, int32_t *rep, int32_t *Euler, int32_t *Represent, int32_t *Depth, int32_t *Number) +{ + int32_t son; + soncell *sc; + + if (CT->tabnodes[node].nbsons > -1) { + (*nbr)++; + Euler[*nbr] = node; + Number[node] = *nbr; + Depth[node] = depth; + Represent[*nbr] = node; + //Represent[(*rep)++] = *nbr; + (*rep)++; + for (sc = CT->tabnodes[node].sonlist; sc != NULL; sc = sc->next) { + son = sc->son; + LCApreprocessDepthFirst(CT, son, depth+1, nbr, rep, Euler, Represent, Depth, Number); + Euler[++(*nbr)] = node; + } + } + return *nbr; +} + +int32_t ** LCApreprocess(ctree *CT, int32_t *Euler, int32_t *Depth, int32_t *Represent, int32_t *Number, int32_t *nbR, int32_t *lognR) +#undef F_NAME +#define F_NAME "LCApreprocess" +{ + //O(n.log(n)) preprocessing + int32_t nbr, rep, nbNodes; + int32_t nbRepresent; + int32_t logn; + int32_t i,j,k1,k2; + int32_t *minim; + int32_t **Minim; + + nbr = -1; // Initialization number of euler nodes + rep = 0; + + + nbr = LCApreprocessDepthFirst(CT, CT->root, 0, &nbr, &rep, Euler, Represent, Depth, Number); +#ifdef _DEBUG_ + ComponentTreePrint(CT); +#endif + nbNodes = rep; + + // Check that the number of nodes in the tree was correct +#ifdef _DEBUG_ + printf("rep = %d, nbr = %d, nbnodes = %d, 2*nbnodes = %d\n", rep, nbr, nbNodes, 2*nbNodes); +#endif + assert((nbr+1) == (2*nbNodes-1)); + + nbRepresent = 2*nbNodes-1; + logn = (int32_t)(ceil(log((double)(nbRepresent))/log(2.0))); + *nbR = nbRepresent; + *lognR = logn; + + minim = (int32_t *)calloc(logn*nbRepresent, sizeof(int32_t)); + Minim = (int32_t **)calloc(logn, sizeof(int32_t*)); + if ((minim == NULL) || (Minim == NULL)) { + fprintf(stderr, "%s : malloc failed\n", F_NAME); + return NULL; + } + Minim[0] = minim; + + for (i=0; i<nbRepresent-1; i++) { + if (Depth[Euler[i]] < Depth[Euler[i+1]]) { + Minim[0][i] = i; + } else { + Minim[0][i] = i+1; + } + } + Minim[0][nbRepresent-1] = nbRepresent-1; + + for (j=1; j<logn; j++) { + k1 = 1<<(j-1); + k2 = k1<<1; + Minim[j] = &minim[j*nbRepresent]; + for (i=0; i<nbRepresent; i++) { + if ((i+ k2) >= nbRepresent) { + Minim[j][i] = nbRepresent-1; + } else { + if (Depth[Euler[Minim[j-1][i]]] <= Depth[Euler[Minim[j-1][i+k1]]]) { + Minim[j][i] = Minim[j-1][i]; + } else { + Minim[j][i] = Minim[j-1][i+k1]; + } + } + } + } +#ifdef _DEBUG_ + for (i=0; i<logn; i++) { + for (j=0; j<nbRepresent; j++) + printf("M[%d][%d] = %d - ", i, j, Minim[i][j]); + printf("\n"); + } +#endif + return Minim; +} + +int32_t LowComAncFast(int32_t n1, int32_t n2, int32_t *Euler, int32_t *Number, int32_t *Depth, int32_t **Minim) +#undef F_NAME +#define F_NAME "LowComAncFast" +{ + int32_t ii, jj, kk, k; + + ii = Number[n1]; + jj = Number[n2]; + if (ii == jj) + return ii; + + if (ii > jj) { + kk = jj; + jj = ii; + ii = kk; + } + + k = (int32_t)(log((double)(jj - ii))/log(2.)); + + if (Depth[Euler[Minim[k][ii]]] < Depth[Euler[Minim[k][jj-(1<<(k))]]]) { + return Number[Euler[Minim[k][ii]]]; + } else { + return Number[Euler[Minim[k][jj-(1<<k)]]]; + } +} + +/* ==================================== */ +static int32_t W_Constructible(int32_t x, u_int8_t *F, int32_t rs, int32_t ps, int32_t N, int32_t connex, + ctree *CT, int32_t *CM, int32_t *tabcomp, + int32_t *c, int32_t *lcalevel +#ifndef LCASLOW + , int32_t *Euler, int32_t *Represent, int32_t *Depth, int32_t *Number, int32_t **Minim +#endif + ) + +/* ==================================== */ +// Si x est W-construcible, le couple [c, lcalevel] représente la composante (avec son niveau) +// à laquelle x peut être ajouté. +// Sinon la valeur retournée dans c est -1 +{ + int32_t c1, k, ncomp = TrouveComposantes(x, F, rs, ps, N, connex, CM, tabcomp); + + if (ncomp > 0) + { + if (ncomp == 1) *c = tabcomp[0]; + else + { + *c = tabcomp[0]; + for (k = 1; k < ncomp; k++) + { +#ifdef LCASLOW + c1 = LowComAncSlow(CT, *c, tabcomp[k]); +#else + c1 = Represent[LowComAncFast(*c, tabcomp[k], Euler, Number, Depth, Minim)]; +#endif + if (c1 != tabcomp[k]) *c = c1; + } + } + *lcalevel = CT->tabnodes[*c].data; + if (*lcalevel <= F[x]) *c = -1; + } + else *c = -1; +} // W_Constructible() + +/* ==================================== */ +static void Watershed(struct xvimage *image, int32_t connex, + Fah * FAH, int32_t *CM, ctree * CT) +/* ==================================== */ +// +// inondation a partir des voisins des maxima, suivant les ndg decroissants +// nouvelle (08/03) caracterisation des points destructibles +// nouvelle (09/03) construction de l'arbre des composantes +// Nouvelle (05/05) lca en temps constant + qq optimisation de l'article JMIV (najmanl) +#undef F_NAME +#define F_NAME "Watershed" +{ + u_int8_t *F = UCHARDATA(image); + int32_t rs = rowsize(image); + int32_t ps = rs * colsize(image); + int32_t N = ps * depth(image); + int32_t i, j, k, x, y; + int32_t c; /* une composante */ + int32_t tabcomp[26]; /* liste de composantes */ + int32_t ncomp; /* nombre de composantes dans tabcomp */ + int32_t nbelev; /* nombre d'elevations effectuees */ + int32_t lcalevel; /* niveau du lca */ + int32_t incr_vois; +#ifndef LCASLOW + int32_t logn, nbRepresent; + int32_t *Euler, *Depth, *Represent, *Number, **Minim; +#endif + // INITIALISATIONS + FahFlush(FAH); // Re-initialise la FAH + +#ifndef LCASLOW + Euler = (int32_t *)calloc(2*CT->nbnodes-1, sizeof(int32_t)); + Represent = (int32_t *)calloc(CT->nbnodes, sizeof(int32_t)); + Depth = (int32_t *)calloc(CT->nbnodes, sizeof(int32_t)); + Number = (int32_t *)calloc(CT->nbnodes, sizeof(int32_t)); + if ((Euler == NULL) || (Represent == NULL) + || (Depth == NULL) || (Number == NULL)) { + fprintf(stderr, "%s : malloc failed\n", F_NAME); + return; + } + + Minim = LCApreprocess(CT, Euler, Depth, Represent, Number, &nbRepresent, &logn); +#ifdef _DEBUG_ + printf("Comparison Slow/Fast lca\n"); + { + int32_t i,j, anc; + int32_t nbErrors = 0; + for (i=0; i<CT->nbnodes; i++) + for (j=0; j<CT->nbnodes; j++) { + if ((CT->tabnodes[i].nbsons > -1) && (CT->tabnodes[j].nbsons > -1)) { + anc = Represent[LowComAncFast(i,j,Euler,Number,Depth,Minim)]; + if (anc != LowComAncSlow(CT,i,j)) { + nbErrors++; + printf("Error node lca(%d, %d) = %d ou %d ?\n", i, j, anc, LowComAncSlow(CT,i,j)); + } else { + printf("Ok node lca(%d, %d) = %d\n", i, j, anc); + } + } + } + printf("Nb errors = %d\n",nbErrors); + } + fflush(stdout); +#endif // _DEBUG_ +#endif //ifndef LCASLOW + + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; + } /* switch (connex) */ + + // etiquetage des c-maxima (doit pouvoir se faire au vol lors de la construction de l'arbre) + for (i = 0; i < N; i++) + { + c = CM[i]; + if (CT->tabnodes[c].nbsons == 0) { + Set(i,MASSIF); + } + } // for (i = 0; i < N; i++) + + // empile les points + for (i = 0; i < N; i++) + { +#ifdef OLDVERSION + // empile tous les points + Set(i,EN_FAH); + FahPush(FAH, i, NDG_MAX - F[i]); +#else + // empile les points voisins d'un minima + char flag=0; + switch (connex) + { + case 4: + case 8: + for (k = 0; (k < 8) && (flag == 0); k += incr_vois) + { y = voisin(i, k, rs, N); + if ((y != -1) && (IsSet(y,MASSIF))) + { flag = 1; } + } + break; + case 6: + for (k = 0; k <= 10; k += 2) + { y = voisin6(x, k, rs, ps, N); + if ((y != -1) && (IsSet(y,MASSIF))) + { flag = 1; } + } break; + case 18: + for (k = 0; k < 18; k += 1) + { y = voisin18(x, k, rs, ps, N); + if ((y != -1) && (IsSet(y,MASSIF))) + { flag = 1; } + } break; + case 26: + for (k = 0; k < 26; k += 1) + { y = voisin26(x, k, rs, ps, N); + if ((y != -1) && (IsSet(y,MASSIF))) + { flag = 1; } + } break; + } /* switch (connex) */ + if (flag) { + Set(i,EN_FAH); FahPush(FAH, i, NDG_MAX - F[i]); + } +#endif + } // for (i = 0; i < N; i++) + + + // BOUCLE PRINCIPALE + nbelev = 0; + while (!FahVide(FAH)) + { + x = FahPop(FAH); + UnSet(x,EN_FAH); + W_Constructible(x, F, rs, ps, N, connex, CT, CM, tabcomp, &c, &lcalevel +#ifndef LCASLOW + , Euler, Represent, Depth, Number, Minim +#endif + ); + if (c != -1) + { + nbelev++; + F[x] = lcalevel; // eleve le niveau du point x + CM[x] = c; // maj pointeur image -> composantes + Set(x,MODIFIE); + if (CT->tabnodes[c].nbsons == 0) // feuille + { + Set(x,MASSIF); + } // if feuille + else + if (CT->tabnodes[c].nbsons > 1) // noeud + { + } +#ifdef PARANO + else + printf("%s : ERREUR COMPOSANTE BRANCHE!!!\n", F_NAME); +#endif + // empile les c-voisins de x non marques MASSIF ni EN_FAH + switch (connex) + { + case 4: + case 8: + for (k = 0; k < 8; k += incr_vois) + { y = voisin(x, k, rs, N); + if ((y != -1) && (!IsSet(y,MASSIF)) && (!IsSet(y,EN_FAH))) + { Set(y,EN_FAH); FahPush(FAH, y, NDG_MAX - F[y]); } + } break; + case 6: + for (k = 0; k <= 10; k += 2) + { y = voisin6(x, k, rs, ps, N); + if ((y != -1) && (!IsSet(y,MASSIF)) && (!IsSet(y,EN_FAH))) + { Set(y,EN_FAH); FahPush(FAH, y, NDG_MAX - F[y]); } + } break; + case 18: + for (k = 0; k < 18; k += 1) + { y = voisin18(x, k, rs, ps, N); + if ((y != -1) && (!IsSet(y,MASSIF)) && (!IsSet(y,EN_FAH))) + { Set(y,EN_FAH); FahPush(FAH, y, NDG_MAX - F[y]); } + } break; + case 26: + for (k = 0; k < 26; k += 1) + { y = voisin26(x, k, rs, ps, N); + if ((y != -1) && (!IsSet(y,MASSIF)) && (!IsSet(y,EN_FAH))) + { Set(y,EN_FAH); FahPush(FAH, y, NDG_MAX - F[y]); } + } break; + } /* switch (connex) */ + } // if (c != -1)} + } // while (!FahVide(FAH)) +#ifdef VERBOSE + printf("Nombre d'elevations %d\n", nbelev); +#endif + +#ifndef LCASLOW + free(Euler); + free(Represent); + free(Depth); + free(Number); + free(Minim[0]); + free(Minim); +#endif //LCASLOW +} // Watershed() + +/* ==================================== */ +int32_t lwshedtopo(struct xvimage *image, int32_t connex) +/* ==================================== */ +/*! \fn int32_t lwshedtopo(struct xvimage *image, int32_t connex) + \param image (entrée/sortie) : une image 2D ndg + \param connex (entrée) : 4 ou 8 (2D), 6, 18 ou 26 (3D) + \return code erreur : 0 si échec, 1 sinon + \brief ligne de partage des eaux "topologique" (algo MC, GB, LN) +*/ +#undef F_NAME +#define F_NAME "lwshedtopo" +{ + register int32_t i, j, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + u_int8_t *F = UCHARDATA(image); /* l'image de depart */ + Fah * FAH; /* la file d'attente hierarchique */ + int32_t *CM, *newCM; /* etat d'un pixel */ + ctree * CT; /* resultat : l'arbre des composantes */ + + FAH = CreeFahVide(N); + if (FAH == NULL) + { fprintf(stderr, "%s() : CreeFahVide failed\n", F_NAME); + return 0; + } + if ((connex == 4) || (connex == 8)) + { + if (!ComponentTree(F, rs, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + else if ((connex == 6) || (connex == 18) || (connex == 26)) + { + if (!ComponentTree3d(F, rs, ps, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + else + { fprintf(stderr, "%s() : bad value for connex : %s\n", F_NAME, connex); + return 0; + } +#ifndef OLDVERSION + newCM = (int32_t *)calloc(CT->nbnodes, sizeof(int32_t)); + if (newCM == NULL) { + fprintf(stderr, "%s : malloc failed\n", F_NAME); + return 0; + } + compressTree(CT, CM, newCM, N); + free(newCM); +#endif + + IndicsInit(N); + Watershed(image, connex, FAH, CM, CT); + for (i=0; i<N; i++) + F[i] = CT->tabnodes[CM[i]].data; + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + IndicsTermine(); + FahTermine(FAH); + ComponentTreeFree(CT); + free(CM); + return(1); +} /* lwshedtopo() */ + +/* ==================================== */ +static void Reconstruction(struct xvimage *g, struct xvimage *f, int32_t *CM, ctree * CT) +/* ==================================== */ +#undef F_NAME +#define F_NAME "Reconstruction" +{ + u_int8_t *F = UCHARDATA(f); + u_int8_t *G = UCHARDATA(g); + int32_t rs = rowsize(f); /* taille ligne */ + int32_t cs = colsize(f); /* taille colonne */ + int32_t ds = depth(f); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + int32_t i, c, d; + + for (i = 0; i < N; i++) if (G[i] >= F[i]) CT->flags[CM[i]] = 1; // marque les feuilles + + for (d = 0; d < CT->nbnodes; d++) + if (CT->flags[d] == 1) + { // pour toutes les feuilles marquees + c = CT->tabnodes[d].father; + while ((c != -1) && (CT->flags[c] == 0)) + { + CT->flags[c] = 1; // marque tous les ancetres de c + c = CT->tabnodes[c].father; + } + } + + for (i = 0; i < N; i++) // AMELIORATION POSSIBLE !!! + { + c = CM[i]; + while ((CT->flags[c] == 0) && (CT->tabnodes[c].father != -1)) + { + c = CT->tabnodes[c].father; + } + G[i] = CT->tabnodes[c].data; + } + +} // Reconstruction() + +/* ==================================== */ +int32_t lreconsdilat( + struct xvimage *g, + struct xvimage *f, + int32_t connex) +/* reconstruction de g sous f */ +/* g : image marqueur */ +/* f : image masque */ +/* connex : 4 ou 8 */ +/* resultat dans g */ +/* ==================================== */ +{ +#undef F_NAME +#define F_NAME "lreconsdilat" + u_int8_t *F = UCHARDATA(f); + int32_t rs = rowsize(f); /* taille ligne */ + int32_t cs = colsize(f); /* taille colonne */ + int32_t ds = depth(f); /* nb plans */ + int32_t N = rs * cs * ds; + int32_t *CM; // component mapping + ctree * CT; // component tree + + if ((rowsize(g) != rs) || (colsize(g) != cs) || (depth(g) != ds)) + { + fprintf(stderr, "%s: incompatible sizes\n", F_NAME); + return 0; + } + + ComponentTree(F, rs, N, connex, &CT, &CM); + Reconstruction(g, f, CM, CT); + + ComponentTreeFree(CT); + free(CM); + return(1); +} /* lreconsdilat() */ + +/* ==================================== */ +int32_t lreconseros( + struct xvimage *g, + struct xvimage *f, + int32_t connex) +/* reconstruction de g sur f */ +/* g : image marqueur */ +/* f : image masque */ +/* connex : 4 ou 8 */ +/* resultat dans g */ +/* ==================================== */ +{ +#undef F_NAME +#define F_NAME "lreconseros" + int32_t ret, i; + int32_t rs = rowsize(f); /* taille ligne */ + int32_t cs = colsize(f); /* taille colonne */ + int32_t ds = depth(f); /* nb plans */ + int32_t N = rs * cs * ds; + u_int8_t *F = UCHARDATA(f); + u_int8_t *G = UCHARDATA(g); + if ((rowsize(g) != rs) || (colsize(g) != cs) || (depth(g) != ds)) + { + fprintf(stderr, "%s: incompatible sizes\n", F_NAME); + return 0; + } + for (i = 0; i < N; i++) F[i] = NDG_MAX - F[i]; + for (i = 0; i < N; i++) G[i] = NDG_MAX - G[i]; + ret = lreconsdilat(g, f, connex); + for (i = 0; i < N; i++) G[i] = NDG_MAX - G[i]; + + return(ret); +} /* lreconseros() */ + + +static void reconsTree(ctree *CT, int32_t *CM, int32_t *newCM, int32_t N, u_int8_t *G) +{ + int32_t d, c, e, i; + +#ifdef _DEBUG_ + printf("Reconstruction - Marquage\n"); +#endif + + for (d = 0; d < CT->nbnodes; d++) CT->flags[d] == 0; // utile ??? + for (i = 0; i < N; i++) if (G[i]) CT->flags[CM[i]] = 1; // marque les feuilles + + for (d = 0; d < CT->nbnodes; d++) + if ((CT->tabnodes[d].nbsons == 0) && (CT->flags[d] == 1)) + { // pour toutes les feuilles marquees + c = CT->tabnodes[d].father; + while ((c != -1) && (CT->flags[c] == 0)) + { + CT->flags[c] = 1; // marque tous les ancetres de c + c = CT->tabnodes[c].father; + } + } + +#ifdef _DEBUG_ + printf("Reconstruction - Elimination arbre\n"); +#endif + // elimine les feuilles non marquees + for (d = 0; d < CT->nbnodes; d++) { + if ((CT->tabnodes[d].nbsons == 0) && (CT->flags[d] == 0)) { + // pour toutes les feuilles non marquees + c = CT->tabnodes[d].father; // récupère le père marqué + while (CT->flags[c] == 0) + { + c = CT->tabnodes[c].father; + } +#ifdef PARANO + if (c < 0) { + printf("ERROR : Father is lower than 0\n"); + } +#endif + e=d; + while ((e != c) && (CT->tabnodes[e].nbsons != -2)) { + if (CT->tabnodes[e].father == c) { // remove the son which is elevated to the father + soncell *sc, *prev = NULL; + for (sc = CT->tabnodes[c].sonlist; sc != NULL; sc = sc->next) { + if (sc->son == e) { + CT->tabnodes[c].nbsons--; + if (prev) { + prev->next = sc->next; + } else { + CT->tabnodes[c].sonlist = sc->next; + } + break; + } + prev = sc; + } + } + // Save the number of the node to which e has been moved + newCM[e] = c; + CT->tabnodes[e].nbsons = -2; + e = CT->tabnodes[e].father; + } + } // if ((CT->tabnodes[d].nbsons == 0) && (CT->flags[d] == 0)) + } // for (d = 0; d < CT->nbnodes; d++) + + // change the component mapping BUT NOT THE GRAY VALUE of the original image + // That allows to place the watershed line on the original contour + // while having done the reconstruction on the component tree only. + + // LNA 16Septembre 2005 + // Well apparently we have to reconstruct the original image + // It is done that later in the main procedure + // I do not fully understand why it is the case + + for (i=0; i<N; i++) { + if (CT->tabnodes[CM[i]].nbsons == -2) { + CM[i] = newCM[CM[i]]; + // However, we can build the reconstructed image. + G[i] = CT->tabnodes[CM[i]].data; + } + } +} + +static void compressTree(ctree *CT, int32_t *CM, int32_t *newCM, int32_t N) +{ + // Compress the component tree + // suppress all nodes that have only one son + int32_t i, d, c, e, f; + + //ComponentTreePrint(CT); + for (d = 0; d < CT->nbnodes; d++) CT->flags[d] == 0; // utile !! + for (d = 0; d < CT->nbnodes; d++) { + if (CT->tabnodes[d].nbsons == 0) { // C'est une feuille + c = CT->tabnodes[d].father; + //while ((CT->tabnodes[c].father != -1) && (CT->flags[c]==0)) { + while ((c!=-1) && (CT->flags[c]==0)) { + if ((CT->tabnodes[c].nbsons == 1) && (CT->tabnodes[c].father != -1)) { + soncell *sc = NULL; + f = CT->tabnodes[c].father; + e = CT->tabnodes[c].sonlist->son; + for (sc = CT->tabnodes[f].sonlist; sc != NULL; sc = sc->next) + { + if (sc->son == c) + { + sc->son = e; + break; + } + } +#ifdef PARANO + if (sc != NULL) + if (sc->son != e) printf("Compress Erreur %d != %d\n", sc->son, e); +#endif + CT->tabnodes[e].father = f; + CT->tabnodes[c].nbsons = -3; + newCM[c] = e; + if (CT->tabnodes[c].father == -1) + CT->root = e; + } + CT->flags[c] = 1; + c = CT->tabnodes[c].father; + } + } + } + + // Change the component mapping BUT NOT THE GRAY VALUE + // That allows to place the watershed line on the original contour + // while having done the reconstruction on the component tree only. + for (i=0; i<N; i++) { + if (CT->tabnodes[CM[i]].nbsons == -3) { + CM[i] = newCM[CM[i]]; + } + } +} + +/* ==================================== */ +int32_t lwshedtopobin(struct xvimage *image, struct xvimage *marqueur, int32_t connex) +/* ==================================== */ +/*! \fn int32_t lwshedtopobin(struct xvimage *image, struct xvimage *marqueur, int32_t connex) + \param image (entrée/sortie) : une image ndg + \param marqueur (entrée/sortie) : une image binaire + \param connex (entrée) : 4 ou 8 (2D), 6, 18 ou 26 (3D) + \return code erreur : 0 si échec, 1 sinon + \brief ligne de partage des eaux "topologique" binaire (algo MC, GB, LN) +*/ +#undef F_NAME +#define F_NAME "lwshedtopobin" +{ + register int32_t i, j, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + u_int8_t *F = UCHARDATA(image); + u_int8_t *G = UCHARDATA(marqueur); + Fah * FAH; /* la file d'attente hierarchique */ + int32_t incr_vois; /* 1 pour la 8-connexite, 2 pour la 4-connexite */ + int32_t *CM, *newCM; /* etat d'un pixel */ + ctree * CT; /* resultat : l'arbre des composantes */ + int32_t c, d, e; + + if ((rowsize(marqueur) != rs) || (colsize(marqueur) != cs) || (depth(marqueur) != ds)) + { + fprintf(stderr, "%s: incompatible sizes\n", F_NAME); + return 0; + } + + FAH = CreeFahVide(N); + if (FAH == NULL) + { fprintf(stderr, "%s() : CreeFahVide failed\n", F_NAME); + return 0; + } + + IndicsInit(N); + // imposition des maxima + for (i = 0; i < N; i++) if (G[i]) F[i] = G[i] = NDG_MAX; + +#ifdef _DEBUG_ + printf("Component tree\n"); +#endif + if ((connex == 4) || (connex == 8)) + { + if (!ComponentTree(F, rs, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + else if ((connex == 6) || (connex == 18) || (connex == 26)) + { + if (!ComponentTree3d(F, rs, ps, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + else + { fprintf(stderr, "%s() : bad value for connex : %s\n", F_NAME, connex); + return 0; + } + +#ifdef OLDVERSIONBIN +#ifdef _DEBUG_ + printf("Reconstruction \n"); +#endif + Reconstruction(marqueur, image, CM, CT); + ComponentTreeFree(CT); // AMELIORATION POSSIBLE: modification du CT et reutilisation pour la suite + free(CM); + +#ifdef _DEBUG_ + printf("Component tree \n"); +#endif + if ((connex == 4) || (connex == 8)) + { + if (!ComponentTree(G, rs, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + else + { + if (!ComponentTree3d(G, rs, ps, N, connex, &CT, &CM)) + { fprintf(stderr, "%s() : ComponentTree failed\n", F_NAME); + return 0; + } + } + + Watershed(marqueur, connex, FAH, CM, CT); +#endif // #ifdef OLDVERSIONBIN + +#ifndef OLDVERSIONBIN +#ifdef _DEBUG_ + printf("Reconstruction - par arbre\n"); +#endif + newCM = (int32_t *)calloc(CT->nbnodes, sizeof(int32_t)); + if (newCM == NULL) { + fprintf(stderr, "%s : malloc failed\n", F_NAME); + return 0; + } + reconsTree(CT, CM, newCM, N, G); + //writeimage(marqueur, "marqueur"); + + compressTree(CT, CM, newCM, N); + + // Reconstruction de l'image + for (x=0; x<N; x++) { + F[x] = CT->tabnodes[CM[x]].data; + } + //writeimage(image, "test"); + + /* Not useful + for (d = 0; d < CT->nbnodes; d++) { + if ((CT->tabnodes[d].nbsons == -2) || (CT->tabnodes[d].nbsons == -3)){ + CT->tabnodes[d].nbsons = -1; + } + } + */ + + Watershed(image, connex, FAH, CM, CT); +#endif // ifndef OLDVERSIONBIN + +#ifdef _DEBUG_ + printf("Watershed\n"); +#endif + +#ifdef _DEBUG_ + printf("Binarisation\n"); +#endif + for (i = 0; i < N; i++) + if (CT->tabnodes[CM[i]].nbsons == 0) // maximum + F[i] = NDG_MAX; + else + F[i] = NDG_MIN; + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + IndicsTermine(); + FahTermine(FAH); + ComponentTreeFree(CT); + free(CM); +#ifndef OLDVERSIONBIN + free(newCM); +#endif + return(1); +} /* lwshedtopobin() */ Index: abraham/tests/morpho/ref/src/lib/mcunionfind.c --- abraham/tests/morpho/ref/src/lib/mcunionfind.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mcunionfind.c (revision 0) @@ -0,0 +1,188 @@ +/* $Id: mcunionfind.c,v 1.5 2006/02/28 07:49:16 michel Exp $ */ +/* +Librairie mcunionfind : + +Structures et algorithmes pour l'union find +Ref: R.E. Tarjan, Data Structures and Network Algorithms, SIAM, 1978. + +Michel Couprie 2003 + +ATTENTION : L'opération de Link n'a de sens que si elle agit sur des représentants +(il faut faire find avant) - pas de vérification + +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mcutil.h> +#include <mcunionfind.h> + +/* +#define TESTUnionfind +*/ + +/* ==================================== */ +Tarjan * CreeTarjan(int32_t taille) +/* ==================================== */ +/*! \fn Tarjan * CreeTarjan(int32_t taille) + \param taille : nombre total d'éléments + \return pointeur sur une structure Tarjan + \brief crée une structure pour la fusion d'ensemble + \warning ne fait pas l'initialisation de la structure +*/ +#undef F_NAME +#define F_NAME "CreeTarjan" +{ + Tarjan * T = (Tarjan *)calloc(1,sizeof(Tarjan)); + T->Size = taille; + if (T == NULL) + { fprintf(stderr, "%s : malloc failed for T\n", F_NAME); + return(NULL); + } + T->Fth = (int32_t *)calloc(1,taille * sizeof(int32_t)); + if (T->Fth == NULL) + { fprintf(stderr, "%s : malloc failed for T->Fth\n", F_NAME); + return(NULL); + } + T->Rank = (int32_t *)calloc(1,taille * sizeof(int32_t)); + if (T->Rank == NULL) + { fprintf(stderr, "%s : malloc failed for T->Rank\n", F_NAME); + return(NULL); + } + return T; +} //CreeTarjan() + +/* ==================================== */ +void TarjanTermine(Tarjan * T) +/* ==================================== */ +/*! \fn void TarjanTermine(Tarjan * T) + \param T: une structure Tarjan + \brief libère la mémoire +*/ +{ + free(T->Fth); + free(T->Rank); + free(T); +} //TarjanTermine() + +/* ==================================== */ +void TarjanInit(Tarjan * T) +/* ==================================== */ +/*! \fn void TarjanInit(Tarjan * T) + \param T: une structure Tarjan + \brief initialise la structure (crée les singletons) +*/ +{ + int32_t i; + for (i = 0; i < T->Size; i++) TarjanMakeSet(T, i); +} //TarjanInit() + +/* ==================================== */ +void TarjanPrint(Tarjan * T) +/* ==================================== */ +/*! \fn void TarjanPrint(Tarjan * T) + \param T: une structure Tarjan + \brief affiche la structure +*/ +{ + int32_t i; + for (i = 0; i < T->Size; i++) + printf("%d: Rank = %d ; Fth = %d\n", i, T->Rank[i], T->Fth[i]); +} //TarjanPrint() + +/* ==================================== */ +void TarjanMakeSet(Tarjan * T, int32_t x) +/* ==================================== */ +/*! \fn void TarjanMakeSet(Tarjan * T, int32_t x) + \param T: une structure Tarjan + \param x: un élément + \brief ajoute le singleton {x} à la famille d'ensembles +*/ +{ + T->Fth[x] = x; + T->Rank[x] = 0; +} //TarjanMakeSet() + +/* ==================================== */ +int32_t TarjanFind(Tarjan * T, int32_t x) +/* ==================================== */ +/*! \fn int32_t TarjanFind(Tarjan * T, int32_t x) + \param T: une structure Tarjan + \param x: un élément + \return un représentant + \brief retourne le représentant de l'ensemble auquel appartient x + \warning x doit appartenir à un ensemble de la famille - pas de vérification +*/ +{ + if (T->Fth[x] != x) T->Fth[x] = TarjanFind(T, T->Fth[x]); + return T->Fth[x]; +} //TarjanFind() + +/* ==================================== */ +int32_t TarjanLink(Tarjan * T, int32_t x, int32_t y) +/* ==================================== */ +/*! \fn int32_t TarjanLink(Tarjan * T, int32_t x, int32_t y) + \param T: une structure Tarjan + \param x, y: deux représentants + \return un représentant + \brief fusionne les ensembles représentés par x et y et retourne le représentant de la fusion + \warning x et y doivent être des représentants - pas de vérification +*/ +{ + if (T->Rank[x] > T->Rank[y]) { int32_t tmp = x; x = y; y = tmp; } + if (T->Rank[x] == T->Rank[y]) T->Rank[y] += 1; + T->Fth[x] = y; + return y; +} //TarjanLink() + +/* ==================================== */ +int32_t TarjanLinkSafe(Tarjan * T, int32_t x, int32_t y) +/* ==================================== */ +/*! \fn int32_t TarjanLinkSafe(Tarjan * T, int32_t x, int32_t y) + \param T: une structure Tarjan + \param x, y: deux éléments + \return un représentant + \brief fusionne les ensembles auxquels appartiennent x et y et retourne le représentant de la fusion +*/ +{ + x = TarjanFind(T, x); + y = TarjanFind(T, y); + if (T->Rank[x] > T->Rank[y]) { int32_t tmp = x; x = y; y = tmp; } + if (T->Rank[x] == T->Rank[y]) T->Rank[y] += 1; + T->Fth[x] = y; + return y; +} //TarjanLinkSafe() + + +#ifdef TESTUnionfind +int32_t main() +{ + Tarjan * T = CreeTarjan(7); + char r[80]; + int32_t A, B; + TarjanInit(T); + + do + { + printf("commande (qUIT, lINK, fIND, pRINT) > "); + scanf("%s", r); + switch (r[0]) + { + case 'p': TarjanPrint(T); break; + case 'f': scanf("%d", &A); + A = TarjanFind(T, A); + printf("Result = %d\n", A); + break; + case 'l': scanf("%d", &A); + scanf("%d", &B); + A = TarjanLinkSafe(T, A, B); + printf("Result = %d\n", A); + break; + case 'q': break; + } + } while (r[0] != 'q'); + TarjanTermine(T); + return 0; +} +#endif Index: abraham/tests/morpho/ref/src/lib/mclifo.c --- abraham/tests/morpho/ref/src/lib/mclifo.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/mclifo.c (revision 0) @@ -0,0 +1,155 @@ +/* $Id: mclifo.c,v 1.6 2006/02/28 07:49:16 michel Exp $ */ +/* + Librairie mclifo : + + fonctions pour la gestion d'une liste lifo + + Michel Couprie 1996 +*/ + +/* #define TESTLifo */ +#include <stdio.h> +#include <sys/types.h> +#include <stdlib.h> +#include <mclifo.h> + +/* ==================================== */ +Lifo * CreeLifoVide( + int32_t taillemax) +/* ==================================== */ +{ + Lifo * L = (Lifo *)calloc(1,sizeof(Lifo) + sizeof(int32_t) * (taillemax-1)); + if (L == NULL) + { + fprintf(stderr, "CreeLifoVide() : malloc failed : %d bytes\n", + sizeof(Lifo) + sizeof(int32_t) * (taillemax-1)); + return NULL; + } + L->Max = taillemax; + L->Sp = 0; + return L; +} + +/* ==================================== */ +void LifoFlush( + Lifo * L) +/* ==================================== */ +{ + L->Sp = 0; +} + +/* ==================================== */ +int32_t LifoVide( + Lifo * L) +/* ==================================== */ +{ + return (L->Sp == 0); +} + +/* ==================================== */ +int32_t LifoPop( + Lifo * L) +/* ==================================== */ +{ + if (L->Sp == 0) + { + fprintf(stderr, "erreur Lifo vide\n"); + exit(1); + } + L->Sp -= 1; + return L->Pts[L->Sp]; +} + +/* ==================================== */ +int32_t LifoHead( + Lifo * L) +/* ==================================== */ +{ + if (L->Sp == 0) + { + fprintf(stderr, "erreur Lifo vide\n"); + exit(1); + } + return L->Pts[L->Sp-1]; +} + +/* ==================================== */ +void LifoPush(Lifo * L, int32_t V) +/* ==================================== */ +{ + if (L->Sp > L->Max - 1) + { + fprintf(stderr, "erreur Lifo pleine\n"); + exit(1); + } + L->Pts[L->Sp] = V; + L->Sp += 1; +} + +/* ==================================== */ +void LifoPrint(Lifo * L) +/* ==================================== */ +{ + int32_t i; + if (LifoVide(L)) {printf("[]"); return;} + printf("[ "); + for (i = 0; i < L->Sp; i++) + printf("%d ", L->Pts[i]); + printf("]"); +} + +/* ==================================== */ +void LifoPrintLine(Lifo * L) +/* ==================================== */ +{ + int32_t i; + if (LifoVide(L)) {printf("[]\n"); return;} +/* + printf("Max = %d ; Sp = %d \n", L->Max, L->Sp); +*/ + printf("[ "); + for (i = 0; i < L->Sp; i++) + printf("%d ", L->Pts[i]); + printf("]\n"); +} + +/* ==================================== */ +void LifoTermine( + Lifo * L) +/* ==================================== */ +{ + free(L); +} + +#ifdef TESTLifo +void main() +{ + Lifo * L = CreeLifoVide(3); + LifoPrint(L); + if (LifoVide(L)) printf("LifoVide OUI\n"); + LifoPush(L,1); + LifoPrint(L); + if (!LifoVide(L)) printf("LifoVide NON\n"); + LifoPush(L,2); + LifoPrint(L); + LifoPush(L,3); + LifoPrint(L); + printf("LifoPop %d attendu 3\n", LifoPop(L)); + LifoPrint(L); + LifoPush(L,4); + LifoPrint(L); + printf("LifoPop %d attendu 4\n", LifoPop(L)); + LifoPrint(L); + printf("LifoPop %d attendu 2\n", LifoPop(L)); + LifoPrint(L); + printf("LifoPop %d attendu 1\n", LifoPop(L)); + LifoPrint(L); + if (LifoVide(L)) printf("LifoVide OUI\n"); + printf("maintenant sortie attendue sur lifo pleine :\n"); + LifoPush(L,3); + LifoPush(L,3); + LifoPush(L,3); + LifoPush(L,3); +} +#endif + Index: abraham/tests/morpho/ref/src/lib/lattribheight.c --- abraham/tests/morpho/ref/src/lib/lattribheight.c (revision 0) +++ abraham/tests/morpho/ref/src/lib/lattribheight.c (revision 0) @@ -0,0 +1,717 @@ +/* $Id: lattribheight.c,v 1.8 2006/12/04 14:34:05 michel Exp $ */ +/* + Operateurs connexes bases sur l'attribut hauteur + ============================================= + (algorithme de P. Salembier) + + Operateurs : + lsegmentheight + lheightmaxima + lheightselnb (selection d'un nombre donne de composantes) + + Michel Couprie - 1999-2002 +*/ + +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> +#include <stdlib.h> +#include <math.h> +#include <mccodimage.h> +#include <mcimage.h> +#include <mclifo.h> +#include <mcfahsalembier.h> +#include <mcutil.h> +#include <mcindic.h> +#include <lattribheight.h> + +#define PARANO +/* +#define VERBOSE +#define DEBUG +#define DEBUGRECONS +#define DEBUGFLOOD +*/ + +#define ATTR_HEIGHT + +#include "lattrib.c" + +/* ======================================================================== */ +/* ======================================================================== */ +/* OPERATEURS BASES SUR L'ARBRE DES COMPOSANTES */ +/* ======================================================================== */ +/* ======================================================================== */ + +/* ==================================== */ +int32_t lsegmentheight(struct xvimage *image, int32_t connex, int32_t param, int32_t maximise) +/* ==================================== */ +{ + register int32_t i, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + uint8_t *F = UCHARDATA(image); /* l'image de depart */ + Fah * FAH; /* la file d'attente hierarchique */ + int32_t incr_vois; /* 1 pour la 8-connexite, 2 pour la 4-connexite */ + uint32_t *STATUS; /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la composante de niveau h */ + /* qui contient le pixel (avec h = valeur du pixel) */ + uint32_t *number_nodes; /* nombre de composantes par niveau */ + uint8_t *node_at_level; /* tableau de booleens */ + CompTree * TREE; /* resultat : l'arbre des composantes */ + CompactTree * CTREE; /* resultat : l'arbre des composantes compacte' */ + + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; + } /* switch (connex) */ + + FAH = CreeFahVide(N); + + STATUS = (uint32_t *)malloc(N * sizeof(int32_t)); + if (STATUS == NULL) + { fprintf(stderr, "lsegmentheight() : malloc failed for STATUS\n"); + return(0); + } + + number_nodes = (uint32_t *)calloc(256, sizeof(int32_t)); + if (number_nodes == NULL) + { fprintf(stderr, "lsegmentheight() : calloc failed for number_nodes\n"); + return(0); + } + + node_at_level = (uint8_t *)calloc(256, sizeof(char)); + if (node_at_level == NULL) + { fprintf(stderr, "lsegmentheight() : calloc failed for node_at_level\n"); + return(0); + } + + TREE = InitCompTree(N); + if (TREE == NULL) + { fprintf(stderr, "lsegmentheight() : InitCompTree failed\n"); + return(0); + } + + /* ================================================ */ + /* INITIALISATIONS */ + /* ================================================ */ + + for (i = 0; i < N; i++) STATUS[i] = NOT_ANALYZED; + k = 0; /* recherche un pixel k de niveau de gris minimal dans l'image */ + for (i = 1; i < N; i++) if (F[i] < F[k]) k = i; + FahPush(FAH, k, F[k]); + +#ifdef VERBOSE + fprintf(stderr, "init terminee\n"); +#endif + + /* ================================================ */ + /* APPEL FONCTION RECURSIVE flood */ + /* ================================================ */ + + if (ds == 1) { + if ((connex == 4) || (connex == 8)) + (void)flood(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, incr_vois, rs, N, F); + else if ((connex == 0) || (connex == 1)) + (void)floodb(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, N, F); + } else + (void)flood3d(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, ps, N, F); + +#ifdef VERBOSE + fprintf(stderr, "flood terminee\n"); +#endif +#ifdef DEBUG + AfficheCompTree(TREE); +#endif + + CTREE = CompTree2CompactTree(TREE, number_nodes); + +#ifdef VERBOSE + fprintf(stderr, "CompTree2CompactTree terminee\n"); +#endif + + CalculeAttributs(CTREE); + +#ifdef VERBOSE + fprintf(stderr, "CalculeAttributs terminee\n"); +#endif + +#ifdef DEBUG + AfficheCompactTree(CTREE); +#endif + + (void)FiltreHeightRec(CTREE, 0, param); + +#ifdef VERBOSE + fprintf(stderr, "FiltreHeightRec terminee\n"); +#endif + + if ( maximise ) + (void)MaximiseSegmentation(CTREE, 0); + +#ifdef VERBOSE + fprintf(stderr, "MaximiseSegmentation terminee\n"); +#endif + +#ifdef DEBUG + AfficheCompactTree(CTREE); + WriteCompactTree(CTREE, "ctree.graph"); +#endif + + RecupereSegmentation(CTREE, STATUS, rs, N, F); + +#ifdef VERBOSE + fprintf(stderr, "RecupereSegmentation terminee\n"); +#endif + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + FahTermine(FAH); + TermineCompTree(TREE); + TermineCompactTree(CTREE); + free(STATUS); + free(number_nodes); + free(node_at_level); + return(1); +} /* lsegmentheight() */ + +/* ==================================== */ +static void ProcessLeafMins(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + Recherche a partir du sommet som, les sommets marques LEAFMIN. + Demarque en remontant jusqu'au premier noeud. + Version pour un filtre morphologique (avec RecupereImageFiltreeH). +*/ +{ + int32_t i, j, n, h; + + if (!(cpct->flags[som] & LEAFMIN)) + { + n = NBFILS(som); /* remonte l'arbre pour trouver une LEAFMIN */ + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + ProcessLeafMins(cpct, j); + } + } + else /* (on a trouve une LEAFMIN) */ + { + cpct->flags[som] &= ~LEAFMIN; /* demarque som */ + while (NBFILS(som) == 1) /* remonte jusqu'au premier noeud ou feuille */ + { + som = INDEXFILS(som, 0); + som = cpct->fils[som]; + cpct->flags[som] &= ~FILTERED_OUT; + } + cpct->flags[som] |= LEAFMIN; /* marque */ + } +} /* ProcessLeafMins() */ + +/* ==================================== */ +static void ProcessLeafMinsOp(CompactTree * cpct, int32_t som) +/* ==================================== */ +/* + Recherche a partir du sommet som, les sommets marques LEAFMIN. + Demarque en remontant jusqu'a la feuille la plus haute. + Version pour une ouverture (avec RecupereImageFiltree). +*/ +{ + int32_t i, j, n, m, jm, h; + + if (!(cpct->flags[som] & LEAFMIN)) + { + n = NBFILS(som); /* remonte l'arbre pour trouver une LEAFMIN */ + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + ProcessLeafMinsOp(cpct, j); + } + } + else /* (on a trouve une LEAFMIN) */ + { + cpct->flags[som] &= ~LEAFMIN; /* demarque som */ + while (NBFILS(som) > 0) /* remonte jusqu'a une (vraie) feuille */ + { + /* recherche l'indice im du fils de hauteur maxi */ + n = NBFILS(som); + m = -1; + for (i = 0; i < n; i++) + { + j = INDEXFILS(som, i); + j = cpct->fils[j]; + h = DECODENIV(cpct->comp[j]) + cpct->height[j]; + if (h > m) { m = h; jm = j; } + } + /* remonte en demarquant */ + som = jm; + cpct->flags[som] &= ~FILTERED_OUT; + } + cpct->flags[som] |= LEAFMIN; /* marque LEAFMIN le sommet atteint */ + } +} /* ProcessLeafMinsOp() */ + +/* ==================================== */ +static void RecupereImageFiltreeH(CompactTree * cpct, + uint32_t *STATUS, + int32_t rs, int32_t N, + uint8_t *ORI /* informations sur l'image originale */ +) +/* ==================================== */ +{ + int32_t i, h; + uint32_t c, comp; + for (i = 0; i < N; i++) + { + h = ORI[i]; + c = STATUS[i]; + comp = INDEXCOMP(h,c); + while (cpct->flags[comp] == FILTERED_OUT) comp = cpct->pere[comp]; + if (cpct->flags[comp] & LEAFMIN) + ORI[i] = DECODENIV(cpct->comp[comp]) + cpct->height[comp]; + else + ORI[i] = DECODENIV(cpct->comp[comp]); + } +} /* RecupereImageFiltreeH() */ + +/* ==================================== */ +int32_t lheightmaxima_variante(struct xvimage *image, int32_t connex, int32_t param) +/* ==================================== */ +{ + register int32_t i, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + uint8_t *F = UCHARDATA(image); /* l'image de depart */ + Fah * FAH; /* la file d'attente hierarchique */ + int32_t incr_vois; /* 1 pour la 8-connexite, 2 pour la 4-connexite */ + uint32_t *STATUS; /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la composante de niveau h */ + /* qui contient le pixel (avec h = valeur du pixel) */ + uint32_t *number_nodes; /* nombre de composantes par niveau */ + uint8_t *node_at_level; /* tableau de booleens */ + CompTree * TREE; /* resultat : l'arbre des composantes */ + CompactTree * CTREE; /* resultat : l'arbre des composantes compacte' */ + + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; + } /* switch (connex) */ + + FAH = CreeFahVide(N); + + STATUS = (uint32_t *)malloc(N * sizeof(int32_t)); + if (STATUS == NULL) + { fprintf(stderr, "lheightopening() : malloc failed for STATUS\n"); + return(0); + } + + number_nodes = (uint32_t *)calloc(256, sizeof(int32_t)); + if (number_nodes == NULL) + { fprintf(stderr, "lheightopening() : calloc failed for number_nodes\n"); + return(0); + } + + node_at_level = (uint8_t *)calloc(256, sizeof(char)); + if (node_at_level == NULL) + { fprintf(stderr, "lheightopening() : calloc failed for node_at_level\n"); + return(0); + } + + TREE = InitCompTree(N); + if (TREE == NULL) + { fprintf(stderr, "lheightopening() : InitCompTree failed\n"); + return(0); + } + + /* ================================================ */ + /* INITIALISATIONS */ + /* ================================================ */ + + for (i = 0; i < N; i++) STATUS[i] = NOT_ANALYZED; + k = 0; /* recherche un pixel k de niveau de gris minimal dans l'image */ + for (i = 1; i < N; i++) if (F[i] < F[k]) k = i; + FahPush(FAH, k, F[k]); + +#ifdef VERBOSE + fprintf(stderr, "init terminee\n"); +#endif + + /* ================================================ */ + /* APPEL FONCTION RECURSIVE flood */ + /* ================================================ */ + if (ds == 1) { + if ((connex == 4) || (connex == 8)) + (void)flood(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, incr_vois, rs, N, F); + else if ((connex == 0) || (connex == 1)) + (void)floodb(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, N, F); + } else + (void)flood3d(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, ps, N, F); + +#ifdef VERBOSE +fprintf(stderr, "flood terminee\n"); +#endif +#ifdef DEBUG + AfficheCompTree(TREE); +#endif + + CTREE = CompTree2CompactTree(TREE, number_nodes); + +#ifdef VERBOSE + fprintf(stderr, "CompTree2CompactTree terminee\n"); +#endif +#ifdef DEBUG + AfficheCompactTree(CTREE); +#endif + + CalculeAttributs(CTREE); + +#ifdef VERBOSE + fprintf(stderr, "CalculeAttributs terminee\n"); +#endif + + (void)FiltreHeightRec(CTREE, 0, param); + +#ifdef VERBOSE + fprintf(stderr, "FiltreHeightRec terminee\n"); +#endif + +#ifdef DEBUG + AfficheCompactTree(CTREE); + WriteCompactTree(CTREE, "ctree.graph"); +#endif + + ProcessLeafMinsOp(CTREE, 0); + +#ifdef VERBOSE + fprintf(stderr, "ProcessLeafMinsOp terminee\n"); +#endif + + RecupereImageFiltree(CTREE, STATUS, rs, N, F); + +#ifdef VERBOSE + fprintf(stderr, "RecupereImageFiltree terminee\n"); +#endif + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + FahTermine(FAH); + TermineCompTree(TREE); + TermineCompactTree(CTREE); + free(STATUS); + free(number_nodes); + free(node_at_level); + return(1); +} /* lheightopening() */ + +/* ==================================== */ +int32_t lheightmaxima(struct xvimage *image, int32_t connex, int32_t param) +/* ==================================== */ +{ + register int32_t i, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + uint8_t *F = UCHARDATA(image); /* l'image de depart */ + Fah * FAH; /* la file d'attente hierarchique */ + int32_t incr_vois; /* 1 pour la 8-connexite, 2 pour la 4-connexite */ + uint32_t *STATUS; /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la composante de niveau h */ + /* qui contient le pixel (avec h = valeur du pixel) */ + uint32_t *number_nodes; /* nombre de composantes par niveau */ + uint8_t *node_at_level; /* tableau de booleens */ + CompTree * TREE; /* resultat : l'arbre des composantes */ + CompactTree * CTREE; /* resultat : l'arbre des composantes compacte' */ + + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; +} /* switch (connex) */ + + FAH = CreeFahVide(N); + + STATUS = (uint32_t *)malloc(N * sizeof(int32_t)); + if (STATUS == NULL) + { fprintf(stderr, "lheightmaxima() : malloc failed for STATUS\n"); + return(0); + } + + number_nodes = (uint32_t *)calloc(256, sizeof(int32_t)); + if (number_nodes == NULL) + { fprintf(stderr, "lheightmaxima() : calloc failed for number_nodes\n"); + return(0); + } + + node_at_level = (uint8_t *)calloc(256, sizeof(char)); + if (node_at_level == NULL) + { fprintf(stderr, "lheightmaxima() : calloc failed for node_at_level\n"); + return(0); + } + + TREE = InitCompTree(N); + if (TREE == NULL) + { fprintf(stderr, "lheightmaxima() : InitCompTree failed\n"); + return(0); + } + + /* ================================================ */ + /* INITIALISATIONS */ + /* ================================================ */ + + for (i = 0; i < N; i++) STATUS[i] = NOT_ANALYZED; + k = 0; /* recherche un pixel k de niveau de gris minimal dans l'image */ + for (i = 1; i < N; i++) if (F[i] < F[k]) k = i; + FahPush(FAH, k, F[k]); + +#ifdef VERBOSE + fprintf(stderr, "init terminee\n"); +#endif + + /* ================================================ */ + /* APPEL FONCTION RECURSIVE flood */ + /* ================================================ */ + + if (ds == 1) { + if ((connex == 4) || (connex == 8)) + (void)flood(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, incr_vois, rs, N, F); + else + if((connex == 0) || (connex == 1)) + (void)floodb(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, N, F); + } + else + (void)flood3d(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, ps, N, F); + +#ifdef VERBOSE + fprintf(stderr, "flood terminee\n"); +#endif +#ifdef DEBUG + AfficheCompTree(TREE); +#endif + + CTREE = CompTree2CompactTree(TREE, number_nodes); + +#ifdef VERBOSE + fprintf(stderr, "CompTree2CompactTree terminee\n"); +#endif +#ifdef DEBUG + AfficheCompactTree(CTREE); +#endif + + CalculeAttributs(CTREE); + +#ifdef VERBOSE + fprintf(stderr, "CalculeAttributs terminee\n"); +#endif + + (void)FiltreHeightRec(CTREE, 0, param); + +#ifdef VERBOSE + fprintf(stderr, "FiltreHeightRec terminee\n"); +#endif + +#ifdef DEBUG + AfficheCompactTree(CTREE); + WriteCompactTree(CTREE, "ctree.graph"); +#endif + + RecupereImageFiltree(CTREE, STATUS, rs, N, F); + +#ifdef VERBOSE + fprintf(stderr, "RecupereImageFiltree terminee\n"); +#endif + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + FahTermine(FAH); + TermineCompTree(TREE); + TermineCompactTree(CTREE); + free(STATUS); + free(number_nodes); + free(node_at_level); + return(1); +} /* lheightmaxima() */ + +/* ==================================== */ +int32_t lheightselnb(struct xvimage *image, int32_t connex, int32_t param, int32_t mode) +/* ==================================== */ +/* + param: nombre de composantes a trouver + mode: parametre obsolete +*/ +{ + register int32_t i, k, l; /* index muet */ + register int32_t w, x, y, z; /* index muet de pixel */ + int32_t rs = rowsize(image); /* taille ligne */ + int32_t cs = colsize(image); /* taille colonne */ + int32_t ds = depth(image); /* nb plans */ + int32_t ps = rs * cs; /* taille plan */ + int32_t N = ps * ds; /* taille image */ + uint8_t *F = UCHARDATA(image); /* l'image de depart */ + Fah * FAH; /* la file d'attente hierarchique */ + int32_t incr_vois; /* 1 pour la 8-connexite, 2 pour la 4-connexite */ + uint32_t *STATUS; /* etat d'un pixel - doit etre initialise a NOT_ANALYZED */ + /* en sortie, contient le numero de la composante de niveau h */ + /* qui contient le pixel (avec h = valeur du pixel) */ + uint32_t *number_nodes; /* nombre de composantes par niveau */ + uint8_t *node_at_level; /* tableau de booleens */ + CompTree * TREE; /* resultat : l'arbre des composantes */ + CompactTree * cpct; /* resultat : l'arbre des composantes compacte' */ + int32_t nbcomp, nbfeuilles; + int32_t *A; /* tableau pour le tri des composantes par hauteurs croissantes */ + + switch (connex) + { + case 4: incr_vois = 2; break; + case 8: incr_vois = 1; break; + } /* switch (connex) */ + + FAH = CreeFahVide(N); + + STATUS = (uint32_t *)malloc(N * sizeof(int32_t)); + if (STATUS == NULL) + { fprintf(stderr, "lheightselnb() : malloc failed for STATUS\n"); + return(0); + } + + number_nodes = (uint32_t *)calloc(256, sizeof(int32_t)); + if (number_nodes == NULL) + { fprintf(stderr, "lheightselnb() : calloc failed for number_nodes\n"); + return(0); + } + + node_at_level = (uint8_t *)calloc(256, sizeof(char)); + if (node_at_level == NULL) + { fprintf(stderr, "lheightselnb() : calloc failed for node_at_level\n"); + return(0); + } + + TREE = InitCompTree(N); + if (TREE == NULL) + { fprintf(stderr, "lheightselnb() : InitCompTree failed\n"); + return(0); + } + + /* ================================================ */ + /* INITIALISATIONS */ + /* ================================================ */ + + for (i = 0; i < N; i++) STATUS[i] = NOT_ANALYZED; + k = 0; /* recherche un pixel k de niveau de gris minimal dans l'image */ + for (i = 1; i < N; i++) if (F[i] < F[k]) k = i; + FahPush(FAH, k, F[k]); + +#ifdef VERBOSE + fprintf(stderr, "init terminee\n"); +#endif + + /* ================================================ */ + /* APPEL FONCTION RECURSIVE flood */ + /* ================================================ */ + + if (ds == 1) { + if ((connex == 4) || (connex == 8)) + (void)flood(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, incr_vois, rs, N, F); + else + if ((connex == 0) || (connex == 1)) + (void)floodb(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, N, F); + } else + (void)flood3d(F[k], FAH, STATUS, number_nodes, node_at_level, TREE, connex, rs, ps, N, F); + +#ifdef VERBOSE + fprintf(stderr, "flood terminee\n"); +#endif +#ifdef DEBUG + AfficheCompTree(TREE); +#endif + + cpct = CompTree2CompactTree(TREE, number_nodes); + +#ifdef VERBOSE + fprintf(stderr, "CompTree2CompactTree terminee\n"); +#endif + + CalculeAttributs(cpct); + +#ifdef VERBOSE + fprintf(stderr, "CalculeAttributs terminee\n"); +#endif +#ifdef DEBUG + AfficheCompactTree(cpct); +#endif + + nbfeuilles = LeafMark(cpct); + nbcomp = cpct->nbcomp; + A = (int32_t *)malloc(nbcomp * sizeof(int32_t)); + if (A == NULL) + { fprintf(stderr, "lheightselnb() : malloc failed\n"); + return(0); + } + for (i = 0; i < nbcomp; i++) A[i] = i; + i_TriRapideStochastique (A, cpct->height, 0, nbcomp-1); + i = 0; + while ((nbfeuilles > param) && (i < nbcomp)) + { + //printf("i = %d, A[i] = %d, cpct->height[A[i]] = %d, nbf = %d\n", + // i, A[i], cpct->height[A[i]], nbfeuilles); + if (NbFilsNonFiltres(cpct, A[i]) == 0) + { + cpct->flags[A[i]] |= FILTERED_OUT; + cpct->flags[A[i]] &= ~LEAF; + k = cpct->pere[A[i]]; + if (NbFilsNonFiltres(cpct, k) != 0) + nbfeuilles--; + else + cpct->flags[k] |= LEAF; + } +#ifdef PARANO + else + printf("Erreur imprevue : Composante non feuille : %d\n", A[i]); +#endif + i++; + } // while ((nbfeuilles > param) && (i < nbcomp)) + +#ifdef DEBUG + AfficheCompactTree(cpct); + WriteCompactTree(cpct, "ctree.graph"); +#endif + + RecupereSegmentation(cpct, STATUS, rs, N, F); + +#ifdef VERBOSE + fprintf(stderr, "RecupereSegmentation terminee\n"); +#endif + + /* ================================================ */ + /* UN PEU DE MENAGE */ + /* ================================================ */ + + FahTermine(FAH); + TermineCompTree(TREE); + TermineCompactTree(cpct); + free(STATUS); + free(number_nodes); + free(node_at_level); + free(A); + return(1); +} /* lheightselnb() */ Index: abraham/tests/morpho/ref/src/com/wshedtopo.c --- abraham/tests/morpho/ref/src/com/wshedtopo.c (revision 0) +++ abraham/tests/morpho/ref/src/com/wshedtopo.c (revision 0) @@ -0,0 +1,97 @@ +/* $Id: wshedtopo.c,v 1.12 2006/12/04 14:33:57 michel Exp $ */ +/*! \file wshedtopo.c + +\brief topological grayscale watershed + +<B>Usage:</B> wshedtopo in.pgm connex [i] out.pgm + +<B>Description:</B> +Topological grayscale watershed as defined in [CB97,CNB05]. + +The parameter \b connex indicates the connectivity of the minima. +Possible choices are 4, 8 in 2d and 6, 26 in 3d. + +If the parameter <B>i</B> is given, then the dual operator is applied. + +References: + +[CB97] M. Couprie and G. Bertrand: +``Topological Grayscale Watershed Transformation'', +SPIE Vision Geometry V Proceedings, 3168 (136--146), 1997. + +[CNB05] M. Couprie and L. Najman and G. Bertrand: +"Quasi-linear algorithms for the topological watershed", +Journal of Mathematical Imaging and Vision, Vol. 22, No. 2-3, pp. 231-249, 2005. + +<B>Types supported:</B> byte 2d, byte 3d + +<B>Category:</B> connect +\ingroup connect + +\author Michel Couprie +*/ + +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> +#include <mccodimage.h> +#include <mcimage.h> +#include <lwshedtopo.h> + +/* ==================================== */ +static void inverse(struct xvimage * image) +/* ==================================== */ +{ + int32_t i, N = rowsize(image) * colsize(image) * depth(image); + uint8_t *pt; + for (pt = UCHARDATA(image), i = 0; i < N; i++, pt++) + *pt = NDG_MAX - *pt; +} // inverse + +/* =============================================================== */ +int32_t main(argc, argv) +/* =============================================================== */ + int32_t argc; char **argv; +{ + struct xvimage * image; + int32_t connex; + + if ((argc != 4) && (argc != 5)) + { + fprintf(stderr, "usage: %s filein.pgm connex [i] fileout.pgm\n", argv[0]); + exit(1); + } + + if ((argc == 5) && strcmp(argv[3],"i")) + { + fprintf(stderr, "usage: %s filein.pgm connex [i] fileout.pgm\n", argv[0]); + exit(1); + } + + image = readimage(argv[1]); + if (image == NULL) + { + fprintf(stderr, "%s: readimage failed\n", argv[0]); + exit(1); + } + + connex = atoi(argv[2]); + + if (argc == 4) inverse(image); + if (! lwshedtopo(image, connex)) + { + fprintf(stderr, "%s: lwshedtopo failed\n", argv[0]); + exit(1); + } + if (argc == 4) inverse(image); + + writeimage(image, argv[argc - 1]); + freeimage(image); + + return 0; +} /* main */ + + + Index: abraham/tests/morpho/ref/Makefile --- abraham/tests/morpho/ref/Makefile (revision 0) +++ abraham/tests/morpho/ref/Makefile (revision 0) @@ -0,0 +1,52 @@ +TOPOWSHD = . +# Version LINUX + CC = cc + CCFLAGS = -g -DUNIXIO + ODIR = $(TOPOWSHD)/obj + BDIR = $(TOPOWSHD)/bin + IDIR = $(TOPOWSHD)/include + CDIR = $(TOPOWSHD)/src/com + LDIR = $(TOPOWSHD)/src/lib + LIBS = -lm + OBJ_COMMON = $(ODIR)/mcimage.o + +all: $(BDIR)/wshedtopo + +clean: + rm -f $(TOPOWSHD)/bin/* + rm -f $(TOPOWSHD)/obj/* + +# =============================================================== +# EXECUTABLES +# =============================================================== + +$(BDIR)/wshedtopo: $(CDIR)/wshedtopo.c $(IDIR)/mcimage.h $(IDIR)/mclifo.h $(IDIR)/mcindic.h $(IDIR)/mcfahsalembier.h $(IDIR)/mccodimage.h $(IDIR)/mccomptree.h $(IDIR)/lwshedtopo.h $(OBJ_COMMON) $(ODIR)/mclifo.o $(ODIR)/mcindic.o $(ODIR)/mcfahsalembier.o $(ODIR)/mccodimage.o $(ODIR)/mccomptree.o $(ODIR)/mcunionfind.o $(ODIR)/lwshedtopo.o + $(CC) $(CCFLAGS) -I$(IDIR) $(CDIR)/wshedtopo.c $(OBJ_COMMON) $(ODIR)/mcindic.o $(ODIR)/mclifo.o $(ODIR)/mcfahsalembier.o $(ODIR)/mccodimage.o $(ODIR)/mccomptree.o $(ODIR)/mcunionfind.o $(ODIR)/lwshedtopo.o $(LIBS) -o $(BDIR)/wshedtopo + +# ********************************* +# OBJECTS +# ********************************* + +$(ODIR)/lwshedtopo.o: $(LDIR)/lwshedtopo.c $(LDIR)/lattrib.c $(IDIR)/mcimage.h $(IDIR)/mccodimage.h $(IDIR)/mclifo.h $(IDIR)/mcfahsalembier.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/lwshedtopo.c -o $(ODIR)/lwshedtopo.o + +$(ODIR)/mccodimage.o: $(LDIR)/mccodimage.c $(IDIR)/mccodimage.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mccodimage.c -o $(ODIR)/mccodimage.o + +$(ODIR)/mccomptree.o: $(LDIR)/mccomptree.c $(IDIR)/mccomptree.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mccomptree.c -o $(ODIR)/mccomptree.o + +$(ODIR)/mcfahsalembier.o: $(LDIR)/mcfahsalembier.c $(IDIR)/mccodimage.h $(IDIR)/mcfahsalembier.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mcfahsalembier.c -o $(ODIR)/mcfahsalembier.o + +$(ODIR)/mcimage.o: $(LDIR)/mcimage.c $(IDIR)/mccodimage.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mcimage.c -o $(ODIR)/mcimage.o + +$(ODIR)/mcindic.o: $(LDIR)/mcindic.c $(IDIR)/mccodimage.h $(IDIR)/mcindic.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mcindic.c -o $(ODIR)/mcindic.o + +$(ODIR)/mclifo.o: $(LDIR)/mclifo.c $(IDIR)/mclifo.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mclifo.c -o $(ODIR)/mclifo.o + +$(ODIR)/mcunionfind.o: $(LDIR)/mcunionfind.c $(IDIR)/mcunionfind.h + $(CC) -c $(CCFLAGS) -I$(IDIR) $(LDIR)/mcunionfind.c -o $(ODIR)/mcunionfind.o Index: abraham/tests/morpho/Makefile --- abraham/tests/morpho/Makefile (revision 0) +++ abraham/tests/morpho/Makefile (revision 0) @@ -0,0 +1,19 @@ +SRC=$(wildcard *.cc) +OBJ=$(SRC:.cc=.o) +EXEC=$(SRC:.cc=) +CC=g++ +CXXFLAGS=-Wall -W -Werror -I ../../ -I ../../../../ -g + +all: $(EXEC) + +clean: + rm -rf *.o + rm -rf *~ + +distclean: clean + rm -rf $(EXEC) + +.PHONY: clean distclean + +## Depedencies +tikz.o: ../../../mln/io/tikz/save.hh \ No newline at end of file Index: abraham/tests/io/tikz/tikz.cc --- abraham/tests/io/tikz/tikz.cc (revision 0) +++ abraham/tests/io/tikz/tikz.cc (working copy) @@ -1,37 +1,44 @@ +#include <string> + #include <mln/core/image2d.hh> #include <mln/value/rgb.hh> #include <mln/value/int_u.hh> #include <mln/io/ppm/load.hh> #include <mln/io/pgm/load.hh> -#include "io/tikz/save.hh" +#include "mln/io/tikz/save_header.hh" +#include "mln/io/tikz/save.hh" -int main () { +int main (int argc, char *argv[]) { using namespace mln; using value::rgb; - typedef image2d< rgb<8> > image2drgb; - - image2drgb input; - - io::ppm::load(input, "../img/lena.ppm"); - - io::tikz::save(input, "tex/lena.tex"); - - typedef image2d< value::int_u<4> > image2dint4; - typedef image2d< value::int_u<8> > image2dint8; - - image2dint8 input2; + if (argc <= 2) + { + std::cout << "usage : " << argv[0] << " input.pnm output.tex" << std::endl; + return 0; + } - io::pgm::load(input2, "../img/test.pgm"); + std::string name(argv[1]); + std::string ext(name.substr(name.size() - 3)); - image2dint4 input3 (input2.domain(), input2.border()); - image2dint8::fwd_piter p(input2.domain()); + if (ext == "pgm") + { + image2d< value::int_u<8> > ima; + io::pgm::load(ima, name); + io::tikz::save(ima, argv[2], ima); + return 0; + } - for_all(p) - input3(p) = input2(p); + if (ext == "ppm") + { + image2d< rgb<8> > ima; + io::ppm::load(ima, name); + io::tikz::save(ima, argv[2]); + return 0; + } - io::tikz::save(input3, "tex/test.tex"); + std::cerr << "Unknown extension, must be ppm or pgm" << std::endl; - return 0; + return 1; } // int main () Index: abraham/tests/io/tikz/Makefile --- abraham/tests/io/tikz/Makefile (revision 0) +++ abraham/tests/io/tikz/Makefile (revision 0) @@ -0,0 +1,34 @@ +SRCPGM=$(wildcard *.pgm) +SRCPPM=$(wildcard *.ppm) +SRC=$(wildcard *.cc) +OBJPGM=$(SRCPGM:.pgm=.tex) +OBJPPM=$(SRCPPM:.ppm=.tex) +OBJ=$(SRC:.cc=.o) +EXEC=$(SRC:.cc=) $(SRCPGM:.pgm=.pdf) $(SRCPPM:.ppm=.pdf) +CC=g++ +CXXFLAGS=-Wall -W -Werror -I ../../../ -I ../../../../../ -g + +%.tex: tikz %.pgm + tikz $< $@ + +%.pdf: %.tex + pdflatex $< + +all: $(EXEC) + +clean: + rm -rf *.o + rm -rf *~ + rm -rf *.log + rm -rf *.aux + rm -rf + +distclean: clean + rm -rf $(EXEC) + rm -rf *.pdf + rm -rf *.tex + +.PHONY: clean distclean + +## Depedencies +tikz.o: ../../../mln/io/tikz/save.hh \ No newline at end of file Index: abraham/mln/morpho/basic_najman.hh --- abraham/mln/morpho/basic_najman.hh (revision 1933) +++ abraham/mln/morpho/basic_najman.hh (working copy) @@ -2,7 +2,9 @@ #include <mln/level/fill.hh> #include <mln/core/image2d.hh> #include <mln/core/p_set.hh> +#include <mln/util/greater_psite.hh> #include <mln/estim/min_max.hh> +#include <mln/math/sqr.hh> #include <queue> #include <set> @@ -10,6 +12,261 @@ namespace mln { + // Here we define some custome priority functions + + namespace util { + + template <typename I> + class najman_distance + { + public: + typedef mln_psite(I) psite; + + najman_distance(const Image<I>& ima); + + /// Is \a x greater than \a y? + bool operator()(const psite& x, const psite& y); + + // mln_value(I) + int + D(const mln_psite(I)& x); + + private: + const I& ima_; + }; + + + template <typename I> + najman_distance<I> + make_najman_distance(const Image<I>& ima); + +# ifndef MLN_INCLUDE_ONLY + + template <typename I> + najman_distance<I>::najman_distance(const Image<I>& ima) + : ima_ (exact(ima)) + { + } + + template <typename I> + // mln_value(I) + int + najman_distance<I>::D(const mln_psite(I)& x) + { + const I& ima = exact(ima_); + + mln_piter(I) it(ima.domain()); + + it.start(); + mln_psite(I) min = it.to_point(); + + for_all(it) + { + // FIXME : REALLY not optimized + // FIXME : REALLY not efficient + + if (ima(it.to_point()) < ima(x)) + // using norm2 + if ( (// math::sqr(int(ima(it.to_point())) - ima(x)) + + math::sqr(int(it.to_point().row()) - x.row()) + + math::sqr(int(it.to_point().col()) - x.col())) < + (// math::sqr(int(ima(min)) - ima(x)) + + math::sqr(int(min.row()) - x.row()) + + math::sqr(int(min.col()) - x.col())) ) + min = it.to_point(); + } + + return /* math::sqr(int(ima(min)) - ima(x)) +*/ math::sqr(int(min.row()) - x.row()) + int(math::sqr(min.col()) - x.col()); + } + + template <typename I> + bool + najman_distance<I>::operator()(const mln_psite(I)& x, const mln_psite(I)& y) + { + if (ima_(x) < ima_(y)) + return false; + else + if (ima_(x) > ima_(y)) + return true; + + // ima(x) = ima(y) + return !(D(x) <= D(y)); + + } + + + template <typename I> + najman_distance<I> + make_najman_distance(const Image<I>& ima) + { + return najman_distance<I>(ima); + } + +# endif // ! MLN_INCLUDE_ONLY + + + + + + + // Priority function for the second wateshed + + template <typename I> + class lesser_psite + { + public: + typedef mln_psite(I) psite; + + lesser_psite(const Image<I>& ima); + + /// Is \a x lesser than \a y? + bool operator()(const psite& x, const psite& y); + + private: + const I& ima_; + }; + + template <typename I> + lesser_psite<I> + make_lesser_psite(const Image<I>& ima); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I> + lesser_psite<I>::lesser_psite(const Image<I>& ima) + : ima_ (exact(ima)) + { + } + + template <typename I> + bool + lesser_psite<I>::operator()(const mln_psite(I)& x, const mln_psite(I)& y) + { + return ima_(x) < ima_(y); + } + + + template <typename I> + lesser_psite<I> + make_lesser_psite(const Image<I>& ima) + { + return lesser_psite<I>(ima); + } + +# endif // ! MLN_INCLUDE_ONLY + + + + template <typename I, typename N> + class my_lesser_psite + { + public: + typedef mln_psite(I) psite; + + my_lesser_psite(const Image<I>& ima, + const Neighborhood<N>& nbh); + + /// Is \a x lesser than \a y? + bool operator()(const psite& x, const psite& y); + + private: + const I& ima_; + const N& nbh_; + }; + + + template <typename I, typename N> + my_lesser_psite<I, N> + make_my_lesser_psite(const Image<I>& ima, + const Neighborhood<N>& nbh); + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I, typename N> + my_lesser_psite<I, N>::my_lesser_psite(const Image<I>& ima, + const Neighborhood<N>& nbh) + : ima_ (exact(ima)), nbh_(exact(nbh)) + { + } + + template <typename I, typename N> + bool + my_lesser_psite<I, N>::operator()(const mln_psite(I)& x, const mln_psite(I)& y) + { + +#ifdef V1 + + if (ima_(x) == ima_(y)) + { + int mx = 0, my = 0; + + mln_niter(N) a(nbh_, x); + for_all(a) + if (ima_.has(a) and ima_(a) > ima_(x)) + ++mx; + + mln_niter(N) b(nbh_, y); + for_all(b) + if (ima_.has(b) and ima_(b) > ima_(y)) + ++my; + + return mx > my; + } + +#else + + + if (ima_(x) == ima_(y)) + { + mln_value(I) mx = ima_(x), my = ima_(y); + + mln_niter(N) a(nbh_, x); + for_all(a) + if (ima_.has(a) and ima_(a) > ima_(mx)) + mx = a; + + mln_niter(N) b(nbh_, y); + for_all(b) + if (ima_.has(b) and ima_(b) > ima_(my)) + my = b; + + return ima_(x) < ima(y); + } + + +#endif + + + return ima_(x) < ima_(y); + } + + + template <typename I, typename N> + my_lesser_psite<I, N> + make_my_lesser_psite(const Image<I>& ima, + const Neighborhood<N>& nbh) + { + return my_lesser_psite<I, N>(ima); + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::util + + + + + + + + + + + + + namespace morpho { @@ -50,6 +307,7 @@ mln_ch_value(I, psite) subtreeRoot; mln_ch_value(I, node) nodes; mln_ch_value(I, bool) isproc; + psite Root; p_array<mln_psite(I)> S; // std::map<psite,psite> M; // to keep the root of any point. @@ -271,14 +529,23 @@ psite lca (psite a, psite b) { - return lca_rec(Root, Par_node(a), Par_node(b)); + psite r = lca_rec(Root, Par_node(a), Par_node(b)); + + // These two conditions make the lca become a plca + // if (r == Par_node(a)) + // return psite(-1, -1); + + // if (r == Par_node(b)) + // return psite(-1, -1); + + return r; } psite lca_rec (psite cur, psite a, psite b) { // FIXME : naive implementation, make something better - // If we found one of the point, we return it so ti can be caught in + // If we found one of the point, we return it so it can be caught in // the loop if (cur == a) @@ -367,8 +634,8 @@ return psite(-1, -1); } - if (components.npoints() == 1) - return components[0]; + // if (components.npoints() == 1) + // return components[0]; psite m = min(components), @@ -383,8 +650,8 @@ psite c = lca(hfork, it.to_point()); if (c != it.to_point()) - hfork = it.to_point(); - // hfork = c; + // hfork = it.to_point(); + hfork = c; } if (nodes(m).level == nodes(hfork).level) @@ -419,7 +686,7 @@ psite m_destructible(psite p) { mln_niter(N) q(nbh, p); - p_set<psite> v; + p_set<psite> v = p_set<psite>(); for_all(q) if (pima.has(q) && pima(q) < pima(p)) @@ -431,7 +698,9 @@ if (nodes(min(v)).children.npoints() != 0) return (psite(-1, -1)); + //std::cout << "hf of " << p << ":" << v; psite hf = highest_fork(v); + //std::cout << " is " << hf << std::endl; if (hf == psite(-1, -1)) return min(v); @@ -439,16 +708,57 @@ return psite(-1, -1); } + psite w_constructible(psite p) + { + mln_niter(N) q(nbh, p); + p_set<psite> v; + + psite pmax = p; + + for_all(q) + if (pima.has(q) && pima(q) > pima(p)) + v.insert(Par_node(q)); + + if (v.npoints() == 0) + return psite(-1, -1); + + if (v.npoints() == 1) + return v[0]; + + psite + c = max(v); + + typename p_set<psite>::fwd_piter it(v); + for_all(it) + { + // Can't remove the point from the set + if (it.to_point() == c) + continue; + + psite c1 = lca(c, it.to_point()); + if (c1 != it.to_point()) + c = c1; + } + + if (nodes(c).level <= pima(p)) + return psite(-1, -1); + + return c; + } + + void m_watershed () { // FIXME : make a better priority function - // typedef - // std::priority_queue< psite, std::vector<psite>, util::greater_psite<I> > - // ordered_queue_type; + typedef + std::priority_queue< psite, std::vector<psite>, util::greater_psite<I> > + // std::priority_queue< psite, std::vector<psite>, util::najman_distance<I> > + ordered_queue_type; - std::priority_queue<psite> l; + ordered_queue_type l(util::make_greater_psite(pima)); + // ordered_queue_type l(util::make_najman_distance(pima)); // Clear the marker map level::fill(isproc, false); @@ -457,6 +767,7 @@ for_all(it) if (m_destructible(it.to_point()) != psite(-1, -1)) { + //std::cout << "init: push " << it.to_point() << std::endl; l.push(it.to_point()); isproc(it.to_point()) = true; } @@ -472,18 +783,21 @@ isproc(p) = false; i = m_destructible(p); + //std::cout << "point " << p << "is m-destructible " << i << std::endl; if (i != psite(-1, -1)) { pima(p) = nodes(i).level - 1 ; Par_node(p) = i; - // isproc(p) = true; mln_niter(N) q(nbh, p); for_all(q) if (pima.has(q) && !isproc(q)) if (m_destructible(q) != psite(-1, -1)) { + // if (q == psite(1, 1)) + // std::cout << "psite(1, 1) ajoute dans la boucle" << std::endl; + // Add priority queue l.push(q); @@ -508,6 +822,7 @@ // I K(pima.domain(), pima.border()); mln_ch_value(I, int) K(pima.domain(), pima.border()); + level::fill(K, 73320); mln_ch_value(I, psite) H(pima.domain(), pima.border()); // For All p of E do @@ -537,6 +852,9 @@ psite p = *(Lk.begin()); Lk.erase(p); + if (K(p) == 73320) + std::cerr << "Comparison with an uninitilized number" << std::endl; + if (K(p) == (int) k) { pima(p) = k; @@ -584,6 +902,136 @@ } } + + void revert_tree (psite p) + { + node& n = nodes(p); + + n.level = 255 - n.level; + + typename p_array<mln_psite(I)>::fwd_piter it(n.children); + + for_all(it) + revert_tree(it.to_psite()); + } + + void gotopo() + { + init(); + + BuildComponentTree(); + + mln_piter(I) p (pima.domain()); + for_all(p) + pima(p) = 255 - pima(p); + + revert_tree(Root); + + topo_watershed(); + + for_all(p) + pima(p) = 255 - pima(p); + } + + + void topo_watershed() + { + // Maxima components + mln_ch_value(I, bool) cmax(pima.domain(), pima.border()); + + // Mark enqueued points + mln_ch_value(I, bool) enqueued(pima.domain(), pima.border()); + + // Not used + // level::fill(isproc, false); + + + typedef + std::priority_queue< psite, std::vector<psite>, util::lesser_psite<I> > + ordered_queue_type; + + ordered_queue_type l(util::make_lesser_psite(pima)); + + + + + // Flag C-maxima + level::fill(cmax, false); + mln_piter(I) it(Par_node.domain()); + for_all(it) + if (nodes(Par_node(it.to_point())).children.npoints() == 0) + cmax(it.to_point()) = true; + +#ifdef SLOW + + // Enqueue all + for_all(it) + { + enqueued(it.to_point()) = true; + l.push(it.to_point()); + } +#else // !SLOW + + // Optimisation : enqueue minima's neighbours + level::fill(enqueued, false); + for_all(it) + { + mln_niter(N) q(nbh, it.to_point()); + for_all(q) + if (cmax.has(q) && cmax(q)) + { + enqueued(it.to_point()) = true; + l.push(it.to_point()); + break; + } + } + +#endif // SLOW + + + // Main loop + while(!l.empty()) + { + psite x = l.top(); + l.pop(); + enqueued(x) = false; + + psite c = w_constructible(x); + + if (x == psite(3, 3)) + { + std::cout << "w-c : " << c << std::endl; + io::pgm::save(pima, "int.pgm"); + } + + if (c != psite(-1, -1)) + { + pima(x) = nodes(c).level; + Par_node(x) = c; + // isproc(x) = true; + + if (nodes(c).children.npoints() == 0) + cmax(x) = true; + else + if (nodes(c).children.npoints() > 1) + { + } + else + std::cerr << "ERREUR COMPOSANTE BRANCHE" << std::endl; + + mln_niter(N) q(nbh, x); + for_all(q) + if (pima.has(q) && !cmax(q) && !enqueued(q)) + { + enqueued(q) = true; + l.push(q); + } + } // if (c != psite(-1, -1)) + } // while(!l.empty()) + + for_all(it) + pima(it.to_point()) = nodes(Par_node(it.to_point())).level; + } }; // struct basic_najman }; // namespace morpho Index: abraham/mln/morpho/test_component_tree.cc --- abraham/mln/morpho/test_component_tree.cc (revision 1933) +++ abraham/mln/morpho/test_component_tree.cc (working copy) @@ -26,6 +26,8 @@ y = memo; } +// In order to the the component tree, we turn it into this structure + template <typename T> class test_tree; @@ -55,7 +57,8 @@ test_tree<T> *n = new test_tree<T>(pdata); return insert_child(n); } -}; + +}; // class test_tree template <typename T> bool compare_tree(test_tree<T>* t1, test_tree<T>* t2) Index: abraham/mln/morpho/test_watershed.cc --- abraham/mln/morpho/test_watershed.cc (revision 1933) +++ abraham/mln/morpho/test_watershed.cc (working copy) @@ -2,10 +2,8 @@ #include <mln/core/window2d.hh> #include <mln/core/neighb2d.hh> #include <mln/core/p_set.hh> - #include <mln/value/int_u8.hh> #include <mln/level/compare.hh> - #include <mln/io/pgm/load.hh> #include <mln/io/pgm/save.hh> @@ -13,14 +11,6 @@ #include <string> #include <iostream> -#include "tikz.h" - -int print_and_exit (std::string s) -{ - std::cerr << s << std::endl; - return 1; -} - int main () { using namespace mln; @@ -33,7 +23,9 @@ // #define TEST // io::pgm::load(input, "./images/test_watershed.pgm"); + // io::pgm::load(input, "./images/little_test.pgm"); io::pgm::load(input, "./images/test_2.pgm"); + // io::pgm::load(input, "./images/lena_light.pgm"); // io::pgm::load(mverif, "./images/result_m_watershed.pgm"); // io::pgm::load(wverif, "./images/result_topo_watershed.pgm"); @@ -59,6 +51,8 @@ n.m_watershed(); + io::pgm::save(n.pima, "int.pgm"); + // io::tikz::save(n.pima, "step.tex"); #ifdef TEST @@ -80,6 +74,9 @@ std::cout << "W-watershed" << std::endl; n.w_watershed(); + // io::pgm::save(n.pima, "int.pgm"); + // std::cout << "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" << std::endl; + // n.w_watershed(); // for_all(it) // n.pima(it) = n.pima(it) * 17; Index: abraham/mln/morpho/test_watershed_topo.cc --- abraham/mln/morpho/test_watershed_topo.cc (revision 0) +++ abraham/mln/morpho/test_watershed_topo.cc (revision 0) @@ -0,0 +1,60 @@ +#include <mln/core/image2d.hh> +#include <mln/core/window2d.hh> +#include <mln/core/neighb2d.hh> +#include <mln/core/p_set.hh> + +#include <mln/value/int_u8.hh> +#include <mln/level/compare.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include "basic_najman.hh" +#include <string> +#include <iostream> + +int print_and_exit (std::string s) +{ + std::cerr << s << std::endl; + return 1; +} + +int main () +{ + using namespace mln; + using value::int_u8; + + typedef image2d<int_u8> image2dint; + + image2dint input, mverif, wverif; + + // #define TEST + + // io::pgm::load(input, "./images/test_watershed.pgm"); + // io::pgm::load(input, "./images/little_test.pgm"); + io::pgm::load(input, "./images/test_2.pgm"); + // io::pgm::load(input, "./images/+irm6.pgm"); + + // io::pgm::load(input, "./images/lena_light.pgm"); + // io::pgm::load(mverif, "./images/result_m_watershed.pgm"); + // io::pgm::load(wverif, "./images/result_topo_watershed.pgm"); + + morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c4()); + + /* + image2dint::fwd_piter it(input.domain()); + for_all(it) + { + input(it) = input(it)/17; + mverif(it) = mverif(it)/17; + } + */ + + // io::tikz::save(input, "start.tex"); + + n.gotopo(); + + io::pgm::save(n.pima, "out.pgm"); + + return 0; +} Index: abraham/mln/morpho/Makefile --- abraham/mln/morpho/Makefile (revision 1933) +++ abraham/mln/morpho/Makefile (working copy) @@ -1,16 +1,22 @@ -CXXFLAGS=-Wall -W -I ../../.. -g +SRC=$(wildcard *.cc) +OBJ=$(SRC:.cc=.o) +EXEC=$(SRC:.cc=) +CC=g++ +CXXFLAGS=-Wall -W -Werror -I ../../../.. -g -test: test.o - g++ ${CXXFLAGS} test.o -o test +all: $(EXEC) -test_component_tree: test_component_tree.o - g++ ${CXXFLAGS} test_component_tree.o -o test_component_tree +clean: + rm -rf *.o + rm -rf *~ -test_watershed: test_watershed.o - g++ ${CXXFLAGS} test_watershed.o -o test_watershed +distclean: clean + rm -rf $(EXEC) -all: tree +.PHONY: clean distclean -test_watershed.o: basic_najman.hh tikz.h +## Depedencies +test_watershed.o: basic_najman.hh +test_watershed_topo.o: basic_najman.hh test_component_tree.o: basic_najman.hh test.o: basic_najman.hh \ No newline at end of file Index: abraham/mln/io/tikz/save_header.hh --- abraham/mln/io/tikz/save_header.hh (revision 1933) +++ abraham/mln/io/tikz/save_header.hh (working copy) @@ -56,6 +56,8 @@ const std::string& filename, std::ofstream& file) { + (void) ima; // to avoid unused parameter warning + if (! file) { std::cerr << "error: cannot open file '" << filename Index: abraham/mln/io/tikz/save.hh --- abraham/mln/io/tikz/save.hh (revision 1933) +++ abraham/mln/io/tikz/save.hh (working copy) @@ -49,8 +49,7 @@ # include <mln/metal/templated_by.hh> -// # include <mln/io/tikz/save_header.hh> -# include "save_header.hh" +# include <mln/io/tikz/save_header.hh> # include <mln/geom/size2d.hh> Index: abraham/img/little_test.pgm --- abraham/img/little_test.pgm (revision 0) +++ abraham/img/little_test.pgm (revision 0) @@ -0,0 +1,5 @@ +P5 +# CREATOR: GIMP PNM Filter Version 1.1 +4 3 +255 +*oyd¿¼¢F³j \ No newline at end of file
participants (1)
-
Alexandre Abraham