MODULE PZCompCands EXPORTS Main; (* Compares files of "found" and "ideal" candidates, writes diff and inter. *) (* Last edited on 2001-11-18 22:30:51 by stolfi *) IMPORT ParseParams, Text, FileRd, FileWr, Wr, Fmt; IMPORT Process, OSError, Thread, Stdio; IMPORT PZCandidate; FROM Stdio IMPORT stderr; FROM PZTypes IMPORT LONG, INT, NAT, BOOL, BOOLS; <* FATAL Wr.Failure, Thread.Alerted, OSError.E *> TYPE Options = RECORD found: TEXT; (* Input file name of "found" candidates. *) ideal: TEXT; (* Input file name of "ideal" candidates. *) good: TEXT; (* Output file name of "good" candidates. *) missing: TEXT; (* Output file name of "missing" candidates. *) bogus: TEXT; (* Output file name of "bogus" candidates. *) step: LONG; (* Nominal sampling step (pixels). *) printGood: BOOL; (* TRUE prints candidates that are in both sets. *) printMissing: BOOL; (* TRUE prints ideal cands that aren't found cands. *) printBogus: BOOL; (* TRUE prints found cands that aren't ideal cands. *) printChainPairs: BOOL; (* TRUE prints summary line per matched chain pair. *) printCandPairs: BOOL; (* TRUE prints every matching candidate pair. *) (* Criteria for ideal candidate selection: *) minIdealLength: LONG; (* Min length (pixels) for ideal cands. *) blurFactor: LONG; (* Corner broadening factor. *) (* Criteria for equality of candidates: *) minCompOverlap: LONG; (* Minimum overlap (pixels). *) maxCompShift: LONG; (* Maximum displacement on each chain (pixels). *) END; PROCEDURE Main() = BEGIN WITH o = GetOptions(), fData = ReadFoundCandidates(o.found), fCand = fData.c^, fOK = NEW(REF BOOLS, NUMBER(fCand))^, lambda = fData.lambda, iData = ReadIdealCandidates( name := o.ideal, minLength := o.minIdealLength, blurFactor := o.blurFactor, lambda := lambda, step := o.step ), iCand = iData.c^, iOK = NEW(REF BOOLS, NUMBER(iCand))^ DO CompareCandSets( fData, iData, fOK, iOK, minCompOverlap := o.minCompOverlap, maxCompShift := o.maxCompShift, step := o.step, printGood := o.printGood, printMissing := o.printMissing, printBogus := o.printBogus, printChainPairs := o.printChainPairs, printCandPairs := o.printCandPairs ); WITH gCand = ExtractCands(fCand, fOK, TRUE)^ DO WriteCandidateSubset( o.good, gCand, "found candidates that match some ideal candidate", fData.cmt, fData.lambda ) END; WITH bCand = ExtractCands(fCand, fOK, FALSE)^ DO WriteCandidateSubset( o.bogus, bCand, "found candidates that don't match any ideal candidates", fData.cmt, fData.lambda ) END; WITH mCand = ExtractCands(iCand, iOK, FALSE)^ DO WriteCandidateSubset( o.missing, mCand, "ideal candidates that don't match any found candidates", iData.cmt, iData.lambda ) END; END; END Main; PROCEDURE GetOptions(): Options = VAR o: Options; BEGIN WITH pp = NEW(ParseParams.T).init(stderr) DO TRY pp.getKeyword("-found"); o.found := pp.getNext(); pp.getKeyword("-ideal"); o.ideal := pp.getNext(); IF pp.keywordPresent("-good") THEN o.good := pp.getNext() ELSE o.good := "" END; IF pp.keywordPresent("-missing") THEN o.missing := pp.getNext() ELSE o.missing := "" END; IF pp.keywordPresent("-bogus") THEN o.bogus := pp.getNext() ELSE o.bogus := "" END; pp.getKeyword("-step"); o.step := pp.getNextLongReal(0.0d0, 1024.0d0); IF pp.keywordPresent("-minIdealLength") THEN o.minIdealLength := pp.getNextLongReal(0.0d0) ELSE o.minIdealLength := 0.0d0 END; pp.getKeyword("-blurFactor"); o.blurFactor := pp.getNextLongReal(0.01d0, 100.0d0); pp.getKeyword("-minCompOverlap"); o.minCompOverlap := pp.getNextLongReal(0.0d0); pp.getKeyword("-maxCompShift"); o.maxCompShift := pp.getNextLongReal(0.0d0); o.printGood := pp.keywordPresent("-printGood"); o.printMissing := pp.keywordPresent("-printMissing"); o.printBogus := pp.keywordPresent("-printBogus"); o.printChainPairs := pp.keywordPresent("-printChainPairs"); o.printCandPairs := pp.keywordPresent("-printCandPairs"); pp.finish(); EXCEPT | ParseParams.Error => Wr.PutText(stderr, "Usage: PZCompCands \\\n"); Wr.PutText(stderr, " -found NAME \\\n"); Wr.PutText(stderr, " -ideal NAME \\\n"); Wr.PutText(stderr, " -good NAME \\\n"); Wr.PutText(stderr, " -missing NAME \\\n"); Wr.PutText(stderr, " -step PIXELS \\\n"); Wr.PutText(stderr, " [ -minIdealLength PIXELS ] \\\n"); Wr.PutText(stderr, " -blurFactor PIXELS \\\n"); Wr.PutText(stderr, " -minCompOverlap PIXELS -maxCompShift PIXELS \\\n"); Wr.PutText(stderr, " [ -printGood ] [ -printMissing ] [ -printBogus ] \\\n"); Wr.PutText(stderr, " [ -printChainPairs ] [ -printCandPairs ]\n"); Process.Exit(1); END; END; RETURN o END GetOptions; PROCEDURE ReadFoundCandidates(name: TEXT): PZCandidate.ReadData = (* Reads a candidate list. *) BEGIN RETURN PZCandidate.Read(FileRd.Open(name & ".can")) END ReadFoundCandidates; PROCEDURE ReadIdealCandidates( name: TEXT; minLength, blurFactor: LONG; lambda, step: LONG; ): PZCandidate.ReadData = (* Reads a candidate list, and removes entries with less than "minLength" (minus corner blurring) on either segment. *) VAR nCands: NAT; cData: PZCandidate.ReadData; BEGIN IF step = 0.0d0 THEN minLength := 0.0d0; step := 1.0d0 END; cData := PZCandidate.Read(FileRd.Open(name & ".can")); WITH c = cData.c^, minCorrLength = MAX(0.0d0, minLength - 2.0d0*blurFactor*cData.lambda), minSteps = FLOOR(minCorrLength/step) DO <* ASSERT cData.lambda = lambda *> Wr.PutText(stderr, "ignoring ideal cands that cover less than " & FI(minSteps,1) & " sampling steps\n" ); nCands := NUMBER(c); PZCandidate.RemoveShort(c, nCands, minSteps); WITH diff = NUMBER(c) - nCands, txt = "PZCompCands: removed candidates with less than " & FI(minSteps,5) & " steps\n" DO IF diff > 0 THEN Wr.PutText(stderr, txt & "\n") END; cData.cmt := cData.cmt & "\n" & txt END; IF nCands < NUMBER(cData.c^) THEN WITH rd = NEW(REF PZCandidate.List, nCands), d = rd^ DO d := SUBARRAY(c, 0, nCands); cData.c := rd END END END; RETURN cData END ReadIdealCandidates; PROCEDURE CompareCandSets( READONLY fData: PZCandidate.ReadData; READONLY iData: PZCandidate.ReadData; VAR (*OUT*) fOK: BOOLS; VAR (*OUT*) iOK: BOOLS; minCompOverlap: LONG; maxCompShift: LONG; step: LONG; printGood: BOOL; printMissing: BOOL; printBogus: BOOL; printChainPairs: BOOL; printCandPairs: BOOL; ) = BEGIN IF NUMBER(iData.c^) > 0 THEN <* ASSERT fData.lambda = iData.lambda *> END; (* Hack to avoid overflow when "step" is zero. *) IF step = 0.0d0 THEN step := minCompOverlap; IF step = 0.0d0 THEN step := 1.0d0 END; END; WITH fCand = fData.c^, iCand = iData.c^, minSteps = FLOOR(minCompOverlap / step + 0.0001d0), maxAdjust = CEILING(maxCompShift / step - 0.0001d0) DO Wr.PutText(stderr, "Candidate comparison parameters:\n"); Wr.PutText(stderr, " overlap minSteps = " & Fmt.Int(minSteps) & "\n"); Wr.PutText(stderr, " alignment maxAdjust = " & Fmt.Int(maxAdjust) & "\n"); PZCandidate.FindSimilarCands( aCand := fCand, bCand := iCand, minSteps := minSteps, maxAdjust := maxAdjust, aOK := fOK, bOK := iOK, printAMatched := printGood, printBMatched := printGood, printAUnmatched := printBogus, printBUnmatched := printMissing, printMatchedCands := printCandPairs, printMatchedChains := printChainPairs ); PZCandidate.PrintSimilarityStatistics( stderr, fOK, "found", iOK, "ideal" ); END END CompareCandSets; PROCEDURE ExtractCands( READONLY oldCand: PZCandidate.List; READONLY mark: BOOLS; (* Marks on each candidate. *) which: BOOL; (* Extract candidates whose "mark" has this value. *) ): REF PZCandidate.List = VAR nCands: NAT := 0; BEGIN <* ASSERT NUMBER(mark) = NUMBER(oldCand) *> FOR i := 0 TO LAST(oldCand) DO IF mark[i] = which THEN INC(nCands) END END; WITH rc = NEW(REF PZCandidate.List, nCands), newCand = rc^ DO nCands := 0; FOR i := 0 TO LAST(oldCand) DO IF mark[i] = which THEN newCand[nCands] := oldCand[i]; INC(nCands) END END; RETURN rc END; END ExtractCands; PROCEDURE WriteCandidateSubset( name: TEXT; (* File name prefix. *) VAR cand: PZCandidate.List; (* The candidate subset. *) desc: TEXT; (* Description of the subset. *) cmt: TEXT; (* Original dataset comments. *) lambda: LONG; (* Filtering scale. *) ) = (* Writes the specified candidates to disk, as "fname.can", provided "fname" is not the empty string. NOTE: Will also reorder the candidates. *) BEGIN IF NOT Text.Empty(name) THEN WITH wr = FileWr.Open(name & ".can"), cmt = cmt & "\n\nPZCompCands: " & desc DO PZCandidate.Sort(cand, PZCandidate.MismatchBetter); PZCandidate.Write(wr, cmt, cand, lambda) END END; END WriteCandidateSubset; <*UNUSED*> PROCEDURE FLR(x: LONG; w, p: NAT): TEXT = BEGIN RETURN Fmt.Pad(Fmt.LongReal(x, Fmt.Style.Fix, prec := p), w) END FLR; PROCEDURE FI(x: NAT; w: NAT): TEXT = BEGIN RETURN Fmt.Pad(Fmt.Int(x), w) END FI; <*UNUSED*> PROCEDURE DebugIntPair(title: TEXT; r, s: INT) = <* FATAL Wr.Failure, Thread.Alerted *> BEGIN Wr.PutText(stderr, title); Wr.PutText(stderr, " "); Wr.PutText(stderr, Fmt.Int(r)); Wr.PutText(stderr, " "); Wr.PutText(stderr, Fmt.Int(s)); Wr.PutText(stderr, "\n"); END DebugIntPair; BEGIN Main() END PZCompCands. (* Copyright © 2001 Universidade Estadual de Campinas (UNICAMP). Authors: Helena C. G. Leitão and Jorge Stolfi. This file can be freely distributed, used, and modified, provided that this copyright and authorship notice is preserved, and that any modified versions are clearly marked as such. This software has NO WARRANTY of correctness or applicability for any purpose. Neither the authors nor their employers chall be held responsible for any losses or damages that may result from its use. *)