IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 16, 2007, 4:00:33 PM (19 years ago)
Author:
bills
Message:

Solved problem with chip and cell boundary calculations by using different
functions than pmChipPixels and pmCellExtents. They don't do their calculations
in image coordinates.

Implemented specifying width/height of the ROI in celestial coordinates.
Removed unneeded WCS calculation methods. (The bug I was chasing was actually
not in ppstamp. It was a bug in ds9

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/ppstamp/src/ppstampMakeStamp.c

    r15318 r15323  
    1616} ppstampOverlap;
    1717
    18 static bool regionContainsPoint(psRegion *region, psPlane *point);
    19 static bool regionContainsRegion(psRegion *outer, psRegion *inner);
    20 static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, pmCell *inCell,
    21                         psRegion *roi);
    22 
    23 
    24 static ppstampOverlap findCell(pmFPAview *view, ppstampOptions *options, pmFPAfile *input,
    25                                 pmAstromObj *center, pmCell **ppCell)
    26 {
    27     pmCell *cell;
    28 
    29     view->cell = -1;
    30     while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
    31         psRegion *cellExtent = pmCellExtent(cell);
    32         if (regionContainsPoint(cellExtent, center->chip)) {
    33             if (regionContainsRegion(cellExtent, &options->roi)) {
    34                 *ppCell = cell;
    35                 psFree(cellExtent);
    36                 return PPSTAMP_ON;
    37             } else {
    38                 fprintf(stderr, "ROI must be confined to single cell. Partial overlap cell %d\n",
    39                     view->cell);
    40                 psFree(cellExtent);
    41                 return PPSTAMP_PARTIALLY_ON;
    42             }
    43         }
    44         psFree(cellExtent);
    45     }
    46 
    47     // This shouldn't ever happen since ROI is on the chip, it must at least partially overlap
    48     // one of the cells
    49     psError(PS_ERR_PROGRAMMING, false, "findCell couldn't find a cell containing the center\n");
    50 
    51     return PPSTAMP_OFF;
    52 }
     18// convert the input chip's transforms to the output
     19static bool convertWCS(pmHDU *outHDU, pmFPA *outFPA, pmChip *outChip, pmChip *inChip, psRegion *roi)
     20{
     21    pmHDU *hdu = pmHDUFromChip(inChip);
     22    PS_ASSERT_PTR_NON_NULL(hdu, 1)
     23    PS_ASSERT_PTR_NON_NULL(hdu->header, 1)
     24
     25    outChip->toFPA   = psPlaneTransformSetCenter(NULL, inChip->toFPA, roi->x0, roi->y0);
     26    outChip->fromFPA = psPlaneTransformInvert(NULL, outChip->toFPA, *roi, 50);
     27
     28    if (!pmAstromWriteWCS(outHDU->header, outFPA, outChip, WCS_NONLIN_TOL)) {
     29        psError(PS_ERR_UNKNOWN, false, "Failed to write WCS\n");
     30        return false;
     31    }
     32
     33    return true;
     34}
     35
     36static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, pmCell *inCell, psRegion *roi)
     37{
     38    pmChip    *outChip;
     39    pmFPAview *view = pmFPAviewAlloc(0);
     40
     41    // our output file has a single chip
     42    view->chip = 0;
     43    outChip = pmFPAviewThisChip(view, output->fpa);
     44    psFree(view);
     45
     46    // XXX we probably should copy some concepts from the chip (skipping those that don't apply)
     47    outChip->parent->concepts = psMetadataCopy(outChip->parent->concepts, inChip->parent->concepts);
     48
     49    pmHDU *inHDU  = pmHDUGetHighest(input->fpa, inChip, NULL);
     50    pmHDU *outHDU = pmHDUGetHighest(output->fpa, outChip, NULL);
     51
     52    if (inHDU->header) {
     53        outHDU->header = psMetadataCopy(outHDU->header, inHDU->header);
     54    } else if (!outHDU->header) {
     55        outHDU->header = psMetadataAlloc();
     56    }
     57
     58    // steal the input fpa's transforms
     59    output->fpa->toTPA = input->fpa->toTPA;
     60    output->fpa->fromTPA = input->fpa->fromTPA;
     61    output->fpa->toSky = input->fpa->toSky;
     62
     63    // drop the references
     64    input->fpa->toTPA = 0;
     65    input->fpa->fromTPA = 0;
     66    input->fpa->toSky = 0;
     67
     68    if (!convertWCS(outHDU, output->fpa, outChip, inChip, roi)) {
     69        return false;
     70    }
     71
     72    return true;
     73}
     74
     75// Build the postage stamp output file
    5376
    5477static bool makeStamp(pmConfig *config, ppstampOptions *options, pmFPAfile *input,
     
    82105    while ((readout = pmFPAviewNextReadout (view, input->fpa, 1)) != NULL) {
    83106        if (!readout->data_exists) {
    84             // XXX if this happens something is wrong
    85107            continue;
    86108        }
     
    92114        }
    93115
    94         // XXX Do we have to do somethign to deal with negative parity
    95116        psImage *subsetImage = psImageSubset(readout->image, options->roi);
    96117        if (subsetImage) {
     
    99120            psFree(subsetImage);
    100121            if (outReadout->image) {
     122                // The image has inherited the source's col0 and row0. We don't want this in
     123                // our output so override it.
    101124                // XXX put this into a function in psImage
    102125                // (What I really needed was a function to "create a copy of this portion of an image")
     
    126149
    127150
    128 static bool copyWCS(pmHDU *outHDU, pmFPA *outFPA, pmChip *outChip, pmChip *inChip, psRegion *roi)
    129 {
    130     pmHDU *hdu = pmHDUFromChip(inChip);
    131     PS_ASSERT_PTR_NON_NULL(hdu, 1)
    132     PS_ASSERT_PTR_NON_NULL(hdu->header, 1)
    133 
    134 #ifdef BRUTE_FORCE
    135     outChip->toFPA = inChip->toFPA;
    136     outChip->fromFPA = inChip->fromFPA;
    137     inChip->toFPA = 0;
    138     inChip->fromFPA = 0;
    139 
    140     // This gets us within one pixel of the correct answer
    141     psMetadataItemSupplement(outHDU->header, hdu->header, "CD1_1");
    142     psMetadataItemSupplement(outHDU->header, hdu->header, "CD1_2");
    143     psMetadataItemSupplement(outHDU->header, hdu->header, "CD2_1");
    144     psMetadataItemSupplement(outHDU->header, hdu->header, "CD2_2");
    145     psMetadataItemSupplement(outHDU->header, hdu->header, "CRVAL1");
    146     psMetadataItemSupplement(outHDU->header, hdu->header, "CRVAL2");
    147 
    148     double crpix1 = psMetadataLookupF64(NULL, hdu->header, "CRPIX1");
    149     double crpix2 = psMetadataLookupF64(NULL, hdu->header, "CRPIX2");
    150 
    151     crpix1 -= roi->x0;
    152     crpix2 -= roi->y0;
    153     psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "CRPIX1", PS_META_REPLACE, "", crpix1);
    154     psMetadataAddF64(outHDU->header, PS_LIST_TAIL, "CRPIX2", PS_META_REPLACE, "", crpix2);
    155 
    156 
    157 #else
    158 
    159     bool combineTransform = false;
    160     if (combineTransform) {
    161         // translation from output chip coordinates to input chip coordinates
    162         psPlaneTransform *trans = psPlaneTransformAlloc(1, 1);
    163 
    164         trans->x->coeff[0][0] = roi->x0;
    165         trans->x->coeff[0][1] = 0;
    166         trans->x->coeff[1][0] = 1.0;
    167         trans->x->coeff[1][1] = 0;
    168 
    169         trans->y->coeff[0][0] = roi->y0;
    170         trans->y->coeff[0][1] = 1.0;
    171         trans->y->coeff[1][0] = 0;
    172         trans->y->coeff[1][1] = 0;
    173 
    174         // combine the translation with the input's transform
    175         // Note: the region and magic number are not actually used by psPlaneTransformCombine
    176         outChip->toFPA = psPlaneTransformCombine(NULL, trans, inChip->toFPA, *roi, 50);
    177 
    178         // for completeness we set fromFPA, but since we don't use it ...
    179         outChip->fromFPA = psPlaneTransformInvert(NULL, outChip->toFPA, *roi, 50);
    180 
    181         // psFree(region);
    182         psFree(trans);
     151
     152static bool regionContainsPoint(psRegion *r, psPlane *pt)
     153{
     154    if (pt->x < r->x0)
     155        return false;
     156    if (pt->x >= r->x1)
     157        return false;
     158    if (pt->y < r->y0)
     159        return false;
     160    if (pt->y >= r->y1)
     161        return false;
     162
     163    return true;
     164}
     165
     166// true if the inner region is equal to or completely contained in
     167// the outer region
     168static bool regionContainsRegion(psRegion *outer, psRegion *inner)
     169{
     170    if ((outer->x0 <= inner->x0) &&
     171        (outer->y0 <= inner->y0) &&
     172        (outer->x1 >= inner->x1) &&
     173        (outer->y1 >= inner->y1)) {
     174        return true;
    183175    } else {
    184         outChip->toFPA = psPlaneTransformSetCenter(NULL, inChip->toFPA, roi->x0, roi->y0);
    185         outChip->fromFPA = psPlaneTransformInvert(NULL, outChip->toFPA, *roi, 50);
    186     }
    187 
    188 
    189     if (!pmAstromWriteWCS(outHDU->header, outFPA, outChip, WCS_NONLIN_TOL)) {
    190         psError(PS_ERR_UNKNOWN, false, "Failed to write WCS\n");
    191         return false;
    192     }
    193 #endif
    194 
    195     return true;
    196 }
    197 
    198 
    199 static bool copyMetadata(pmFPAfile *output, pmFPAfile *input, pmChip *inChip, pmCell *inCell, psRegion *roi)
    200 {
    201     pmChip    *outChip;
    202     pmFPAview *view = pmFPAviewAlloc(0);
    203 
    204     // our output file has a single chip
    205     view->chip = 0;
    206     outChip = pmFPAviewThisChip(view, output->fpa);
    207     psFree(view);
    208 
    209     outChip->parent->concepts = psMetadataCopy(outChip->parent->concepts, inChip->parent->concepts);
    210 
    211     pmHDU *inHDU  = pmHDUGetHighest(input->fpa, inChip, NULL);
    212     pmHDU *outHDU = pmHDUGetHighest(output->fpa, outChip, NULL);
    213 
    214     if (inHDU->header) {
    215         outHDU->header = psMetadataCopy(outHDU->header, inHDU->header);
    216     } else if (!outHDU->header) {
    217         outHDU->header = psMetadataAlloc();
    218     }
    219 
    220     // steal the input fpa's transforms
    221     output->fpa->toTPA = input->fpa->toTPA;
    222     output->fpa->fromTPA = input->fpa->fromTPA;
    223     output->fpa->toSky = input->fpa->toSky;
    224     // drop references
    225     input->fpa->toTPA = 0;
    226     input->fpa->fromTPA = 0;
    227     input->fpa->toSky = 0;
    228 
    229     if (!copyWCS(outHDU, output->fpa, outChip, inChip, roi)) {
    230         return false;
    231     }
    232 
    233     return true;
    234 }
    235 
    236 
    237 // findROI: find whether the region of interest is completely contained in a cell on a given chip.
    238 //  If so return the cell
    239 ppstampOverlap findROI(ppstampOptions *options, pmFPAview *view, pmFPAfile *input, pmChip *chip,
    240                 pmAstromObj *center, psRegion *roi, pmCell **ppCell)
    241 {
    242     psRegion    *chipExtent = pmChipPixels(chip);
     176        return false;
     177    }
     178}
     179
     180
     181static void skyToChip(pmAstromObj *pt, pmFPA *fpa, pmChip *chip)
     182{
     183    // convert from sky to FP
     184    psProject(pt->TP, pt->sky, fpa->toSky);
     185    psPlaneTransformApply(pt->FP, fpa->fromTPA, pt->TP);
     186    // convert from FP to chip
     187    psPlaneTransformApply(pt->chip, chip->fromFPA, pt->FP);
     188}
     189
     190static void chipToSky(pmAstromObj *pt, pmFPA *fpa, pmChip *chip)
     191{
     192    psPlaneTransformApply(pt->FP, chip->toFPA, pt->chip);
     193    psPlaneTransformApply(pt->TP, fpa->toTPA, pt->FP);
     194    psDeproject(pt->sky, pt->TP, fpa->toSky);
     195
     196}
     197
     198static void compareToBox(psRegion *region, psPlane *pt)
     199{
     200    if (pt->x < region->x0)
     201        region->x0 = pt->x;
     202    if (pt->x > region->x1)
     203        region->x1 = pt->x;
     204    if (pt->y < region->y0)
     205        region->y0 = pt->y;
     206    if (pt->y > region->y1)
     207        region->y1 = pt->y;
     208}
     209
     210static void findBoundingBox(ppstampOptions *options, pmFPA *fpa, pmChip *chip, pmAstromObj *center)
     211{
     212    pmAstromObj *pt = pmAstromObjAlloc();
     213
     214    if (!options->celestialCenter) {
     215        // Center was specified in chip coordinates, transform to the sky
     216        chipToSky(center, fpa, chip);
     217    }
     218
     219    // calculate the four corners of the bounding box in sky coordinates, translate them to
     220    // chip coordinates and build the ROI by comparison.
     221
     222    options->roi.x0 = INFINITY;
     223    options->roi.x1 = -INFINITY;
     224    options->roi.y0 = INFINITY;
     225    options->roi.y1 = -INFINITY;
     226   
     227    pt->sky->rErr = 0;
     228    pt->sky->dErr = 0;
     229
     230    pt->sky->r = center->sky->r - options->dRA/2;
     231    pt->sky->d = center->sky->d - options->dDEC/2;
     232    skyToChip(pt, fpa, chip);
     233    compareToBox(&options->roi, pt->chip);
     234
     235    pt->sky->r = center->sky->r + options->dRA/2;
     236    pt->sky->d = center->sky->d - options->dDEC/2;
     237    skyToChip(pt, fpa, chip);
     238    compareToBox(&options->roi, pt->chip);
     239
     240    pt->sky->r = center->sky->r + options->dRA/2;
     241    pt->sky->d = center->sky->d + options->dDEC/2;
     242    skyToChip(pt, fpa, chip);
     243    compareToBox(&options->roi, pt->chip);
     244
     245    pt->sky->r = center->sky->r - options->dRA/2;
     246    pt->sky->d = center->sky->d + options->dDEC/2;
     247    skyToChip(pt, fpa, chip);
     248    compareToBox(&options->roi, pt->chip);
     249
     250    psFree(pt);
     251}
     252
     253
     254// find cell on given chip that contains the region of interest
     255// return the status of the overlap and if the cell completely contains the ROI
     256// set a pointer to reference the cell
     257
     258static ppstampOverlap findCell(pmFPAview *view, ppstampOptions *options, pmFPAfile *input,
     259                                pmAstromObj *center, pmCell **ppCell)
     260{
     261    pmCell *cell;
     262
     263    view->cell = -1;
     264    while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) {
     265        psRegion *cellExtent = ppstampCellRegion(cell);
     266        if (regionContainsPoint(cellExtent, center->chip)) {
     267            if (regionContainsRegion(cellExtent, &options->roi)) {
     268                *ppCell = cell;
     269                psFree(cellExtent);
     270                return PPSTAMP_ON;
     271            } else {
     272                fprintf(stderr, "ROI must be confined to single cell. Partial overlap cell %d\n",
     273                    view->cell);
     274                fprintf(stderr, "Partial Overlap cell %d\n", view->cell);
     275                fprintf(stderr, "  ROI:         %s\n", psRegionToString(options->roi));
     276                fprintf(stderr, "  Cell Extent: %s\n", psRegionToString(*cellExtent));
     277                psFree(cellExtent);
     278                return PPSTAMP_PARTIALLY_ON;
     279            }
     280        }
     281        psFree(cellExtent);
     282    }
     283
     284    // This shouldn't ever happen since ROI is on the chip, it must at least partially overlap
     285    // one of the cells
     286    psError(PS_ERR_PROGRAMMING, false, "findCell couldn't find a cell containing the center\n");
     287
     288    return PPSTAMP_OFF;
     289}
     290
     291// findROI
     292// calculate the region of interest in chip coordinates and determine whether that region
     293// whether the region of interest is completely contained in a cell on a given chip.
     294
     295static ppstampOverlap findROI(ppstampOptions *options, pmFPAview *view, pmFPAfile *input, pmChip *chip,
     296                       pmAstromObj *center, pmCell **ppCell)
     297{
     298    psString chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
     299    psRegion    *chipExtent = ppstampChipRegion(chip);
    243300    bool        onChip = false;
    244301    ppstampOverlap   returnval = PPSTAMP_OFF;
    245     psString chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
    246302
    247303    // set up the astrometry
     
    253309        psError(PS_ERR_UNKNOWN, false, "Failed to Read WCS\n");
    254310        psFree(chipExtent);
    255         psFree(center);
    256311        return PPSTAMP_ERROR;
    257312    }
     
    259314    if (options->celestialCenter) {
    260315
    261         // convert from sky to FP
    262316        center->sky->r = options->centerRA;
    263317        center->sky->d = options->centerDEC;
    264         center->sky->rErr = 0;  // TODO: is this right?
     318        center->sky->rErr = 0;
    265319        center->sky->dErr = 0;
    266320
    267         psProject(center->TP, center->sky, input->fpa->toSky);
    268         psPlaneTransformApply(center->FP, input->fpa->fromTPA, center->TP);
    269 
    270         // convert from FP to chip
     321        skyToChip(center, input->fpa, chip);
    271322        psPlaneTransformApply(center->chip, chip->fromFPA, center->FP);
    272323
     
    277328        }
    278329    } else {
    279         // center specified in pixels, user needs to have specified the chip
    280         if (chipName == NULL) {
    281             psError(PS_ERR_UNKNOWN, true, "Failed to find CHIP.NAME\n");
    282             returnval = PPSTAMP_ERROR;
    283         }
    284         // ppstampArguments insures that options->chipName is not null
    285         if (!strcmp(chipName, options->chipName)) {
     330        // center specified in pixels.
     331        // If the user specified a name of a chip name wait until we get to that one.
     332        // If no chip name was specified, select this one (the first one that had data)
     333        if ((options->chipName == NULL) || !strcmp(chipName, options->chipName)) {
    286334            psLogMsg("ppstampMakeStamp", 3, "Center on chip: %s\n", chipName);
    287             onChip = true;
    288             onChip = true;
    289335            center->chip->x = options->centerX;
    290336            center->chip->y = options->centerY;
     337            center->chip->xErr = 0;
     338            center->chip->yErr = 0;
     339            onChip = true;
    291340        }
    292341    }
     
    294343    if (onChip) {
    295344        if (options->celestialRange) {
    296             // Protect against unimplemented feature
    297             psError(PS_ERR_PROGRAMMING, true, "not ready for Range in celestial coordinates yet.\n");
    298             exit(PS_EXIT_PROG_ERROR);
    299             // find the bounding box in pixel space that encloses the ROI
     345            findBoundingBox(options, input->fpa, chip, center);
    300346        } else {
    301347            int width  = options->dX;
     
    303349
    304350            // calculate the ROI in chip coordinates
    305             roi->x0 = center->chip->x - width / 2;
    306             roi->x1 = roi->x0 + width;
    307             roi->y0 = center->chip->y - height / 2;
    308             roi->y1 = roi->y0 + height;
    309 
    310             if (regionContainsRegion(chipExtent, roi)) {
    311                 returnval = findCell(view, options, input, center, ppCell);
    312             } else {
    313                 fprintf(stderr, "Partial Overlap chip %s\n", chipName);
    314                 fprintf(stderr, "ChipExtent: %s\n", psRegionToString(*chipExtent));
    315                 fprintf(stderr, "ROI:        %s\n", psRegionToString(*roi));
    316 
    317                 returnval = PPSTAMP_PARTIALLY_ON;
    318             }
     351            options->roi.x0 = center->chip->x - width / 2;
     352            options->roi.x1 = options->roi.x0 + width;
     353            options->roi.y0 = center->chip->y - height / 2;
     354            options->roi.y1 = options->roi.y0 + height;
     355        }
     356
     357        if (regionContainsRegion(chipExtent, &options->roi)) {
     358            returnval = findCell(view, options, input, center, ppCell);
     359        } else {
     360            fprintf(stderr, "Partial Overlap chip %s\n", chipName);
     361            fprintf(stderr, "ROI:         %s\n", psRegionToString(options->roi));
     362            fprintf(stderr, "Chip Extent: %s\n", psRegionToString(*chipExtent));
     363
     364            returnval = PPSTAMP_PARTIALLY_ON;
    319365        }
    320366    }
     
    363409
    364410        pmCell *cell;
    365         ppstampOverlap overlap = findROI(options, view, input, chip, center, &options->roi, &cell);
     411        ppstampOverlap overlap = findROI(options, view, input, chip, center, &cell);
    366412
    367413        if (overlap == PPSTAMP_ON) {
     
    409455
    410456
    411 static bool regionContainsPoint(psRegion *r, psPlane *pt)
    412 {
    413     // TODO: should this comparison be done with integers since we
    414     // are dealing with pixels?
    415     // Maybe we should round and truncate before we get here.
    416     if (pt->x < r->x0)
    417         return false;
    418     if (pt->x >= r->x1)
    419         return false;
    420     if (pt->y < r->y0)
    421         return false;
    422     if (pt->y >= r->y1)
    423         return false;
    424 
    425     return true;
    426 }
    427 
    428 // true if the inner region is equal to or completely contained in
    429 // the outer region
    430 static bool regionContainsRegion(psRegion *outer, psRegion *inner)
    431 {
    432     if ((outer->x0 <= inner->x0) &&
    433         (outer->y0 <= inner->y0) &&
    434         (outer->x1 >= inner->x1) &&
    435         (outer->y1 >= inner->y1)) {
    436         return true;
    437     } else {
    438         return false;
    439     }
    440 }
Note: See TracChangeset for help on using the changeset viewer.