ruby-vips 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }