libidx
|
00001 /*************************************************************************** 00002 * Copyright (C) 2008 by Yann LeCun and Pierre Sermanet * 00003 * yann@cs.nyu.edu, pierre.sermanet@gmail.com * 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are met: 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Redistribution under a license not approved by the Open Source 00014 * Initiative (http://www.opensource.org) must display the 00015 * following acknowledgement in all advertising material: 00016 * This product includes software developed at the Courant 00017 * Institute of Mathematical Sciences (http://cims.nyu.edu). 00018 * * The names of the authors may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00023 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00024 * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY 00025 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00026 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00027 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00028 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 ***************************************************************************/ 00032 00033 #ifndef IMAGE_HPP_ 00034 #define IMAGE_HPP_ 00035 00036 #include <math.h> 00037 #include <stdlib.h> 00038 00039 using namespace std; 00040 00041 #define BLK_AVRG(nlin, ncol) { \ 00042 int k,l; int norm = ncol * nlin; \ 00043 int acc0=0, acc1=0, acc2=0; \ 00044 for (k=0; k<nlin; k++) { \ 00045 register T *pinptr = pin+k*in_mod0; \ 00046 for (l=0; l<ncol; l++) { \ 00047 acc0 += (int) pinptr[0]; \ 00048 acc1 += (int) pinptr[1]; \ 00049 acc2 += (int) pinptr[2]; \ 00050 pinptr += in_mod1; }} \ 00051 pout[0] = acc0 / norm;pout[1] = acc1 / norm;pout[2] = acc2 / norm;} 00052 00053 namespace ebl { 00054 00055 template <typename T> 00056 idx<T> image_crop(idx<T> &in, int x, int y, int w, int h) { 00057 idx<T> bla = in.narrow(0, h, y).narrow(1, w, x); 00058 idx<T> bla3(bla.dim(0), bla.dim(1), bla.order() < 3 ? -1 : bla.dim(2)); 00059 idx_copy(bla, bla3); 00060 return bla3; 00061 } 00062 00064 // resize 00065 00066 template <typename T> 00067 idx<T> image_resize(idx<T> &image, double h, double w, int mode, 00068 rect<int> *iregion_, rect<int> *oregion_) { 00069 if (image.order() < 2) eblerror("image must have at least an order of 2."); 00070 // iregion is optional, set it to entire image if not given 00071 rect<int> iregion = rect<int>(0, 0, image.dim(0), image.dim(1)); 00072 if (iregion_) 00073 iregion = *iregion_; 00074 double ratioh = h / iregion.height; 00075 double ratiow = w / iregion.width; 00076 double ratiomin = min(ratiow, ratioh); 00077 // if data is not contiguous, copy it to a contiguous buffer 00078 idx<T> contim(image); 00079 if (!image.contiguousp()) { 00080 idxdim d(image.spec); 00081 idx<T> tmp(d); 00082 idx_copy(image, tmp); 00083 contim = tmp; 00084 } 00085 int imw = (int) contim.dim(1); 00086 int imh = (int) contim.dim(0); 00087 // int rw = 0, rh = 0; 00088 double ow = 0, oh = 0; 00089 if ((imw == 0) || (imh == 0)) 00090 eblerror("cannot have dimensions of size 0" 00091 << " while trying to resize image " << image 00092 << " to " << h << "x" << w << " with mode " << mode); 00093 // determine actual size of output image 00094 if ((0 == w) || (0 == h)) { 00095 if (0 == w) { 00096 if (0 == h) 00097 eblerror("desired width and height cannot be both zero" 00098 << " while trying to resize image " << image 00099 << " to " << h << "x" << w << " with mode " << mode) 00100 else w = max(1, (int) (imw * (w / imh))); 00101 } else h = max(1, (int) (imh * (h / imw))); 00102 } 00103 if ((mode == 0) || (mode == 3)) { // preserve aspect ratio 00104 ratiow = ratiomin; 00105 ratioh = ratiomin; 00106 } 00107 else if (mode == 1) { // possibly modify aspect ratio 00108 // ratiow = w; //ratiow; 00109 // ratioh = h; //ratioh; 00110 } 00111 else if (mode == 2) { // use w and h as scaling ratios 00112 ratiow = w; 00113 ratioh = h; 00114 } 00115 else 00116 eblerror("illegal mode or desired dimensions" 00117 << " while trying to resize image " << image 00118 << " to " << h << "x" << w << " with mode " << mode); 00119 // output sizes of entire image 00120 if (iregion_ || (mode == 2) || (mode == 0) || (mode == 3)) { 00121 ow = rint(max(1.0, imw * ratiow)); 00122 oh = rint(max(1.0, imh * ratioh)); 00123 } else { 00124 ow = w;//max(1.0, imw * ratiow); 00125 oh = h;//max(1.0, imh * ratioh); 00126 } 00127 // // compute closest integer subsampling ratio 00128 // rw = std::max(1, (int) (1 / ratiow)); 00129 // rh = std::max(1, (int) (1 / ratioh)); 00130 // compute output region 00131 rect<int> oregion((uint)(iregion.h0 * ratioh), 00132 (uint)(iregion.w0 * ratiow), 00133 (uint)(iregion.height * ratioh), 00134 (uint)(iregion.width * ratiow)); 00135 if (oregion_) 00136 *oregion_ = oregion; 00137 // TODO: why is this useful? for ubyte images? 00138 // subsample by integer ratio if necessary 00139 // if ((rh > 1) || (rw > 1)) { 00140 // contim = image_subsample(contim, rh, rw); 00141 // imw = contim.dim(1); 00142 // imh = contim.dim(0); 00143 // } 00144 // resample from subsampled image with bilinear interpolation 00145 idx<T> rez((intg) oh, (intg) ow, (contim.order() == 3) ? contim.dim(2) : 1); 00146 idx<T> bg(4); 00147 idx_clear(bg); 00148 // the 0.5 thingies are necessary because warp-bilin interprets 00149 // integer coordinates as being at the center of each pixel. 00150 float x1 = (float) -0.5, y1 = (float) -0.5; 00151 float x3 = (float) imw - (float) 0.5, y3 = (float) imh - (float) 0.5; 00152 float p1 = (float) -0.5, q1 = (float) -0.5; 00153 float p3 = (float) ow - (float) 0.5, q3 = (float) oh - (float) 0.5; 00154 image_warp_quad(contim, rez, bg, 1, x1, y1, x3, y1, x3, y3, x1, y3, 00155 p1, q1, p3, q3); 00156 if (contim.order() == 2) 00157 return rez.select(2, 0); 00158 // copy preserved ratio output in the middle of the wanted out size 00159 if ((mode == 3) && ((rez.dim(0) != h) || (rez.dim(1) != w))) { 00160 idx<T> out((intg) h, (intg) w, rez.dim(2)); 00161 idx_clear(out); 00162 idx<T> tmp = out.narrow(0, rez.dim(0), (intg) ((h - rez.dim(0)) / 2)); 00163 tmp = tmp.narrow(1, rez.dim(1), (intg) ((w - rez.dim(1)) / 2)); 00164 idx_copy(rez, tmp); 00165 rez = out; 00166 } 00167 return rez; 00168 } 00169 00170 template <typename T> 00171 idx<T> image_gaussian_resize(idx<T> &im, double oheight, double owidth, 00172 uint mode, rect<int> *iregion_, 00173 rect<int> *oregion) { 00174 // only accept 2D or 3D images 00175 if ((im.order() != 2) && (im.order() != 3)) { 00176 cerr << "illegal order: " << im << endl; 00177 eblerror("unexpected image format"); 00178 } 00179 // iregion is optional, set it to entire image if not given 00180 rect<uint> iregion(0, 0, im.dim(0), im.dim(1)); 00181 if (iregion_) 00182 iregion = *iregion_; 00183 // if region's height and width already have the correct size, return 00184 if ((iregion.height == oheight) && (iregion.width <= owidth)) { 00185 if (oregion) 00186 *oregion = iregion; 00187 return im; 00188 } 00189 // gaussian resize 00190 gaussian_pyramid<T> gp; 00191 rect<uint> outr; 00192 idx<T> rim; 00194 if ((iregion.width > owidth) || (iregion.height > oheight)) { // reduce 00195 rect<uint> exact_inr; 00196 uint reductions; 00197 00198 switch (mode) { 00199 case 0: // keep aspect ratio 00200 // compute biggest down/up-sizing factor. do not use a double variable 00201 // to compute ratio, compute it directly. somehow the results are 00202 // more precise without the variable. 00203 if (oheight / (double) iregion.height < 00204 owidth / (double) iregion.width) 00205 outr = rect<uint> 00206 ((uint)(iregion.h0 * oheight / (double)iregion.height), 00207 (uint)(iregion.w0 * oheight / (double)iregion.height), 00208 (uint)(iregion.height * oheight / (double)iregion.height), 00209 (uint)(iregion.width * oheight / (double)iregion.height)); 00210 else 00211 outr = rect<uint> 00212 ((uint) (iregion.h0 * owidth / (double)iregion.width), 00213 (uint) (iregion.w0 * owidth / (double)iregion.width), 00214 (uint) (iregion.height * owidth / (double)iregion.width), 00215 (uint) (iregion.width * owidth / (double)iregion.width)); 00216 reductions = gp.count_reductions_exact(iregion, outr, exact_inr); 00217 break ; 00218 default: 00219 eblerror("unsupported mode " << mode); 00220 } 00221 // bilinear resize at closest resolution to current resolution 00222 double exact_imh = (exact_inr.height / (double) iregion.height) 00223 * (double) im.dim(0); 00224 double exact_imw = (exact_inr.width / (double) iregion.width) 00225 * (double) im.dim(1); 00226 rim = image_resize(im, exact_imh, exact_imw, 1); 00227 // now gaussian resize to exact target size 00228 rim = rim.shift_dim(2, 0); 00229 rim = gp.reduce(rim, reductions); 00230 rim = rim.shift_dim(0, 2); 00232 } else { // expand 00233 uint expansions; 00234 uint imax, omax, dist; 00235 rect<uint> outr2; 00236 // select biggest side 00237 if (iregion.height > iregion.width) { 00238 imax = iregion.height; 00239 omax = (uint) oheight; 00240 } else { 00241 imax = iregion.width; 00242 omax = (uint) owidth; 00243 } 00244 // count how many expansions necessary 00245 switch (mode) { 00246 case 0: // keep aspect ratio 00247 expansions = gp.count_expansions(imax, omax, dist); 00248 break ; 00249 default: 00250 eblerror("unsupported mode"); 00251 } 00252 // now gaussian resize to exact target size 00253 rim = im.shift_dim(2, 0); 00254 rim = gp.expand(rim, expansions); 00255 outr2 = gp.expand_rect(iregion, expansions); 00256 // bilinear resize to target resolution 00257 rim = rim.shift_dim(0, 2); 00258 // TODO: casting to int correct? 00259 rect<int> oor2, oor; 00260 oor2 = outr2; oor = outr; 00261 rim = image_resize(rim, oheight, owidth, mode, &oor2, &oor); 00262 outr2 = oor2; outr = oor; 00263 } 00265 if (oregion) 00266 *oregion = outr; 00267 return rim; 00268 } 00269 00270 template <typename T> 00271 idx<T> image_mean_resize(idx<T> &im, double oheight, double owidth, 00272 uint mode, rect<int> *iregion_, rect<int> *oregion) { 00273 // only accept 2D or 3D images 00274 if ((im.order() != 2) && (im.order() != 3)) { 00275 cerr << "illegal order: " << im << endl; 00276 eblerror("unexpected image format"); 00277 } 00278 if (oheight == 0 || owidth == 0) { 00279 cerr << "oheight: " << oheight << " owidth " << owidth << endl; 00280 eblerror("illegal resize image to zero"); 00281 } 00282 // iregion is optional, set it to entire image if not given 00283 rect<int> iregion(0, 0, im.dim(0), im.dim(1)); 00284 if (iregion_) 00285 iregion = *iregion_; 00286 // if region's height and width already have the correct size, return 00287 if ((iregion.height == oheight) && (iregion.width <= owidth)) { 00288 if (oregion) 00289 *oregion = iregion; 00290 return im; 00291 } 00292 // mean resize 00293 rect<int> outr, inr; 00294 idx<T> rim, out; 00296 if ((iregion.width > owidth) || (iregion.height > oheight)) { // reduce 00297 switch (mode) { 00298 case 0: // keep aspect ratio 00299 // compute biggest down/up-sizing factor. do not use a double variable 00300 // to compute ratio, compute it directly. somehow the results are 00301 // more precise without the variable. 00302 if (oheight / (double) iregion.height < 00303 owidth / (double) iregion.width) { 00304 outr = 00305 rect<int>((uint)(iregion.h0 * oheight / (double)iregion.height), 00306 (uint)(iregion.w0 * oheight / (double)iregion.height), 00307 (uint)(iregion.height* oheight / (double)iregion.height), 00308 (uint)(iregion.width * oheight / (double)iregion.height)); 00309 inr = 00310 rect<int>(0, 0, 00311 (uint) (im.dim(0) * oheight / (double)iregion.height), 00312 (uint) (im.dim(1) * oheight / (double)iregion.height)); 00313 } else { // use width factor (smaller factor) 00314 outr = 00315 rect<int>((uint) (iregion.h0 * owidth / (double)iregion.width), 00316 (uint) (iregion.w0 * owidth / (double)iregion.width), 00317 (uint) (iregion.height * owidth / (double)iregion.width), 00318 (uint) (iregion.width * owidth / (double)iregion.width)); 00319 inr = 00320 rect<int>(0, 0, 00321 (uint) (im.dim(0) * owidth / (double)iregion.width), 00322 (uint) (im.dim(1) * owidth / (double)iregion.width)); 00323 } 00324 break ; 00325 default: 00326 eblerror("unsupported mode"); 00327 } 00328 // find closest multiple of target area that is smaller than input area 00329 // (smaller to avoid upsampling) 00330 uint fact = (std::min)((uint)floor(iregion.height / (float) outr.height), 00331 (uint)floor(iregion.width / (float) outr.width)); 00332 if (fact == 0) // no multiple smaller than input, go straight for bilinear 00333 return image_resize(im, oheight, owidth, mode, iregion_, oregion); 00334 // bilinear resize at closest resolution to current resolution 00335 rim = image_resize(im, inr.height * fact, inr.width * fact, 1); 00336 // add extra padding around original image if it's not a multiple of fact 00337 // rect rrim(0, 0, rim.dim(0), rim.dim(1)); 00338 // rect cropped; 00339 // uint hmod = rim.dim(0) % fact; 00340 // if (hmod) hmod = fact - hmod; 00341 // uint wmod = rim.dim(1) % fact; 00342 // if (wmod) wmod = fact - wmod; 00343 // idx<T> rimf = image_region_to_rect(rim, rrim, rim.dim(0) + hmod, 00344 // rim.dim(1) + wmod, cropped); 00345 // allocate output 00346 out = idx<T>(rim.dim(0) / fact, rim.dim(1) / fact, rim.dim(2)); 00347 idx<T> tmp, tmpout; 00348 uint i = 0, j = 0; 00349 // now mean resize to exact target size 00350 idx_bloop1(ou, out, T) { // loop on output rows 00351 idx_bloop1(o, ou, T) { // loop on output cols 00352 tmp = rim.narrow(0, fact, i * fact); 00353 tmp = tmp.narrow(1, fact, j * fact); 00354 idx_eloop2(layer, tmp, T, olayer, o, T) { // loop on each layer 00355 olayer.set(idx_mean(layer)); 00356 } 00357 j++; 00358 } 00359 i++; 00360 j = 0; 00361 } 00363 } else { // expansion: return bilinear resizing 00364 return image_resize(im, oheight, owidth, mode, iregion_, oregion); 00365 } 00367 if (oregion) 00368 *oregion = outr; 00369 return out; 00370 } 00371 00372 template <typename T> 00373 idx<T> image_region_to_square(idx<T> &im, const rect<uint> &r) { 00374 // TODO: check expecting 2D or 3D 00375 // TODO: check that rectangle is within image 00376 uint sz = std::max(r.height, r.width); 00377 idxdim d(im); 00378 uint dh = 0; 00379 uint dw = 1; 00380 d.setdim(dh, sz); 00381 d.setdim(dw, sz); 00382 idx<T> res(d); 00383 uint tmp_h = MIN(sz, r.height); 00384 uint tmp_w = MIN(sz, r.width); 00385 idx<T> tmpres = res.narrow(dh, tmp_h, res.dim(dh) / 2 - tmp_h / 2); 00386 tmpres = tmpres.narrow(dw, tmp_w, res.dim(dw) / 2 - tmp_w / 2); 00387 idx<T> tmpim = im.narrow(dh, tmp_h, r.h0); 00388 tmpim = tmpim.narrow(dw, tmp_w, r.w0); 00389 idx_clear(res); 00390 idx_copy(tmpim, tmpres); 00391 return res; 00392 } 00393 00394 template <typename T> 00395 idx<ubyte> image_to_ubyte(idx<T> &im, double zoomh, double zoomw, 00396 T minv, T maxv) { 00397 // check the order and dimensions 00398 if ((im.order() < 2) || (im.order() > 3) || 00399 ((im.order() == 3) && (im.dim(2) != 1) && (im.dim(2) != 3))) { 00400 eblerror("expected a 2D idx or a 3D idx with 1 or 3 channels only " 00401 << "but got: " << im); 00402 } 00403 // create a copy 00404 idxdim d(im); 00405 idx<T> im1(d); 00406 idx_copy(im, im1); 00407 // check zoom factor 00408 if ((zoomw <= 0.0) || (zoomh <= 0.0)) 00409 eblerror("cannot zoom by a factor <= 0.0"); 00410 // check minv maxv 00411 if (minv > maxv) { 00412 T tmp = minv; 00413 minv = maxv; 00414 maxv = tmp; 00415 } 00416 // if minv and maxv are defaults, take actual min and max of the image 00417 if (minv == maxv) { 00418 minv = idx_min(im1); 00419 maxv = idx_max(im1); 00420 } 00421 if (minv == maxv) { // if minv still == maxv, use 0 and 1 00422 minv = 0; 00423 maxv = 1; 00424 } 00425 // create target image 00426 int newh = (int) (im1.dim(0) * zoomh); 00427 int neww = (int) (im1.dim(1) * zoomw); 00428 idx<T> im2 = ((newh == im1.dim(0)) && (neww == im1.dim(1))) ? 00429 im1 : image_resize(im1, newh, neww); 00430 d.setdim(0, newh); 00431 d.setdim(1, neww); 00432 idx<ubyte> image(d); 00433 // map values between minv and maxv to 0 .. 255 00434 idx_subc_bounded(im2, minv, im2); 00435 idx_dotc_bounded(im2, (T) (255.0 / (double) (maxv - minv)), im2); 00436 idx_copy_clip(im2, image); 00437 return image; 00438 } 00439 00440 template <typename T> 00441 idx<T> image_subsample_grayscale(idx<T> &in, int nlin, int ncol) { 00442 intg h = in.dim(0); 00443 intg w = in.dim(1); 00444 intg nh = h / nlin; 00445 intg nw = w / ncol; 00446 idx<T> out(nh, nw); 00447 if ((nlin == 1) && (ncol == 1)) { 00448 idx_copy(in, out); 00449 return out; 00450 } 00451 idx<T> inp = in.narrow(0, nlin * nh, 0); 00452 inp = inp.narrow(1, ncol * nw, 0); 00453 T *_idx2loopc1, *pin; 00454 T *_idx2loopc2, *pout; 00455 int i, _imax = out.dim(0); 00456 int j, _jmax = out.dim(1); 00457 int _imat1_m0 = inp.mod(0); 00458 int _imat1_m1 = inp.mod(1); 00459 int _imat2_m0 = out.mod(0); 00460 int _imat2_m1 = out.mod(1); 00461 int pin_incr = ncol * _imat1_m1; 00462 int norm = ncol * nlin; 00463 register int acc0; 00464 register int k,l; 00465 register T *pinptr; 00466 register int pinptr_incr = _imat1_m0 - ncol* _imat1_m1; 00467 _idx2loopc1 = inp.idx_ptr(); 00468 _idx2loopc2 = out.idx_ptr(); 00469 for (i = 0; i < _imax; i++) { 00470 pin = _idx2loopc1; 00471 pout = _idx2loopc2; 00472 for (j = 0; j < _jmax; j++) { 00473 acc0 =0; 00474 pinptr = pin; 00475 for (k=0; k<nlin; k++) { 00476 for (l=0; l<ncol; l++) { 00477 acc0 += (int) pinptr[0]; 00478 pinptr += _imat1_m1; 00479 } 00480 pinptr += pinptr_incr; 00481 } 00482 pout[0] = acc0/norm; 00483 pin += pin_incr; 00484 pout += _imat2_m1; 00485 } 00486 _idx2loopc1 += _imat1_m0 * nlin; 00487 _idx2loopc2 += _imat2_m0; 00488 } 00489 return out; 00490 } 00491 00492 template <typename T> idx<T> image_subsample_rgb(idx<T> &in, int nlin, int ncol) { 00493 intg h = in.dim(0); 00494 intg w = in.dim(1); 00495 intg nh = h / nlin; 00496 intg nw = w / ncol; 00497 idx<T> out(nh, nw, in.dim(2)); 00498 if ((nlin == 1) && (ncol == 1)) { 00499 idx_copy(in, out); 00500 return out; 00501 } 00502 idx<T> inp = in.narrow(0, nlin * nh, 0).narrow(1, ncol * nw, 0); 00503 T *in_line, *pin; 00504 T *out_line, *pout; 00505 int i, _imax = out.dim(0); 00506 int j, _jmax = out.dim(1); 00507 int in_mod0 = inp.mod(0); 00508 int in_mod1 = inp.mod(1); 00509 int out_mod0 = out.mod(0); 00510 int out_mod1 = out.mod(1); 00511 int pin_incr = ncol * in_mod1; 00512 in_line = inp.idx_ptr(); 00513 out_line = out.idx_ptr(); 00514 for (i = 0; i < _imax; i++) { 00515 pin = in_line; 00516 pout = out_line; 00517 for (j = 0; j < _jmax; j++) { 00518 BLK_AVRG(nlin, ncol); 00519 pin += pin_incr; 00520 pout += out_mod1; 00521 } 00522 in_line += in_mod0 * nlin; 00523 out_line += out_mod0; 00524 } 00525 return out; 00526 } 00527 00528 template <typename T> idx<T> image_subsample(idx<T> &in, int nlin, int ncol) { 00529 switch (in.order()) { 00530 case 2: 00531 return image_subsample_grayscale(in, nlin, ncol); 00532 case 3: 00533 return image_subsample_rgb(in, nlin, ncol); 00534 default: 00535 eblerror("image must have at least an order of 2."); 00536 return in; 00537 } 00538 } 00539 00540 template <typename T> 00541 void image_warp_quad(idx<T> &in, idx<T> &out, 00542 idx<T> &background, int mode, 00543 float x1, float y1, float x2, float y2, 00544 float x3, float y3, float x4, float y4, 00545 float p1, float q1, float p3, float q3) { 00546 intg outi = out.dim(0); 00547 intg outj = out.dim(1); 00548 idx<int> dispi(outi, outj); 00549 idx<int> dispj(outi, outj); 00550 compute_bilin_transform<float>(dispi, dispj, x1, y1, x2, y2, x3, y3, 00551 x4, y4, p1, q1, p3, q3); 00552 if (0 == mode) 00553 image_warp_fast(in, out, background.idx_ptr(), dispi, dispj); 00554 else 00555 image_warp(in, out, background, dispi, dispj); 00556 } 00557 00558 00559 template <typename T> 00560 void image_warp(idx<T> &in, idx<T> &out, idx<T> &background, 00561 idx<int> &pi, idx<int> &pj) { 00562 T* pin = in.idx_ptr(); 00563 int indimi = in.dim(0); 00564 int indimj = in.dim(1); 00565 int inmodi = in.mod(0); 00566 int inmodj = in.mod(1); 00567 int ppi, ppj; 00568 { idx_bloop3(lout, out, T, lpi, pi, int, lpj, pj, int) { 00569 { idx_bloop3(llout, lout, T, llpi, lpi, int, llpj, lpj, int) { 00570 ppi = llpi.get(); 00571 ppj = llpj.get(); 00572 image_interpolate_bilin(background.idx_ptr(), pin, indimi, indimj, 00573 inmodi, inmodj, ppi, ppj, llout.idx_ptr(), 00574 (int) out.dim(2)); 00575 }} 00576 }} 00577 } 00578 00579 template <typename T> 00580 void image_warp_fast(idx<T> &in, idx<T> &out, T *background, 00581 idx<int> &pi, idx<int> &pj) { 00582 T* pin = in.idx_ptr(); 00583 int indimi = in.dim(0); 00584 int indimj = in.dim(1); 00585 int inmodi = in.mod(0); 00586 int inmodj = in.mod(1); 00587 int ppi, ppj; 00588 register int li, lj; 00589 register T *inn, *outt; 00590 int outsize = out.dim(2); 00591 { idx_bloop3(lout, out, T, lpi, pi, int, lpj, pj, int) { 00592 { idx_bloop3(llout, lout, T, llpi, lpi, int, llpj, lpj, int) { 00593 outt = llout.idx_ptr(); 00594 ppi = llpi.get(); 00595 ppj = llpj.get(); 00596 li = (ppi+0x7f) >> 16; 00597 lj = (ppj+0x7f) >> 16; 00598 if ((li>=0) && (li<indimi) && (lj>=0) && (lj<indimj)) { 00599 inn = (T*)(pin) + inmodi * li + inmodj * lj; 00600 outt[0] = inn[0]; 00601 if (outsize >= 3) { 00602 outt[1] = inn[1]; 00603 outt[2] = inn[2]; 00604 } 00605 if (outsize >= 4) 00606 outt[3] = inn[3]; 00607 } else { 00608 outt[0] = *(background); 00609 if (outsize >= 3) { 00610 outt[1] = *(background+1); 00611 outt[2] = *(background+2); 00612 } 00613 if (outsize >= 4) 00614 outt[3] = *(background+3); 00615 } 00616 }} 00617 }} 00618 } 00619 00620 template <typename T> 00621 void image_warp_flow(idx<T> &src, idx<T> &dst, idx<float> &flow, 00622 bool bilinear, bool use_bg, T background) { 00623 // dims 00624 int width = src.dim(1); 00625 int height = src.dim(0); 00626 int channels = src.dim(2); 00627 intg *is = src.mod_ptr(); 00628 intg *os = dst.mod_ptr(); 00629 intg *fs = flow.mod_ptr(); 00630 00631 // get raw pointers 00632 T *dst_data = dst.idx_ptr(); 00633 T *src_data = src.idx_ptr(); 00634 float *flow_data = flow.idx_ptr(); 00635 00636 // resample 00637 intg k,x,y; 00638 for (y = 0; y < height; y++) { 00639 for (x = 0; x < width; x++) { 00640 // subpixel position: 00641 float flow_y = flow_data[ 0*fs[0] + y*fs[1] + x*fs[2] ]; 00642 float flow_x = flow_data[ 1*fs[0] + y*fs[1] + x*fs[2] ]; 00643 float iy = y + flow_y; 00644 float ix = x + flow_x; 00645 00646 // when going beyond image's boundaries, use background value 00647 if (use_bg && (ix < 0 || ix >= width || iy < 0 || iy >= height)) { 00648 for (k = 0; k < channels; k++) 00649 dst_data[ y*os[0] + x*os[1] + k*os[2] ] = background; 00650 continue ; 00651 } 00652 00653 // borders 00654 ix = std::max(ix,(float)0); 00655 ix = std::min(ix,(float)(width-1)); 00656 iy = std::max(iy,(float)0); 00657 iy = std::min(iy,(float)(height-1)); 00658 00659 // bilinear? 00660 if (bilinear) { 00661 // 4 nearest neighbors: 00662 int ix_nw = (int) floor(ix); 00663 int iy_nw = (int) floor(iy); 00664 int ix_ne = ix_nw + 1; 00665 int iy_ne = iy_nw; 00666 int ix_sw = ix_nw; 00667 int iy_sw = iy_nw + 1; 00668 int ix_se = ix_nw + 1; 00669 int iy_se = iy_nw + 1; 00670 00671 // get surfaces to each neighbor: 00672 float nw = ((float)(ix_se-ix))*(iy_se-iy); 00673 float ne = ((float)(ix-ix_sw))*(iy_sw-iy); 00674 float sw = ((float)(ix_ne-ix))*(iy-iy_ne); 00675 float se = ((float)(ix-ix_nw))*(iy-iy_nw); 00676 00677 // weighted sum of neighbors: 00678 for (k=0; k<channels; k++) { 00679 dst_data[ k*os[2] + y*os[0] + x*os[1] ] = 00680 src_data[ k*is[2] + iy_nw*is[0] + ix_nw*is[1] ] * nw 00681 + src_data[ k*is[2] + iy_ne*is[0] 00682 + std::min(ix_ne,width-1)*is[1]] * ne 00683 + src_data[ k*is[2] + std::min(iy_sw,height-1)*is[0] 00684 + ix_sw*is[1] ] * sw 00685 + src_data[ k*is[2] + std::min(iy_se,height-1)*is[0] 00686 + std::min(ix_se,width-1)*is[1] ] * se; 00687 } 00688 } else { 00689 // 1 nearest neighbor: 00690 int ix_n = (int) floor(ix+0.5); 00691 int iy_n = (int) floor(iy+0.5); 00692 00693 // weighted sum of neighbors: 00694 for (k = 0; k < channels; k++) 00695 dst_data[ y*os[0] + x*os[1] + k*os[2] ] = 00696 src_data[ iy_n*is[0] + ix_n*is[1] + k*is[2] ]; 00697 } 00698 } 00699 } 00700 } 00701 00702 template <typename T> 00703 void image_interpolate_bilin(T* background, T *pin, int indimi, int indimj, 00704 int inmodi, int inmodj, int ppi, int ppj, 00705 T* out, int outsize) { 00706 int li0, lj0; 00707 register int li1, lj1; 00708 int deltai, ndeltai; 00709 int deltaj, ndeltaj; 00710 register T *pin00; 00711 register T *v00, *v01, *v10, *v11; 00712 li0 = ppi >> 16; 00713 li1 = li0+1; 00714 deltai = ppi & 0x0000ffff; 00715 ndeltai = 0x00010000 - deltai; 00716 lj0 = ppj >> 16; 00717 lj1 = lj0+1; 00718 deltaj = ppj & 0x0000ffff; 00719 ndeltaj = 0x00010000 - deltaj; 00720 pin00 = (T*)(pin) + inmodi * li0 + inmodj * lj0; 00721 if ((li1>0)&&(li1<indimi)) { 00722 if ((lj1>0)&&(lj1<indimj)) { 00723 v00 = (pin00); 00724 v01 = (pin00+inmodj); 00725 v11 = (pin00+inmodi+inmodj); 00726 v10 = (pin00+inmodi); 00727 } else if (lj1==0) { 00728 v00 = background; 00729 v01 = (pin00+inmodj); 00730 v11 = (pin00+inmodi+inmodj); 00731 v10 = background; 00732 } else if (lj1==indimj) { 00733 v00 = (pin00); 00734 v01 = background; 00735 v11 = background; 00736 v10 = (pin00+inmodi); 00737 } else { 00738 v00 = background; 00739 v01 = background; 00740 v11 = background; 00741 v10 = background; 00742 } 00743 } else if (li1==0) { 00744 if ((lj1>0)&&(lj1<indimj)) { 00745 v00 = background; 00746 v01 = background; 00747 v11 = (pin00+inmodi+inmodj); 00748 v10 = (pin00+inmodi); 00749 } else if (lj1==0) { 00750 v00 = background; 00751 v01 = background; 00752 v11 = (pin00+inmodi+inmodj); 00753 v10 = background; 00754 } else if (lj1==indimj) { 00755 v00 = background; 00756 v01 = background; 00757 v11 = background; 00758 v10 = (pin00+inmodi); 00759 } else { 00760 v00 = background; 00761 v01 = background; 00762 v11 = background; 00763 v10 = background; 00764 } 00765 } else if (li1==indimi) { 00766 if ((lj1>0)&&(lj1<indimj)) { 00767 v00 = (pin00); 00768 v01 = (pin00+inmodj); 00769 v11 = background; 00770 v10 = background; 00771 } else if (lj1==0) { 00772 v00 = background; 00773 v01 = (pin00+inmodj); 00774 v11 = background; 00775 v10 = background; 00776 } else if (lj1==indimj) { 00777 v00 = (pin00); 00778 v01 = background; 00779 v11 = background; 00780 v10 = background; 00781 } else { 00782 v00 = background; 00783 v01 = background; 00784 v11 = background; 00785 v10 = background; 00786 } 00787 } else { 00788 v00 = background; 00789 v01 = background; 00790 v11 = background; 00791 v10 = background; 00792 } 00793 // TODO: this does not work for ubyte (cf ubyte implementation in image.cpp) 00794 // make it generic to avoid code redondancy. 00795 double dd = 1.0 / 65536.0; 00796 T d = (T) dd; 00797 if (sizeof (T) <= 2) 00798 d = 0; 00799 if (outsize >= 1) 00800 *out = (ndeltaj * (( *v10*deltai + *v00*ndeltai )*d) + 00801 deltaj * (( *v11*deltai + *v01*ndeltai )*d))*d; 00802 if (outsize >= 2) 00803 *(out + 1) = (ndeltaj * ((v10[1]*deltai + v00[1]*ndeltai) * d) + 00804 deltaj * ((v11[1]*deltai + v01[1]*ndeltai) * d)) * d; 00805 if (outsize >= 3) 00806 *(out + 2) = (ndeltaj * ((v10[2]*deltai + v00[2]*ndeltai) * d) + 00807 deltaj * ((v11[2]*deltai + v01[2]*ndeltai) * d)) * d; 00808 if (outsize >= 4) 00809 *(out + 3) = (ndeltaj * ((v10[3]*deltai + v00[3]*ndeltai) * d) + 00810 deltaj * ((v11[3]*deltai + v01[3]*ndeltai) * d)) * d; 00811 if (outsize >= 5) { 00812 eblerror("not implemented for more than 4 channels (" 00813 << outsize << " channels in " << indimi << "x" << indimj 00814 << " image)"); 00815 } 00816 } 00817 00818 template <typename T> void compute_bilin_transform(idx<int> &dispi, 00819 idx<int> &dispj, 00820 float x1, float y1, float x2, 00821 float y2, float x3, float y3, 00822 float x4, float y4, float p1, 00823 float q1, float p3, float q3) { 00824 // compute transformation matrix from coordinates 00825 // in target (rectangular) space to coordinates 00826 // in original (irregular quadrilateral) image 00827 // transformation matrix is in 16.16 fixed point format. 00828 float k = 65536 / ((p3 - p1) * (q3 - q1)); 00829 float x41 = x4 - x1; 00830 float x21 = x2 - x1; 00831 float x43 = x4 - x3; 00832 float x23 = x2 - x3; 00833 int mx0 = (int) (k * ((q3 * x21) + (q1 * x43))); 00834 int mx1 = (int) (k * ((p3 * x41) + (p1 * x23))); 00835 int mx2 = (int) ((-k) * (x41 + x23)); 00836 int mx3 = (int) (k * (((p3 * q3 * x1) + (p1 * q1 * x3)) - 00837 ((p1 * q3 * x2) + (p3 * q1 * x4)))); 00838 float y41 = y4 - y1; 00839 float y21 = y2 - y1; 00840 float y43 = y4 - y3; 00841 float y23 = y2 - y3; 00842 int my0 = (int) (k * ((q3 * y21) + (q1 * y43))); 00843 int my1 = (int) (k * ((p3 * y41) + (p1 * y23))); 00844 int my2 = (int) ((-k) * (y41 + y23)); 00845 int my3 = (int) (k * (((p3 * q3 * y1) + (p1 * q1 * y3)) - 00846 ((p1 * q3 * y2) + (p3 * q1 * y4)))); 00847 int q = 0, p = 0; 00848 { idx_bloop2(ispi, dispi, int, ispj, dispj, int) { 00849 p = 0; 00850 { idx_bloop2(di, ispi, int, dj, ispj, int) { 00851 di.set(my0 * p + my1 * q + my2 * p * q + my3); 00852 dj.set(mx0 * p + mx1 * q + mx2 * p * q + mx3); 00853 p++; 00854 }} 00855 q++; 00856 }} 00857 } 00858 00859 00860 // template <typename T> void compute_bilin_transform2(idx<int> &dispi, 00861 // idx<int> &dispj, 00862 // float x1, float y1, 00863 // float x2, float y2, 00864 // float x3, float y3, 00865 // float x4, float y4, 00866 // float p1, float q1, 00867 // float p2, float q2, 00868 // float p3, float q3, 00869 // float p4, float q4) { 00870 // // compute transformation matrix from coordinates 00871 // // in target (rectangular) space to coordinates 00872 // // in original (irregular quadrilateral) image 00873 // // transformation matrix is in 16.16 fixed point format. 00874 // float k = 65536 / ((p3 - p1) * (q3 - q1)); 00875 // float x41 = x4 - x1; 00876 // float x21 = x2 - x1; 00877 // float x43 = x4 - x3; 00878 // float x23 = x2 - x3; 00879 // int mx0 = (int) (k * ((q3 * x21) + (q1 * x43))); 00880 // int mx1 = (int) (k * ((p3 * x41) + (p1 * x23))); 00881 // int mx2 = (int) ((-k) * (x41 + x23)); 00882 // int mx3 = (int) (k * (((p3 * q3 * x1) + (p1 * q1 * x3)) - 00883 // ((p1 * q3 * x2) + (p3 * q1 * x4)))); 00884 // float y41 = y4 - y1; 00885 // float y21 = y2 - y1; 00886 // float y43 = y4 - y3; 00887 // float y23 = y2 - y3; 00888 // int my0 = (int) (k * ((q3 * y21) + (q1 * y43))); 00889 // int my1 = (int) (k * ((p3 * y41) + (p1 * y23))); 00890 // int my2 = (int) ((-k) * (y41 + y23)); 00891 // int my3 = (int) (k * (((p3 * q3 * y1) + (p1 * q1 * y3)) - 00892 // ((p1 * q3 * y2) + (p3 * q1 * y4)))); 00893 // int q = 0, p = 0; 00894 // { idx_bloop2(ispi, dispi, int, ispj, dispj, int) { 00895 // p = 0; 00896 // { idx_bloop2(di, ispi, int, dj, ispj, int) { 00897 // di.set(my0 * p + my1 * q + my2 * p * q + my3); 00898 // dj.set(mx0 * p + mx1 * q + mx2 * p * q + mx3); 00899 // p++; 00900 // }} 00901 // q++; 00902 // }} 00903 // } 00904 00905 template <typename T> 00906 idx<T> image_rotscale(idx<T> &src, double sx, double sy, double dx, 00907 double dy, double angle, double coeff, T bg_val) { 00908 if (!src.contiguousp()) 00909 eblerror("image must be contiguous"); 00910 double q = 1000; 00911 double coeff_inv = 1/coeff; 00912 double sa = q*sin(angle * 0.017453292); 00913 double ca = q*cos(angle * 0.017453292); 00914 double ca_plus_sa = coeff_inv * (sa + ca); 00915 double ca_minus_sa = coeff_inv * (ca - sa); 00916 float x1 = sy - ca_plus_sa; 00917 float y1 = sx - ca_minus_sa; 00918 float x2 = sy + ca_minus_sa; 00919 float y2 = sx - ca_plus_sa; 00920 float x3 = sy + ca_plus_sa; 00921 float y3 = sx + ca_minus_sa; 00922 float x4 = sy - ca_minus_sa; 00923 float y4 = sx + ca_plus_sa; 00924 float p1 = dy - q; 00925 float q1 = dx - q; 00926 float p3 = dy + q; 00927 float q3 = dx + q; 00928 idx<T> out(src.get_idxdim()); 00929 idx<T> bg(src.dim(0)); 00930 idx_fill(bg, bg_val); 00931 image_warp_quad(src, out, bg, 1, x1, y1, x2, y2, x3, y3, x4, y4, 00932 p1, q1, p3, q3); 00933 return out; 00934 } 00935 00936 template <typename T> 00937 idx<T> image_rotate(idx<T> &src, double angle, float ch, float cw, T bg_val) { 00938 if (!src.contiguousp()) 00939 eblerror("image must be contiguous"); 00940 if (ch == -1) ch = src.dim(0) / (float) 2; 00941 if (cw == -1) cw = src.dim(1) / (float) 2; 00942 idx<T> rotated(src.get_idxdim()); 00943 double q = 1000; 00944 double sa = q*sin(angle * 0.017453292); 00945 double ca = q*cos(angle * 0.017453292); 00946 double ca_plus_sa = sa + ca; 00947 double ca_minus_sa = ca - sa; 00948 float x1 = cw - ca_plus_sa; 00949 float y1 = ch - ca_minus_sa; 00950 float x2 = cw + ca_minus_sa; 00951 float y2 = ch - ca_plus_sa; 00952 float x3 = cw + ca_plus_sa; 00953 float y3 = ch + ca_minus_sa; 00954 float x4 = cw - ca_minus_sa; 00955 float y4 = ch + ca_plus_sa; 00956 float p1 = cw - q; 00957 float q1 = ch - q; 00958 float p3 = cw + q; 00959 float q3 = ch + q; 00960 idx<T> bg(src.dim(0)); 00961 idx_fill(bg, bg_val); 00962 image_warp_quad(src, rotated, bg, 1, x1, y1, x2, y2, x3, y3, x4, y4, 00963 p1, q1, p3, q3); 00964 return rotated; 00965 } 00966 00968 // Drawing 00969 00970 template <typename T> void image_draw_box(idx<T> &img, T val, 00971 uint x, uint y, uint dx, uint dy) { 00972 idx_checkorder1(img, 2); 00973 for (unsigned int i = x; i < x + dx; ++i) { 00974 img.set(val, i, y); 00975 img.set(val, i, y + dy); 00976 } 00977 for (unsigned int j = y; j < y + dy; ++j) { 00978 img.set(val, x, j); 00979 img.set(val, x + dx, j); 00980 } 00981 } 00982 00984 // Filters 00985 00986 template <typename T> 00987 void image_mexican_filter(idx<T> &in, idx<T> &out, double s, int n, 00988 idx<T> *filter_, idx<T> *tmp_) { 00989 idx<T> filter = filter_ ? *filter_ : create_mexican_hat<T>(s, n); 00990 idxdim d(in); 00991 idx<T> tmp = tmp_ ? *tmp_ : idx<T>(d); 00992 idx_checkorder3(in, 2, filter, 2, out, 2); 00993 image_apply_filter(in, out, filter, &tmp); 00994 } 00995 00996 // TODO: handle empty sides 00997 // TODO: check for tmp size incompatibilities 00998 template <typename T> 00999 void image_global_normalization(idx<T> &in) { 01000 idx_std_normalize(in, in); 01001 // problem with code below: it separates by channels which are assumed to 01002 // be in last dimension. this can lead to nasty bugs. 01003 // switch (in.order()) { 01004 // case 2: 01005 // idx_std_normalize(in, in); // zero-mean and divide by standard deviation 01006 // break ; 01007 // case 3: 01008 // // normalize layer by layer 01009 // { idx_eloop1(i, in, T) { 01010 // idx_std_normalize(i, i); // zero-mean and divide by standard deviation 01011 // }} 01012 // break ; 01013 // default: 01014 // eblerror("image_global_normalization: dimension not implemented"); 01015 // } 01016 } 01017 01018 // TODO: handle empty sides 01019 // TODO: check for tmp size incompatibilities 01020 // TODO: cleanup 01021 template <typename T> 01022 void image_local_normalization(idx<T> &in, idx<T> &out, int n) { 01023 if (in.order() != 2 || out.order() != 2) 01024 eblerror("this function only accepts 2D inputs, but got " << in 01025 << " and " << out); 01026 // 1. create normalized gaussian kernel (kernel / sum(kernel)) 01027 idx<T> kernel = create_gaussian_kernel<T>(n); 01028 idx<T> tmp(in.dim(0) + n - 1, in.dim(1) + n - 1); 01029 idx<T> tmp2 = tmp.narrow(0, in.dim(0), (intg) floor((float) n / 2)); 01030 tmp2 = tmp2.narrow(1, in.dim(1), (intg) floor((float) n / 2)); 01031 idx<T> tmp3(n, n); 01032 idxdim d(in); 01033 idx<T> tmp4(d); 01034 idx<T> tmp5(d); 01035 01036 // sum_j (w_j * in_j) 01037 idx<T> out1 = image_filter(in, kernel); 01038 idx<T> in2 = in.narrow(0, out1.dim(0), (intg)floor((float)kernel.dim(0)/2)); 01039 in2 = in2.narrow(1, out1.dim(1), (intg) floor((float)kernel.dim(1)/2)); 01040 idxdim outd(out1); 01041 idx<T> out2(outd); 01042 // in - mean 01043 idx_sub(in2, out1, out1); 01044 // (in - mean)^2 01045 idx_mul(out1, out1, out2); 01046 // sum_j (w_j * (in - mean)^2) 01047 idx<T> out3 = image_filter(out2, kernel); 01048 // sqrt(sum_j (w_j (in - mean)^2)) 01049 idx_sqrt(out3, out3); 01050 // std(std < 1) = 1 01051 idx_threshold(out3, (T)1.0); 01052 // 1/std 01053 idx_inv(out3, out3); 01054 // out = (in - mean) / std 01055 idx<T> out4 = out1.narrow(0, out3.dim(0), 01056 (intg) floor((float)kernel.dim(0)/2)); 01057 out4 = out4.narrow(1, out3.dim(1), (intg) floor((float)kernel.dim(1)/2)); 01058 idx_mul(out4, out3, out3); 01059 // finally copy result centered on an image the same size as in 01060 idx<T> out5 = out.narrow(0, out3.dim(0), (out.dim(0) - out3.dim(0)) / 2); 01061 out5 = out5.narrow(1, out3.dim(1), (out.dim(1) - out3.dim(1)) / 2); 01062 idx_clear(out); 01063 idx_copy(out3, out5); 01064 01065 // // in - mean 01066 // idx_sub(in, tmp5, tmp5); 01067 // // (in - mean)^2 01068 // idx_mul(tmp5, tmp5, tmp4); 01069 // // sum_j (w_j * (in - mean)^2) 01070 // image_apply_filter(tmp4, out, kernel, &tmp); 01071 // // sqrt(sum_j (w_j (in - mean)^2)) 01072 // idx_sqrt(out, out); 01073 // // std(std < 1) = 1 01074 // idx_threshold(out, (T)1.0, out); 01075 // // 1/std 01076 // idx_inv(out, out); 01077 // // out = (in - mean) / std 01078 // idx_mul(tmp5, out, out); 01079 } 01080 01081 // TODO: get rid of this function 01082 template <typename T> 01083 void image_apply_filter(idx<T> &in, idx<T> &out, idx<T> &filter, 01084 idx<T> *tmp_) { 01085 idxdim d(in); 01086 if ((out.dim(0) != d.dim(0)) || (out.dim(1) != d.dim(1))) 01087 out.resize(d); 01088 idx_clear(out); 01089 idx<T> tmp = out.narrow(0, in.dim(0) - filter.dim(0) + 1, 01090 (intg) floor((float)filter.dim(0)/2)); 01091 tmp = tmp.narrow(1, in.dim(1) - filter.dim(1) + 1, 01092 (intg) floor((float)filter.dim(1)/2)); 01093 idx_2dconvol(in, filter, tmp); 01094 01095 // // compute sizes of the temporary buffer 01096 // d.setdim(0, in.dim(0) + filter.dim(0) - 1); 01097 // d.setdim(1, in.dim(1) + filter.dim(1) - 1); 01098 // idx<T> tmp; 01099 // if (tmp_) { 01100 // tmp = *tmp_; 01101 // if ((tmp.dim(0) != d.dim(0)) || (tmp.dim(1) != d.dim(1))) { 01102 // tmp.resize(d); 01103 // *tmp_ = tmp; 01104 // } 01105 // } else 01106 // tmp = idx<T>(d); 01107 // // copy input into temporary buffer 01108 // idx_clear(tmp); 01109 // idx<T> tmp2 = tmp.narrow(0, in.dim(0), floor(filter.dim(0)/2)); 01110 // tmp2 = tmp2.narrow(1, in.dim(1), floor(filter.dim(1)/2)); 01111 // idx_copy(in, tmp2); 01112 // idx_2dconvol(tmp, filter, out); 01113 } 01114 01115 template <typename T> 01116 idx<T> image_filter(idx<T> &in, idx<T> &filter) { 01117 // check that image is bigger than filter 01118 if ((in.dim(0) < filter.dim(0)) || 01119 (in.dim(1) < filter.dim(1))) { 01120 cerr << "error: image " << in << " is too small to be convolved with "; 01121 cerr << filter << " filter." << endl; 01122 eblerror("too small image for convolution"); 01123 } 01124 idxdim d(in); 01125 d.setdim(0, in.dim(0) - filter.dim(0) + 1); 01126 d.setdim(1, in.dim(1) - filter.dim(1) + 1); 01127 idx<T> out(d); 01128 idx_clear(out); 01129 idx_2dconvol(in, filter, out); 01130 return out; 01131 } 01132 01133 // deformations ////////////////////////////////////////////////////////////// 01134 01135 template <typename T> 01136 void image_deformation_ranperspective(idx<T> &in, idx<T> &out, 01137 int hrange, int wrange, T background) { 01138 idx<float> bg(1); 01139 bg.set(background, 0); 01140 float x1diff = (float) drand( wrange/2, -wrange/2); 01141 float y1diff = (float) drand( hrange/2, -hrange/2); 01142 float x2diff = (float) drand(-wrange/2, wrange/2); 01143 float y2diff = (float) drand( hrange/2, -hrange/2); 01144 float x3diff = (float) drand(-wrange/2, wrange/2); 01145 float y3diff = (float) drand(-hrange/2, hrange/2); 01146 float x4diff = (float) drand( wrange/2, -wrange/2); 01147 float y4diff = (float) drand(-hrange/2, hrange/2); 01148 image_warp_quad(in, out, bg, 1, 01149 -.5 + x1diff, -.5 + y1diff, // x1 y1 01150 in.dim(1) -.5 + x2diff, -.5 + y2diff, // x2 y2 01151 in.dim(1) -.5 + x3diff, in.dim(0) -.5 + y3diff, // x3 y3 01152 -.5 + x4diff, in.dim(0) - .5 + y4diff, // x4 y4 01153 -.5, -.5, in.dim(1) - .5, in.dim(0) - .5); 01154 } 01155 01156 template <typename T> 01157 idx<float> image_deformation_flow(idx<T> &in, float th, float tw, 01158 float sh, float sw, float deg, 01159 float shh, float shw, 01160 uint elsize, float elcoeff, 01161 T background) { 01162 idxdim d(in); 01163 d.remove_dim(2); 01164 idx<float> grid = create_grid(d); 01165 idx<float> flow(grid.get_idxdim()); 01166 idx<T> bg(in.dim(2)); 01167 idx_fill(bg, background); 01168 idx_clear(flow); 01169 01170 01171 if (th != 0 || tw != 0) translation_flow(grid, flow, th, tw); 01172 if (deg != 0) rotation_flow(grid, flow, deg); 01173 if (th != 1 || tw != 1) scale_flow(grid, flow, sh, sw); 01174 if (shh != 0 || shw != 0) shear_flow(grid, flow, shh, shw); 01175 if (elsize > 0) elastic_flow(flow, elsize, elcoeff); 01176 01177 // affine_flow(grid, flow, 0, 0, sh, sw, 0, 0, deg); 01178 return flow; 01179 } 01180 01181 template <typename T> 01182 void image_deformation(idx<T> &in, idx<T> &out, float th, float tw, 01183 float sh, float sw, float deg, 01184 float shh, float shw, uint elsize, float elcoeff, 01185 T background) { 01186 idx<float> flow = 01187 image_deformation_flow(in, th, tw, sh, sw, deg, shh, shw, elsize, elcoeff, 01188 background); 01189 // apply flow 01190 image_warp_flow(in, out, flow); 01191 } 01192 01193 } // end namespace ebl 01194 01195 #endif /* IMAGE_HPP_ */