~ubuntu-branches/ubuntu/vivid/nip2/vivid-proposed

« back to all changes in this revision

Viewing changes to share/nip2/compat/7.16/Filter.def

  • Committer: Bazaar Package Importer
  • Author(s): Michael Terry
  • Date: 2009-05-12 09:26:46 UTC
  • mfrom: (1.2.11 upstream) (2.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090512092646-j8lb1w2x69pvgma4
Tags: 7.18.1-1ubuntu1
* Merge from debian unstable (LP: #375435), remaining changes:
  - debian/control: Also Recommend abrowser

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Filter_conv_item = class
 
2
        Menupullright "_Convolution" "various spatial convolution filters" {
 
3
        /* Some useful masks.
 
4
         */
 
5
        filter_blur = Matrix_con 9 0 [[1, 1, 1], [1, 1, 1], [1, 1, 1]];
 
6
        filter_sharp = Matrix_con 8 0 [[-1, -1, -1], [-1, 16, -1], [-1, -1, -1]];
 
7
        filter_emboss = Matrix_con 1 128 [[-1, 0], [0, 1]];
 
8
        filter_laplacian = Matrix_con 1 128 
 
9
                [[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]];
 
10
        filter_sobel = Matrix_con 1 128 [[1, 2, 1], [0, 0, 0], [-1, -2, -1]];
 
11
        filter_lindet = Matrix_con 1 0 [[1, 1, 1], [-2, -2, -2], [1, 1, 1]];
 
12
 
 
13
        Blur_item = class
 
14
                Menuaction "_Blur" "3x3 blur of image" {
 
15
                action x = map_unary (conv filter_blur) x;
 
16
        }
 
17
 
 
18
        Sharpen_item = class
 
19
                Menuaction "_Sharpen" "3x3 sharpen of image" {
 
20
                action x = map_unary (conv filter_sharp) x;
 
21
        }
 
22
 
 
23
        Emboss_item = class
 
24
                Menuaction "_Emboss" "1 pixel displace emboss" {
 
25
                action x = map_unary (conv filter_emboss) x;
 
26
        }
 
27
 
 
28
        Laplacian_item = class
 
29
                Menuaction "_Laplacian" "3x3 laplacian edge detect" {
 
30
                action x = map_unary (conv filter_laplacian) x;
 
31
        }
 
32
 
 
33
        Sobel_item = class
 
34
                Menuaction "So_bel" "3x3 Sobel edge detect" {
 
35
                action x 
 
36
                        = map_unary sobel x
 
37
                {
 
38
                        sobel im
 
39
                                = abs (a - 128) + abs (b - 128)
 
40
                        {
 
41
                                a = conv filter_sobel im;
 
42
                                b = conv (rot270 filter_sobel) im;
 
43
                        }
 
44
                }
 
45
        }
 
46
 
 
47
/* 3x3 line detect of image
 
48
diagonals should be scaled down by root(2) I guess
 
49
Kirk 
 
50
*/
 
51
        Linedet_item = class
 
52
                Menuaction "Li_ne Detect" "3x3 line detect" {
 
53
                action x 
 
54
                        = map_unary lindet x
 
55
                {
 
56
                        lindet im
 
57
                                = foldr1 max_pair images
 
58
                        {
 
59
                                masks = take 4 (iterate rot45 filter_lindet);
 
60
                                images = map (converse conv im) masks;
 
61
                        }
 
62
                }
 
63
        }
 
64
 
 
65
        Usharp_item = class
 
66
                Menuaction "_Unsharp Mask" "cored sharpen of L only in LAB image" {
 
67
                action x = class
 
68
                        _result {
 
69
                        _vislevel = 3;
 
70
        
 
71
                        size = Option "Radius" [
 
72
                                "3 pixels",
 
73
                                "5 pixels",
 
74
                                "7 pixels",
 
75
                                "9 pixels",
 
76
                                "11 pixels",
 
77
                                "51 pixels"
 
78
                        ] 0;
 
79
        
 
80
                        st = Scale "Smoothness threshold" 0 5 1.5;
 
81
                        bm = Scale "Brighten by at most" 1 50 10;
 
82
                        dm = Scale "Darken by at most" 1 50 50;
 
83
                        fs = Scale "Sharpen flat areas by" (-2) 5 1;
 
84
                        js = Scale "Sharpen jaggy areas by" (-2) 5 2;
 
85
        
 
86
                        _result
 
87
                                = map_unary process x
 
88
                        {
 
89
                                process in
 
90
                                        = Image in'''
 
91
                                {
 
92
                                        in' = colour_transform_to Image_type.LABS in.value;
 
93
                                        in'' = sharpen [3, 5, 7, 9, 11, 51]?size st bm dm fs js in';
 
94
                                        in''' = colour_transform_to (get_type in) in'';
 
95
                                }
 
96
                        }
 
97
                }
 
98
        }
 
99
 
 
100
        sep1 = Menuseparator;
 
101
 
 
102
        Custom_blur_item = class
 
103
                Menuaction "Custom B_lur / Sharpen" 
 
104
                        "blur or sharpen with tuneable parameters" {
 
105
                action x = class 
 
106
                        _result {
 
107
                        _vislevel = 3;
 
108
 
 
109
                        type = Option "Type" ["Blur", "Sharpen"] 0;
 
110
                        r = Scale "Radius" 1 100 1;
 
111
                        fac = Scale "Amount" 0 1 1;
 
112
                        shape = Option "Mask shape" [
 
113
                                "Square",
 
114
                                "Gaussian"
 
115
                        ] 0;
 
116
                        prec = Option "Precision" ["Int", "Float"] 0;
 
117
 
 
118
                        _result 
 
119
                                = map_unary process x
 
120
                        {
 
121
                                process in
 
122
                                        = clip2fmt blur.format proc
 
123
                                {
 
124
                                        mask
 
125
                                                = matrix_blur r.value, shape.value == 0
 
126
                                                = matrix_gaussian_blur r.value;
 
127
                                        blur = [convsep, convsepf]?prec mask in;
 
128
                                        proc
 
129
                                                = in + fac * (in - blur), type == 1
 
130
                                                = blur * fac + in * (1 - fac);
 
131
                                }
 
132
                        }
 
133
                }
 
134
        }
 
135
 
 
136
        Custom_conv_item = class
 
137
                Menuaction "Custom C_onvolution" 
 
138
                        "convolution filter with tuneable parameters" {
 
139
                action x = class 
 
140
                        _result {
 
141
                        _vislevel = 3;
 
142
 
 
143
                        matrix = Matrix_con 1 0 [[0, 0, 0], [0, 1, 0], [0, 0, 0]];
 
144
                        separable 
 
145
                                = Toggle "Seperable convolution" false, 
 
146
                                        matrix.width == 1 || matrix.height == 1
 
147
                                = false;
 
148
                        type = Option "Convolution type" ["Int", "Float"] 0;
 
149
 
 
150
                        _result 
 
151
                                = map_unary process x
 
152
                        {
 
153
                                process in
 
154
                                        = in.Image in'
 
155
                                {
 
156
                                        conv_fn 
 
157
                                                = im_conv, !separable && type == 0
 
158
                                                = im_convsep, separable && type == 0
 
159
                                                = im_convf, !separable && type == 1
 
160
                                                = im_convsepf, separable && type == 1
 
161
                                                = error "boink!";
 
162
                                        in' = conv_fn in.value matrix;
 
163
                                }
 
164
                        }
 
165
                }
 
166
        }
 
167
}
 
168
 
 
169
Filter_rank_item = class
 
170
        Menupullright "_Rank" "various rank filters" {
 
171
        Median_item = class
 
172
                Menuaction "_Median" "3x3 median rank filter" {
 
173
                action x = map_unary (rank 3 3 5) x;
 
174
        }
 
175
 
 
176
        Image_rank_item = class
 
177
                Menuaction "_Image Rank" "pixelwise rank a list or group of images" {
 
178
                action x = class 
 
179
                        _result {
 
180
                        _vislevel = 3;
 
181
 
 
182
                        select 
 
183
                                = Expression "Rank" ((int) (guess_size / 2))
 
184
                        {
 
185
                                guess_size
 
186
                                        = len x, is_list x
 
187
                                        = len x.value, is_Group x
 
188
                                        = 0;
 
189
                        }
 
190
 
 
191
                        // can't really iterate over groups ... since we allow a group
 
192
                        // argument
 
193
                        _result = rank_image select x;
 
194
                }
 
195
        }
 
196
 
 
197
        Custom_rank_item = class
 
198
                Menuaction "Custom _Rank" "rank filter with tuneable parameters" {
 
199
                action x = class 
 
200
                        _result {
 
201
                        _vislevel = 3;
 
202
 
 
203
                        window_width = Expression "Window width" 3;
 
204
                        window_height = Expression "Window height" 3;
 
205
                        select = Expression "Rank" 
 
206
                                ((int) ((to_real window_width * to_real window_height + 1) / 2));
 
207
 
 
208
                        _result 
 
209
                                = map_unary process x
 
210
                        {
 
211
                                process in
 
212
                                        = rank window_width window_height select in;
 
213
                        }
 
214
                }
 
215
        }
 
216
}
 
217
 
 
218
Filter_morphology_item = class
 
219
        Menupullright "_Morphology" "various morphological filters" {
 
220
        /* Some useful masks.
 
221
         */
 
222
        mask8 = Matrix_mor [[255, 255, 255], [255, 255, 255], [255, 255, 255]];
 
223
        mask4 = Matrix_mor [[128, 255, 128], [255, 255, 255], [128, 255, 128]];
 
224
        mask1 = Matrix_mor [[0, 0, 0], [0, 255, 0], [0, 0, 0]];
 
225
        thin = Matrix_mor [[0, 0, 0], [128, 255, 128], [255, 255, 255]];
 
226
 
 
227
        Threshold_item = Select_item.Threshold_item;
 
228
 
 
229
        sep1 = Menuseparator;
 
230
 
 
231
        Dilate_item = class
 
232
                Menupullright "_Dilate" "morphological dilate" {
 
233
                Dilate8_item = class
 
234
                        Menuaction "_8-connected" "dilate with an 8-connected mask" {
 
235
                        action x = map_unary (dilate mask8) x;
 
236
                }
 
237
 
 
238
                Dilate4_item = class
 
239
                        Menuaction "_4-connected" "dilate with a 4-connected mask" {
 
240
                        action x = map_unary (dilate mask4) x;
 
241
                }
 
242
        }
 
243
 
 
244
        Erode_item = class
 
245
                Menupullright "_Erode" "morphological erode" {
 
246
                Erode8_item = class
 
247
                        Menuaction "_8-connected" "erode with an 8-connected mask" {
 
248
                        action x = map_unary (erode mask8) x;
 
249
                }
 
250
 
 
251
                Erode4_item = class
 
252
                        Menuaction "_4-connected" "erode with a 4-connected mask" {
 
253
                        action x = map_unary (erode mask4) x;
 
254
                }
 
255
        }
 
256
 
 
257
        Custom_morph_item = class
 
258
                Menuaction "Custom _Morphology" 
 
259
                        "convolution morphological operator" {
 
260
                action x = class 
 
261
                        _result {
 
262
                        _vislevel = 3;
 
263
 
 
264
                        mask = mask4;
 
265
                        type = Option "Operation" ["Erode", "Dilate"] 1;
 
266
                        apply = Expression "Number of times to apply mask" 1;
 
267
 
 
268
                        _result 
 
269
                                = map_unary morph x
 
270
                        {
 
271
                                morph image
 
272
                                        = Image value'
 
273
                                {
 
274
                                        fatmask = (iterate (dilate mask) mask)?(to_real apply - 1);
 
275
 
 
276
                                        value'
 
277
                                                = im_erode image.value fatmask, type.value == 0
 
278
                                                = im_dilate image.value fatmask;
 
279
                                }
 
280
                        }
 
281
                }
 
282
        }
 
283
 
 
284
        sep2 = Menuseparator;
 
285
 
 
286
        Open_item = class
 
287
                Menuaction "_Open" "open with an 8-connected mask" {
 
288
                action x = map_unary (dilate mask8 @ erode mask8) x;
 
289
        }
 
290
 
 
291
        Close_item = class
 
292
                Menuaction "_Close" "close with an 8-connected mask" {
 
293
                action x = map_unary (erode mask8 @ dilate mask8) x;
 
294
        }
 
295
 
 
296
        Clean_item = class
 
297
                Menuaction "C_lean" "remove 8-connected isolated points" {
 
298
                action x 
 
299
                        = map_unary clean x
 
300
                {
 
301
                        clean x = x ^ erode mask1 x;
 
302
                }
 
303
        }
 
304
 
 
305
        Thin_item = class
 
306
                Menuaction "_Thin" "thin once" {
 
307
                action x 
 
308
                        = map_unary thinall x
 
309
                {
 
310
                        masks = take 8 (iterate rot45 thin);
 
311
                        thin1 m x = x ^ erode m x;
 
312
                        thinall x = foldr thin1 x masks;
 
313
                }
 
314
        }
 
315
}
 
316
 
 
317
Filter_fourier_item = class
 
318
        Menupullright "_Fourier" "various Fourier filters" {
 
319
        preview_size = 64;
 
320
 
 
321
        sense_option = Option "Sense" [
 
322
                "Pass", 
 
323
                "Reject"
 
324
        ] 0;
 
325
 
 
326
        // make a visualisation image 
 
327
        make_vis fn = (Image @ image_set_type Image_type.FOURIER @ rotquad @ fn)
 
328
                (im_create_fmask preview_size preview_size);
 
329
 
 
330
        // make the process function
 
331
        process fn in
 
332
                = (Image @ fn) (im_flt_image_freq in.value);
 
333
 
 
334
        New_ideal_item = class 
 
335
                Menupullright "_Ideal" "various ideal Fourier filters" {
 
336
                High_low_item = class 
 
337
                        Menuaction "_High or Low Pass" 
 
338
                                "highpass/lowpass ideal Fourier filter" {
 
339
                        action x = class
 
340
                                _result {
 
341
                                _vislevel = 3;
 
342
 
 
343
                                sense = sense_option;
 
344
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
345
 
 
346
                                // call a freq func with our parameters
 
347
                                _params f = f sense.value fc.value 0 0 0 0;
 
348
 
 
349
                                visualize_mask = make_vis _params;
 
350
 
 
351
                                _result = map_unary (process _params) x;
 
352
                        }
 
353
                }
 
354
 
 
355
                Ring_item = class 
 
356
                        Menuaction "_Ring Pass or Ring Reject"
 
357
                                "ring pass/reject ideal Fourier filter" {
 
358
                        action x = class
 
359
                                _result {
 
360
                                _vislevel = 3;
 
361
 
 
362
                                sense = sense_option;
 
363
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
364
                                rw = Scale "Ring width" 0.01 0.99 0.5;
 
365
 
 
366
                                // call a freq func with our parameters
 
367
                                _params f = f (sense.value + 6) fc.value 
 
368
                                        rw.value 0 0 0;
 
369
 
 
370
                                visualize_mask = make_vis _params;
 
371
 
 
372
                                _result = map_unary (process _params) x;
 
373
                        }
 
374
                }
 
375
 
 
376
                Band_item = class 
 
377
                        Menuaction "_Band Pass or Band Reject"
 
378
                                "band pass/reject ideal Fourier filter" {
 
379
                        action x = class
 
380
                                _result {
 
381
                                _vislevel = 3;
 
382
 
 
383
                                sense = sense_option;
 
384
                                fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5;
 
385
                                fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5;
 
386
                                r = Scale "Radius" 0.01 0.99 0.5;
 
387
 
 
388
                                // call a freq func with our parameters
 
389
                                _params f = f (sense.value + 12) fcx.value fcy.value
 
390
                                        r.value 0 0;
 
391
 
 
392
                                visualize_mask = make_vis _params;
 
393
 
 
394
                                _result = map_unary (process _params) x;
 
395
                        }
 
396
                }
 
397
        }
 
398
 
 
399
        New_gaussian_item = class 
 
400
                Menupullright "_Gaussian" "various Gaussian Fourier filters" {
 
401
                High_low_item = class 
 
402
                        Menuaction "_High or Low Pass" 
 
403
                                "highpass/lowpass Gaussian Fourier filter" {
 
404
                        action x = class
 
405
                                _result {
 
406
                                _vislevel = 3;
 
407
 
 
408
                                sense = sense_option;
 
409
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
410
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
411
 
 
412
                                // call a freq func with our parameters
 
413
                                _params f = f (sense.value + 4) fc.value 
 
414
                                        ac.value 0 0 0;
 
415
 
 
416
                                visualize_mask = make_vis _params;
 
417
 
 
418
                                _result = map_unary (process _params) x;
 
419
                        }
 
420
                }
 
421
 
 
422
                Ring_item = class 
 
423
                        Menuaction "_Ring Pass or Ring Reject"
 
424
                                "ring pass/reject Gaussian Fourier filter" {
 
425
                        action x = class
 
426
                                _result {
 
427
                                _vislevel = 3;
 
428
 
 
429
                                sense = sense_option;
 
430
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
431
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
432
                                rw = Scale "Ring width" 0.01 0.99 0.5;
 
433
 
 
434
                                // call a freq func with our parameters
 
435
                                _params f = f (sense.value + 10) fc.value 
 
436
                                        rw.value ac.value 0 0;
 
437
 
 
438
                                visualize_mask = make_vis _params;
 
439
 
 
440
                                _result = map_unary (process _params) x;
 
441
                        }
 
442
                }
 
443
 
 
444
                Band_item = class 
 
445
                        Menuaction "_Band Pass or Band Reject"
 
446
                                "band pass/reject Gaussian Fourier filter" {
 
447
                        action x = class
 
448
                                _result {
 
449
                                _vislevel = 3;
 
450
 
 
451
                                sense = sense_option;
 
452
                                fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5;
 
453
                                fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5;
 
454
                                r = Scale "Radius" 0.01 0.99 0.5;
 
455
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
456
 
 
457
                                // call a freq func with our parameters
 
458
                                _params f = f (sense.value + 16) fcx.value fcy.value 
 
459
                                        r.value ac.value 0;
 
460
 
 
461
                                visualize_mask = make_vis _params;
 
462
 
 
463
                                _result = map_unary (process _params) x;
 
464
                        }
 
465
                }
 
466
        }
 
467
 
 
468
        New_butterworth_item = class 
 
469
                Menupullright "_Butterworth" 
 
470
                        "various Butterworth Fourier filters" {
 
471
                High_low_item = class 
 
472
                        Menuaction "_High or Low Pass" 
 
473
                                "highpass/lowpass Butterworth Fourier filter" {
 
474
                        action x = class
 
475
                                _result {
 
476
                                _vislevel = 3;
 
477
 
 
478
                                sense = sense_option;
 
479
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
480
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
481
                                o = Scale "Order" 1 10 2;
 
482
 
 
483
                                // call a freq func with our parameters
 
484
                                _params f = f (sense.value + 2) o.value fc.value ac.value
 
485
                                                0 0;
 
486
 
 
487
                                visualize_mask = make_vis _params;
 
488
 
 
489
                                _result = map_unary (process _params) x;
 
490
                        }
 
491
                }
 
492
 
 
493
                Ring_item = class 
 
494
                        Menuaction "_Ring Pass or Ring Reject"
 
495
                                "ring pass/reject Butterworth Fourier filter" {
 
496
                        action x = class
 
497
                                _result {
 
498
                                _vislevel = 3;
 
499
 
 
500
                                sense = sense_option;
 
501
                                fc = Scale "Frequency cutoff" 0.01 0.99 0.5;
 
502
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
503
                                rw = Scale "Ring width" 0.01 0.99 0.5;
 
504
                                o = Scale "Order" 1 10 2;
 
505
 
 
506
                                // call a freq func with our parameters
 
507
                                _params f = f (sense.value + 8) o.value fc.value rw.value 
 
508
                                        ac.value 0;
 
509
 
 
510
                                visualize_mask = make_vis _params;
 
511
 
 
512
                                _result = map_unary (process _params) x;
 
513
                        }
 
514
                }
 
515
 
 
516
                Band_item = class 
 
517
                        Menuaction "_Band Pass or Band Reject"
 
518
                                "band pass/reject Butterworth Fourier filter" {
 
519
                        action x = class
 
520
                                _result {
 
521
                                _vislevel = 3;
 
522
 
 
523
                                sense = sense_option;
 
524
                                fcx = Scale "Horizontal frequency cutoff" 0.01 0.99 0.5;
 
525
                                fcy = Scale "Vertical frequency cutoff" 0.01 0.99 0.5;
 
526
                                r = Scale "Radius" 0.01 0.99 0.5;
 
527
                                ac = Scale "Amplitude cutoff" 0.01 0.99 0.5;
 
528
                                o = Scale "Order" 1 10 2;
 
529
 
 
530
                                // call a freq func with our parameters
 
531
                                _params f = f (sense.value + 14) o.value fcx.value fcy.value
 
532
                                                r.value ac.value;
 
533
 
 
534
                                visualize_mask = make_vis _params;
 
535
 
 
536
                                _result = map_unary (process _params) x;
 
537
                        }
 
538
                }
 
539
        }
 
540
}
 
541
 
 
542
Filter_enhance_item = class
 
543
        Menupullright "_Enhance" "various enhancement filters" {
 
544
        Falsecolour_item = class
 
545
                Menuaction "_False Colour" "false colour a mono image" {
 
546
                action x = class
 
547
                        _result {
 
548
                        _vislevel = 3;
 
549
        
 
550
                        o = Scale "Offset" (-255) 255 0;
 
551
                        clip = Toggle "Clip colour range" false;
 
552
        
 
553
                        _result 
 
554
                                = map_unary process x
 
555
                        {
 
556
                                process im
 
557
                                        = falsecolour mono''
 
558
                                {
 
559
                                        mono = colour_transform_to Image_type.B_W im;
 
560
                                        mono' = mono + o;
 
561
                                        mono'' 
 
562
                                                = (unsigned char) mono', clip
 
563
                                                = (unsigned char) (mono' & 0xff);
 
564
                                }
 
565
                        }
 
566
                }
 
567
        }
 
568
 
 
569
        Statistical_diff_item = class
 
570
                Menuaction "_Statistical Difference" 
 
571
                        "statistical difference of an image" {
 
572
                action x = class
 
573
                        _result {
 
574
                        _vislevel = 3;
 
575
        
 
576
                        wsize = Expression "Window size" 11;
 
577
                        tmean = Expression "Target mean" 128;
 
578
                        mean_weight = Scale "Mean weight" 0 1 0.8;
 
579
                        tdev = Expression "Target deviation" 50;
 
580
                        dev_weight = Scale "Deviation weight" 0 1 0.8;
 
581
                        border = Toggle "Output image matches input image in size" true;
 
582
        
 
583
                        _result 
 
584
                                = map_unary process x
 
585
                        {
 
586
                                process in 
 
587
                                        = Image in''
 
588
                                {
 
589
                                        in' = colour_transform_to Image_type.B_W in.value;
 
590
                                        fn
 
591
                                                = im_stdif, border
 
592
                                                = im_stdif_raw;
 
593
                                        in'' = fn in'
 
594
                                                mean_weight.value tmean.expr
 
595
                                                dev_weight.value tdev.expr
 
596
                                                wsize.expr wsize.expr;
 
597
                                }
 
598
                        }
 
599
                }
 
600
        }
 
601
 
 
602
        Hist_equal_item = class
 
603
                Menupullright "_Equalise Histogram" "equalise contrast" {
 
604
                Global_item = class
 
605
                        Menuaction "_Global" "equalise contrast globally" {
 
606
                        action x = map_unary hist_equalize x;
 
607
                }
 
608
 
 
609
                Local_item = class
 
610
                        Menuaction "_Local" "equalise contrast within a roving window" {
 
611
                        action x = class 
 
612
                                _result {
 
613
                                _vislevel = 3;
 
614
        
 
615
                                window_width = Expression "Window width" 20;
 
616
                                window_height = Expression "Window height" 20;
 
617
        
 
618
                                _result 
 
619
                                        = map_unary process x
 
620
                                {
 
621
                                        process in 
 
622
                                                = hist_equalize_local 
 
623
                                                        window_width.expr window_height.expr in;
 
624
                                }
 
625
                        }
 
626
                }
 
627
        }
 
628
}
 
629
 
 
630
Filter_correlate_item = class
 
631
        Menupullright "Spatial _Correlation" "calculate correlation surfaces" {
 
632
        Correlate_item = class
 
633
                Menuaction "_Correlate" "calculate correlation coefficient" {
 
634
                action a b 
 
635
                        = map_binary corr a b
 
636
                {
 
637
                        corr a b
 
638
                                = correlate a b, 
 
639
                                        a.width <= b.width && a.height <= b.height
 
640
                                = correlate b a;
 
641
                }
 
642
        }
 
643
 
 
644
        Correlate_fast_item = class
 
645
                Menuaction "_Simple Difference" 
 
646
                        "calculate sum of squares of differences" {
 
647
                action a b 
 
648
                        = map_binary corr a b
 
649
                {
 
650
                        corr a b
 
651
                                = correlate_fast a b, 
 
652
                                        a.width <= b.width && a.height <= b.height
 
653
                                = correlate_fast b a;
 
654
                }
 
655
        }
 
656
}
 
657
 
 
658
Filter_greyc_item = class 
 
659
        Menupullright "_GREYCstoration" "noise-removing filter" {
 
660
        Denoise_item = class 
 
661
                Menuaction "Denoise" "Noise-removing filter" {
 
662
                action x = class 
 
663
                        _result {
 
664
                        _vislevel = 3;
 
665
 
 
666
                        iterations = Scale "Iterations" 1 5 1;
 
667
                        amplitude = Scale "Amplitude" 1 100 40;
 
668
                        sharpness = Scale "Sharpness" 0 3 0.9;
 
669
                        anisotropy = Scale "Anisotropy" 0 1 0.15;
 
670
                        alpha = Scale "Noise scale" 0 5 0.6;
 
671
                        sigma = Scale "Geometry regularity" 0 2 1.1;
 
672
                        dl = Scale "Spatial integration step" 0 1 0.8;
 
673
                        da = Scale "Angular integration step" 0 90 30;
 
674
                        gauss_prec = Scale "Precision" 1 10 2;
 
675
                        interpolation = Option "Interpolation" 
 
676
                                ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0;
 
677
                        fast_approx = Toggle "Fast approximation" true;
 
678
 
 
679
                        _result = greyc 
 
680
                                (to_real iterations) (to_real amplitude) (to_real sharpness)
 
681
                                (to_real anisotropy) (to_real alpha) (to_real sigma) 
 
682
                                (to_real dl) (to_real da) 
 
683
                                (to_real gauss_prec) (to_real interpolation) 
 
684
                                (to_real fast_approx) x;
 
685
                }
 
686
        }
 
687
 
 
688
        Enlarge_item = class
 
689
                Menuaction "Enlarge" "Enlarge image" {
 
690
                action x = class 
 
691
                        _result {
 
692
                        _vislevel = 3;
 
693
 
 
694
                        scale = Scale "Enlarge" 1 10 3;
 
695
                        iterations = Scale "Iterations" 1 5 3;
 
696
                        amplitude = Scale "Amplitude" 1 100 20;
 
697
                        sharpness = Scale "Sharpness" 0 3 0.2;
 
698
                        anisotropy = Scale "Anisotropy" 0 1 0.9;
 
699
                        alpha = Scale "Noise scale" 0 5 0.1;
 
700
                        sigma = Scale "Geometry regularity" 0 2 1.5;
 
701
                        dl = Scale "Spatial integration step" 0 1 0.8;
 
702
                        da = Scale "Angular integration step" 0 90 30;
 
703
                        gauss_prec = Scale "Precision" 1 10 2;
 
704
                        interpolation = Option "Interpolation" 
 
705
                                ["Nearest-neighbour", "Bilinear", "Runge-Kutta"] 0;
 
706
                        fast_approx = Toggle "Fast approximation" true;
 
707
 
 
708
                        _result = greyc 
 
709
                                (to_real iterations) (to_real amplitude) (to_real sharpness)
 
710
                                (to_real anisotropy) (to_real alpha) (to_real sigma) 
 
711
                                (to_real dl) (to_real da) 
 
712
                                (to_real gauss_prec) (to_real interpolation) 
 
713
                                (to_real fast_approx) 
 
714
                                        (resize (to_real scale) (to_real scale) 
 
715
                                                Interpolate.BILINEAR x);
 
716
                }
 
717
        }
 
718
 
 
719
}
 
720
 
 
721
#separator
 
722
 
 
723
Filter_tilt_item = class
 
724
        Menupullright "Ti_lt Brightness" "tilt brightness" {
 
725
        Left_right_item = class
 
726
                Menuaction "_Left to Right" "linear left-right brighten" {
 
727
                action x = class
 
728
                        _result {
 
729
                        _vislevel = 3;
 
730
 
 
731
                        tilt = Scale "Left-right tilt" (-1) 1 0;
 
732
 
 
733
                        _result
 
734
                                        = map_unary tilt_lr x
 
735
                        {
 
736
                                tilt_lr image
 
737
                                        = image * scale
 
738
                                {
 
739
                                        ramp = im_fgrey image.width image.height;
 
740
                                        scale = (ramp - 0.5) * tilt + 1;
 
741
                                }
 
742
                        }
 
743
                }
 
744
        }
 
745
 
 
746
        Top_bottom_item = class
 
747
                Menuaction "_Top to Bottom" "linear top-bottom brighten" {
 
748
                action x = class
 
749
                        _result {
 
750
                        _vislevel = 3;
 
751
 
 
752
                        tilt = Scale "Top-bottom tilt" (-1) 1 0;
 
753
 
 
754
                        _result
 
755
                                = map_unary tilt_tb x
 
756
                        {
 
757
                                tilt_tb image 
 
758
                                        = image * scale
 
759
                                {
 
760
                                        ramp = rot90 
 
761
                                                (im_fgrey image.height image.width);
 
762
                                        scale = (ramp - 0.5) * tilt + 1;
 
763
                                }
 
764
                        }
 
765
                }
 
766
        }
 
767
 
 
768
        sep1 = Menuseparator;
 
769
 
 
770
        Left_right_cos_item = class
 
771
                Menuaction "Cosine Left-_right" "cosine left-right brighten" {
 
772
                action x = class
 
773
                        _result {
 
774
                        _vislevel = 3;
 
775
 
 
776
                        tilt = Scale "Left-right tilt" (-1) 1 0;
 
777
                        shift = Scale "Shift by" (-1) 1 0;
 
778
 
 
779
                        _result
 
780
                                        = map_unary tilt_lr x
 
781
                        {
 
782
                                tilt_lr image
 
783
                                        = image * scale
 
784
                                {
 
785
                                        ramp = im_fgrey image.width image.height - 0.5 -
 
786
                                                        shift.value;
 
787
                                        scale = 0.5 * tilt.value * cos (ramp * 180) + 1;
 
788
                                }
 
789
                        }
 
790
                }
 
791
        }
 
792
 
 
793
        Top_bottom_cos_item = class
 
794
                Menuaction "Cosine Top-_bottom" "cosine top-bottom brighten" {
 
795
                action x = class
 
796
                        _result {
 
797
                        _vislevel = 3;
 
798
 
 
799
                        tilt = Scale "Top-bottom tilt" (-1) 1 0;
 
800
                        shift = Scale "Shift by" (-1) 1 0;
 
801
 
 
802
                        _result
 
803
                                = map_unary tilt_tb x
 
804
                        {
 
805
                                tilt_tb image 
 
806
                                        = image * scale
 
807
                                {
 
808
                                        ramp = rot90 (im_fgrey image.height image.width) - 0.5 -
 
809
                                                        shift.value;
 
810
                                        scale = 0.5 * tilt.value * cos (ramp * 180) + 1;
 
811
                                }
 
812
                        }
 
813
                }
 
814
        }
 
815
 
 
816
        sep2 = Menuseparator;
 
817
 
 
818
        Circular_item = class
 
819
                Menuaction "_Circular" "circular brighten" {
 
820
                action x = class
 
821
                        _result {
 
822
                        _vislevel = 3;
 
823
 
 
824
                        tilt = Scale "Tilt" (-1) 1 0;
 
825
                        hshift = Scale "Horizontal shift by" (-1) 1 0;
 
826
                        vshift = Scale "Vertical shift by" (-1) 1 0;
 
827
 
 
828
                        _result
 
829
                                = map_unary tilt_tb x
 
830
                        {
 
831
                                tilt_tb image 
 
832
                                        = image * scale
 
833
                                {
 
834
                                        hramp = im_fgrey image.width image.height - 0.5 -
 
835
                                                hshift.value;
 
836
                                        vramp = rot90 (im_fgrey image.height image.width) - 0.5 -
 
837
                                                vshift.value;
 
838
                                        ramp = (hramp ** 2 + vramp ** 2) ** 0.5;
 
839
                                        scale = 0.5 * tilt.value * cos (ramp * 180) + 1;
 
840
                                }
 
841
                        }
 
842
                }
 
843
        }
 
844
}
 
845
 
 
846
Filter_blend_item = class
 
847
        Menupullright "_Blend" "blend objects together" {
 
848
        Scale_blend_item = class
 
849
                Menuaction "_Scale" "blend two objects together with a scale" {
 
850
                action a b = class
 
851
                        _result {
 
852
                        _vislevel = 3;
 
853
 
 
854
                        p = Scale "Blend position" 0 1 0.5;
 
855
 
 
856
                        _result
 
857
                                = map_binary process a b
 
858
                        {
 
859
                                process im1 im2 = im1 * (1 - p.value) + im2 * p.value;
 
860
                        }
 
861
                }
 
862
        }
 
863
 
 
864
        Image_blend_item = class
 
865
                Menuaction "_Image" "use an image to blend two objects" {
 
866
                action a b c = class
 
867
                        _result {
 
868
                        _vislevel = 3;
 
869
 
 
870
                        i = Toggle "Invert mask" false;
 
871
 
 
872
                        _result 
 
873
                                = map_trinary process a b c
 
874
                        {
 
875
                                process a b c 
 
876
                                        = blend condition in1 in2, !i
 
877
                                        = blend (invert condition) in1 in2
 
878
                                {
 
879
                                        compare a b
 
880
                                                // prefer image as the condition
 
881
                                                = false, 
 
882
                                                        !has_image a && has_image b
 
883
                                                // prefer mono images as the condition
 
884
                                                = false, 
 
885
                                                        has_bands a && has_bands b && 
 
886
                                                        get_bands a > 1 && get_bands b == 1
 
887
                                                // prefer uchar as the condition
 
888
                                                = false,
 
889
                                                        has_format a && has_format b && 
 
890
                                                        get_format a > Image_format.UCHAR && 
 
891
                                                                get_format b == Image_format.UCHAR
 
892
                                                = true;
 
893
                                        [condition, in1, in2] = sortc compare [a, b, c];
 
894
                                }
 
895
                        }
 
896
                }
 
897
        }
 
898
 
 
899
        Line_blend_item = class
 
900
                Menuaction "_Along Line" 
 
901
                        "blend between image a and image b along a line" {
 
902
                action a b = class
 
903
                        _result {
 
904
                        _vislevel = 3;
 
905
 
 
906
                        orientation = Option "Orientation" [
 
907
                                "Left to Right",
 
908
                                "Top to Bottom"
 
909
                        ] 0;
 
910
                        blend_position = Scale "Blend position" 0 1 0.5;
 
911
                        blend_width = Scale "Blend width" 0 1 0.05;
 
912
 
 
913
                        _result
 
914
                                = map_binary process a b
 
915
            {
 
916
                process a b 
 
917
                                        = blend (Image condition) b a
 
918
                {
 
919
                                        output_width = max_pair a.width b.width;
 
920
                                        output_height = max_pair a.height b.height;
 
921
                                        range
 
922
                                                = output_width, orientation == 0
 
923
                                                = output_height;
 
924
                                        blend_position' 
 
925
                                                = floor (range * blend_position.value);
 
926
                                        blend_width' 
 
927
                                                = 1, blend_width.value == 0
 
928
                                                = floor (range * blend_width.value);
 
929
                        start = blend_position' - blend_width' / 2;
 
930
 
 
931
                                        background = (make_xy output_width output_height) >= 
 
932
                                                blend_position';
 
933
                        ramp 
 
934
                                                = im_grey blend_width' output_height, orientation == 0
 
935
                        = rot90 (im_grey blend_width' output_width);
 
936
                                        condition 
 
937
                                                = insert_noexpand start 0 ramp background?0, 
 
938
                                                        orientation == 0
 
939
                                                = insert_noexpand 0 start ramp background?1;
 
940
                }
 
941
                        }
 
942
                }
 
943
        } 
 
944
 
 
945
        Blend_alpha_item = class
 
946
                Menuaction "_Alpha" "blend images with optional alpha channels" {
 
947
                // usage: layerit foreground background
 
948
                // input images must be either 1 or 3 bands, optionally + 1 band 
 
949
                // which is used as the alpha channel
 
950
                // rich lott
 
951
        
 
952
                scale_mask im opacity
 
953
                        = (unsigned char) (to_real opacity / 255 * im);
 
954
        
 
955
                // to mono
 
956
                intensity = colour_transform_to Image_type.B_W;
 
957
        
 
958
                // All the blend functions
 
959
                // I am grateful to this page
 
960
                // http://www.pegtop.net/delphi/blendmodes/
 
961
                // for most of the formulae.
 
962
        
 
963
                blend_normal mask opacity fg bg
 
964
                        = blend (scale_mask mask opacity) fg bg;
 
965
        
 
966
                blend_iflighter mask opacity fg bg
 
967
                        = blend (if fg' > bg' then mask' else 0) fg bg
 
968
                { 
 
969
                        fg' = intensity fg;
 
970
                        bg' = intensity bg;
 
971
                        mask' = scale_mask mask opacity ;
 
972
                }
 
973
        
 
974
                blend_ifdarker mask opacity fg bg
 
975
                        = blend (if fg' < bg' then mask' else 0) fg bg
 
976
                { 
 
977
                        fg' = intensity fg ;
 
978
                        bg' = intensity bg ;    
 
979
                        mask' = scale_mask mask opacity ;
 
980
                }
 
981
        
 
982
                blend_multiply mask opacity fg bg
 
983
                        = blend (scale_mask mask opacity) fg' bg
 
984
                {
 
985
                        fg' = fg / 255 * bg;
 
986
                }
 
987
        
 
988
                blend_add mask opacity fg bg
 
989
                        = blend mask fg' bg             
 
990
                {
 
991
                        fg' = opacity / 255 * fg + bg;
 
992
                }
 
993
        
 
994
                blend_subtract mask opacity fg bg
 
995
                        = blend mask fg' bg 
 
996
                {
 
997
                        fg' = bg - opacity / 255 * fg;
 
998
                }
 
999
        
 
1000
                blend_screen mask opacity fg bg
 
1001
                        = blend mask fg' bg 
 
1002
                {
 
1003
                        fg' = 255 - (255 - bg) * (255 - (opacity / 255 * fg)) / 255;
 
1004
                }
 
1005
        
 
1006
                blend_burn mask opacity fg bg
 
1007
                        = blend mask fg'' bg
 
1008
                {
 
1009
                        // fades to white which has no effect.
 
1010
                        fg' = (255 - opacity) + opacity * fg / 255;
 
1011
                        fg'' = 255 - 255 * (255 - bg) / fg';
 
1012
                }
 
1013
        
 
1014
                blend_softlight mask opacity fg bg
 
1015
                        = blend mask' fg' bg
 
1016
                {
 
1017
                        mask' = scale_mask mask opacity;
 
1018
                        fg' = (2 * bg * fg + bg * bg * (1 - 2 * fg / 255)) / 255;
 
1019
                }
 
1020
        
 
1021
                blend_hardlight mask opacity fg bg
 
1022
                        = blend mask' fg' bg            
 
1023
                {
 
1024
                        mask' = scale_mask mask opacity;
 
1025
                        fg'
 
1026
                                = 2 / 255 * fg * bg, bg < 129
 
1027
                                = 255 - 2 * (255 - bg) * (255 - fg) / 255;
 
1028
                }
 
1029
        
 
1030
                blend_lighten mask opacity fg bg
 
1031
                        = blend mask' fg' bg            
 
1032
                {
 
1033
                        mask' = scale_mask mask opacity;
 
1034
                        fg' = if bg < fg then fg else bg;
 
1035
                }
 
1036
        
 
1037
                blend_darken mask opacity fg bg
 
1038
                        = blend mask' fg' bg            
 
1039
                {
 
1040
                        mask' = scale_mask mask opacity;
 
1041
                        fg' = if bg > fg then fg else bg;
 
1042
                }
 
1043
        
 
1044
                blend_dodge mask opacity fg bg
 
1045
                        = blend mask fg'' bg 
 
1046
                {
 
1047
                        // one added to avoid divide by zero
 
1048
                        fg' = 1 + 255 - (opacity / 255 * fg); 
 
1049
                        fg'' = bg * 255 / fg';
 
1050
                }
 
1051
        
 
1052
                blend_reflect mask opacity fg bg
 
1053
                        = blend mask' fg' bg 
 
1054
                {
 
1055
                        mask' = scale_mask mask opacity;
 
1056
                        fg' = bg * bg / (255 - fg);
 
1057
                }
 
1058
        
 
1059
                blend_freeze mask opacity fg bg
 
1060
                        = blend mask' fg' bg
 
1061
                {
 
1062
                        mask' = scale_mask mask opacity;
 
1063
                        fg' = 255 - (255 - bg) * (255 - bg) / (1 + fg);
 
1064
                }
 
1065
        
 
1066
                blend_or mask opacity fg bg
 
1067
                        = bg | (unsigned char) fg'
 
1068
                {
 
1069
                        mask' = scale_mask mask opacity;
 
1070
                        fg' = fg * mask' / 255;
 
1071
                }
 
1072
        
 
1073
                blend_and mask opacity fg bg
 
1074
                        = bg & (unsigned char) fg'
 
1075
                {
 
1076
                        mask' = scale_mask mask opacity;
 
1077
                        fg' = fg * mask' / 255;
 
1078
                }
 
1079
        
 
1080
                // blend types
 
1081
                NORMAL = 0;
 
1082
                IFLIGHTER = 1;
 
1083
                IFDARKER = 2;
 
1084
                MULTIPLY = 3;
 
1085
                ADD = 4;
 
1086
                SUBTRACT = 5;
 
1087
                SCREEN = 6;
 
1088
                BURN = 7;
 
1089
                DODGE = 8;
 
1090
                HARDLIGHT = 9;
 
1091
                SOFTLIGHT = 10;
 
1092
                LIGHTEN = 11;
 
1093
                DARKEN = 12;
 
1094
                REFLECT = 13;
 
1095
                FREEZE = 14;
 
1096
                OR = 15;
 
1097
                AND = 16;
 
1098
        
 
1099
                // names we show the user for blend types
 
1100
                names = Enum [
 
1101
                        [_ "Normal", NORMAL],
 
1102
                        [_ "If Lighter", IFLIGHTER],
 
1103
                        [_ "If Darker", IFDARKER],
 
1104
                        [_ "Multiply", MULTIPLY],
 
1105
                        [_ "Add", ADD],
 
1106
                        [_ "Subtract", SUBTRACT],
 
1107
                        [_ "Screen", SCREEN],
 
1108
                        [_ "Burn", BURN],
 
1109
                        [_ "Soft Light", SOFTLIGHT],
 
1110
                        [_ "Hard Light", HARDLIGHT],
 
1111
                        [_ "Lighten", LIGHTEN],
 
1112
                        [_ "Darken", DARKEN],
 
1113
                        [_ "Dodge", DODGE],
 
1114
                        [_ "Reflect", REFLECT],
 
1115
                        [_ "Freeze", FREEZE],
 
1116
                        [_ "Bitwise OR", OR],
 
1117
                        [_ "Bitwise AND", AND]
 
1118
                ];
 
1119
        
 
1120
                // functions we call for each blend type
 
1121
                actions = Table [
 
1122
                        [NORMAL, blend_normal],
 
1123
                        [IFLIGHTER, blend_iflighter],
 
1124
                        [IFDARKER, blend_ifdarker],
 
1125
                        [MULTIPLY, blend_multiply],
 
1126
                        [ADD, blend_add],
 
1127
                        [SUBTRACT, blend_subtract],
 
1128
                        [SCREEN, blend_screen],
 
1129
                        [BURN, blend_burn],
 
1130
                        [SOFTLIGHT, blend_softlight],
 
1131
                        [HARDLIGHT, blend_hardlight],
 
1132
                        [LIGHTEN, blend_lighten],
 
1133
                        [DARKEN, blend_darken],
 
1134
                        [DODGE, blend_dodge],
 
1135
                        [REFLECT, blend_reflect],
 
1136
                        [FREEZE, blend_freeze],
 
1137
                        [OR, blend_or],
 
1138
                        [AND, blend_and]
 
1139
                ];
 
1140
        
 
1141
                // make sure im has an alpha channel (set opaque if it hasn't)
 
1142
                put_alpha im
 
1143
                        = im, im.bands == 4 || im.bands == 2 
 
1144
                        = im ++ 255;
 
1145
        
 
1146
                // make sure im has no alpha channel 
 
1147
                lose_alpha im
 
1148
                        = extract_bands 0 3 im, im.bands == 4 
 
1149
                        = im?0, im.bands == 2 
 
1150
                        = im;
 
1151
        
 
1152
                // does im have al alpha channel?
 
1153
                has_alpha im = im.bands == 2 || im.bands == 4;
 
1154
        
 
1155
                // get the alpha (set opaque if no alpha)
 
1156
                get_alpha img
 
1157
                        = img'?3, img.bands == 4 
 
1158
                        = img'?1
 
1159
                {
 
1160
                        img' = put_alpha img;
 
1161
                }
 
1162
        
 
1163
                // add an alpha ... cast the alpha image to match the main image
 
1164
                append_alpha im alpha
 
1165
                        = im ++ clip2fmt im.format alpha;
 
1166
        
 
1167
                // makes fg the same size as bg, displaced with u, v pixel offset
 
1168
                moveit fg bg u v
 
1169
                        = insert_noexpand u v fg bg'
 
1170
                {
 
1171
                        bg' = image_new bg.width bg.height 
 
1172
                                fg.bands fg.format fg.coding fg.type 0 0 0;
 
1173
                }
 
1174
        
 
1175
                action bg fg = class 
 
1176
                        _value {
 
1177
                        _vislevel = 3;
 
1178
        
 
1179
                        method = Option_enum names "Blend mode" "Normal";
 
1180
                        opacity = Scale "Opacity" 0 255 255;
 
1181
                        hmove = Scale "Horizontal move by" (-bg.width) (bg.width) 0; 
 
1182
                        vmove = Scale "Vertical move by" (-bg.height) (bg.height) 0;            
 
1183
        
 
1184
                        _value
 
1185
                                = append_alpha blended merged_alpha, has_alpha bg
 
1186
                                = blended 
 
1187
                        {
 
1188
                                // displace and resize fg (need to displace alpha too)
 
1189
                                fg' = moveit (put_alpha fg) bg hmove vmove;
 
1190
        
 
1191
                                // transform to sRGB
 
1192
                                fg'' = colour_transform_to Image_type.sRGB (lose_alpha fg');
 
1193
                                bg' = colour_transform_to Image_type.sRGB (lose_alpha bg);
 
1194
        
 
1195
                                // alphas merged
 
1196
                                merged_alpha = get_alpha bg | get_alpha fg';
 
1197
        
 
1198
                                // blend together
 
1199
                                blended = (actions.lookup 0 1 method.value_thing) 
 
1200
                                        (get_alpha fg') opacity.value fg'' bg';
 
1201
                        }
 
1202
                }
 
1203
        }
 
1204
}
 
1205
 
 
1206
Filter_overlay_header_item = class
 
1207
        Menuaction "_Overlay" 
 
1208
                "make a colour overlay of two monochrome images" {
 
1209
        action  a b = class 
 
1210
                _result {
 
1211
                _vislevel = 3;
 
1212
 
 
1213
                colour = Option "Colour overlay as" [
 
1214
                        _ "Green over Red",
 
1215
                        _ "Blue over Red",
 
1216
                        _ "Red over Green",
 
1217
                        _ "Red over Blue",
 
1218
                        _ "Blue over Green",
 
1219
                        _ "Green over Blue"
 
1220
                ] 0;
 
1221
 
 
1222
                _result
 
1223
                        = map_binary overlay a b
 
1224
                {
 
1225
                        overlay a b
 
1226
                                = image_set_type Image_type.sRGB 
 
1227
                                        [(a' ++ b' ++ 0), 
 
1228
                                                (a' ++ 0 ++ b'), 
 
1229
                                                (b' ++ a' ++ 0), 
 
1230
                                                (b' ++ 0 ++ a'), 
 
1231
                                                (0 ++ a' ++ b'), 
 
1232
                                                (0 ++ b' ++ a')]?colour
 
1233
                        {
 
1234
                                a' = colour_transform_to Image_type.B_W a;
 
1235
                                b' = colour_transform_to Image_type.B_W b;
 
1236
                        }
 
1237
                }
 
1238
        }
 
1239
}
 
1240
 
 
1241
Filter_colourize_item = class 
 
1242
        Menuaction "_Colourize" "use a colour image or patch to tint a mono image" {
 
1243
        action a b = class
 
1244
                _result {
 
1245
                _vislevel = 3;
 
1246
 
 
1247
                tint = Scale "Tint" 0 1 0.6;
 
1248
 
 
1249
                _result
 
1250
                        = map_binary tintit a b
 
1251
                {
 
1252
                        tintit a b
 
1253
                                = colour_transform_to (get_type colour) colourized'
 
1254
                        {
 
1255
                                // get the mono thing first
 
1256
                                [mono, colour] = 
 
1257
                                        sortc (const (is_colour_type @ get_type)) [a, b];
 
1258
 
 
1259
                                colour' = tint * colour_transform_to Image_type.LAB colour;
 
1260
                                mono' = colour_transform_to Image_type.B_W mono;
 
1261
                                colourized = (mono' / 2.55) ++ colour'?1 ++ colour'?2;
 
1262
                                colourized' = image_set_type Image_type.LAB colourized;
 
1263
                        }
 
1264
                }
 
1265
        }
 
1266
}
 
1267
 
 
1268
Filter_browse_multiband_item = class 
 
1269
        Menupullright "Bro_wse" "browse though an image, bitwise or bandwise" {
 
1270
        Bandwise_item = class
 
1271
                Menuaction "B_andwise" "browse through the bands of a multiband image" {
 
1272
                action image = class  
 
1273
                _result {
 
1274
                        _vislevel = 3;
 
1275
 
 
1276
                band = Scale "Band" 0 (image.bands - 1) 0;
 
1277
                display = Option "Display as" [
 
1278
                                _ "Grey",
 
1279
                                _ "Green over Red",
 
1280
                                _ "Blue over Red",
 
1281
                                _ "Red over Green",
 
1282
                                _ "Red over Blue",
 
1283
                                _ "Blue over Green",
 
1284
                                _ "Green over Blue"
 
1285
                        ] 0;
 
1286
        
 
1287
                _result 
 
1288
                                = output
 
1289
                        {
 
1290
                                down = (int) band.value;
 
1291
                                up = down + 1;
 
1292
                                remainder = band.value - down;
 
1293
 
 
1294
                                fade x a
 
1295
                                        = Vector [0], x == 0
 
1296
                                        = a * x;
 
1297
 
 
1298
                                a = fade remainder image?up;
 
1299
                                b = fade (1 - remainder) image?down;
 
1300
 
 
1301
                                output = [
 
1302
                                        a + b, 
 
1303
                                        a ++ b ++ 0, 
 
1304
                                        a ++ 0 ++ b, 
 
1305
                                        b ++ a ++ 0,
 
1306
                                        b ++ 0 ++ a, 
 
1307
                                        0 ++ a ++ b, 
 
1308
                                        0 ++ b ++ a
 
1309
                                ] ? display;
 
1310
                        }
 
1311
                }
 
1312
        }
 
1313
 
 
1314
        Bitwise_item = class
 
1315
                Menuaction "Bi_twise" "browse through the bits of an image" {
 
1316
                action x = class  
 
1317
                _result {
 
1318
                        _vislevel = 3;
 
1319
 
 
1320
                bit 
 
1321
                                = Islider "Bit" 0 (nbits - 1) (nbits - 1)
 
1322
                        {
 
1323
                                nbits 
 
1324
                                        = x.bits, is_Image x
 
1325
                                        = 8;
 
1326
                                Islider c f t v = class 
 
1327
                                        scope.Scale c f t ((int) v) {
 
1328
                                        Scale = Islider;
 
1329
                                }
 
1330
                        }
 
1331
 
 
1332
                _result 
 
1333
                                = map_unary process x
 
1334
                        {
 
1335
                                process im = (im & (0x1 << bit.value)) != 0;
 
1336
                        }
 
1337
                }
 
1338
        }
 
1339
}
 
1340
 
 
1341
#separator
 
1342
 
 
1343
Filter_negative_item = class
 
1344
        Menuaction "Photographic _Negative" "swap black and white" {
 
1345
        action x 
 
1346
                = map_unary invert x
 
1347
        {
 
1348
                invert in
 
1349
                        = clip2fmt in.format (colour_transform_to (get_type in) rgb')
 
1350
                {
 
1351
                        rgb = colour_transform_to Image_type.sRGB in;
 
1352
                        rgb' = 255 - rgb;
 
1353
                }
 
1354
        }
 
1355
}
 
1356
 
 
1357
Filter_solarize_item = class
 
1358
        Menuaction "_Solarise" "invert colours above a threshold" {
 
1359
        action x = class
 
1360
                _result {
 
1361
                _vislevel = 3;
 
1362
                
 
1363
                kink = Scale "Kink" 0 1 0.5;
 
1364
 
 
1365
                _result
 
1366
                        = map_unary process x
 
1367
                {
 
1368
                        process image
 
1369
                                = hist_map tab'''' image
 
1370
                        {
 
1371
                                // max pixel value for this format
 
1372
                                mx = Image_format.maxval image.format;
 
1373
 
 
1374
                                // make a LUT ... just 8 and 16 bit
 
1375
                                tab 
 
1376
                                        = im_identity_ushort image.bands mx,
 
1377
                                                image.format == 
 
1378
                                                        Image_format.USHORT
 
1379
                                        = im_identity image.bands;
 
1380
                                tab' = Image tab;
 
1381
 
 
1382
                                // make basic ^ shape
 
1383
                                tab'' 
 
1384
                                        = tab' * (1 / kink), tab' < mx * kink
 
1385
                                        = (mx - tab') / (1 - kink);
 
1386
                                tab''' = clip2fmt image.format tab'';
 
1387
 
 
1388
                                // smooth a bit
 
1389
                                mask = matrix_blur (tab'''.width / 8);
 
1390
                                tab'''' = convsep mask tab''';
 
1391
                        }
 
1392
                }
 
1393
        }
 
1394
}
 
1395
 
 
1396
Filter_diffuse_glow_item = class
 
1397
        Menuaction "_Diffuse Glow" "add a halo to highlights" {
 
1398
        action x = class
 
1399
                _result {
 
1400
                _vislevel = 3;
 
1401
                
 
1402
                r = Scale "Radius" 0 50 5;
 
1403
                highlights = Scale "Highlights" 0 100 95;
 
1404
                glow = Scale "Glow" 0 1 0.5;
 
1405
                colour = Colour_new_item.Widget_colour_item.action;
 
1406
 
 
1407
                _result
 
1408
                        = map_unary process x
 
1409
                {
 
1410
                        process image
 
1411
                                = image'
 
1412
                        {
 
1413
                                mono = (unsigned char) (colour_transform_to 
 
1414
                                        Image_type.B_W image);
 
1415
                                thresh = hist_thresh (highlights.value / 100) mono;
 
1416
                                mask = mono > thresh;
 
1417
                                blur = convsep (matrix_gaussian_blur r.value) mask;
 
1418
                                colour' = colour_transform_to image.type colour;
 
1419
                                image' = image + colour' * glow * (blur / 255);
 
1420
                        }
 
1421
                }
 
1422
        }
 
1423
}
 
1424
 
 
1425
Filter_drop_shadow_item = class
 
1426
        Menuaction "Drop S_hadow" "add a drop shadow to an image" {
 
1427
        action x = class
 
1428
        _result {
 
1429
        _vislevel = 3;
 
1430
 
 
1431
        sx = Scale "Horizontal shadow" (-50) 50 5;
 
1432
        sy = Scale "Vertical shadow" (-50) 50 5;
 
1433
        ss = Scale "Shadow softness" 0 20 5;
 
1434
        bg_colour = Expression "Background colour" 255;
 
1435
        sd_colour = Expression "Shadow colour" 128;
 
1436
        alpha = Toggle "Shadow in alpha channel" false;
 
1437
        transparent = Toggle "Zero pixels are transparent" false;
 
1438
 
 
1439
        _result
 
1440
            = map_unary shadow x
 
1441
        {
 
1442
            shadow image
 
1443
                = Image final
 
1444
            {
 
1445
                blur_size = ss.value * 2 + 1;
 
1446
 
 
1447
                // matrix we blur with to soften shadows
 
1448
                blur_matrix = matrix_gaussian_blur blur_size;
 
1449
                matrix_size = blur_matrix.width;
 
1450
                matrix_radius = (int) (matrix_size / 2) + 1;
 
1451
 
 
1452
                // position and size of shadow image in input cods
 
1453
                // before and after fuzzing
 
1454
                shadow_rect = Rect sx.value sy.value 
 
1455
                                        image.width image.height;
 
1456
                fuzzy_shadow_rect = shadow_rect.margin_adjust matrix_radius;
 
1457
 
 
1458
                // size and pos of final image, in input cods
 
1459
                final_rect = image.rect.union fuzzy_shadow_rect;
 
1460
 
 
1461
                // hard part of shadow in output cods
 
1462
                shadow_rect' = Rect 
 
1463
                    (shadow_rect.left - final_rect.left)
 
1464
                    (shadow_rect.top - final_rect.top)
 
1465
                    shadow_rect.width shadow_rect.height;
 
1466
 
 
1467
                // make the shadow mask ... true for parts which cast
 
1468
                // a shadow
 
1469
                mask 
 
1470
                    = (foldr1 bitwise_and @ bandsplit) (image.value != 0), 
 
1471
                                transparent
 
1472
                    = image_new image.width image.height 1 Image_format.UCHAR
 
1473
                        Image_coding.NOCODING Image_type.B_W 255 0 0;
 
1474
                mask' = embed 0 shadow_rect'.left shadow_rect'.top
 
1475
                        final_rect.width final_rect.height mask;
 
1476
                                mask'' = convsep blur_matrix mask';
 
1477
 
 
1478
                // use mask to fade between bg and shadow colour
 
1479
                mk_background colour = image_new 
 
1480
                        final_rect.width final_rect.height
 
1481
                    image.bands image.format image.coding image.type
 
1482
                    colour 0 0;
 
1483
 
 
1484
                bg_image = mk_background bg_colour.expr;
 
1485
                shadow_image = mk_background sd_colour.expr;
 
1486
                bg = blend mask'' shadow_image bg_image;
 
1487
 
 
1488
                // make a full size mask 
 
1489
                fg_mask = embed 0
 
1490
                    (image.rect.left - final_rect.left)
 
1491
                    (image.rect.top - final_rect.top)
 
1492
                    final_rect.width final_rect.height mask;
 
1493
 
 
1494
                // wrap up the input image ... put the shadow colour
 
1495
                // around it, so if we are outputting a separate
 
1496
                // alpha the shadow colour will be set correctly
 
1497
                fg = insert (image.rect.left - final_rect.left)
 
1498
                    (image.rect.top - final_rect.top)
 
1499
                    image.value shadow_image;
 
1500
 
 
1501
                final
 
1502
                    // make a separate alpha
 
1503
                    = fg ++ mask'', alpha
 
1504
 
 
1505
                    // paste image over shadow
 
1506
                    = if fg_mask then fg else bg;
 
1507
            }
 
1508
        }
 
1509
    }
 
1510
}
 
1511
 
 
1512
Filter_paint_text_item = class 
 
1513
        Menuaction "_Paint Text" "paint text into an image" {
 
1514
        action x 
 
1515
                = paint_position, is_Group x
 
1516
                = paint_area
 
1517
        {
 
1518
                paint_area = class
 
1519
                        _result {
 
1520
                        _check_args = [
 
1521
                                [x, "x", check_Image]
 
1522
                        ] ++ super._check_args;
 
1523
                        _vislevel = 3;
 
1524
                
 
1525
                        text = String "Text to paint" "<i>Hello</i> world!";
 
1526
                        font = Fontname "Use font" Workspaces.Preferences.PAINTBOX_FONT;
 
1527
                        align = Option "Alignment" ["Left", "Centre", "Right"] 0;
 
1528
                        dpi = Expression "DPI" 300;
 
1529
                        colour = Expression "Text colour" 255;
 
1530
                        place = Region x (x.width / 4) (x.height / 4) 
 
1531
                                (x.width / 2) (x.height / 2);
 
1532
        
 
1533
                        _result
 
1534
                                = insert_noexpand place.left place.top (blend txt' fg place) x
 
1535
                        {
 
1536
                                fg = image_new place.width place.height x.bands x.format 
 
1537
                                        x.coding x.type colour.expr 0 0;
 
1538
                                txt = Image (im_text text.value font.value 
 
1539
                                        place.width align.value (to_real dpi));
 
1540
                    bg = im_black place.width place.height 1;
 
1541
                                txt' = insert_noexpand 0 0 txt bg;
 
1542
                        }
 
1543
                }
 
1544
        
 
1545
                paint_position = class
 
1546
                        _result {
 
1547
                        _vislevel = 3;
 
1548
        
 
1549
                        text = Pattern_images_item.Text_item.action;
 
1550
                        colour = Expression "Text colour" 255;
 
1551
                        position = Option "Position" [
 
1552
                                _ "North-west",
 
1553
                                _ "North",
 
1554
                                _ "North-east",
 
1555
                                _ "West",
 
1556
                                _ "Centre",
 
1557
                                _ "East",
 
1558
                                _ "South-west",
 
1559
                                _ "South",
 
1560
                                _ "South-east",
 
1561
                                _ "Specify in pixels"
 
1562
                        ] 4;
 
1563
                        left = Expression "Pixels from left" 0;
 
1564
                        top = Expression "Pixels from top" 0;
 
1565
        
 
1566
                        _result
 
1567
                                = map_unary paint x
 
1568
                        {
 
1569
                                paint image
 
1570
                                        = insert_noexpand x' y' place' image
 
1571
                                {
 
1572
                                        xr = image.width - text.width;
 
1573
                                        yr = image.height - text.height;
 
1574
                                        x 
 
1575
                                                = left.expr, position == 9
 
1576
                                                = [0, xr / 2, xr]?(position % 3);
 
1577
                                        y
 
1578
                                                = top.expr, position == 9
 
1579
                                                = [0, yr / 2, yr]?(position / 3);
 
1580
                                        x' = range 0 x (image.width - 1);
 
1581
                                        y' = range 0 y (image.height - 1);
 
1582
                                        w' = range 1 text.width (image.width - x');
 
1583
                                        h' = range 1 text.height (image.height - y');
 
1584
        
 
1585
                                        place = extract_area x' y' w' h' image;
 
1586
                                        text' = insert_noexpand 0 0 text (im_black w' h' 1);
 
1587
                                        fg = image_new w' h' image.bands image.format 
 
1588
                                                image.coding image.type colour.expr 0 0;
 
1589
                                        place' = blend text' fg place;
 
1590
                                }
 
1591
                        }
 
1592
                }
 
1593
        }
 
1594
}