1Tasks_capture_item = class 2 Menupullright "_Capture" 3 "useful stuff for capturing and preprocessing images" { 4 Video_item = class 5 Menuaction "Capture _Video Frame" "capture a frame of still video" { 6 // shortcut to prefs 7 prefs = Workspaces.Preferences; 8 9 action = class 10 _result { 11 _vislevel = 3; 12 13 device = prefs.VIDEO_DEVICE; 14 channel = Option "Input channel" [ 15 "TV", 16 "Composite 1", 17 "Composite 2", 18 "Composite 3" 19 ] prefs.VIDEO_CHANNEL; 20 brightness = Slider 0 32767 prefs.VIDEO_BRIGHTNESS; 21 colour = Slider 0 32767 prefs.VIDEO_COLOUR; 22 contrast = Slider 0 32767 prefs.VIDEO_CONTRAST; 23 hue = Slider 0 32767 prefs.VIDEO_HUE; 24 frames_hint = "Average this many frames:"; 25 frames = Slider 0 100 prefs.VIDEO_FRAMES; 26 mono = Toggle "Monochrome grab" prefs.VIDEO_MONO; 27 crop = Toggle "Crop image" prefs.VIDEO_CROP; 28 29 // grab, but hide it ... if we let the crop edit 30 _raw_grab = Image (im_video_v4l1 device channel.value 31 brightness.value colour.value contrast.value 32 hue.value frames.value); 33 34 edit_crop 35 = Region _raw_grab left top width height 36 { 37 left = prefs.VIDEO_CROP_LEFT; 38 top = prefs.VIDEO_CROP_TOP; 39 width = min_pair 40 prefs.VIDEO_CROP_WIDTH (_raw_grab.width + left); 41 height = min_pair 42 prefs.VIDEO_CROP_HEIGHT (_raw_grab.height + top); 43 } 44 45 aspect_ratio = Expression "Stretch vertically by" 46 prefs.VIDEO_ASPECT; 47 48 _result 49 = frame' 50 { 51 frame 52 = edit_crop, crop 53 = _raw_grab; 54 55 frame' 56 = colour_transform_to Image_type.B_W frame, mono 57 = frame; 58 } 59 } 60 } 61 62 Smooth_image_item = class 63 Menuaction "_Smooth" "remove small features from image" { 64 action in = class 65 _result { 66 _vislevel = 3; 67 68 feature = Slider 1 50 20; 69 70 _result = map_unary (smooth feature.value) in; 71 } 72 } 73 74 Light_correct_item = class 75 Menuaction "_Flatfield" "use white image w to flatfield image i" { 76 action w i 77 = map_binary wc w i 78 { 79 wc w i 80 = clip2fmt i.format (w' * i) 81 { 82 fac = mean w / max w; 83 w' = fac * (max w / w); 84 } 85 } 86 } 87 88 Image_rank_item = Filter_rank_item.Image_rank_item; 89 90 Tilt_item = Filter_tilt_item; 91 92 sep1 = Menuseparator; 93 94 White_balance_item = class 95 Menuaction "_White Balance" 96 "use average of small image to set white of large image" { 97 action a b = class 98 _result { 99 _vislevel = 3; 100 101 white_hint = "Set image white to:"; 102 white = Colour_picker "Lab" [100, 0, 0]; 103 104 _result 105 = map_binary wb a b 106 { 107 wb a b 108 = colour_transform_to (get_type image) image_xyz' 109 { 110 area x = x.width * x.height; 111 larger x y = area x > area y; 112 args = sortc larger [a, b]; 113 image = args?0; 114 patch = args?1; 115 to_xyz = colour_transform_to Image_type.XYZ; 116 117 // white balance in XYZ 118 patch_xyz = to_colour (to_xyz patch); 119 white_xyz = to_xyz white; 120 121 facs = (mean patch_xyz / mean white_xyz) * 122 (white_xyz / patch_xyz); 123 124 image_xyz = to_xyz image; 125 image_xyz' = image_xyz * facs; 126 } 127 } 128 } 129 } 130 131 Gamma_item = Image_levels_item.Gamma_item; 132 133 Tone_item = Image_levels_item.Tone_item; 134 135 sep2 = Menuseparator; 136 137 Crop_item = Image_crop_item; 138 139 Rotate_item = Image_transform_item.Rotate_item; 140 141 Flip_item = Image_transform_item.Flip_item; 142 143 Resize_item = Image_transform_item.Resize_item; 144 145 Rubber_item = Image_transform_item.Image_rubber_item; 146 147 sep3 = Menuseparator; 148 149 ICC_item = Colour_icc_item; 150 151 Temp_item = Colour_temperature_item; 152 153 Find_calib_item = class 154 Menuaction "Find _Colour Calibration" 155 "find an RGB -> XYZ transform from an image of a colour chart" { 156 action image = class 157 _result { 158 _check_args = [ 159 [image, "image", check_Image] 160 ]; 161 _vislevel = 3; 162 163 // get macbeth data file to use 164 macbeth = Pathname "Pick a Macbeth data file" 165 "$VIPSHOME/share/$PACKAGE/data/macbeth_lab_d65.mat"; 166 167 // get max of input image 168 _max_value = Image_format.maxval image.format; 169 170 // measure chart image 171 _camera = im_measure image.value 0 0 image.width image.height 6 4; 172 173 // load true values 174 _true_Lab = Matrix_file macbeth.value; 175 _true_XYZ = colour_transform 176 Image_type.LAB Image_type.XYZ _true_Lab; 177 178 // get Ys of greyscale 179 _true_grey_Y = map (extract 1) (drop 18 _true_XYZ.value); 180 181 // camera greyscale (all bands) 182 _camera_grey = drop 18 _camera.value; 183 184 // normalise both to 0-1 and combine 185 _camera_grey' = map (map (multiply (1 / _max_value))) _camera_grey; 186 _true_grey_Y' = map (multiply (1 / 100)) _true_grey_Y; 187 _comb = Matrix (map2 cons _true_grey_Y' _camera_grey'); 188 189 // make a linearising lut ... zero on left 190 _linear_lut = im_invertlut _comb (_max_value + 1); 191 192 // and display it 193 linearising_lut = Image _linear_lut; 194 195 // map the original image through the lineariser to 196 // get linear 0-1 RGB image 197 _image' = hist_map linearising_lut.value image.value; 198 199 // remeasure and solve for RGB -> XYZ 200 _camera' = im_measure _image' 0 0 image.width image.height 6 4; 201 _pinv = (transpose _camera' * _camera') ** -1; 202 M = transpose (_pinv * transpose _camera' * _true_XYZ); 203 204 // convert linear RGB camera to Lab 205 _result = (Image @ 206 colour_transform Image_type.XYZ Image_type.LAB @ 207 cast_float @ 208 recomb M) _image'; 209 210 // measure again and compute dE76 211 _camera'' = im_measure _result.value 0 0 212 image.width image.height 6 4; 213 214 _dEs = map abs_vec (map Vector (_camera'' - _true_Lab).value); 215 final_dE76 = mean (Vector _dEs); 216 _max_dE = foldr max_pair 0 _dEs; 217 _worst = index (equal _max_dE) _dEs; 218 worst_patch = _macbeth_names ? _worst ++ " (patch " ++ 219 print (_worst + 1) ++ ", " ++ 220 print _max_dE ++ " dE)"; 221 } 222 } 223 224 Apply_calib_item = class 225 Menuaction "_Apply Colour Calibration" 226 "apply an RGB -> LAB transform to an image" { 227 action a b 228 = result, is_instanceof calib_name calib && is_Image image 229 = error (_ "bad arguments to " ++ "Calibrate_image") 230 { 231 // the name of the calib object we need 232 calib_name = "Tasks_capture_item.Find_calib_item.action"; 233 234 // get the Calibrate_chart arg first 235 args = sortc (const (is_instanceof calib_name)) [a, b]; 236 calib = args?1; 237 image = args?0; 238 239 // map the original image through the lineariser to get 240 // linear 0-1 RGB image 241 image' = hist_map calib.linearising_lut image; 242 243 // convert linear RGB camera to Lab 244 result = colour_transform Image_type.XYZ Image_type.LAB 245 ((float) (recomb calib.M image')); 246 } 247 } 248} 249 250Tasks_mosaic_item = class 251 Menupullright "_Mosaic" "building image mosaics" { 252 /* Check and group a point list by image. 253 */ 254 mosaic_sort_test l 255 = error "mosaic: not all points", 256 !is_listof is_Mark l 257 = error "mosaic: points not on two images", 258 len images != 2 259 = error "mosaic: images do not match in format and coding", 260 !all_equal (map get_format l) || !all_equal (map get_coding l) 261 = error "mosaic: not same number of points on each image", 262 !foldr1 equal (map len l') 263 = l' 264 { 265 // test for all elements of a list equal 266 all_equal l = land (map (equal (hd l)) (tl l)); 267 268 // all the different images 269 images = mkset pointer_equal (map get_image l); 270 271 // find all points defined on image 272 test_image image p = (get_image p) === image; 273 find l image = filter (test_image image) l; 274 275 // group point list by image 276 l' = map (find l) images; 277 } 278 279 /* Sort a point group to get right before left, and within each group to 280 * get above before below. 281 */ 282 mosaic_sort_lr l 283 = l'' 284 { 285 // sort to get upper point first 286 above a b = a.top < b.top; 287 l' = map (sortc above) l; 288 289 // sort to get right group before left group 290 right a b = a?0.left > b?0.left; 291 l'' = sortc right l'; 292 } 293 294 /* Sort a point group to get top before bottom, and within each group to 295 * get left before right. 296 */ 297 mosaic_sort_tb l 298 = l'' 299 { 300 // sort to get upper point first 301 left a b = a.left < b.left; 302 l' = map (sortc left) l; 303 304 // sort to get right group before left group 305 below a b = a?0.top > b?0.top; 306 l'' = sortc below l'; 307 } 308 309 /* Put 'em together! Group by image, sort vertically (or horizontally) with 310 * one of the above, transpose to get pairs matched up, and flatten again. 311 */ 312 mosaic_sort fn = concat @ transpose @ fn @ mosaic_sort_test; 313 314 Mosaic_1point_item = class 315 Menupullright "_One Point" "join two images with a single tie point" { 316 check_ab_args a b = [ 317 [a, "a", check_Mark], 318 [b, "b", check_Mark] 319 ]; 320 321 // shortcut to prefs 322 prefs = Workspaces.Preferences; 323 search_area = prefs.MOSAIC_WINDOW_SIZE; 324 object_size = prefs.MOSAIC_OBJECT_SIZE; 325 blend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; 326 refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; 327 328 lr_mos _refine a b = class 329 Image _result { 330 _check_args = check_ab_args a b; 331 332 blend_width = blend_width_widget; 333 refine = _refine; 334 335 _result 336 = im_lrmosaic a'.image.value b'.image.value 0 337 a'.left a'.top b'.left b'.top 338 (object_size / 2) (search_area / 2) 0 blend_width.value, 339 refine 340 = im_lrmerge a'.image.value b'.image.value 341 (b'.left - a'.left) (b'.top - a'.top) blend_width.value 342 { 343 sorted = mosaic_sort mosaic_sort_lr [a, b]; 344 a' = sorted?0; 345 b' = sorted?1; 346 } 347 } 348 349 tb_mos _refine a b = class 350 Image _result { 351 _check_args = check_ab_args a b; 352 353 blend_width = blend_width_widget; 354 refine = _refine; 355 356 _result 357 = im_tbmosaic a'.image.value b'.image.value 0 358 a'.left a'.top b'.left b'.top 359 (object_size / 2) (search_area / 2) 0 blend_width.value, 360 refine 361 = im_tbmerge a'.image.value b'.image.value 362 (b'.left - a'.left) (b'.top - a'.top) blend_width.value 363 { 364 sorted = mosaic_sort mosaic_sort_tb [a, b]; 365 a' = sorted?0; 366 b' = sorted?1; 367 } 368 } 369 370 Left_right_item = class 371 Menuaction "_Left to Right" 372 "join two images left-right with a single tie point" { 373 action a b = lr_mos refine_widget a b; 374 } 375 376 Top_bottom_item = class 377 Menuaction "_Top to Bottom" 378 "join two images top-bottom with a single tie point" { 379 action a b = tb_mos refine_widget a b; 380 } 381 382 sep1 = Menuseparator; 383 384 Left_right_manual_item = class 385 Menuaction "Manual L_eft to Right" 386 "join left-right, no auto-adjust of tie points" { 387 action a b = lr_mos false a b; 388 } 389 390 Top_bottom_manual_item = class 391 Menuaction "Manual T_op to Bottom" 392 "join top-bottom, no auto-adjust of tie points" { 393 action a b = tb_mos false a b; 394 } 395 } 396 397 Mosaic_2point_item = class 398 Menupullright "_Two Point" "join two images with two tie points" { 399 check_abcd_args a b c d = [ 400 [a, "a", check_Mark], 401 [b, "b", check_Mark], 402 [c, "c", check_Mark], 403 [d, "d", check_Mark] 404 ]; 405 406 // shortcut to prefs 407 prefs = Workspaces.Preferences; 408 search_area = prefs.MOSAIC_WINDOW_SIZE; 409 object_size = prefs.MOSAIC_OBJECT_SIZE; 410 blend_width_widget = Slider 0 100 prefs.MOSAIC_MAX_BLEND_WIDTH; 411 refine_widget = Toggle "Refine selected tie-points" prefs.MOSAIC_REFINE; 412 413 Left_right_item = class 414 Menuaction "_Left to Right" 415 "join two images left-right with a pair of tie points" { 416 action a b c d = class 417 Image _result { 418 _check_args = check_abcd_args a b c d; 419 420 blend_width = blend_width_widget; 421 refine = refine_widget; 422 423 _result 424 = im_lrmosaic1 a'.image.value b'.image.value 0 425 a'.left a'.top b'.left b'.top 426 c'.left c'.top d'.left d'.top 427 (object_size / 2) (search_area / 2) 428 0 blend_width.value, 429 refine 430 = im_lrmerge1 a'.image.value b'.image.value 431 a'.left a'.top b'.left b'.top 432 c'.left c'.top d'.left d'.top 433 blend_width.value 434 { 435 sorted = mosaic_sort mosaic_sort_lr [a, b, c, d]; 436 a' = sorted?0; 437 b' = sorted?1; 438 c' = sorted?2; 439 d' = sorted?3; 440 } 441 } 442 } 443 444 Top_bottom_item = class 445 Menuaction "_Top to Bottom" 446 "join two images top-bottom with a pair of tie points" { 447 action a b c d = class 448 Image _result { 449 _check_args = check_abcd_args a b c d; 450 451 blend_width = blend_width_widget; 452 refine = refine_widget; 453 454 _result 455 = im_tbmosaic1 a'.image.value b'.image.value 0 456 a'.left a'.top b'.left b'.top 457 c'.left c'.top d'.left d'.top 458 (object_size / 2) (search_area / 2) 459 0 blend_width.value, 460 refine 461 = im_tbmerge1 a'.image.value b'.image.value 462 a'.left a'.top b'.left b'.top 463 c'.left c'.top d'.left d'.top 464 blend_width.value 465 { 466 sorted = mosaic_sort mosaic_sort_tb [a, b, c, d]; 467 a' = sorted?0; 468 b' = sorted?1; 469 c' = sorted?2; 470 d' = sorted?3; 471 } 472 } 473 } 474 } 475 476 sep1 = Menuseparator; 477 478 Balance_item = class 479 Menuaction "Mosaic _Balance" 480 "disassemble mosaic, scale brightness to match, reassemble" { 481 action x 482 = map_unary balance x 483 { 484 balance x 485 = oo_unary_function balance_op x, is_class x 486 = im_global_balancef x 487 Workspaces.Preferences.MOSAIC_BALANCE_GAMMA, 488 is_image x 489 = error (_ "bad arguments to " ++ "balance") 490 { 491 balance_op = Operator "balance" balance 492 Operator_type.COMPOUND_REWRAP false; 493 } 494 } 495 } 496 497//////////////////////////////////////////////////////////////////////////////////// 498//////////////////////////////////////////////////////////////////////////////////// 499Manual_balance_item = class 500 Menupullright "Manual B_alance" "balance tonality of user defined areas" { 501 prefs = Workspaces.Preferences; 502 503 //////////////////////////////////////////////////////////////////////////////////// 504 Balance_find_item = class 505 Menuaction "_Find Values" 506 "calculates values required to scale and offset balance user defined areas in a given image" 507 /* Outputs a matrix of scale and offset values. Eg. Values required to balance the secondary 508 * structure in an X-ray image. Takes an X-ray image an 8-bit control mask and a list of 509 * 8-bit reference masks, where the masks are white on a black background. 510 */ 511 { 512 action im_in m_control m_group = class 513 Matrix values{ 514 _vislevel = 1; 515 516 _control_im = if_then_else m_control im_in 0; 517 _control_meanmax = so_meanmax _control_im; 518 _group_check = is_instanceof "Group" m_group; 519 _m_list = m_group.value, _group_check 520 = m_group; 521 522 process m_current mat_in = mat_out 523 {so_values = so_calculate _control_meanmax im_in m_current; 524 mat_out = join [so_values] mat_in;} 525 526 values = (foldr process [] _m_list); 527 } 528 } 529 530 //////////////////////////////////////////////////////////////////////////////////// 531 Balance_check_item = class 532 Menuaction "_Check Values" 533 "allows calculated set of scale and offset values to be checked and adjusted if required" 534 /* Outputs adjusted matrix of scale and offset values and scale and offset image maps. 535 * Eg. Check values required to balance the secondary structure in an X-ray image. 536 * Takes an X-ray image an 8-bit control mask and a list of 8-bit reference masks, 537 * where the masks are white on a black background. 538 */ 539 { 540 action im_in m_matrix m_group = class 541 Image value 542 { 543 _vislevel = 3; 544 545 blur = Slider 1 10 1; 546 _blur = (blur.value/2 + 0.5), blur.value > 1 547 = 1; 548 549 _group_check = is_instanceof "Group" m_group; 550 _m_list = m_group.value, _group_check 551 = m_group; 552 553 adjust = Matrix_rec mat_a 554 { 555 no_masks = len _m_list; 556 mat_a = replicate no_masks [0, 0]; 557 } 558 559 // Apply the user defined adjustments to the inputted matrix of scale and offset values 560 _adjusted = map2 fn_adjust m_matrix.value adjust.value; 561 fn_adjust a b = [(a?0 + b?0), (a?1 + (a?1 * b?1))]; 562 563 _scaled_ims = map (fn_so_apply im_in) _adjusted; 564 fn_so_apply im so = map_unary adj im 565 {adj im = im * (so?0) + (so?1);} 566 _im_pairs = zip2 _m_list _scaled_ims; 567 568 // Prepare black images as starting point. //////////// 569 _blank = image_new (_m_list?0).width (_m_list?0).height 1 6 Image_coding.NOCODING 1 0 0 0; 570 _pair_start = [(_blank + 1), _blank]; 571 572 Build = Toggle "Build Scale and Offset Correction Images" false; 573 574 Output = class 575 { 576 _vislevel = 1; 577 scale_im = _build?0; 578 offset_im = _build?1; 579 so_values = Matrix _adjusted; 580 581 _build = [Image so_images?0, Image so_images?1], Build 582 = ["Scale image not built.", "Offset image not built."] 583 { 584 m_list' = transpose [_m_list]; 585 m_all = map2 join m_list' _adjusted; 586 so_images = foldr process_2 _pair_start m_all; 587 } 588 } 589 590 value = (foldr process_1 im_in_b _im_pairs).value 591 {im_in_b = map_unary cast_float im_in;} 592 593 process_1 m_current im_start 594 = im_out 595 { 596 bl_mask = convsep (matrix_blur _blur) (get_image m_current?0); 597 blended_im = im_blend bl_mask (m_current?1).value im_start.value; 598 im_out = Image (clip2fmt im_start.format blended_im); 599 } 600 601 // Process for building scale and offset image. 602 process_2 current p_start 603 = p_out 604 { 605 im_s = if ((current?0) > 128) then current?1 else _blank; 606 im_o = if ((current?0) > 128) then current?2 else _blank; 607 608 im_s' = convsep (matrix_blur _blur) (im_s != 0); 609 im_o' = convsep (matrix_blur _blur) (im_o != 0); 610 611 im_s'' = im_blend im_s'.value im_s.value p_start?0; 612 im_o'' = im_blend im_o'.value im_o.value p_start?1; 613 614 p_out = [im_s'', im_o'']; 615 } 616 } 617 } 618 619 //////////////////////////////////////////////////////////////////////////////////// 620 Balance_apply_item = class 621 Menuaction "_Apply Values" 622 "apply scale and offset corrections, defined as image maps, to a given image" 623 /* Outputs the balanced image. Eg. Balance the secondary structure in an X-ray image. Takes an 624 * X-ray image an 32-bit float scale image and a 32-bit offset image. 625 */ 626 { 627 action im_in scale_im offset_im = class 628 Image value 629 { 630 _vislevel = 1; 631 632 xfactor = im_in.width/scale_im.width; 633 yfactor = im_in.height/scale_im.height; 634 635 _scale_im = resize xfactor yfactor 1 scale_im; 636 _offset_im = resize xfactor yfactor 1 offset_im; 637 638 value = get_image ( clip2fmt im_in.format ( ( im_in * _scale_im ) + _offset_im ) ); 639 } 640 } 641} 642 643 Tilt_item = Filter_tilt_item; 644 645 sep2 = Menuseparator; 646 647 Rebuild_item = class 648 Menuaction "_Rebuild" 649 "disassemble mosaic, substitute image files and reassemble" { 650 action x = class 651 _result { 652 _vislevel = 3; 653 654 old = String "In each filename, replace" "foo"; 655 new = String "With" "bar"; 656 657 _result 658 = map_unary remosaic x 659 { 660 remosaic image 661 = Image (im_remosaic image.value old.value new.value); 662 } 663 } 664 } 665 666 sep3 = Menuseparator; 667 668Clone_area_item = class 669 Menuaction "_Clone Area" 670 "replace dark or light section of im1 with pixels from im2" 671 { 672 action im1 im2 = class 673 _result { 674 _check_args = [ 675 [im1, "im1", check_Image], 676 [im2, "im2", check_Image] 677 ]; 678 _vislevel = 3; /* Region on first 679image placed in the top left hand corner, 680 * positioned and size relative to the height and width of im1. 681 */ 682 r1 = Region_relative im1 0.05 0.05 0.05 0.05; 683 /* Mark on second image placed in the top left hand corner, 684 * positioned relative to the height and width of im2. Used to 685 * define _r2, the region from which the section of image is cloned 686 * from. 687 */ 688 p2 = Mark_relative im2 0.05 0.05; _r2 = Region im2 p2.left 689p2.top r1.width r1.height; 690 mask = [r1 <= Options.scale_cutoff, r1 >= 691Options.scale_cutoff]?(Options.replace); 692 Options = class 693 { 694 _vislevel = 3; 695 pause = Toggle "Pause process" true; 696 /* Option toggle used to define whether the user is 697 * replacing a dark or a light area. 698 */ 699 replace = Option "Replace" [ "A Dark Area", "A Light Area" ] 1; 700 701 // Used to select the area to be replaced. 702 scale_cutoff = Slider 0.01 mx (mx / 2) 703 {mx = Image_format.maxval im1.format;} 704 //Allows replacement with scale&offset balanced gaussian noise. 705 balance = Toggle "Balance cloned data to match surroundings." true; 706 //Allows replacement with scale&offset balanced 707 //gaussian noise. 708 process = Toggle "Replace area with Gaussian noise." false; 709 } 710 _result = im1, Options.pause 711 = Image (im_insert im1.value patch r1.left r1.top) 712 { r2 = Region im2 p2.left p2.top r1.width r1.height; 713 ref_meanmax = so_meanmax (if mask then 0 else r1); 714 mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], 715[255, 255, 255]]; 716 mask_a = map_unary (dilate mask8) mask; 717 mask_b = convsep (matrix_blur 2) mask_a; 718 patch = so_balance ref_meanmax r1 r2 mask_b 719Options.process, Options.balance 720 = so_balance ref_meanmax r1 r2 mask_b Options.process, 721Options.process 722 = im_blend (get_image mask_b) (get_image r2) (get_image r1); 723 } 724 } 725 } 726} 727 728Tasks_frame_item = Frame_item; 729 730Tasks_print_item = class 731 Menupullright "_Print" "useful stuff for image output" { 732 733 Rotate_item = Image_transform_item.Rotate_item; 734 735 Flip_item = Image_transform_item.Flip_item; 736 737 Resize_item = Image_transform_item.Resize_item; 738 739 Tone_item = class 740 Menuaction "_Adjust Tone Curve" "adjust tone curve on L*" { 741 action x = class 742 _result { 743 _vislevel = 3; 744 745 auto = Option "Set black and white point" [ 746 "Manually", 747 "Automatically from image histogram" 748 ] 0; 749 black = Slider 0 100 0; 750 white = Slider 0 100 100; 751 752 shadow_point = Slider 0.1 0.3 0.2; 753 mid_point = Slider 0.4 0.6 0.5; 754 highlight_point = Slider 0.7 0.9 0.8; 755 756 shadow_adjust = Slider (-15) 15 0; 757 mid_adjust = Slider (-30) 30 0; 758 highlight_adjust = Slider (-15) 15 0; 759 760 preview_curve = Image (im_tone_build black.value white.value 761 shadow_point.value mid_point.value highlight_point.value 762 shadow_adjust.value mid_adjust.value highlight_adjust.value); 763 764 _result 765 = map_unary process x 766 { 767 process image 768 = tone_map curve lab 769 { 770 lab = colour_transform_to Image_type.LABQ image; 771 curve 772 = preview_curve, auto == 0 773 = tone_analyse 774 shadow_point mid_point highlight_point 775 shadow_adjust mid_adjust highlight_adjust 776 lab; 777 } 778 } 779 } 780 } 781 782 Sharpen_item = class 783 Menuaction "_Sharpen" 784 "unsharp filter tuned for typical inkjet printers" { 785 action x = class 786 _result { 787 _vislevel = 3; 788 789 // strange order forced on us by need to keep numbering backwards 790 // compatible though 7.10 791 target_dpi = Option "Sharpen for print at" [ 792 "300 dpi", 793 "150 dpi", 794 "75 dpi", 795 "400 dpi" 796 ] 0; 797 798 _result 799 = map_unary process x 800 { 801 process image 802 = sharpen params?0 params?1 803 params?2 params?3 params?4 params?5 804 (colour_transform_to Image_type.LABQ image) 805 { 806 // sharpen params for various dpi 807 // just change the size of the area we search 808 param_table = [ 809 [7, 2.5, 40, 20, 0.5, 1.5], 810 [5, 2.5, 40, 20, 0.5, 1.5], 811 [3, 2.5, 40, 20, 0.5, 1.5], 812 [11, 2.5, 40, 20, 0.5, 1.5] 813 ]; 814 params = param_table?target_dpi; 815 } 816 } 817 } 818 } 819 820 sep1 = Menuseparator; 821 822 Temp_item = Colour_temperature_item; 823 824 ICC_item = Colour_icc_item; 825} 826