fun rconstLess( ( X, C ) : real * rconst ) : bool = case C of rconst( Compl, StepSize, Current ) => realLess( X, Current ) fun abs( X : real ) : real = case X<0.0 of false => X | true => ~X fun f( ( Delta1, Delta2, M, M1, M2, M3, M4 ) : real * real * real * real * real * real * real ) : real = case abs( Delta1/Delta2 ) of Theta => let fun lerp( ( X, Y, T ) : real * real * real ) : real = X*( tor( rconst( 0, 0.1, 1.0 ) )-T)+Y*T in case lerp( M1, M2, Theta ) of TM1 => case lerp( M3, M4, Theta ) of TM2 => case M ( case M M | true => tor( rconst( 0, 0.1, 0.0 ) ) ) | true => tor( rconst( 0, 0.1, 0.0 ) ) end %% type main_domain = GrayscaleImageReal.image type main_range = BooleanImage.image val toi = Int64.toInt val fri = Int64.fromInt local datatype thresholdOptions = highLow of real * real (* Specify thresholds directly *) | highPercentageLowRatio of real * real (* Specify percentage of pixels for calculating the high threshold and the ratio of the high threshold to use as the low threshold *) | otsuHighLowRatio of real (* Use Otsu's method to determine the high threshold then use the ratio to determine the low threshold *) val foldl = GrayscaleImageReal.foldl val modify = GrayscaleImageReal.modify val convolve = GrayscaleImageReal.convolve ( ImageCommon.copy, ImageCommon.original ) val transposed = GrayscaleImageReal.transposed val sub = GrayscaleImageReal.sub val sub' = GrayscaleImageReal.sub' fun cap ( Max : Int.int ) ( X : Int.int ) : Int.int = if X>=Max then Max-1 else if X<0 then 0 else X fun toA( X : real ) : real = X*0.5 fun fromA( X : real ) : real = X*2.0 in fun main( Image : GrayscaleImageReal.image ) : BooleanImage.image = let val { Width, Height, Values } = Image val capX = cap Width val capY = cap Height val Gaussian = FilterUtil.createGaussianMask 3.25 (* val Gaussian = FilterUtil.createGaussianMask( Math.sqrt 2.0 ) *) val GaussianDerived = ImageUtil.gradientXReal Gaussian val ( SumPos, SumNeg ) = foldl ( fn( X, ( SumPos, SumNeg ) ) => if X > 0.0 then ( SumPos+X, SumNeg ) else if X < 0.0 then ( SumPos, SumNeg+X ) else ( SumPos, SumNeg ) ) ( 0.0, 0.0 ) GaussianDerived val _ = modify ( fn X => if X > 0.0 then X/SumPos else if X < 0.0 then X/( Real.abs SumNeg ) else X ) GaussianDerived val SmoothX = convolve( Image, transposed Gaussian ) val GradX = convolve( SmoothX, GaussianDerived ) val SmoothY = convolve( Image, Gaussian ) val GradY = convolve( SmoothY, transposed GaussianDerived ) val Magnitude = GrayscaleImageReal.zeroImage( Width, Height ) val _ = GrayscaleImageReal.modifyi ( fn( I, _ ) => Math.sqrt( Math.pow( sub'( GradX, I ), 2.0 ) + Math.pow( sub'( GradY, I ), 2.0 ) ) ) Magnitude val NormalizedMagnitude = ImageUtil.normalizeReal Magnitude val Max = GrayscaleImageReal.zeroImage( Width, Height ) val _ = GrayscaleImageReal.modifyxy ( fn( X, Y, _ ) => let val DX = sub( GradX, X, Y ) val DY = sub( GradY, X, Y ) val M = sub( NormalizedMagnitude, X, Y ) in if ( DY<=0.0 andalso DX>( ~DY ) ) orelse ( DY>=0.0 andalso DX<( ~DY ) ) then let (* val T = Real.abs( DY/DX ) val M1 = MathUtil.lerp( sub( NormalizedMagnitude, capX( X+1 ), Y ), sub( NormalizedMagnitude, capX( X+1 ), capY( Y-1 ) ), T ) val M2 = MathUtil.lerp( sub( NormalizedMagnitude, capX( X-1 ), Y ), sub( NormalizedMagnitude, capX( X-1 ), capY( Y+1 ) ), T ) *) in fromA( f( toA DY, toA DX, toA M, toA( sub( NormalizedMagnitude, capX( X+1 ), Y ) ), toA( sub( NormalizedMagnitude, capX( X+1 ), capY( Y-1 ) ) ), toA( sub( NormalizedMagnitude, capX( X-1 ), Y ) ), toA( sub( NormalizedMagnitude, capX( X-1 ), capY( Y+1 ) ) ) ) ) (* if M>=M1 andalso M>=M2 then M else 0.0 *) end else if ( DX>0.0 andalso ~DY>=DX ) orelse ( DX<0.0 andalso ~DY<=DX ) then let (* val T = Real.abs( DX/DY ) val M1 = MathUtil.lerp( sub( NormalizedMagnitude, X, capY( Y-1 ) ), sub( NormalizedMagnitude, capX( X+1 ), capY( Y-1 ) ), T ) val M2 = MathUtil.lerp( sub( NormalizedMagnitude, X, capY( Y+1 ) ), sub( NormalizedMagnitude, capX( X-1 ), capY( Y+1 ) ), T ) *) in fromA( f( toA DX, toA DY, toA M, toA( sub( NormalizedMagnitude, X, capY( Y-1 ) ) ), toA( sub( NormalizedMagnitude, capX( X+1 ), capY( Y-1 ) ) ), toA( sub( NormalizedMagnitude, X, capY( Y+1 ) ) ), toA( sub( NormalizedMagnitude, capX( X-1 ), capY( Y+1 ) ) ) ) ) (* if M>=M1 andalso M>=M2 then M else 0.0 *) end else if ( DX<=0.0 andalso DX>DY ) orelse ( DX>=0.0 andalso DX=M1 andalso M>=M2 then M else 0.0 *) end else let (* val T = Real.abs( DY/DX ) val M1 = MathUtil.lerp( sub( NormalizedMagnitude, capX( X-1 ), Y ), sub( NormalizedMagnitude, capX( X-1 ), capY( Y-1 ) ), T ) val M2 = MathUtil.lerp( sub( NormalizedMagnitude, capX( X+1 ), Y ), sub( NormalizedMagnitude, capX( X+1 ), capY( Y+1 ) ), T ) *) in fromA( f( toA DY, toA DX, toA M, toA( sub( NormalizedMagnitude, capX( X-1 ), Y ) ), toA( sub( NormalizedMagnitude, capX( X-1 ), capY( Y-1 ) ) ), toA( sub( NormalizedMagnitude, capX( X+1 ), Y ) ), toA( sub( NormalizedMagnitude, capX( X+1 ), capY( Y+1 ) ) ) ) ) (* if M>=M1 andalso M>=M2 then M else 0.0 *) end end ) Max val Options = highLow( 0.3125, 0.1875 ) (* val Options = highLow( 0.3125, 0.2734375 ) *) val ( High, Low ) = case Options of highLow( High, Low ) => ( High, Low ) | highPercentageLowRatio( HighPercentage, LowRatio ) => ( let val [ High ] = GrayscaleImageReal.thresholds' ( ImageCommon.percentage( 256, HighPercentage ) ) NormalizedMagnitude in ( High, High*LowRatio ) end ) | otsuHighLowRatio LowRatio => let val [ High ] = GrayscaleImageReal.thresholds' ( ImageCommon.otsu( 256 ) ) NormalizedMagnitude in ( High, High*LowRatio ) end val Edge = BooleanImage.zeroImage( Width, Height ) val _ = GrayscaleImageReal.appxy ( fn( X, Y, M ) => let fun check( X : Int.int, Y : Int.int ) : bool = if X=( capX X ) andalso Y=( capY Y ) then let val M' = sub( Max, X, Y ) val E = BooleanImage.sub( Edge, X, Y ) in ( not E andalso M'>Low ) end else false fun follow( X : Int.int, Y : Int.int ) : unit = ( if check( X+1, Y ) then ( BooleanImage.update( Edge, X+1, Y, true ); follow( X+1, Y ) ) else () ; if check( X+1, Y+1 ) then ( BooleanImage.update( Edge, X+1, Y+1, true ); follow( X+1, Y+1 ) ) else () ; if check( X, Y+1 ) then ( BooleanImage.update( Edge, X, Y+1, true ); follow( X, Y+1 ) ) else () ; if check( X-1, Y+1 ) then ( BooleanImage.update( Edge, X-1, Y+1, true ); follow( X-1, Y+1 ) ) else () ; if check( X-1, Y ) then ( BooleanImage.update( Edge, X-1, Y, true ); follow( X-1, Y ) ) else () ; if check( X-1, Y-1 ) then ( BooleanImage.update( Edge, X-1, Y-1, true ); follow( X-1, Y-1 ) ) else () ; if check( X, Y-1 ) then ( BooleanImage.update( Edge, X, Y-1, true ); follow( X, Y-1 ) ) else () ; if check( X+1, Y-1 ) then ( BooleanImage.update( Edge, X+1, Y-1, true ); follow( X+1, Y-1 ) ) else () ) val E = BooleanImage.sub( Edge, X, Y ) in if not E andalso M>High then ( BooleanImage.update( Edge, X, Y, true ); follow( X, Y ) ) else () end ) Max in Edge end end (* local *) (* val PNMDir = "/local/Canny/BSDS_PNM/" *) val PNMDir = "../data/BSDS_PNM/" val ImageDir = PNMDir ^ "images/" val TruthDir = PNMDir ^ "truth/" val OutDir = "canny_nonmax_output/" val ImageTrainFilenameFile = "bsds.train.grayscale.filenames" val ImageTestFilenameFile = "bsds.val.grayscale.filenames" val TruthTrainFilenameFile = "bsds.train.best.truth.filenames" val TruthTestFilenameFile = "bsds.val.best.truth.filenames" val ImageFilenames = List.map ( fn Filename => ImageDir ^ Filename ) ( TextFileUtil.readFilenames( PNMDir ^ ImageTrainFilenameFile ) @ TextFileUtil.readFilenames( PNMDir ^ ImageTestFilenameFile )) val TruthFilenames = List.map ( fn Filename => TruthDir ^ Filename ) ( TextFileUtil.readFilenames( PNMDir ^ TruthTrainFilenameFile ) @ TextFileUtil.readFilenames( PNMDir ^ TruthTestFilenameFile ) ) val Inputs = List.map ( fn ImageFilename => Option.valOf( GrayscaleImageReal.load ImageFilename ) ) ( List.take( ImageFilenames, 50 ) ) val Test_inputs = List.map ( fn ImageFilename => Option.valOf( GrayscaleImageReal.load ImageFilename ) ) ( List.drop( ImageFilenames, 50 ) ) val Truths = Array.fromList( List.map ( fn TruthFilename => Option.valOf( BooleanImage.load TruthFilename ) ) TruthFilenames ) val CFuns = [] val Abstract_types = [] val Funs_to_use = [ "false", "true", "realLess", "realAdd", "realSubtract", "realMultiply", "realDivide", "tanh", "tor", "rconstLess" ] val Reject_funs = [] fun restore_transform D = D fun compile_transform D = D fun print_synted_program D = Print.print_dec' D structure Grade : GRADE = struct type grade = LargeInt.int val NONE = LargeInt.maxInt (* To check that LargeInt has infinite precision. *) val zero = LargeInt.fromInt 0 val op+ = LargeInt.+ val comparisons = [ LargeInt.compare ] fun toString( G : grade ) : string = Real.toString( Real.fromLargeInt G / 1.0E14 ) val N = LargeInt.fromInt 1000000 * LargeInt.fromInt 1000000 val significantComparisons = [ fn ( E1 , E2 ) => LargeInt.compare ( E1 div N, E2 div N ) ] fun toString ( G : grade ) : string = Real.toString ( Real.fromLargeInt G / 1.0E14 ) val pack = LargeInt.toString fun unpack( S : string ) : grade = case LargeInt.fromString S of SOME G => G val post_process = fn X => X val toRealOpt = NONE end fun to( G : real ) : LargeInt.int = Real.toLargeInt IEEEReal.TO_NEAREST ( G * 1.0e14 ) datatype oeArg = exactlyOne of ( Int.int * main_domain * main_range ) | allAtOnce of dec * ( Int.int * main_domain * main_range )List.list Option.option * ( Int.int * main_domain * main_range )List.list fun output_eval_fun( exactlyOne( I: Int.int, X : GrayscaleImageReal.image, Y : BooleanImage.image ) ) : { numCorrect : Int.int, numWrong : Int.int, grade : Grade.grade } list = let val Score as ( _, _, _, _, P, R, F ) = FMeasureBerkeleyEdge.evaluate( Y, [ Array.sub( Truths, I ) ] ) (*val _ = print( Int.toString I ^ " " ^ FMeasureBerkeleyEdge.toString Score ^ "\n" ) *) (* val _ = BooleanImage.save( Y, OutDir ^ Int.toString I ^ ".pbm" ) *) in [ { numCorrect=1, numWrong=0, grade= ~( to F ) } ] end val cFuns = [] val AllAtOnce = false val Max_output_genus_card = 4 val OnlyCountCalls = false val max_time_limit : unit -> word = fn () => 0w1000000000 val max_test_time_limit : unit -> word = fn () => 0w1000000000 val time_limit_base = fn () => 1000000000.0 fun max_syntactic_complexity() = 500.0 fun min_syntactic_complexity() = 0.0 val Use_test_data_for_max_syntactic_complexity = false fun main_range_hash( Truth : main_range ) = array_hash( fn X => if X then 0w1 else 0w0, #Values Truth ) val File_name_extension = "" val Resolution = NONE val StochasticMode = false val Number_of_output_attributes : int = 4 fun terminate( Nc, G ) = false