1 /* 2 # This file is part of the Astrometry.net suite. 3 # Licensed under a 3-clause BSD style license - see LICENSE 4 */ 5 %module(package="astrometry.plot") plotstuff_c 6 7 %include <typemaps.i> 8 9 %import "util.i" 10 11 #undef ATTRIB_FORMAT 12 #define ATTRIB_FORMAT(x,y,z) 13 #undef WarnUnusedResult 14 #define WarnUnusedResult 15 %{ 16 #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION 17 #include <numpy/arrayobject.h> 18 #include <stdlib.h> 19 #include <math.h> 20 21 #include "os-features.h" 22 #include "plotstuff.h" 23 #include "plotimage.h" 24 #include "plotoutline.h" 25 #include "plotgrid.h" 26 #include "plotindex.h" 27 #include "plotxy.h" 28 #include "plotradec.h" 29 #include "plotmatch.h" 30 #include "plotannotations.h" 31 #include "plothealpix.h" 32 #include "sip.h" 33 #include "sip-utils.h" 34 #include "sip_qfits.h" 35 #include "log.h" 36 #include "fitsioutils.h" 37 #include "anwcs.h" 38 #include "coadd.h" 39 #include "anqfits.h" 40 #include "mathutil.h" 41 #include "convolve-image.h" 42 #include "resample.h" 43 #include "cairoutils.h" 44 #include "an-bool.h" 45 46 47 #define true 1 48 #define false 0 49 %} 50 51 %apply double *OUTPUT { double *pramin, double *pramax, double *pdecmin, double *pdecmax }; 52 %apply double *OUTPUT { double *pra, double *pdec }; 53 %apply double *OUTPUT { double *pradius }; 54 %apply double *OUTPUT { double *pra, double *pdec, double *pradius }; 55 %apply double *OUTPUT { double *p_x, double *p_y }; 56 %apply int *OUTPUT { int* p_r, int* p_g, int* p_b, int* p_a }; 57 58 %include "plotstuff.h" 59 %include "coadd.h" 60 %include "qfits_image.h" 61 %include "fitsioutils.h" 62 %include "convolve-image.h" 63 64 /* 65 number* coadd_create_weight_image_from_range(const number* img, int W, int H, 66 number lowval, number highval); 67 */ 68 69 %inline %{ c_image_numpy_view(float * data,int nx,int ny)70 PyObject* c_image_numpy_view(float* data, int nx, int ny) { 71 npy_intp dims[2]; 72 dims[0] = ny; 73 dims[1] = nx; 74 return PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, data); 75 } 76 %} 77 78 %pythoncode %{ 79 def qfits_load_image(fn, ext=1, plane=0, map=1, ptype=PTYPE_FLOAT): 80 ld = qfitsloader() 81 ld.filename = fn 82 ld.xtnum = ext 83 ld.pnum = plane 84 ld.map = map 85 ld.ptype = ptype 86 if qfitsloader_init(ld): 87 raise RuntimeError('qfitsloader_init(file "%s", ext %i) failed' % (fn, ext)) 88 if qfits_loadpix(ld): 89 raise RuntimeError('qfits_loadpix(file "%s", ext %i) failed' % (fn, ext)) 90 91 class qfits_image(object): 92 def __init__(self, pix, nx, ny, ld): 93 self.pix = pix 94 self.nx = nx 95 self.ny = ny 96 self.ld = ld 97 def __del__(self): 98 qfitsloader_free_buffer(self.ld) 99 100 return qfits_image(ld.fbuf, ld.lx, ld.ly, ld) 101 %} 102 103 void free(void* ptr); 104 105 %apply int* OUTPUT { int* newW, int* newH }; 106 #define Const 107 #define InlineDeclare 108 %include "mathutil.h" 109 #undef Const 110 #undef InlineDeclare 111 112 /* Set the input argument to point to a temporary variable */ 113 %typemap(in, numinputs=0) unsigned char* rgbout (unsigned char temp[3]) { 114 $1 = temp; 115 } 116 117 %typemap(argout) unsigned char* rgbout { 118 // Append output value $1 to $result 119 if (result) { 120 Py_DECREF($result); 121 $result = Py_None; 122 } else { 123 int i; 124 Py_DECREF($result); 125 $result = PyList_New(3); 126 for (i=0; i<3; i++) { 127 PyObject *o = PyInt_FromLong((long)$1[i]); 128 PyList_SetItem($result,i,o); 129 } 130 } 131 } 132 133 %typemap(in) int rgb[3] (int temp[3]) { 134 int i; 135 // Convert sequence of ints to int[3] 136 if (!PySequence_Check($input) || 137 (PySequence_Length($input) != 3)) { 138 PyErr_SetString(PyExc_ValueError,"Expected a sequence of length 3"); 139 return NULL; 140 } 141 for (i=0; i<3; i++) { 142 PyObject *o = PySequence_GetItem($input, i); 143 if (PyNumber_Check(o)) { 144 temp[i] = (int)PyInt_AsLong(o); 145 } else { 146 PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers"); 147 return NULL; 148 } 149 } 150 $1 = temp; 151 } 152 153 %include "plotimage.h" 154 %include "plotoutline.h" 155 %include "plotgrid.h" 156 %include "plotindex.h" 157 %include "plotxy.h" 158 %include "plotradec.h" 159 %include "plotmatch.h" 160 %include "plotannotations.h" 161 %include "plothealpix.h" 162 %include "sip.h" 163 %include "sip_qfits.h" 164 %include "sip-utils.h" 165 %include "anwcs.h" 166 167 %init %{ 168 import_array(); 169 %} 170 171 // HACK! 172 enum cairo_op { 173 CAIRO_OPERATOR_CLEAR, 174 CAIRO_OPERATOR_SOURCE, 175 CAIRO_OPERATOR_OVER, 176 CAIRO_OPERATOR_IN, 177 CAIRO_OPERATOR_OUT, 178 CAIRO_OPERATOR_ATOP, 179 CAIRO_OPERATOR_DEST, 180 CAIRO_OPERATOR_DEST_OVER, 181 CAIRO_OPERATOR_DEST_IN, 182 CAIRO_OPERATOR_DEST_OUT, 183 CAIRO_OPERATOR_DEST_ATOP, 184 CAIRO_OPERATOR_XOR, 185 CAIRO_OPERATOR_ADD, 186 CAIRO_OPERATOR_SATURATE, 187 // Since cairo 1.10 188 CAIRO_OPERATOR_MULTIPLY, 189 CAIRO_OPERATOR_SCREEN, 190 CAIRO_OPERATOR_OVERLAY, 191 CAIRO_OPERATOR_DARKEN, 192 CAIRO_OPERATOR_LIGHTEN, 193 CAIRO_OPERATOR_COLOR_DODGE, 194 CAIRO_OPERATOR_COLOR_BURN, 195 CAIRO_OPERATOR_HARD_LIGHT, 196 CAIRO_OPERATOR_SOFT_LIGHT, 197 CAIRO_OPERATOR_DIFFERENCE, 198 CAIRO_OPERATOR_EXCLUSION, 199 CAIRO_OPERATOR_HSL_HUE, 200 CAIRO_OPERATOR_HSL_SATURATION, 201 CAIRO_OPERATOR_HSL_COLOR, 202 CAIRO_OPERATOR_HSL_LUMINOSITY 203 }; 204 typedef enum cairo_op cairo_operator_t; 205 206 %{ 207 sip_t* new_sip_t(double crpix1, double crpix2, double crval1, double crval2, 208 double cd11, double cd12, double cd21, double cd22) { 209 sip_t* sip = sip_create(); 210 tan_t* tan = &(sip->wcstan); 211 tan->crpix[0] = crpix1; 212 tan->crpix[1] = crpix2; 213 tan->crval[0] = crval1; 214 tan->crval[1] = crval2; 215 tan->cd[0][0] = cd11; 216 tan->cd[0][1] = cd12; 217 tan->cd[1][0] = cd21; 218 tan->cd[1][1] = cd22; 219 return sip; 220 } 221 %} 222 223 %extend sip_t { 224 sip_t(double, double, double, double, double, double, double, double); 225 226 double crval1() { 227 return self->wcstan.crval[0]; 228 } 229 double crval2() { 230 return self->wcstan.crval[1]; 231 } 232 double crpix1() { 233 return self->wcstan.crpix[0]; 234 } 235 double crpix2() { 236 return self->wcstan.crpix[1]; 237 } 238 double cd11() { 239 return self->wcstan.cd[0][0]; 240 } 241 double cd12() { 242 return self->wcstan.cd[0][1]; 243 } 244 double cd21() { 245 return self->wcstan.cd[1][0]; 246 } 247 double cd22() { 248 return self->wcstan.cd[1][1]; 249 } 250 } 251 252 %inline %{ 253 void image_debug(float* img, int W, int H) { 254 int i; 255 double mn,mx; 256 mn = 1e300; 257 mx = -1e300; 258 for (i=0; i<(W*H); i++) { 259 mn = MIN(mn, img[i]); 260 mx = MAX(mx, img[i]); 261 } 262 logmsg("Image min,max %g,%g\n", mn,mx); 263 } 264 265 void image_add(float* img, int W, int H, float val) { 266 int i; 267 for (i=0; i<(W*H); i++) 268 img[i] += val; 269 } 270 271 void image_weighted_smooth(float* img, int W, int H, const float* weight, 272 float sigma) { 273 int K0, NK; 274 float* kernel = convolve_get_gaussian_kernel_f(sigma, 5., &K0, &NK); 275 convolve_separable_weighted_f(img, W, H, weight, kernel, K0, NK, img, NULL); 276 free(kernel); 277 } 278 %} 279 280 %extend plot_args { 281 PyObject* view_image_as_numpy() { 282 npy_intp dim[3]; 283 unsigned char* img; 284 PyObject* npimg; 285 dim[0] = self->H; 286 dim[1] = self->W; 287 dim[2] = 4; 288 img = cairo_image_surface_get_data(self->target); 289 npimg = PyArray_SimpleNewFromData(3, dim, NPY_UBYTE, img); 290 return npimg; 291 } 292 293 PyObject* get_image_as_numpy(int flip, PyObject* out) { 294 npy_intp dim[3]; 295 unsigned char* img; 296 PyObject* npimg; 297 dim[0] = self->H; 298 dim[1] = self->W; 299 dim[2] = 4; 300 img = cairo_image_surface_get_data(self->target); 301 // Possible memory problems here... 302 if (out == Py_None || out == NULL) { 303 // rgba 304 npimg = PyArray_EMPTY(3, dim, NPY_UBYTE, 0); 305 if (!npimg) { 306 PyErr_SetString(PyExc_ValueError, "Failed to allocate numpy array in plotstuff.get_image_as_numpy"); 307 return NULL; 308 } 309 assert(npimg); 310 } else { 311 npimg = out; 312 } 313 if (flip) { 314 cairoutils_argb32_to_rgba_flip(img, PyArray_DATA((PyArrayObject*)npimg), self->W, self->H); 315 } else { 316 cairoutils_argb32_to_rgba_2(img, PyArray_DATA((PyArrayObject*)npimg), self->W, self->H); 317 } 318 return npimg; 319 } 320 321 PyObject* get_image_as_numpy_view() { 322 unsigned char* img; 323 npy_intp dim[3]; 324 PyArray_Descr* dtype = PyArray_DescrFromType(NPY_UBYTE); 325 dim[0] = self->H; 326 dim[1] = self->W; 327 dim[2] = 4; 328 img = cairo_image_surface_get_data(self->target); 329 if (!img) { 330 PyErr_SetString(PyExc_ValueError, "Cairo image survey data is NULL in plotstuff.get_image_as_numpy_view"); 331 return NULL; 332 } 333 Py_INCREF(dtype); 334 PyObject* npimg = PyArray_NewFromDescr(&PyArray_Type, dtype, 3, dim, NULL, 335 img, 0, NULL); 336 return npimg; 337 } 338 339 int set_image_from_numpy(PyObject* py_img, int flip) { 340 unsigned char* img; 341 unsigned char* inimg; 342 PyArray_Descr* dtype = PyArray_DescrFromType(NPY_UBYTE); 343 int req = NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED; 344 PyArrayObject *np_img=NULL; 345 Py_INCREF(dtype); 346 np_img = (PyArrayObject*)PyArray_FromAny(py_img, dtype, 3, 3, req, NULL); 347 if ((PyArray_DIM(np_img, 0) != self->H) || 348 (PyArray_DIM(np_img, 1) != self->W) || 349 (PyArray_DIM(np_img, 2) != 4)) { 350 PyErr_SetString(PyExc_ValueError, "Expected image with shape (H, W, 4)"); 351 return -1; 352 } 353 if (!np_img) { 354 PyErr_SetString(PyExc_ValueError, "img wasn't the type expected"); 355 Py_DECREF(dtype); 356 return -1; 357 } 358 inimg = PyArray_DATA(np_img); 359 img = cairo_image_surface_get_data(self->target); 360 if (flip) { 361 cairoutils_rgba_to_argb32_flip(inimg, img, self->W, self->H); 362 } else { 363 cairoutils_rgba_to_argb32_2(inimg, img, self->W, self->H); 364 } 365 Py_DECREF(np_img); 366 Py_DECREF(dtype); 367 return 0; 368 } 369 370 int set_wcs_file(const char* fn, int ext) { 371 return plotstuff_set_wcs_file(self, fn, ext); 372 } 373 374 int set_size_from_wcs() { 375 return plotstuff_set_size_wcs(self); 376 } 377 378 int count_ra_labels() { 379 return plot_grid_count_ra_labels(self); 380 } 381 int count_dec_labels() { 382 return plot_grid_count_dec_labels(self); 383 } 384 385 void loginit(int level) { 386 log_init(level); 387 } 388 } 389 390 %extend annotation_args { 391 void add_target(double ra, double dec, const char* name) { 392 plot_annotations_add_target(self, ra, dec, name); 393 } 394 void add_named_target(const char* name) { 395 plot_annotations_add_named_target(self, name); 396 } 397 void clear_targets() { 398 plot_annotations_clear_targets(self); 399 } 400 } 401 402 %extend plotgrid_args { 403 int set_formats(const char* raformat, const char* decformat) { 404 return plot_grid_set_formats(self, raformat, decformat); 405 } 406 } 407 408 %extend plotoutline_args { 409 int set_wcs_file(const char* fn, int ext) { 410 return plot_outline_set_wcs_file(self, fn, ext); 411 } 412 int set_wcs_size(int W, int H) { 413 return plot_outline_set_wcs_size(self, W, H); 414 } 415 int set_wcs(const tan_t* wcs) { 416 return plot_outline_set_tan_wcs(self, wcs); 417 } 418 } 419 %pythoncode %{ 420 def plotoutline_setattr(self, name, val): 421 if name == 'wcs_file': 422 if type(val) is tuple: 423 (fn,ext) = val 424 else: 425 fn = val 426 ext = 0 427 plot_outline_set_wcs_file(self, fn, ext) 428 return 429 self.__swig__setattr__(name, val) 430 431 plotoutline_args.__swig__setattr__ = plotoutline_args.__setattr__ 432 plotoutline_args.__setattr__ = plotoutline_setattr 433 %} 434 435 %extend plotxy_args { 436 void set_filename(const char* fn) { 437 plot_xy_set_filename(self, fn); 438 } 439 } 440 441 %extend plotradec_args { 442 void set_filename(const char* fn) { 443 plot_radec_set_filename(self, fn); 444 } 445 } 446 447 %extend plotimage_args { 448 int _set_image_from_numpy(PyObject* arr) { 449 // Pirate array 450 PyArrayObject* yarr; 451 int hasalpha = 0; 452 int i, N; 453 unsigned char* src; 454 455 // MAGIC 3: min_depth and max_depth (number of dims) 456 yarr = (PyArrayObject*)PyArray_FROMANY(arr, NPY_UBYTE, 3, 3, 457 NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED); 458 if (!yarr) { 459 PyErr_SetString(PyExc_ValueError, "Array must be 3-dimensional ubyte"); 460 return -1; 461 } 462 463 switch (PyArray_DIM(yarr, 2)) { 464 // RGB 465 case 3: 466 hasalpha = 0; 467 break; 468 // RGBA 469 case 4: 470 hasalpha = 1; 471 break; 472 default: 473 PyErr_SetString(PyExc_ValueError, "Array must be RGB or RGBA"); 474 return -1; 475 } 476 src = PyArray_DATA(yarr); 477 if (self->img) { 478 free(self->img); 479 } 480 self->H = (int)PyArray_DIM(yarr, 0); 481 self->W = (int)PyArray_DIM(yarr, 1); 482 //printf("Allocating new %i x %i image\n", self->W, self->H); 483 self->img = malloc(self->W * self->H * 4); 484 N = self->W * self->H; 485 for (i=0; i<N; i++) { 486 if (hasalpha) 487 memcpy(self->img + 4*i, src + 4*i, 4); 488 else { 489 memcpy(self->img + 4*i, src + 3*i, 3); 490 self->img[4*i+3] = 255; 491 } 492 } 493 Py_DECREF(yarr); 494 return 0; 495 } 496 497 int set_wcs_file(const char* fn, int ext) { 498 return plot_image_set_wcs(self, fn, ext); 499 } 500 int set_file(const char* fn) { 501 return plot_image_set_filename(self, fn); 502 } 503 void set_rgbscale(double r, double g, double b) { 504 self->rgbscale[0] = r; 505 self->rgbscale[1] = g; 506 self->rgbscale[2] = b; 507 } 508 int get_image_width() { 509 int W; 510 if (plot_image_getsize(self, &W, NULL)) { 511 return -1; 512 } 513 return W; 514 } 515 int get_image_height() { 516 int H; 517 if (plot_image_getsize(self, NULL, &H)) { 518 return -1; 519 } 520 return H; 521 } 522 } 523 524 %pythoncode %{ 525 def plotimage_set_image_from_numpy(self, img): 526 rtn = self._set_image_from_numpy(img) 527 if rtn: 528 raise RuntimeError('set_image_from_numpy() failed') 529 plotimage_args.set_image_from_numpy = plotimage_set_image_from_numpy 530 %} 531 532 %extend plotindex_args { 533 int add_file(const char* fn) { 534 return plot_index_add_file(self, fn); 535 } 536 } 537