1/* Various operators as functions. 2 */ 3 4logical_and a b = a && b; 5logical_or a b = a || b; 6bitwise_and a b = a & b; 7bitwise_or a b = a | b; 8eor a b = a ^ b; 9left_shift a b = a << b; 10right_shift a b = a >> b; 11not a = !a; 12 13less a b = a < b; 14more a b = a > b; 15less_equal a b = a <= b; 16more_equal a b = a >= b; 17equal a b = a == b; 18not_equal a b = a != b; 19pointer_equal a b = a === b; 20not_pointer_equal a b = a !== b; 21 22add a b = a + b; 23subtract a b = a - b; 24multiply a b = a * b; 25divide a b = a / b; 26power a b = a ** b; 27square x = x * x; 28remainder a b = a % b; 29 30cons a b = a : b; 31join a b = a ++ b; 32subscript a b = a ? b; 33 34generate s n f = [s, n .. f]; 35comma r i = (r, i); 36 37compose f g = f @ g; 38 39cast_unsigned_char x = (unsigned char) x; 40cast_signed_char x = (signed char) x; 41cast_unsigned_short x = (unsigned short) x; 42cast_signed_short x = (signed short) x; 43cast_unsigned_int x = (unsigned int) x; 44cast_signed_int x = (signed int) x; 45cast_float x = (float) x; 46cast_double x = (double) x; 47cast_complex x = (complex) x; 48cast_double_complex x = (double complex) x; 49 50unary_minus x = -x; 51negate x = !x; 52complement x = ~x; 53unary_plus x = +x; 54 55if_then_else a b c = if a then b else c; 56 57// the vector ops ... im is an image, vec is a real_list 58vec op_name im vec 59 = im_lintra_vec ones im vec, 60 op_name == "add" || op_name == "add'" 61 = im_lintra_vec ones (-1 * im) vec, 62 op_name == "subtract'" 63 = im_lintra_vec ones im inv, 64 op_name == "subtract" 65 = im_lintra_vec vec im zeros, 66 op_name == "multiply" || op_name == "multiply'" 67 = im_lintra_vec vec (1 / im) zeros, 68 op_name == "divide'" 69 = im_lintra_vec recip im zeros, 70 op_name == "divide" 71 = im_expntra_vec im vec, 72 op_name == "power'" 73 = im_powtra_vec im vec, 74 op_name == "power" 75 = im_remainderconst_vec im vec, 76 op_name == "remainder" 77 = im_andimage_vec im vec, 78 op_name == "bitwise_and" || op_name == "bitwise_and'" 79 = im_orimage_vec im vec, 80 op_name == "bitwise_or" || op_name == "bitwise_or'" 81 = im_eorimage_vec im vec, 82 op_name == "eor" || op_name == "eor'" 83 = im_equal_vec im vec, 84 op_name == "equal" || op_name == "equal'" 85 = im_notequal_vec im vec, 86 op_name == "not_equal" || op_name == "not_equal'" 87 = im_less_vec im vec, 88 op_name == "less" 89 = im_moreeq_vec im vec, 90 op_name == "less'" 91 = im_lesseq_vec im vec, 92 op_name == "less_equal" 93 = im_more_vec im vec, 94 op_name == "less_equal'" 95 = error "unimplemented vector operation" 96{ 97 zeros = replicate (len vec) 0; 98 ones = replicate (len vec) 1; 99 recip = map (divide 1) vec; 100 inv = map (multiply (-1)) vec; 101} 102 103/* Macbeth chart patch names. 104 */ 105_macbeth_names = [ 106 "Dark skin", 107 "Light skin", 108 "Blue sky", 109 "Foliage", 110 "Blue flower", 111 "Bluish green", 112 "Orange", 113 "Purplish blue", 114 "Moderate red", 115 "Purple", 116 "Yellow green", 117 "Orange yellow", 118 "Blue", 119 "Green", 120 "Red", 121 "Yellow", 122 "Magenta", 123 "Cyan", 124 "White (density 0.05)", 125 "Neutral 8 (density 0.23)", 126 "Neutral 6.5 (density 0.44)", 127 "Neutral 5 (density 0.70)", 128 "Neutral 3.5 (density 1.05)", 129 "Black (density 1.50)" 130]; 131 132bandsplit x 133 = oo_unary_function bandsplit_op x, is_class x 134 = map (subscript x) [0 .. bands - 1], is_image x 135 = error (_ "bad arguments to " ++ "bandsplit") 136{ 137 bands = im_header_int "Bands" x; 138 bandsplit_op = Operator "bandsplit" (map Image @ bandsplit) 139 Operator_type.COMPOUND false; 140} 141 142bandjoin l 143 = wrapper joined, 144 has_wrapper 145 = joined, is_listof has_image l 146 = error (_ "bad arguments to " ++ "bandjoin") 147{ 148 has_wrapper = has_member_list (has_member "Image") l; 149 wrapper = get_member_list (has_member "Image") (get_member "Image") l; 150 joined = im_gbandjoin (map get_image l); 151} 152 153mean x 154 = oo_unary_function mean_op x, is_class x 155 = im_avg x, is_image x 156 = mean_list x, is_real_list x || is_matrix x 157 = error (_ "bad arguments to " ++ "mean") 158{ 159 mean_op = Operator "mean" mean_object Operator_type.COMPOUND false; 160 161 mean_object x 162 = im_avg x, is_image x 163 = mean_list x, is_real_list x || is_matrix x 164 = error (_ "bad arguments to " ++ "mean"); 165 166 mean_list l 167 = s / n 168 { 169 totals = sum l; 170 n = totals?0; 171 s = totals?1; 172 } 173 174 // return [n, sum] for a list of numbers, or a list of list of num 175 // etc. 176 sum x 177 = foldr accumulate [0, 0] x 178 { 179 accumulate x sofar 180 = [n + 1, x + s], is_real x 181 = [n + n', s + s'], is_list x 182 = error "mean_list: not real or [real]" 183 { 184 n = sofar?0; 185 s = sofar?1; 186 187 sub_acc = sum x; 188 189 n' = sub_acc?0; 190 s' = sub_acc?1; 191 } 192 } 193} 194 195deviation x 196 = oo_unary_function deviation_op x, is_class x 197 = im_deviate x, is_image x 198 = deviation_list x, is_real_list x || is_matrix x 199 = error (_ "bad arguments to " ++ "deviation") 200{ 201 deviation_op = Operator "deviation" 202 deviation_object Operator_type.COMPOUND false; 203 204 deviation_object x 205 = im_deviate x, is_image x 206 = deviation_list x, is_real_list x || is_matrix x 207 = error (_ "bad arguments to " ++ "deviation"); 208 209 deviation_list l 210 = (abs (s2 - (s * s / n)) / (n - 1)) ** 0.5 211 { 212 totals = sum_sum2_list l; 213 n = totals?0; 214 s = totals?1; 215 s2 = totals?2; 216 } 217 218 // return n, sum, sum of squares for a list of reals 219 sum_sum2_list x 220 = foldr accumulate [0, 0, 0] x 221 { 222 accumulate x sofar 223 = [n + 1, x + s, x * x + s2], is_real x 224 = [n + n', s + s', s2 + s2'], is_list x 225 = error "sum_sum2_list: not real or [real]" 226 { 227 n = sofar?0; 228 s = sofar?1; 229 s2 = sofar?2; 230 231 sub_acc = sum_sum2_list x; 232 233 n' = sub_acc?0; 234 s' = sub_acc?1; 235 s2' = sub_acc?2; 236 } 237 } 238} 239 240abs x 241 = oo_unary_function abs_op x, is_class x 242 = im_abs x, is_image x 243 = abs_cmplx x, is_complex x 244 = abs_num x, is_real x 245 = error (_ "bad arguments to " ++ "abs") 246{ 247 abs_op = Operator "abs" abs_object Operator_type.COMPOUND false; 248 249 abs_object x 250 = im_abs x, is_image x 251 = abs_cmplx x, is_complex x 252 = abs_num x, is_real x 253 = abs_list x, is_real_list x 254 = abs_list (map abs_list x), is_matrix x 255 = error (_ "bad arguments to " ++ "abs"); 256 257 abs_list l = (foldr1 add (map square l)) ** 0.5; 258 259 abs_num n 260 = n, n >= 0 261 = -n; 262 263 abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; 264} 265 266copy x 267 = oo_unary_function copy_op x, is_class x 268 = im_copy x, is_image x 269 = x 270{ 271 copy_op = Operator "copy" copy Operator_type.COMPOUND_REWRAP false; 272} 273 274// like abs, but treat pixels as vectors ... ie. always get a 1-band image 275// back ... also treat matricies as lists of vectors 276// handy for dE from object difference 277abs_vec x 278 = oo_unary_function abs_vec_op x, is_class x 279 = abs_vec_image x, is_image x 280 = abs_vec_cmplx x, is_complex x 281 = abs_vec_num x, is_real x 282 = error (_ "bad arguments to " ++ "abs_vec") 283{ 284 abs_vec_op = Operator "abs_vec" 285 abs_vec_object Operator_type.COMPOUND false; 286 287 abs_vec_object x 288 = abs_vec_image x, is_image x 289 = abs_vec_cmplx x, is_complex x 290 = abs_vec_num x, is_real x 291 = abs_vec_list x, is_real_list x 292 = mean (Vector (map abs_vec_list x)), is_matrix x 293 = error (_ "bad arguments to " ++ "abs_vec"); 294 295 abs_vec_list l = (foldr1 add (map square l)) ** 0.5; 296 297 abs_vec_num n 298 = n, n >= 0 299 = -n; 300 301 abs_vec_cmplx c = ((re c)**2 + (im c)**2) ** 0.5; 302 303 abs_vec_image im 304 = (foldr1 add (map square (bandsplit im))) ** 0.5; 305} 306 307transpose x 308 = oo_unary_function transpose_op x, is_class x 309 = transpose_image x, is_image x 310 = transpose_matrix x, is_list x && is_list (hd x) 311 = error (_ "bad arguments to " ++ "transpose") 312{ 313 transpose_op = Operator "transpose" 314 transpose_object Operator_type.COMPOUND_REWRAP false; 315 316 transpose_object x 317 = transpose_matrix x, is_matrix x 318 = transpose_image x, is_image x 319 = error (_ "bad arguments to " ++ "transpose"); 320 321 transpose_matrix l 322 = [], l' == [] 323 = (map hd l') : (transpose_matrix (map tl l')) 324 { 325 l' = takewhile (not_equal []) l; 326 } 327 328 transpose_image = im_flipver @ im_rot270; 329} 330 331rot45 x 332 = oo_unary_function rot45_op x, is_class x 333 = error "rot45 image: not implemented", is_image x 334 = error (_ "bad arguments to " ++ "rot45") 335{ 336 rot45_op = Operator "rot45" 337 rot45_object Operator_type.COMPOUND_REWRAP false; 338 339 rot45_object x 340 = rot45_matrix x, is_odd_square_matrix x 341 = error "rot45 image: not implemented", is_image x 342 = error (_ "bad arguments to " ++ "rot45"); 343 344 // slow, but what the heck 345 rot45_matrix l = (im_rotate_dmask45 (Matrix l)).value; 346} 347 348// apply an image function to a [[real]] ... matrix is converted to a 1 band 349// image for processing 350apply_matrix_as_image fn m 351 = (get_value @ im_vips2mask @ fn @ im_mask2vips @ Matrix) m; 352 353rot90 x 354 = oo_unary_function rot90_op x, is_class x 355 = im_rot90 x, is_image x 356 = error (_ "bad arguments to " ++ "rot90") 357{ 358 rot90_op = Operator "rot90" 359 rot90_object Operator_type.COMPOUND_REWRAP false; 360 361 rot90_object x 362 = rot90_matrix x, is_matrix x 363 = im_rot90 x, is_image x 364 = error (_ "bad arguments to " ++ "rot90"); 365 366 // slow, but what the heck 367 // avoid im_rotate_dmask90(), it can only do square odd-sided matricies 368 rot90_matrix l = apply_matrix_as_image im_rot90 l; 369} 370 371rot180 x 372 = oo_unary_function rot180_op x, is_class x 373 = im_rot180 x, is_image x 374 = error (_ "bad arguments to " ++ "rot180") 375{ 376 rot180_op = Operator "rot180" 377 rot180_object Operator_type.COMPOUND_REWRAP false; 378 379 rot180_object x 380 = rot180_matrix x, is_matrix x 381 = im_rot180 x, is_image x 382 = error (_ "bad arguments to " ++ "rot180"); 383 384 // slow, but what the heck 385 rot180_matrix l = apply_matrix_as_image im_rot180 l; 386} 387 388rot270 x 389 = oo_unary_function rot270_op x, is_class x 390 = im_rot270 x, is_image x 391 = error (_ "bad arguments to " ++ "rot270") 392{ 393 rot270_op = Operator "rot270" 394 rot270_object Operator_type.COMPOUND_REWRAP false; 395 396 rot270_object x 397 = rot270_matrix x, is_matrix x 398 = im_rot270 x, is_image x 399 = error (_ "bad arguments to " ++ "rot270"); 400 401 // slow, but what the heck 402 rot270_matrix l = apply_matrix_as_image im_rot270 l; 403} 404 405image_set_type type x 406 = oo_unary_function image_set_type_op x, is_class x 407 = im_copy_set x (to_real type) 408 (im_header_double "Xres" x) (im_header_double "Yres" x) 409 (im_header_int "Xoffset" x) (im_header_int "Yoffset" x), 410 is_image x 411 = error (_ "bad arguments to " ++ "image_set_type:" ++ 412 print type ++ " " ++ print x) 413{ 414 image_set_type_op = Operator "image_set_type" 415 (image_set_type type) Operator_type.COMPOUND_REWRAP false; 416} 417 418image_set_origin xoff yoff x 419 = oo_unary_function image_set_origin_op x, is_class x 420 = im_copy_set x 421 (im_header_int "Type" x) 422 (im_header_double "Xres" x) (im_header_double "Yres" x) 423 (to_real xoff) (to_real yoff), 424 is_image x 425 = error (_ "bad arguments to " ++ "image_set_origin") 426{ 427 image_set_origin_op = Operator "image_set_origin" 428 (image_set_origin xoff yoff) 429 Operator_type.COMPOUND_REWRAP false; 430} 431 432rotquad x 433 = oo_unary_function rotquad_op x, is_class x 434 = im_rotquad x, is_image x 435 = error (_ "bad arguments to " ++ "rotquad") 436{ 437 rotquad_op = Operator "rotquad" 438 rotquad_object Operator_type.COMPOUND_REWRAP false; 439 440 rotquad_object x 441 = rotquad_matrix x, is_matrix x 442 = im_rotquad x, is_image x 443 = error (_ "bad arguments to " ++ "rotquad"); 444 445 rotquad_matrix l = apply_matrix_as_image im_rotquad l; 446} 447 448cache tile_width tile_height max_tiles x 449 = oo_unary_function cache_op x, is_class x 450 = im_cache x (to_real tile_width) (to_real tile_height) 451 (to_real max_tiles), is_image x 452 = error (_ "bad arguments to " ++ "cache") 453{ 454 cache_op = Operator "cache" 455 (cache tile_width tile_height max_tiles) 456 Operator_type.COMPOUND_REWRAP false; 457} 458 459tile across down x 460 = oo_unary_function tile_op x, is_class x 461 = im_replicate x (to_real across) (to_real down), is_image x 462 = error (_ "bad arguments to " ++ "tile") 463{ 464 tile_op = Operator "tile" 465 (tile across down) Operator_type.COMPOUND_REWRAP false; 466} 467 468fliptb x 469 = oo_unary_function fliptb_op x, is_class x 470 = im_flipver x, is_image x 471 = error (_ "bad arguments to " ++ "fliptb") 472{ 473 fliptb_op = Operator "fliptb" 474 fliptb_object Operator_type.COMPOUND_REWRAP false; 475 476 fliptb_object x 477 = fliptb_matrix x, is_matrix x 478 = im_flipver x, is_image x 479 = error (_ "bad arguments to " ++ "fliptb"); 480 481 fliptb_matrix l = reverse l; 482} 483 484fliplr x 485 = oo_unary_function fliplr_op x, is_class x 486 = im_fliphor x, is_image x 487 = error (_ "bad arguments to " ++ "fliplr") 488{ 489 fliplr_op = Operator "fliplr" 490 fliplr_object Operator_type.COMPOUND_REWRAP false; 491 492 fliplr_object x 493 = fliplr_matrix x, is_matrix x 494 = im_fliphor x, is_image x 495 = error (_ "bad arguments to " ++ "fliplr"); 496 497 fliplr_matrix l = map reverse l; 498} 499 500max_pair a b 501 = a, a > b 502 = b; 503 504min_pair a b 505 = a, a < b 506 = b; 507 508range min value max = min_pair max (max_pair min value); 509 510max x 511 = oo_unary_function max_op x, is_class x 512 = im_max x, is_image x 513 = max_list x, is_real_list x || is_matrix x 514 = x, is_number x 515 = error (_ "bad arguments to " ++ "max") 516{ 517 max_op = Operator "max" max Operator_type.COMPOUND false; 518 519 max_list x 520 = foldr1 max_pair x, is_real_list x 521 = foldr1 max_pair (map max_list x), is_matrix x 522 = max x; 523} 524 525min x 526 = oo_unary_function min_op x, is_class x 527 = im_min x, is_image x 528 = min_list x, is_real_list x || is_matrix x 529 = x, is_number x 530 = error (_ "bad arguments to " ++ "min") 531{ 532 min_op = Operator "min" min Operator_type.COMPOUND false; 533 534 min_list x 535 = foldr1 min_pair x, is_real_list x 536 = foldr1 min_pair (map min_list x), is_matrix x 537 = min x; 538} 539 540maxpos x 541 = oo_unary_function maxpos_op x, is_class x 542 = im_maxpos x, is_image x 543 = maxpos_matrix x, is_matrix x 544 = error (_ "bad arguments to " ++ "maxpos") 545{ 546 maxpos_op = Operator "maxpos" maxpos Operator_type.COMPOUND false; 547 548 maxpos_matrix m 549 = (indexes?row, row) 550 { 551 max_value = max (Matrix m); 552 indexes = map (index (equal max_value)) m; 553 row = index (not_equal (-1)) indexes; 554 } 555} 556 557minpos x 558 = oo_unary_function minpos_op x, is_class x 559 = im_minpos x, is_image x 560 = minpos_matrix x, is_matrix x 561 = error (_ "bad arguments to " ++ "minpos") 562{ 563 minpos_op = Operator "minpos" minpos Operator_type.COMPOUND false; 564 565 minpos_matrix m 566 = (indexes?row, row) 567 { 568 min_value = min (Matrix m); 569 indexes = map (index (equal min_value)) m; 570 row = index (not_equal (-1)) indexes; 571 } 572} 573 574stats x 575 = oo_unary_function stats_op x, is_class x 576 = im_stats x, is_image x 577 = im_stats (to_image x).value, is_matrix x 578 = error (_ "bad arguments to " ++ "stats") 579{ 580 stats_op = Operator "stats" 581 stats Operator_type.COMPOUND false; 582} 583 584e = 2.7182818284590452354; 585 586pi = 3.14159265358979323846; 587 588rad d = 2 * pi * (d / 360); 589 590deg r = 360 * r / (2 * pi); 591 592sign x 593 = oo_unary_function sign_op x, is_class x 594 = im_sign x, is_image x 595 = sign_cmplx x, is_complex x 596 = sign_num x, is_real x 597 = error (_ "bad arguments to " ++ "sign") 598{ 599 sign_op = Operator "sign" sign Operator_type.COMPOUND_REWRAP false; 600 601 sign_num n 602 = 0, n == 0 603 = 1, n > 0 604 = -1; 605 606 sign_cmplx c 607 = (0, 0), mod == 0 608 = (re c / mod, im c / mod) 609 { 610 mod = abs c; 611 } 612} 613 614rint x 615 = oo_unary_function rint_op x, is_class x 616 = im_rint x, is_image x 617 = rint_value x, is_number x 618 = error (_ "bad arguments to " ++ "rint") 619{ 620 rint_op = Operator "rint" rint Operator_type.ARITHMETIC false; 621 622 rint_value x 623 = (int) (x + 0.5), x > 0 624 = (int) (x - 0.5); 625} 626 627scale x 628 = oo_unary_function scale_op x, is_class x 629 = (unsigned char) x, is_number x 630 = im_scale x, is_image x 631 = scale_list x, is_real_list x || is_matrix x 632 = error (_ "bad arguments to " ++ "scale") 633{ 634 scale_op = Operator "scale" scale Operator_type.COMPOUND_REWRAP false; 635 636 scale_list l 637 = apply_scale s o l 638 { 639 mn = find_limit min_pair l; 640 mx = find_limit max_pair l; 641 s = 255.0 / (mx - mn); 642 o = -(mn * s); 643 } 644 645 find_limit fn l 646 = find_limit fn (map (find_limit fn) l), is_listof is_list l 647 = foldr1 fn l; 648 649 apply_scale s o x 650 = x * s + o, is_number x 651 = map (apply_scale s o) x; 652} 653 654scaleps x 655 = oo_unary_function scale_op x, is_class x 656 = im_scaleps x, is_image x 657 = error (_ "bad arguments to " ++ "scale") 658{ 659 scale_op = Operator "scaleps" 660 scaleps Operator_type.COMPOUND_REWRAP false; 661} 662 663fwfft x 664 = oo_unary_function fwfft_op x, is_class x 665 = im_fwfft x, is_image x 666 = error (_ "bad arguments to " ++ "fwfft") 667{ 668 fwfft_op = Operator "fwfft" 669 fwfft Operator_type.COMPOUND_REWRAP false; 670} 671 672invfft x 673 = oo_unary_function invfft_op x, is_class x 674 = im_invfftr x, is_image x 675 = error (_ "bad arguments to " ++ "invfft") 676{ 677 invfft_op = Operator "invfft" 678 invfft Operator_type.COMPOUND_REWRAP false; 679} 680 681falsecolour x 682 = oo_unary_function falsecolour_op x, is_class x 683 = image_set_type Image_type.sRGB (im_falsecolour x), is_image x 684 = error (_ "bad arguments to " ++ "falsecolour") 685{ 686 falsecolour_op = Operator "falsecolour" 687 falsecolour Operator_type.COMPOUND_REWRAP false; 688} 689 690polar x 691 = oo_unary_function polar_op x, is_class x 692 = im_c2amph x, is_image x 693 = polar_cmplx x, is_complex x 694 = error (_ "bad arguments to " ++ "polar") 695{ 696 polar_op = Operator "polar" polar Operator_type.COMPOUND false; 697 698 polar_cmplx r 699 = (l, a) 700 { 701 a 702 = 270, x == 0 && y < 0 703 = 90, x == 0 && y >= 0 704 = 360 + atan (y / x), x > 0 && y < 0 705 = atan (y / x), x > 0 && y >= 0 706 = 180 + atan (y / x); 707 708 l = (x ** 2 + y ** 2) ** 0.5; 709 710 x = re r; 711 y = im r; 712 } 713} 714 715rectangular x 716 = oo_unary_function rectangular_op x, is_class x 717 = im_c2rect x, is_image x 718 = rectangular_cmplx x, is_complex x 719 = error (_ "bad arguments to " ++ "rectangular") 720{ 721 rectangular_op = Operator "rectangular" 722 rectangular Operator_type.COMPOUND false; 723 724 rectangular_cmplx p 725 = (x, y) 726 { 727 l = re p; 728 a = im p; 729 730 x = l * cos a; 731 y = l * sin a; 732 } 733} 734 735recomb matrix image 736 = colour_unary recomb_op image 737{ 738 recomb_op x 739 = im_recomb x (to_matrix matrix), is_image x 740 = error (_ "bad arguments to " ++ "recomb"); 741} 742 743extract_area x y w h obj 744 = oo_unary_function extract_area_op obj, is_class obj 745 = im_extract_area obj x' y' w' h', is_image obj 746 = map (extract_range x' w') (extract_range y' h' obj), is_matrix obj 747 = error (_ "bad arguments to " ++ "extract_area") 748{ 749 x' = to_real x; 750 y' = to_real y; 751 w' = to_real w; 752 h' = to_real h; 753 754 extract_area_op = Operator "extract_area" (extract_area x y w h) 755 Operator_type.COMPOUND_REWRAP false; 756 757 extract_range from length list 758 = (take length @ drop from) list; 759} 760 761extract_band b obj = subscript obj b; 762 763extract_row y obj 764 = oo_unary_function extract_row_op obj, is_class obj 765 = extract_area 0 y' (get_width obj) 1 obj, is_image obj 766 = [obj?y'], is_matrix obj 767 = error (_ "bad arguments to " ++ "extract_row") 768{ 769 y' = to_real y; 770 771 extract_row_op = Operator "extract_row" (extract_row y) 772 Operator_type.COMPOUND_REWRAP false; 773} 774 775extract_column x obj 776 = oo_unary_function extract_column_op obj, is_class obj 777 = extract_area x' 0 1 height obj, is_image obj 778 = map (converse cons [] @ converse subscript x') obj, is_matrix obj 779 = error (_ "bad arguments to " ++ "extract_column") 780{ 781 x' = to_real x; 782 height = im_header_int "Ysize" obj; 783 784 extract_column_op = Operator "extract_column" (extract_column x) 785 Operator_type.COMPOUND_REWRAP false; 786} 787 788blend cond in1 in2 789 = oo_binary_function blend_op cond [in1,in2], is_class cond 790 = im_blend (get_image cond) (get_image in1) (get_image in2), 791 has_image cond && has_image in1 && has_image in2 792 = error (_ "bad arguments to " ++ "blend") 793{ 794 blend_op = Operator "blend" 795 blend_obj Operator_type.COMPOUND_REWRAP false; 796 797 blend_obj cond x 798 = blend_result_image 799 { 800 then_part = x?0; 801 else_part = x?1; 802 803 // get things about our output from inputs in this order 804 objects = [then_part, else_part, cond]; 805 806 // properties of our output image 807 target_width = get_member_list has_width get_width objects; 808 target_height = get_member_list has_height get_height objects; 809 target_bands = get_member_list has_bands get_bands objects; 810 target_format = get_member_list has_format get_format objects; 811 target_type = get_member_list has_type get_type objects; 812 813 to_image x 814 = x, is_image x 815 = x.value, is_Image x 816 = black + x 817 { 818 black = im_black target_width target_height target_bands; 819 } 820 821 then_image = to_image then_part; 822 else_image = to_image else_part; 823 824 then_image' = clip2fmt target_format then_image; 825 else_image' = clip2fmt target_format else_image; 826 827 resized = size_alike [cond, then_image', else_image']; 828 829 blend_result_image = image_set_type target_type 830 (im_blend resized?0 resized?1 resized?2); 831 } 832} 833 834insert x y small big 835 = oo_binary_function insert_op small big, is_class small 836 = oo_binary'_function insert_op small big, is_class big 837 = im_insert big small (to_real x) (to_real y), 838 is_image small && is_image big 839 = error (_ "bad arguments to " ++ "insert") 840{ 841 insert_op = Operator "insert" 842 (insert x y) Operator_type.COMPOUND_REWRAP false; 843} 844 845insert_noexpand x y small big 846 = oo_binary_function insert_noexpand_op small big, is_class small 847 = oo_binary'_function insert_noexpand_op small big, is_class big 848 = im_insert_noexpand big small (to_real x) (to_real y), 849 is_image small && is_image big 850 = error (_ "bad arguments to " ++ "insert_noexpand") 851{ 852 insert_noexpand_op = Operator "insert_noexpand" 853 (insert_noexpand x y) Operator_type.COMPOUND_REWRAP false; 854} 855 856measure x y w h u v image 857 = oo_unary_function measure_op image, is_class image 858 = im_measure image 859 (to_real x) (to_real y) (to_real w) (to_real h) 860 (to_real u) (to_real v), 861 is_image image 862 = error (_ "bad arguments to " ++ "measure") 863{ 864 measure_op = Operator "measure" 865 (measure x y w h u v) Operator_type.COMPOUND_REWRAP false; 866} 867 868extract_bands b n obj 869 = oo_unary_function extract_bands_op obj, is_class obj 870 = im_extract_bands obj (to_real b) (to_real n), is_image obj 871 = error (_ "bad arguments to " ++ "extract_bands") 872{ 873 extract_bands_op = Operator "extract_bands" 874 (extract_bands b n) Operator_type.COMPOUND_REWRAP false; 875} 876 877transform ipol wrap params image 878 = oo_unary_function transform_op image, is_class image 879 = im_transform image 880 (to_matrix params) (to_real ipol) (to_real wrap), is_image image 881 = error (_ "bad arguments to " ++ "transform") 882{ 883 transform_op = Operator "transform" 884 (transform ipol wrap params) 885 Operator_type.COMPOUND_REWRAP false; 886} 887 888transform_search max_error max_iterations order ipol wrap sample reference 889 = oo_binary_function transform_search_op sample reference, is_class sample 890 = oo_binary'_function transform_search_op sample reference, 891 is_class reference 892 = im_transform_search sample reference 893 (to_real max_error) (to_real max_iterations) (to_real order) 894 (to_real ipol) (to_real wrap), 895 is_image sample && is_image reference 896 = error (_ "bad arguments to " ++ "transform_search") 897{ 898 transform_search_op = Operator "transform_search" 899 (transform_search max_error max_iterations order ipol wrap) 900 Operator_type.COMPOUND false; 901} 902 903rotate angle image 904 = oo_binary_function rotate_op angle image, is_class angle 905 = oo_binary'_function rotate_op angle image, is_class image 906 = im_similarity image (cos angle) (sin angle) 0 0, 907 is_real angle && is_image image 908 = error (_ "bad arguments to " ++ "rotate") 909{ 910 rotate_op = Operator "rotate" 911 rotate Operator_type.COMPOUND_REWRAP false; 912} 913 914conj x 915 = oo_unary_function conj_op x, is_class x 916 = (re x, -im x), 917 is_complex x || 918 (is_image x && format == Image_format.COMPLEX) || 919 (is_image x && format == Image_format.DPCOMPLEX) 920 // assume it's some sort of real 921 = x 922{ 923 format = im_header_int "BandFmt" x; 924 conj_op = Operator "conj" conj Operator_type.COMPOUND false; 925} 926 927clip2fmt format image 928 = oo_unary_function clip2fmt_op image, is_class image 929 = im_clip2fmt image (to_real format), is_image image 930 = error (_ "bad arguments to " ++ "clip2fmt") 931{ 932 clip2fmt_op = Operator "clip2fmt" 933 (clip2fmt format) Operator_type.COMPOUND_REWRAP false; 934} 935 936embed type x y w h im 937 = oo_unary_function embed_op im, is_class im 938 = im_embed im (to_real type) 939 (to_real x) (to_real y) (to_real w) (to_real h), is_image im 940 = error (_ "bad arguments to " ++ "embed") 941{ 942 embed_op = Operator "embed" 943 (embed type x y w h) Operator_type.COMPOUND_REWRAP false; 944} 945 946/* Morph a mask with a [[real]] matrix ... turn m2 into an image, morph it 947 * with m1, turn it back to a matrix again. 948 */ 949_morph_2_masks fn m1 m2 950 = m'' 951{ 952 image = (unsigned char) im_mask2vips (Matrix m2); 953 m2_width = get_width image; 954 m2_height = get_height image; 955 956 // need to embed m2 in an image large enough for us to be able to 957 // position m1 all around the edges, with a 1 pixel overlap 958 image' = embed 0 959 (m1.width / 2) (m1.height / 2) 960 (m2_width + (m1.width - 1)) (m2_height + (m1.height - 1)) 961 image; 962 963 // morph! 964 image'' = fn m1 image'; 965 966 // back to mask 967 m' = im_vips2mask ((double) image''); 968 969 // Turn 0 in output to 128 (don't care). 970 m'' 971 = map (map fn) m'.value 972 { 973 fn a 974 = 128, a == 0; 975 = a; 976 } 977} 978 979dilate mask image 980 = oo_unary_function dilate_op image, is_class image 981 = im_dilate image (to_matrix mask), is_image image 982 = error (_ "bad arguments to " ++ "dilate") 983{ 984 dilate_op = Operator "dilate" 985 dilate_object Operator_type.COMPOUND_REWRAP false; 986 987 dilate_object x 988 = _morph_2_masks dilate mask x, is_matrix x 989 = dilate mask x; 990} 991 992erode mask image 993 = oo_unary_function erode_op image, is_class image 994 = im_erode image (to_matrix mask), is_image image 995 = error (_ "bad arguments to " ++ "erode") 996{ 997 erode_op = Operator "erode" 998 erode_object Operator_type.COMPOUND_REWRAP false; 999 1000 erode_object x 1001 = _morph_2_masks erode mask x, is_matrix x 1002 = erode mask x; 1003} 1004 1005conv mask image 1006 = oo_unary_function conv_op image, is_class image 1007 = im_conv image (to_matrix mask), is_image image 1008 = error (_ "bad arguments to " ++ "conv") 1009{ 1010 conv_op = Operator "conv" 1011 (conv mask) Operator_type.COMPOUND_REWRAP false; 1012} 1013 1014convsep mask image 1015 = oo_unary_function convsep_op image, is_class image 1016 = im_convsep image (to_matrix mask), is_image image 1017 = error (_ "bad arguments to " ++ "convsep") 1018{ 1019 convsep_op = Operator "convsep" 1020 (convsep mask) Operator_type.COMPOUND_REWRAP false; 1021} 1022 1023rank w h n image 1024 = oo_unary_function rank_op image, is_class image 1025 = im_rank image (to_real w) (to_real h) (to_real n), is_image image 1026 = error (_ "bad arguments to " ++ "rank") 1027{ 1028 rank_op = Operator "rank" 1029 (rank w h n) Operator_type.COMPOUND_REWRAP false; 1030} 1031 1032rank_image n x 1033 // work for groups too (convenient) 1034 = rlist x.value, is_Group x 1035 = rlist x, is_list x 1036 = error (_ "bad arguments to " ++ "rank_image") 1037{ 1038 rlist l 1039 = wrapper ranked, has_wrapper 1040 = ranked 1041 { 1042 has_wrapper = has_member_list (has_member "Image") l; 1043 wrapper = get_member_list (has_member "Image") (get_member "Image") l; 1044 ranked = im_rank_image (map get_image l) (to_real n); 1045 } 1046} 1047 1048hist_find image 1049 = oo_unary_function hist_find_op image, is_class image 1050 = im_histgr image (-1), is_image image 1051 = error (_ "bad arguments to " ++ "hist_find") 1052{ 1053 hist_find_op = Operator "hist_find" 1054 hist_find Operator_type.COMPOUND_REWRAP false; 1055} 1056 1057hist_find_nD bins image 1058 = oo_unary_function hist_find_nD_op image, is_class image 1059 = im_histnD image (to_real bins), is_image image 1060 = error (_ "bad arguments to " ++ "hist_find_nD") 1061{ 1062 hist_find_nD_op = Operator "hist_find_nD" 1063 (hist_find_nD bins) Operator_type.COMPOUND_REWRAP false; 1064} 1065 1066hist_map hist image 1067 = oo_binary_function hist_map_op hist image, is_class hist 1068 = oo_binary'_function hist_map_op hist image, is_class image 1069 = im_maplut image hist, is_image hist && is_image image 1070 = error (_ "bad arguments to " ++ "hist_map") 1071{ 1072 hist_map_op = Operator "hist_map" 1073 hist_map Operator_type.COMPOUND_REWRAP false; 1074} 1075 1076hist_cum hist 1077 = oo_unary_function hist_cum_op hist, is_class hist 1078 = im_histcum hist, is_image hist 1079 = error (_ "bad arguments to " ++ "hist_cum") 1080{ 1081 hist_cum_op = Operator "hist_cum" 1082 hist_cum Operator_type.COMPOUND_REWRAP false; 1083} 1084 1085hist_norm hist 1086 = oo_unary_function hist_norm_op hist, is_class hist 1087 = im_histnorm hist, is_image hist 1088 = error (_ "bad arguments to " ++ "hist_norm") 1089{ 1090 hist_norm_op = Operator "hist_norm" 1091 hist_norm Operator_type.COMPOUND_REWRAP false; 1092} 1093 1094hist_match in ref 1095 = oo_binary_function hist_match_op in ref, is_class in 1096 = oo_binary'_function hist_match_op in ref, is_class ref 1097 = im_histspec in ref, is_image in && is_image ref 1098 = error (_ "bad arguments to " ++ "hist_match") 1099{ 1100 hist_match_op = Operator "hist_match" 1101 hist_match Operator_type.COMPOUND_REWRAP false; 1102} 1103 1104hist_equalize x = hist_map ((hist_norm @ hist_cum @ hist_find) x) x; 1105 1106hist_equalize_local w h image 1107 = oo_unary_function hist_equalize_local_op image, is_class image 1108 = lhisteq image, is_image image 1109 = error (_ "bad arguments to " ++ "hist_equalize_local") 1110{ 1111 hist_equalize_local_op = Operator "hist_equalize_local" 1112 (hist_equalize_local w h) Operator_type.COMPOUND_REWRAP false; 1113 1114 // loop over bands, if necessary 1115 lhisteq im 1116 = im_lhisteq im (to_real w) (to_real h), get_bands im == 1 1117 = (foldl1 join @ map lhisteq @ bandsplit) im; 1118} 1119 1120// find the threshold below which are percent of the image (percent in [0,1]) 1121// eg. hist_thresh 0.1 x == 12, then x < 12 will light up 10% of the pixels 1122hist_thresh percent image 1123 = x 1124{ 1125 // our own normaliser ... we don't want to norm channels separately 1126 // norm to [0,1] 1127 my_hist_norm h = h / max h; 1128 sum = foldr1 add; 1129 1130 // normalised cumulative hist 1131 // we sum the channels before we normalise, because we want to treat them 1132 // all the same 1133 h = (my_hist_norm @ sum @ bandsplit @ hist_cum @ hist_find) 1134 image.value; 1135 1136 // threshold that, then use im_profile to search for the x position in the 1137 // histogram 1138 x = mean (im_profile (h > percent) 1); 1139} 1140 1141resize xfac yfac interp image 1142 = oo_unary_function resize_op image, is_class image 1143 = resize_im image, is_image image 1144 = error (_ "bad arguments to " ++ "resize") 1145{ 1146 resize_op = Operator "resize" 1147 resize_im Operator_type.COMPOUND_REWRAP false; 1148 1149 xfac' = to_real xfac; 1150 yfac' = to_real yfac; 1151 1152 rxfac' = 1 / xfac'; 1153 ryfac' = 1 / yfac'; 1154 1155 resize_im im 1156 // upscale by integer factor, nearest neighbour 1157 = im_zoom im xfac' yfac', 1158 is_int xfac' && is_int yfac' && 1159 xfac' >= 1 && yfac' >= 1 && 1160 interp == Interpolate.NEAREST_NEIGHBOUR 1161 1162 // downscale by integer factor, nearest neighbour 1163 = im_subsample im rxfac' ryfac', 1164 is_int rxfac' && is_int ryfac' && 1165 rxfac' >= 1 && ryfac' >= 1 && 1166 interp == Interpolate.NEAREST_NEIGHBOUR 1167 1168 // upscale by any factor, nearest neighbour 1169 // can't really do this right ... upscale by integer part, then 1170 // bilinear to exact size 1171 = scale (break xfac')?1 (break yfac')?1 1172 (im_zoom im (break xfac')?0 (break yfac')?0), 1173 xfac' >= 1 && yfac' >= 1 && 1174 interp == Interpolate.NEAREST_NEIGHBOUR 1175 1176 // downscale by any factor, nearest neighbour 1177 // can't really do this right ... downscale by integer part, 1178 // then bilinear to exact size 1179 = scale (1 / (break rxfac')?1) (1 / (break ryfac')?1) 1180 (im_subsample im (break rxfac')?0 (break ryfac')?0), 1181 rxfac' >= 1 && ryfac' >= 1 && 1182 interp == Interpolate.NEAREST_NEIGHBOUR 1183 1184 // upscale by any factor, bilinear 1185 = scale xfac' yfac' im, 1186 xfac' >= 1 && yfac' >= 1 && 1187 interp == Interpolate.BILINEAR 1188 1189 // downscale by any factor, bilinear 1190 // block shrink by integer factor, then bilinear resample to 1191 // exact 1192 = scale (1 / (break rxfac')?1) (1 / (break ryfac')?1) 1193 (im_shrink im (break rxfac')?0 (break ryfac')?0), 1194 rxfac' >= 1 && ryfac' >= 1 && 1195 interp == Interpolate.BILINEAR 1196 1197 = error ("resize: unimplemented argument combination:\n" ++ 1198 " xfac = " ++ print xfac' ++ "\n" ++ 1199 " yfac = " ++ print yfac' ++ "\n" ++ 1200 " interp = " ++ print interp ++ " (" ++ 1201 Interpolate.names.lookup 1 0 interp ++ ")") 1202 { 1203 // convert a float scale to integer plus fraction 1204 // eg. scale by 2.5 becomes [2, 1.25] (x * 2.5 == x * 2 * 1.25) 1205 break f = [floor f, f / floor f]; 1206 1207 // binlinear resize 1208 scale xfac yfac im 1209 = im_affine im 1210 xfac 0 0 yfac 1211 0 0 1212 0 0 1213 (rint (get_width im * xfac)) 1214 (rint (get_height im * yfac)); 1215 } 1216} 1217 1218sharpen radius x1 y2 y3 m1 m2 in 1219 = oo_unary_function sharpen_op in, is_class in 1220 = im_sharpen in (to_real radius) 1221 (to_real x1) (to_real y2) (to_real y3) 1222 (to_real m1) (to_real m2), is_image in 1223 = error (_ "bad arguments to " ++ "sharpen") 1224{ 1225 sharpen_op = Operator "sharpen" 1226 (sharpen radius x1 y2 y3 m1 m2) 1227 Operator_type.COMPOUND_REWRAP false; 1228} 1229 1230tone_analyse s m h sa ma ha in 1231 = oo_unary_function tone_analyse_op in, is_class in 1232 = im_tone_analyse in 1233 (to_real s) (to_real m) (to_real h) 1234 (to_real sa) (to_real ma) (to_real ha), is_image in 1235 = error (_ "bad arguments to " ++ "tone_analyse") 1236{ 1237 tone_analyse_op = Operator "tone_analyse" 1238 (tone_analyse s m h sa ma ha) 1239 Operator_type.COMPOUND_REWRAP false; 1240} 1241 1242tone_map hist image 1243 = oo_binary_function tone_map_op hist image, is_class hist 1244 = oo_binary'_function tone_map_op hist image, is_class image 1245 = im_tone_map image hist, is_image hist && is_image image 1246 = error (_ "bad arguments to " ++ "tone_map") 1247{ 1248 tone_map_op = Operator "tone_map" 1249 tone_map Operator_type.COMPOUND_REWRAP false; 1250} 1251 1252tone_build fmt b w s m h sa ma ha 1253 = (Image @ clip2fmt fmt) 1254 (im_tone_build_range mx mx 1255 (to_real b) (to_real w) 1256 (to_real s) (to_real m) (to_real h) 1257 (to_real sa) (to_real ma) (to_real ha)) 1258{ 1259 mx = Image_format.maxval fmt; 1260} 1261 1262icc_export depth profile intent in 1263 = oo_unary_function icc_export_op in, is_class in 1264 = im_icc_export_depth in 1265 (to_real depth) (expand profile) (to_real intent), is_image in 1266 = error (_ "bad arguments to " ++ "icc_export") 1267{ 1268 icc_export_op = Operator "icc_export" 1269 (icc_export depth profile intent) 1270 Operator_type.COMPOUND_REWRAP false; 1271} 1272 1273icc_import profile intent in 1274 = oo_unary_function icc_import_op in, is_class in 1275 = im_icc_import in 1276 (expand profile) (to_real intent), is_image in 1277 = error (_ "bad arguments to " ++ "icc_import") 1278{ 1279 icc_import_op = Operator "icc_import" 1280 (icc_import profile intent) 1281 Operator_type.COMPOUND_REWRAP false; 1282} 1283 1284icc_transform in_profile out_profile intent in 1285 = oo_unary_function icc_transform_op in, is_class in 1286 = im_icc_transform in 1287 (expand in_profile) (expand out_profile) 1288 (to_real intent), is_image in 1289 = error (_ "bad arguments to " ++ "icc_transform") 1290{ 1291 icc_transform_op = Operator "icc_transform" 1292 (icc_transform in_profile out_profile intent) 1293 Operator_type.COMPOUND_REWRAP false; 1294} 1295 1296icc_ac2rc profile in 1297 = oo_unary_function icc_ac2rc_op in, is_class in 1298 = im_icc_ac2rc in (expand profile), is_image in 1299 = error (_ "bad arguments to " ++ "icc_ac2rc") 1300{ 1301 icc_ac2rc_op = Operator "icc_ac2rc" 1302 (icc_ac2rc profile) 1303 Operator_type.COMPOUND_REWRAP false; 1304} 1305 1306print_base base in 1307 = oo_unary_function print_base_op in, is_class in 1308 = map (print_base base) in, is_list in 1309 = print_base_real, is_real in 1310 = error (_ "bad arguments to " ++ "print_base") 1311{ 1312 print_base_op 1313 = Operator "print_base" (print_base base) Operator_type.COMPOUND false; 1314 1315 print_base_real 1316 = error "print_base: bad base", base < 2 || base > 16 1317 = "0", in < 0 || chars == [] 1318 = reverse chars 1319 { 1320 digits = map (converse remainder base) 1321 (takewhile (not_equal 0) 1322 (iterate (converse idiv base) in)); 1323 chars = map tohd digits; 1324 1325 tohd x 1326 = (char) ((int) '0' + x), x < 10 1327 = (char) ((int) 'A' + (x - 10)); 1328 1329 idiv a b = (int) (a / b); 1330 } 1331} 1332 1333/* id x: the identity function 1334 * 1335 * id :: * -> * 1336 */ 1337id x = x; 1338 1339/* const x y: junk y, return x 1340 * 1341 * (const 3) is the function that always returns 3. 1342 * const :: * -> ** -> * 1343 */ 1344const x y = x; 1345 1346/* converse fn a b: swap order of args to fn 1347 * 1348 * converse fn a b == fn b a 1349 * converse :: (* -> ** -> ***) -> ** -> * -> *** 1350 */ 1351converse fn a b = fn b a; 1352 1353/* fix fn x: find the fixed point of a function 1354 */ 1355fix fn x = limit (iterate fn x); 1356 1357/* until pred fn n: apply fn to n until pred succeeds; return that value 1358 * 1359 * until (more 1000) (multiply 2) 1 = 1024 1360 * until :: (* -> bool) -> (* -> *) -> * -> * 1361 */ 1362until pred fn n 1363 = n, pred n 1364 = until pred fn (fn n); 1365 1366/* Infinite list of primes. 1367 */ 1368primes 1369 = 1 : (sieve [2..]) 1370{ 1371 sieve l = hd l : sieve (filter (nmultiple (hd l)) (tl l)); 1372 nmultiple n x = x / n != (int) (x / n); 1373} 1374 1375/* Map a 3-ary function over three objects. 1376 */ 1377map_trinary fn a b c 1378 = wrap (map3 (map_trinary fn) a' b' c'), 1379 is_list a' && is_list b' && is_list c' 1380 1381 = wrap (map2 (map_trinary fn a') b' c'), 1382 is_list b' && is_list c' 1383 = wrap (map2 (map_trinary (converse31 fn) b') a' c'), 1384 is_list a' && is_list c' 1385 = wrap (map2 (map_trinary (converse32 fn) c') a' b'), 1386 is_list a' && is_list b' 1387 1388 = wrap (map (map_trinary fn a' b') c'), 1389 is_list c' 1390 = wrap (map (map_trinary (converse32 fn) a' c') b'), 1391 is_list b' 1392 = wrap (map (map_trinary (converse34 fn) b' c') a'), 1393 is_list a' 1394 1395 = fn a b c 1396{ 1397 converse31 fn a b c = fn b a c; 1398 converse32 fn a b c = fn c a b; 1399 converse33 fn a b c = fn a c b; 1400 converse34 fn a b c = fn b c a; 1401 1402 a' 1403 = a.value, is_Group a 1404 = a; 1405 b' 1406 = b.value, is_Group b 1407 = b; 1408 c' 1409 = c.value, is_Group c 1410 = c; 1411 wrap 1412 = Group, is_Group a || is_Group b || is_Group c 1413 = id; 1414} 1415 1416/* Map a 2-ary function over a pair of objects. 1417 */ 1418map_binary fn a b 1419 = wrap (map2 (map_binary fn) a' b'), is_list a' && is_list b' 1420 = wrap (map (map_binary fn a') b'), is_list b' 1421 = wrap (map (map_binary (converse fn) b') a'), is_list a' 1422 = fn a b 1423{ 1424 a' 1425 = a.value, is_Group a 1426 = a; 1427 b' 1428 = b.value, is_Group b 1429 = b; 1430 wrap 1431 = Group, is_Group a || is_Group b 1432 = id; 1433} 1434 1435/* Map a 1-ary function over an object. 1436 */ 1437map_unary fn a 1438 = wrap (map (map_unary fn) a'), is_list a' 1439 = fn a 1440{ 1441 a' 1442 = a.value, is_Group a 1443 = a; 1444 wrap 1445 = Group, is_Group a 1446 = id; 1447} 1448 1449/* Remove features smaller than x pixels across from an image. This used to be 1450 * rather complex ... convsep is now good enough to use. 1451 */ 1452smooth x image = convsep (matrix_gaussian_blur (to_real x * 2)) image; 1453 1454/* Chop up an image into a list of lists of smaller images. Pad edges with 1455 * black. 1456 */ 1457imagearray_chop tile_width tile_height hoverlap voverlap i 1458 = map chop' [0, vstep .. height] 1459{ 1460 width = get_width i; 1461 height = get_height i; 1462 bands = get_bands i; 1463 format = get_format i; 1464 type = get_type i; 1465 1466 tile_width' = to_real tile_width; 1467 tile_height' = to_real tile_height; 1468 hoverlap' = to_real hoverlap; 1469 voverlap' = to_real voverlap; 1470 1471 /* Unique pixels per tile. 1472 */ 1473 hstep = tile_width' - hoverlap'; 1474 vstep = tile_height' - voverlap'; 1475 1476 /* Calculate padding ... pad up to tile_size pixel boundary. 1477 */ 1478 sx = tile_width' + (width - width % hstep); 1479 sy = tile_height' + (height - height % vstep); 1480 1481 /* Expand image with black to pad size. 1482 */ 1483 pad = embed 0 0 0 sx sy i; 1484 1485 /* Chop up a row. 1486 */ 1487 chop' y 1488 = map chop'' [0, hstep .. width] 1489 { 1490 chop'' x = extract_area x y tile_width' tile_height' pad; 1491 } 1492} 1493 1494/* Reassemble image. 1495 */ 1496imagearray_assemble hoverlap voverlap il 1497 = (image_set_origin 0 0 @ foldl1 tbj @ map (foldl1 lrj)) il 1498{ 1499 lrj l r = insert (get_width l + hoverlap) 0 r l; 1500 tbj t b = insert 0 (get_height t + voverlap) b t; 1501} 1502 1503/* Generate an nxn identity matrix. 1504 */ 1505identity_matrix n 1506 = error "identity_matrix: n > 0", n < 1 1507 = map line [0 .. n - 1] 1508{ 1509 line p = take p [0, 0 ..] ++ [1] ++ take (n - p - 1) [0, 0 ..]; 1510} 1511