https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Alexandre Abraham <abraham(a)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