ruby-vips 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ VALUE img_histgr(int, VALUE*, VALUE);
2
+ VALUE img_histnd(VALUE, VALUE);
3
+ VALUE img_hist_indexed(VALUE, VALUE);
4
+ VALUE img_s_identity(VALUE, VALUE);
5
+ VALUE img_s_identity_ushort(VALUE, VALUE, VALUE);
6
+ VALUE img_s_invertlut(VALUE, VALUE, VALUE);
7
+ VALUE img_s_buildlut(VALUE, VALUE);
8
+ VALUE img_project(VALUE);
9
+ VALUE img_histnorm(VALUE);
10
+ VALUE img_histcum(VALUE);
11
+ VALUE img_histeq(VALUE);
12
+ VALUE img_histspec(VALUE, VALUE);
13
+ VALUE img_maplut(VALUE, VALUE);
14
+ VALUE img_histplot(VALUE);
15
+ VALUE img_monotonic_p(VALUE);
16
+ VALUE img_hist(int, VALUE*, VALUE);
17
+ VALUE img_hsp(VALUE, VALUE);
18
+ VALUE img_gammacorrect(VALUE, VALUE);
19
+ VALUE img_mpercent_hist(VALUE, VALUE);
20
+ VALUE img_mpercent(VALUE, VALUE);
21
+ VALUE img_heq(int, VALUE*, VALUE);
22
+ VALUE img_lhisteq(VALUE, VALUE, VALUE);
23
+ VALUE img_stdif(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
24
+ VALUE img_s_tone_build_range(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE,
25
+ VALUE, VALUE, VALUE, VALUE);
26
+ VALUE img_s_tone_build(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE,
27
+ VALUE);
28
+ VALUE img_tone_analyze(VALUE, VALUE, VALUE, VALUE, VALUE, VALUE, VALUE);
@@ -0,0 +1,330 @@
1
+ #include "ruby_vips.h"
2
+ #include "image.h"
3
+ #include "mask.h"
4
+ #include "image_morphology.h"
5
+
6
+ /*
7
+ * call-seq:
8
+ * im.dilate(mask) -> image
9
+ *
10
+ * Dilates *self*, according to <i>mask</i>. The output image is the same size
11
+ * as the input. Sets pixels in the output if *any* part of the mask matches.
12
+ *
13
+ * *self* must be a one channel binary image ie. with pixels that are either 0
14
+ * (black) or 255 (white). This method assume that *self* contains white
15
+ * objects against a black background.
16
+ *
17
+ * <i>mask</i> can be a two-dimensional array or a Mask object. All mask values
18
+ * must be integers or this method will raise an exception.
19
+ *
20
+ * Mask coefficients can be either 0 (for object) or 255 (for background) or
21
+ * 128 (for do not care). The mask should have odd length sides and the origin
22
+ * of the mask is at location (mask_columns/2, mask_rows/2) integer division.
23
+ *
24
+ * Based on the book "Fundamentals of Digital Image Processing" by A. Jain,
25
+ * pp 384-388, Prentice-Hall, 1989.
26
+ */
27
+
28
+ VALUE
29
+ img_dilate(VALUE obj, VALUE mask)
30
+ {
31
+ INTMASK *imask;
32
+
33
+ GetImg(obj, data, im);
34
+ OutImg2(obj, mask, new, data_new, im_new);
35
+
36
+ mask_arg2mask(mask, &imask, NULL);
37
+
38
+ if (im_dilate(im, im_new, imask))
39
+ vips_lib_error();
40
+
41
+ return new;
42
+ }
43
+
44
+ /*
45
+ * call-seq:
46
+ * im.erode(mask) -> image
47
+ *
48
+ * Erodes *self*, according to <i>mask</i>. The output image is the same size
49
+ * as the input. Sets pixels in the output if *all* part of the mask matches.
50
+ *
51
+ * *self* must be a one channel binary image ie. with pixels that are either 0
52
+ * (black) or 255 (white). This method assume that *self* contains white
53
+ * objects against a black background.
54
+ *
55
+ * <i>mask</i> can be a two-dimensional array or a Mask object. All mask values
56
+ * must be integers or this method will raise an exception.
57
+ *
58
+ * Mask coefficients can be either 0 (for object) or 255 (for background) or
59
+ * 128 (for do not care). The mask should have odd length sides and the origin
60
+ * of the mask is at location (mask_columns/2, mask_rows/2) integer division.
61
+ *
62
+ * Based on the book "Fundamentals of Digital Image Processing" by A. Jain,
63
+ * pp 384-388, Prentice-Hall, 1989.
64
+ */
65
+
66
+ VALUE
67
+ img_erode(VALUE obj, VALUE mask)
68
+ {
69
+ INTMASK *imask;
70
+
71
+ GetImg(obj, data, im);
72
+ OutImg2(obj, mask, new, data_new, im_new);
73
+
74
+ mask_arg2mask(mask, &imask, NULL);
75
+
76
+ if (im_erode(im, im_new, imask))
77
+ vips_lib_error();
78
+
79
+ return new;
80
+ }
81
+
82
+ /*
83
+ * call-seq:
84
+ * im.rank(xsize, ysize, n) -> image
85
+ *
86
+ * Does rank filtering on an image. A window of size <i>xsize</i> by
87
+ * <i>ysize</i> is passed over the image. At each position, the pixels inside
88
+ * the window are sorted into ascending order and the pixel at the <i>n</i>th
89
+ * position is output. <i>n</i> numbers from 0.
90
+ *
91
+ * It works for any non-complex image type, with any number of bands. The input
92
+ * is expanded by copying edge pixels before performing the operation so that
93
+ * the output image has the same size as *self*. Edge pixels in the output
94
+ * image are therefore only approximate.
95
+ */
96
+
97
+ VALUE
98
+ img_rank(VALUE obj, VALUE xsize, VALUE ysize, VALUE order)
99
+ {
100
+ GetImg(obj, data, im);
101
+ OutImg(obj, new, data_new, im_new);
102
+
103
+ if (im_rank(im, im_new, NUM2INT(xsize), NUM2INT(ysize), NUM2INT(order)))
104
+ vips_lib_error();
105
+
106
+ return new;
107
+ }
108
+
109
+ VALUE
110
+ img_rank_image_internal(int argc, VALUE *argv, VALUE obj, int index)
111
+ {
112
+ vipsImg *im_t;
113
+ IMAGE **ins;
114
+ int i;
115
+ GetImg(obj, data, im);
116
+ OutImg(obj, new, data_new, im_new);
117
+
118
+ ins = IM_ARRAY(im_new, argc + 1, IMAGE*);
119
+ ins[0] = im;
120
+
121
+ for (i = 0; i < argc; i++) {
122
+ img_add_dep(data_new, argv[i]);
123
+ Data_Get_Struct(argv[i], vipsImg, im_t);
124
+ ins[i + 1] = im_t->in;
125
+ }
126
+
127
+ if (im_rank_image(ins, im_new, argc + 1, index))
128
+ vips_lib_error();
129
+
130
+ return new;
131
+ }
132
+
133
+ /*
134
+ * call-seq:
135
+ * im.rank_image(index, other_image, ...)
136
+ *
137
+ * Sorts the input images pixel-wise, then outputs an image in which each pixel
138
+ * is selected from the sorted list by <i>index</i> parameter. For example, if
139
+ * <i>index</i> is zero, then each output pixel will be the minimum of all the
140
+ * corresponding input pixels.
141
+ *
142
+ * It works for any uncoded, non-complex image type. All input images must
143
+ * match in size, format, and number of bands.
144
+ */
145
+
146
+ VALUE
147
+ img_rank_image(int argc, VALUE *argv, VALUE obj)
148
+ {
149
+ VALUE index, *images;
150
+ if (argc < 2)
151
+ rb_raise(rb_eArgError, "Need an index and at least one image");
152
+
153
+ index = argv[0];
154
+ images = RARRAY_PTR(rb_ary_new4(argc - 1, argv + 1));
155
+
156
+ return img_rank_image_internal(argc - 1, images, obj, NUM2INT(index));
157
+ }
158
+
159
+ /*
160
+ * call-seq:
161
+ * im.maxvalue(other_image, ...) -> image
162
+ *
163
+ * Sorts the input images pixel-wise, then outputs an image in which each pixel
164
+ * is the maximum from the input pixels.
165
+ *
166
+ * It works for any uncoded, non-complex image type. All input images must
167
+ * match in size, format, and number of bands.
168
+ */
169
+
170
+ VALUE
171
+ img_maxvalue(int argc, VALUE *argv, VALUE obj)
172
+ {
173
+ img_rank_image_internal(argc, argv, obj, argc - 1);
174
+ }
175
+
176
+ static VALUE
177
+ img_cntlines(VALUE obj, int flag) {
178
+ double nolines;
179
+ GetImg(obj, data, im);
180
+
181
+ if (im_cntlines(im, &nolines, flag))
182
+ vips_lib_error();
183
+
184
+ return DBL2NUM(nolines);
185
+ }
186
+
187
+ /*
188
+ * call-seq:
189
+ * im.cntlines_h -> number
190
+ *
191
+ * Calculates the number of transitions between black and white for the
192
+ * horizontal direction of an image. black is < 128, and white is >= 128.
193
+ *
194
+ * Returns the mean of the result. Input should be binary one channel.
195
+ */
196
+
197
+ VALUE
198
+ img_cntlines_h(VALUE obj) {
199
+ return img_cntlines(obj, 0);
200
+ }
201
+
202
+ /*
203
+ * call-seq:
204
+ * im.cntlines_v -> number
205
+ *
206
+ * Calculates the number of transitions between black and white for the
207
+ * vertical direction of an image. black is < 128, and white is >= 128.
208
+ *
209
+ * Returns the mean of the result. Input should be binary one channel.
210
+ */
211
+
212
+ VALUE
213
+ img_cntlines_v(VALUE obj) {
214
+ return img_cntlines(obj, 1);
215
+ }
216
+
217
+ static VALUE
218
+ img_zerox(VALUE obj, int flag)
219
+ {
220
+ GetImg(obj, data, im);
221
+ OutImg(obj, new, data_new, im_new);
222
+
223
+ if (im_zerox(im, im_new, flag))
224
+ vips_lib_error();
225
+
226
+ return new;
227
+ }
228
+
229
+ /*
230
+ * call-seq:
231
+ * im.zerox_pos -> image
232
+ *
233
+ * Detects the +ve edges of zero crossings of *self*. Works on integer images.
234
+ * The output image is byte with zero crossing set to 255 and all other values
235
+ * set to zero.
236
+ */
237
+
238
+ VALUE
239
+ img_zerox_pos(VALUE obj)
240
+ {
241
+ return img_zerox(obj, 1);
242
+ }
243
+
244
+ /*
245
+ * call-seq:
246
+ * im.zerox_neg -> image
247
+ *
248
+ * Detects the -ve edges of zero crossings of *self*. Works on integer images.
249
+ * The output image is byte with zero crossing set to 255 and all other values
250
+ * set to zero.
251
+ */
252
+
253
+ VALUE
254
+ img_zerox_neg(VALUE obj)
255
+ {
256
+ return img_zerox(obj, -1);
257
+ }
258
+
259
+ static VALUE
260
+ img_profile(VALUE obj, int dir)
261
+ {
262
+ GetImg(obj, data, im);
263
+ OutImg(obj, new, data_new, im_new);
264
+
265
+ if (im_profile(im, im_new, dir))
266
+ vips_lib_error();
267
+
268
+ return new;
269
+ }
270
+
271
+ /*
272
+ * call-seq:
273
+ * im.profile_h -> image
274
+ *
275
+ * For each horizontal line, find the position of the first non-zero pixel from
276
+ * the left. Output is USHORT with width = 1 and height = input height.
277
+ */
278
+
279
+ VALUE
280
+ img_profile_h(VALUE obj)
281
+ {
282
+ return img_profile(obj, 1);
283
+ }
284
+
285
+ /*
286
+ * call-seq:
287
+ * im.profile_v -> image
288
+ *
289
+ * For each vertical line, find the position of the first non-zero pixel from
290
+ * the top. Output is USHORT with width = input width and height = 1.
291
+ */
292
+
293
+ VALUE
294
+ img_profile_v(VALUE obj)
295
+ {
296
+ return img_profile(obj, 0);
297
+ }
298
+
299
+ /*
300
+ * call-seq:
301
+ * im.label_regions -> image, segments
302
+ *
303
+ * *self* is repeatedly scanned and regions of 4-connected pixels with the same
304
+ * pixel value found. Every time a region is discovered, those pixels are
305
+ * marked in the output image with a unique serial number. Once all pixels have
306
+ * been labelled, the operation returns, returning an an image and
307
+ * <i>segments</i>, the number of discrete regions which were detected.
308
+ *
309
+ * The output image is always a 1-band image with band format :UINT, and of the
310
+ * same dimensions as *self*.
311
+ *
312
+ * This operation is useful for, for example, blob counting. You can use the
313
+ * morphological operators to detect and isolate a series of objects, then use
314
+ * this method to number them all.
315
+ *
316
+ * Use Image#histindexed to (for example) find blob coordinates.
317
+ */
318
+
319
+ VALUE
320
+ img_label_regions(VALUE obj)
321
+ {
322
+ int segments;
323
+ GetImg(obj, data, im);
324
+ OutImg(obj, new, data_new, im_new);
325
+
326
+ if (im_label_regions(im, im_new, &segments))
327
+ vips_lib_error();
328
+
329
+ return rb_ary_new3(2, new, segments);
330
+ }
@@ -0,0 +1,13 @@
1
+ VALUE img_dilate(VALUE, VALUE);
2
+ VALUE img_erode(VALUE, VALUE);
3
+ VALUE img_rank(VALUE, VALUE, VALUE, VALUE);
4
+ VALUE img_rank_image_internal(int, VALUE*, VALUE, int);
5
+ VALUE img_rank_image(int, VALUE*, VALUE);
6
+ VALUE img_maxvalue(int, VALUE*, VALUE);
7
+ VALUE img_cntlines_h(VALUE);
8
+ VALUE img_cntlines_v(VALUE);
9
+ VALUE img_zerox_pos(VALUE);
10
+ VALUE img_zerox_neg(VALUE);
11
+ VALUE img_profile_h(VALUE);
12
+ VALUE img_profile_v(VALUE);
13
+ VALUE img_label_regions(VALUE);
@@ -0,0 +1,556 @@
1
+ #include "ruby_vips.h"
2
+ #include "image.h"
3
+ #include "image_mosaicing.h"
4
+
5
+ ID id_match_left, id_match_right, id_match_both, id_match_none;
6
+
7
+ /*
8
+ * call-seq:
9
+ * im.lrmerge(other_image, dx, dy [,mwidth]) -> image
10
+ *
11
+ * Merge *self* as the reference image and <i>other_image</i> as the secondary
12
+ * image according to the values <i>dx</i> and <i>dy</i>. <i>dx</i> and
13
+ * <i>dy</i> give the displacement of <i>other_image</i> relative to *self*.
14
+ * The result is written to the output image.
15
+ *
16
+ * The program carries out a smooth merge using a raised cosine function.
17
+ * Works for any image type, including LABPACK.
18
+ *
19
+ * Pixels are treated with the value zero as "transparent", that is, zero
20
+ * pixels in the overlap area do not contribute to the merge. This makes it
21
+ * possible to join non-rectangular images.
22
+ *
23
+ * The "mwidth" parameter limits the maximum width of the blend area. If not
24
+ * given, the width will be unlimited.
25
+ */
26
+
27
+ VALUE
28
+ img_lrmerge(int argc, VALUE *argv, VALUE obj)
29
+ {
30
+ VALUE obj2, dx, dy, mwidth_v;
31
+ int mwidth = -1;
32
+
33
+ rb_scan_args(argc, argv, "31", &obj2, &dx, &dy, &mwidth_v);
34
+ if (!NIL_P(mwidth_v))
35
+ mwidth = NUM2INT(mwidth_v);
36
+
37
+ GetImg(obj, data, im);
38
+ GetImg(obj2, data2, im2);
39
+ OutImg2(obj, obj2, new, data_new, im_new);
40
+
41
+ if (im_lrmerge(im, im2, im_new, NUM2INT(dx), NUM2INT(dy), mwidth))
42
+ vips_lib_error();
43
+
44
+ return new;
45
+ }
46
+
47
+ /*
48
+ * call-seq:
49
+ * im.tbmerge(other_image, dx, dy [,mheight]) -> image
50
+ *
51
+ * see Image#lrmerge .
52
+ */
53
+
54
+ VALUE
55
+ img_tbmerge(int argc, VALUE *argv, VALUE obj)
56
+ {
57
+ VALUE obj2, dx, dy, mwidth_v;
58
+ int mwidth = -1;
59
+
60
+ rb_scan_args(argc, argv, "31", &obj2, &dx, &dy, &mwidth_v);
61
+ if (!NIL_P(mwidth_v))
62
+ mwidth = NUM2INT(mwidth_v);
63
+
64
+ GetImg(obj, data, im);
65
+ GetImg(obj2, data2, im2);
66
+ OutImg2(obj, obj2, new, data_new, im_new);
67
+
68
+ if (im_tbmerge(im, im2, im_new, NUM2INT(dx), NUM2INT(dy), mwidth))
69
+ vips_lib_error();
70
+
71
+ return new;
72
+ }
73
+
74
+ /*
75
+ * call-seq:
76
+ * im.lrmerge1(other_image, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2
77
+ * [,mwidth]) -> image
78
+ *
79
+ * 1st order left-right merge.
80
+ */
81
+
82
+ VALUE
83
+ img_lrmerge1(int argc, VALUE *argv, VALUE obj)
84
+ {
85
+ VALUE obj2, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, mwidth_v;
86
+ int mwidth = -1;
87
+
88
+ rb_scan_args(argc, argv, "91", &obj2, &xr1, &yr1, &xs1, &ys1, &xr2, &yr2,
89
+ &xs2, &ys2, &mwidth_v);
90
+ if (!NIL_P(mwidth_v))
91
+ mwidth = NUM2INT(mwidth_v);
92
+
93
+ GetImg(obj, data, im);
94
+ GetImg(obj2, data2, im2);
95
+ OutImg2(obj, obj2, new, data_new, im_new);
96
+
97
+ if (im_lrmerge1(im, im2, im_new, NUM2INT(xr1), NUM2INT(yr1), NUM2INT(xs1),
98
+ NUM2INT(ys1), NUM2INT(xr2), NUM2INT(yr2), NUM2INT(xs2), NUM2INT(ys2),
99
+ mwidth))
100
+ vips_lib_error();
101
+
102
+ return new;
103
+ }
104
+
105
+ /*
106
+ * call-seq:
107
+ * im.tbmerge1(other_image, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2
108
+ * [,mheight]) -> image
109
+ *
110
+ * 1st order top-bottom merge.
111
+ */
112
+
113
+ VALUE
114
+ img_tbmerge1(int argc, VALUE *argv, VALUE obj)
115
+ {
116
+ VALUE obj2, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, mwidth_v;
117
+ int mwidth = -1;
118
+
119
+ rb_scan_args(argc, argv, "91", &obj2, &xr1, &yr1, &xs1, &ys1, &xr2, &yr2,
120
+ &xs2, &ys2, &mwidth_v);
121
+ if (!NIL_P(mwidth_v))
122
+ mwidth = NUM2INT(mwidth_v);
123
+
124
+ GetImg(obj, data, im);
125
+ GetImg(obj2, data2, im2);
126
+ OutImg2(obj, obj2, new, data_new, im_new);
127
+
128
+ if (im_tbmerge1(im, im2, im_new, NUM2INT(xr1), NUM2INT(yr1), NUM2INT(xs1),
129
+ NUM2INT(ys1), NUM2INT(xr2), NUM2INT(yr2), NUM2INT(xs2), NUM2INT(ys2),
130
+ mwidth))
131
+ vips_lib_error();
132
+
133
+ return new;
134
+ }
135
+
136
+ /*
137
+ * call-seq:
138
+ * im.lrmosaic(other_image, band, xref, yref, xsec, ysec,
139
+ * halfcorrelation=5, halfarea=14 [,balancetype] [,mwidth]) -> image
140
+ *
141
+ * Mosaic *self* and <i>other_image</i> left-right.
142
+ *
143
+ * In order to carry out mosaicing, the coordinates of one tie point are
144
+ * required. The tie point is expected to be in the overlapping area and has
145
+ * coordinates (<i>xref</i>, <i>yref</i>) on *self*, and (<i>xsec</i>,
146
+ * <i>ysec</i>) on <i>other_image</i>. The tie-point is not used as a start
147
+ * point for the search, but is used to specify the overlap of the two images.
148
+ *
149
+ * The function splits the overlap area into three parts (top, middle and
150
+ * bottom) and searches t*self* in each part for the 20 best high contrast
151
+ * points. These 60 points are then searched for in <i>other_image</i>, giving
152
+ * a set of 60 possible corrected vectors.
153
+ *
154
+ * A straight line is fitted through the 60 vectors, and points discarded which
155
+ * lie a significant distance from the line. The line is then refitted to the
156
+ * remaining points, and the process repeated until either all remaining points
157
+ * lie on a straight line, or too many points have been discarded.
158
+ *
159
+ * If a good straight line fit is found, *self* and <i>other_image</i> are
160
+ * joined. If no fit was found, the function fails with an error message. Note
161
+ * that this function detects rotation: if the straight line found requires
162
+ * <i>other_image</i> to be rotated, it also fails with an error message.
163
+ *
164
+ * <i>halfcorrelationsize</i> - sets the size of the fragments of *self* for
165
+ * which the function searches sec. The actual window will be of size
166
+ * 2 * <i>halfcorrelationsize</i> + 1. We recommend a value of 5.
167
+ *
168
+ * <i>halfareasize</i> - sets the size of the area of sec that is searched. The
169
+ * The actual area searched will be of size 2 * <i>halfareasize</i> + 1. We
170
+ * recommend a value of 14.
171
+ *
172
+ * <i>balancetype</i> - sets the style of the balancing the functions perform.
173
+ * Balancing finds the average value of pixels in the overlap area, and scales
174
+ * the left and right images so as to make the images match in average overlap.
175
+ *
176
+ * * :balance_none - no balancing.
177
+ * * :balance_left - keep the left image unadjusted and adjust the contrast of
178
+ * the right image to match the left.
179
+ * * :balance_right - keep the right image unadjusted and scale the left image
180
+ * to match it.
181
+ * * :balance_both - adjust the contrast of both the left and right images to
182
+ * bring both averages to a middle value. The middle value chosen is weighted
183
+ * by the number of pixels in each image: large images will be adjusted less
184
+ * than small images.
185
+ *
186
+ * Balancing is useful for mosaicing frames from photographic or video sources
187
+ * where exact colour control is impossible and exposure varies from frame to
188
+ * frame. Balancing is only allowed for uncoded uchar images.
189
+ *
190
+ * The <i>mwidth</i> parameter sets the maximum blend width, see Image#lrmerge.
191
+ */
192
+
193
+ VALUE
194
+ img_lrmosaic(int argc, VALUE *argv, VALUE obj)
195
+ {
196
+ VALUE obj2, bandno, xref, yref, xsec, ysec, halfcorrelation_v, halfarea_v,
197
+ balancetype_v, mwidth_v;
198
+ ID balancetype_id;
199
+ int mwidth = -1, halfcorrelation = 5, halfarea = 14, balancetype = 0;
200
+
201
+ rb_scan_args(argc, argv, "64", &obj2, &bandno, &xref, &yref, &xsec, &ysec,
202
+ &halfcorrelation_v, &halfarea_v, &balancetype_v, &mwidth_v);
203
+
204
+ if (!NIL_P(halfcorrelation_v))
205
+ halfcorrelation = NUM2INT(halfcorrelation_v);
206
+
207
+ if (!NIL_P(halfarea_v))
208
+ halfarea = NUM2INT(halfarea_v);
209
+
210
+ if (!NIL_P(balancetype_v)) {
211
+ balancetype_id = SYM2ID(balancetype_v);
212
+ if (balancetype_id == id_match_none) balancetype = 0;
213
+ else if (balancetype_id == id_match_left) balancetype = 1;
214
+ else if (balancetype_id == id_match_right) balancetype = 2;
215
+ else if (balancetype_id == id_match_both) balancetype = 3;
216
+ else
217
+ rb_raise(rb_eArgError, "Balance type must be nil, :match_left, :match_right, or :match_both");
218
+ }
219
+
220
+ if (!NIL_P(mwidth_v))
221
+ mwidth = NUM2INT(mwidth_v);
222
+
223
+ GetImg(obj, data, im);
224
+ GetImg(obj2, data2, im2);
225
+ OutImg2(obj, obj2, new, data_new, im_new);
226
+
227
+ if (im_lrmosaic(im, im2, im_new, NUM2INT(bandno), NUM2INT(xref),
228
+ NUM2INT(yref), NUM2INT(xsec), NUM2INT(ysec), NUM2INT(halfcorrelation),
229
+ NUM2INT(halfarea), NUM2INT(balancetype), NUM2INT(mwidth)))
230
+ vips_lib_error();
231
+
232
+ return new;
233
+ }
234
+
235
+ /*
236
+ * call-seq:
237
+ * im.tbmosaic(other_image, band, xref, yref, xsec, ysec,
238
+ * halfcorrelation=5, halfarea=14 [,balancetype] [,mheight]) -> image
239
+ *
240
+ * Mosaic *self* and <i>other_image</i> top-bottom.
241
+ *
242
+ * See Image#lrmosaic .
243
+ */
244
+
245
+ VALUE
246
+ img_tbmosaic(int argc, VALUE *argv, VALUE obj)
247
+ {
248
+ VALUE obj2, bandno, xref, yref, xsec, ysec, halfcorrelation_v, halfarea_v,
249
+ balancetype_v, mwidth_v;
250
+ ID balancetype_id;
251
+ int mwidth = -1, halfcorrelation = 5, halfarea = 14, balancetype = 0;
252
+
253
+ rb_scan_args(argc, argv, "64", &obj2, &bandno, &xref, &yref, &xsec, &ysec,
254
+ &halfcorrelation_v, &halfarea_v, &balancetype_v, &mwidth_v);
255
+
256
+ if (!NIL_P(halfcorrelation_v))
257
+ halfcorrelation = NUM2INT(halfcorrelation_v);
258
+
259
+ if (!NIL_P(halfarea_v))
260
+ halfarea = NUM2INT(halfarea_v);
261
+
262
+ if (!NIL_P(balancetype_v)) {
263
+ balancetype_id = SYM2ID(balancetype_v);
264
+
265
+ if (balancetype_id == id_match_left) balancetype = 1;
266
+ else if (balancetype_id == id_match_right) balancetype = 2;
267
+ else if (balancetype_id == id_match_both) balancetype = 3;
268
+ else
269
+ rb_raise(rb_eArgError, "Balance type must be nil, :match_left, :match_right, or :match_both");
270
+ }
271
+
272
+ if (!NIL_P(mwidth_v))
273
+ mwidth = NUM2INT(mwidth_v);
274
+
275
+ GetImg(obj, data, im);
276
+ GetImg(obj2, data2, im2);
277
+ OutImg2(obj, obj2, new, data_new, im_new);
278
+
279
+ if (im_tbmosaic(im, im2, im_new, NUM2INT(bandno), NUM2INT(xref),
280
+ NUM2INT(yref), NUM2INT(xsec), NUM2INT(ysec), halfcorrelation, halfarea,
281
+ balancetype, mwidth))
282
+ vips_lib_error();
283
+
284
+ return new;
285
+ }
286
+
287
+ /*
288
+ * call-seq:
289
+ * im.lrmosaic1(other_image, band, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2,
290
+ * halfcorrelation=5, halfarea=14 [,balancetype] [,mwidth]) -> image
291
+ *
292
+ * 1st order left-right mosaic.
293
+ */
294
+
295
+ VALUE
296
+ img_lrmosaic1(int argc, VALUE *argv, VALUE obj)
297
+ {
298
+ VALUE obj2, bandno, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2,
299
+ halfcorrelation_v, halfarea_v, balancetype_v, mwidth_v;
300
+ ID balancetype_id;
301
+ int mwidth = -1, halfcorrelation = 5, halfarea = 14, balancetype = 0;
302
+
303
+ rb_scan_args(argc, argv, "95", &obj2, &bandno, &xr1, &yr1, &xs1, &ys1, &xr2,
304
+ &yr2, &xs2, &ys2, &halfcorrelation_v, &halfarea_v, &balancetype_v,
305
+ &mwidth_v);
306
+
307
+ if (argc < 10)
308
+ rb_raise(rb_eArgError, "Need at least 10 arguments.");
309
+
310
+ if (!NIL_P(halfcorrelation_v))
311
+ halfcorrelation = NUM2INT(halfcorrelation_v);
312
+
313
+ if (!NIL_P(halfarea_v))
314
+ halfarea = NUM2INT(halfarea_v);
315
+
316
+ if (!NIL_P(balancetype_v)) {
317
+ balancetype_id = SYM2ID(balancetype_v);
318
+
319
+ if (balancetype_id == id_match_left) balancetype = 1;
320
+ else if (balancetype_id == id_match_right) balancetype = 2;
321
+ else if (balancetype_id == id_match_both) balancetype = 3;
322
+ else
323
+ rb_raise(rb_eArgError, "Balance type must be nil, :match_left, :match_right, or :match_both");
324
+ }
325
+
326
+ if (!NIL_P(mwidth_v))
327
+ mwidth = NUM2INT(mwidth_v);
328
+
329
+ GetImg(obj, data, im);
330
+ GetImg(obj2, data2, im2);
331
+ OutImg2(obj, obj2, new, data_new, im_new);
332
+
333
+ if (im_lrmosaic1(im, im2, im_new, NUM2INT(bandno), NUM2INT(xr1),
334
+ NUM2INT(yr1), NUM2INT(xs1), NUM2INT(ys1), NUM2INT(xr2), NUM2INT(yr2),
335
+ NUM2INT(xs2), NUM2INT(ys2), halfcorrelation, halfarea, balancetype,
336
+ mwidth))
337
+ vips_lib_error();
338
+
339
+ return new;
340
+ }
341
+
342
+ /*
343
+ * call-seq:
344
+ * im.tbmosaic1(other_image, band, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2,
345
+ * halfcorrelation=5, halfarea=14 [,balancetype] [,mheight]) -> image
346
+ *
347
+ * 1st order top-bottom mosaic.
348
+ */
349
+
350
+ VALUE
351
+ img_tbmosaic1(int argc, VALUE *argv, VALUE obj)
352
+ {
353
+ VALUE obj2, bandno, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2,
354
+ halfcorrelation_v, halfarea_v, balancetype_v, mwidth_v;
355
+ ID balancetype_id;
356
+ int mwidth = -1, halfcorrelation = 5, halfarea = 14, balancetype = 0;
357
+
358
+ rb_scan_args(argc, argv, "95", &obj2, &bandno, &xr1, &yr1, &xs1, &ys1, &xr2,
359
+ &yr2, &xs2, &ys2, &halfcorrelation_v, &halfarea_v, &balancetype_v,
360
+ &mwidth_v);
361
+
362
+ if (argc < 10)
363
+ rb_raise(rb_eArgError, "Need at least 10 arguments.");
364
+
365
+ if (!NIL_P(halfcorrelation_v))
366
+ halfcorrelation = NUM2INT(halfcorrelation_v);
367
+
368
+ if (!NIL_P(halfarea_v))
369
+ halfarea = NUM2INT(halfarea_v);
370
+
371
+ if (!NIL_P(balancetype_v)) {
372
+ balancetype_id = SYM2ID(balancetype_v);
373
+
374
+ if (balancetype_id == id_match_left) balancetype = 1;
375
+ else if (balancetype_id == id_match_right) balancetype = 2;
376
+ else if (balancetype_id == id_match_both) balancetype = 3;
377
+ else
378
+ rb_raise(rb_eArgError, "Balance type must be nil, :match_left, :match_right, or :match_both");
379
+ }
380
+
381
+ if (!NIL_P(mwidth_v))
382
+ mwidth = NUM2INT(mwidth_v);
383
+
384
+ GetImg(obj, data, im);
385
+ GetImg(obj2, data2, im2);
386
+ OutImg2(obj, obj2, new, data_new, im_new);
387
+
388
+ if (im_tbmosaic1(im, im2, im_new, NUM2INT(bandno), NUM2INT(xr1),
389
+ NUM2INT(yr1), NUM2INT(xs1), NUM2INT(ys1), NUM2INT(xr2), NUM2INT(yr2),
390
+ NUM2INT(xs2), NUM2INT(ys2), halfcorrelation, halfarea, balancetype,
391
+ mwidth))
392
+ vips_lib_error();
393
+
394
+ return new;
395
+ }
396
+
397
+ /*
398
+ * call-seq:
399
+ * im.global_balance(gamma) -> image
400
+ *
401
+ * Takes an image assembled with the mosaicing functions, take it apart, and
402
+ * reassemble it, globally optimising the image balance. This is useful for
403
+ * assembling image mosaics from sources where the exposure is uncontrolled and
404
+ * may vary from tile to tile --- such as video, or photographic sources.
405
+ *
406
+ * The function finds a set of factors, one for each of the input images, and
407
+ * scales each image by its factor before reassembling. The factors are chosen
408
+ * so as to minimise the average grey-level difference between neighboring
409
+ * images at their overlaps. Trivial overlaps (where the width and height of
410
+ * the overlap are both less than 20 pixels) are ignored.
411
+ *
412
+ * The <i>gamma</i> parameter is the gamma of the image input system. It is
413
+ * used during brightness adjustment. Set to 1.0 to disable gamma, to 1.6 for a
414
+ * typical IR vidicon camera, or 2.3 for a typical video camera.
415
+ *
416
+ * It relies on information left by the mosaicing functions in ".desc" files.
417
+ * If the ".desc" file of the input image has been corrupted, or is strangely
418
+ * complicated, or if any of the original input images have been moved or
419
+ * deleted, the function can fail.
420
+ *
421
+ * The function will fail for mosaics larger than about 7 by 7 frames, since it
422
+ * will run out of file descriptors (UNIX sets a limit of 256 per process). To
423
+ * balance larger mosaics, just assemble them in 7x7 sections, balancing and
424
+ * saving each part in turn, before loading, assembling and balancing the final
425
+ * image. The function can also fail if there are significant mosaicing errors.
426
+ */
427
+
428
+ VALUE
429
+ img_global_balance(VALUE obj, VALUE gamma)
430
+ {
431
+ GetImg(obj, data, im);
432
+ OutImg(obj, new, data_new, im_new);
433
+
434
+ if (im_global_balance(im, im_new, NUM2DBL(gamma)))
435
+ vips_lib_error();
436
+
437
+ return new;
438
+ }
439
+
440
+ /*
441
+ * call-seq:
442
+ * im.global_balancef(gamma) -> image
443
+ *
444
+ * Works as Image#global_balance, but outputs a float rather than a uchar
445
+ * image. This lets you adjust the range of the image manually, if the
446
+ * automatically-found scales are causing burn-out.
447
+ */
448
+
449
+ VALUE
450
+ img_global_balancef(VALUE obj, VALUE gamma)
451
+ {
452
+ GetImg(obj, data, im);
453
+ OutImg(obj, new, data_new, im_new);
454
+
455
+ if (im_global_balancef(im, im_new, NUM2DBL(gamma)))
456
+ vips_lib_error();
457
+
458
+ return new;
459
+ }
460
+
461
+ /*
462
+ * call-seq:
463
+ * im.correl(other_image, xref, yref, xsec, ysec, hwindowsize,
464
+ * hsearchsize) -> correlation, x, y
465
+ *
466
+ * Find position of <i>other_image</i> within *self*. Search around point
467
+ * <i>xsec</i>, <i>ysec</i> for the best match for the area around <i>xref</i>,
468
+ * <i>yref</i>. Search an area of size <i>hsearchsize</i> for an of size
469
+ * <i>hwindowsize</i>.
470
+ *
471
+ * Return a new value for xsec, ysec and the correlation at that point.
472
+ */
473
+
474
+ VALUE
475
+ img_correl(VALUE obj, VALUE obj2, VALUE xref, VALUE yref, VALUE xsec,
476
+ VALUE ysec, VALUE hwindowsize, VALUE hsearchsize)
477
+ {
478
+ int x, y;
479
+ double correlation;
480
+ GetImg(obj, data, im);
481
+ GetImg(obj2, data2, im2);
482
+
483
+ if (im_correl(im, im2, NUM2INT(xref), NUM2INT(yref), NUM2INT(xsec),
484
+ NUM2INT(ysec), NUM2INT(hwindowsize), NUM2INT(hsearchsize), &correlation,
485
+ &x, &y))
486
+ vips_lib_error();
487
+
488
+ return rb_ary_new3(3, DBL2NUM(correlation), INT2NUM(x), INT2NUM(y));
489
+ }
490
+
491
+ /*
492
+ * call-seq:
493
+ * im.align_bands -> image
494
+ *
495
+ * Brute force align the bands of an image.
496
+ */
497
+
498
+ VALUE
499
+ img_align_bands(VALUE obj)
500
+ {
501
+ RUBY_VIPS_UNARY(im_align_bands);
502
+ }
503
+
504
+ /*
505
+ * call-seq:
506
+ * im.maxpos_subpel -> x, y
507
+ *
508
+ * This function implements "Extension of Phase Correlation to Subpixel
509
+ * Registration" by H. Foroosh, from IEEE trans. Im. Proc. 11(3), 2002.
510
+ *
511
+ * If the best three matches in the correlation are aranged:
512
+ *
513
+ * 02 or 01
514
+ * 1 2
515
+ *
516
+ * then we return a subpixel match using the ratio of correlations in the
517
+ * vertical and horizontal dimension.
518
+ *
519
+ * ( xs[0], ys[0] ) is the best integer alignment
520
+ * ( xs[ use_x ], ys[ use_x ] ) is equal in y and (+/-)1 off in x
521
+ * ( xs[ use_y ], ys[ use_y ] ) is equal in x and (+/-)1 off in y
522
+ *
523
+ * Alternatively if the best four matches in the correlation are aranged in
524
+ * a square:
525
+ *
526
+ * 01 or 03 or 02 or 03
527
+ * 32 12 31 21
528
+ *
529
+ * then we return a subpixel match weighting with the sum the two on each
530
+ * side over the sum of all four, but only if all four of them are very
531
+ * close to the best, and the fifth is nowhere near.
532
+ *
533
+ * This alternative method is not described by Foroosh, but is often the
534
+ * case where the match is close to n-and-a-half pixels in both dimensions.
535
+ */
536
+
537
+ VALUE
538
+ img_maxpos_subpel(VALUE obj)
539
+ {
540
+ double x, y;
541
+ GetImg(obj, data, im);
542
+
543
+ if (im_maxpos_subpel(im, &x, &y))
544
+ vips_lib_error();
545
+
546
+ return rb_ary_new3(2, DBL2NUM(x), INT2NUM(y));
547
+ }
548
+
549
+ void
550
+ init_Image_mosaicing(void)
551
+ {
552
+ id_match_none = rb_intern("match_none");
553
+ id_match_left = rb_intern("match_left");
554
+ id_match_right = rb_intern("match_right");
555
+ id_match_both = rb_intern("match_both");
556
+ }