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.
- data/CHANGELOG.md +15 -0
- data/Gemfile.lock +31 -0
- data/LICENSE +20 -0
- data/README.md +96 -0
- data/TODO +18 -0
- data/ext/extconf.rb +10 -0
- data/ext/header.c +440 -0
- data/ext/header.h +8 -0
- data/ext/image.c +639 -0
- data/ext/image.h +71 -0
- data/ext/image_arithmetic.c +940 -0
- data/ext/image_arithmetic.h +38 -0
- data/ext/image_boolean.c +302 -0
- data/ext/image_boolean.h +8 -0
- data/ext/image_colour.c +593 -0
- data/ext/image_colour.h +36 -0
- data/ext/image_conversion.c +863 -0
- data/ext/image_conversion.h +37 -0
- data/ext/image_convolution.c +371 -0
- data/ext/image_convolution.h +13 -0
- data/ext/image_freq_filt.c +742 -0
- data/ext/image_freq_filt.h +27 -0
- data/ext/image_histograms_lut.c +646 -0
- data/ext/image_histograms_lut.h +28 -0
- data/ext/image_morphology.c +330 -0
- data/ext/image_morphology.h +13 -0
- data/ext/image_mosaicing.c +556 -0
- data/ext/image_mosaicing.h +14 -0
- data/ext/image_relational.c +386 -0
- data/ext/image_relational.h +8 -0
- data/ext/image_resample.c +253 -0
- data/ext/image_resample.h +9 -0
- data/ext/interpolator.c +106 -0
- data/ext/interpolator.h +6 -0
- data/ext/mask.c +349 -0
- data/ext/mask.h +17 -0
- data/ext/reader.c +315 -0
- data/ext/ruby_vips.c +131 -0
- data/ext/ruby_vips.h +26 -0
- data/ext/writer.c +346 -0
- data/lib/vips.rb +7 -0
- data/lib/vips/reader.rb +183 -0
- data/lib/vips/version.rb +3 -0
- data/lib/vips/writer.rb +275 -0
- data/ruby-vips.gemspec +93 -0
- metadata +163 -0
@@ -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
|
+
}
|