IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 21143


Ignore:
Timestamp:
Jan 19, 2009, 4:56:51 PM (17 years ago)
Author:
eugene
Message:

significant re-work to support 8 and 16 bit values in a backwards-compatible way

Location:
branches/eam_branch_20081230/psModules/src/config
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branch_20081230/psModules/src/config/pmConfigMask.c

    r21130 r21143  
    99#include "pmConfigMask.h"
    1010
    11 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    12 // Private functions
    13 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    14 
    15 // maskSetValues examine named mask values and set the bits for maskValue and markValue.
    16 // Ensures that the below-named bad mask values are set, and calculates the mask value to catch them all
    17 // Ensure that the below-named other mask values are set (to 0x00 if necessary)
    18 
    19 // List of mask names for "bad" (i.e., mask me please) pixels
    20 static const char *badMaskNames[] = { "DETECTOR", // Something is wrong with the detector
    21                                       "DARK", // Pixel doesn't dark-subtract properly
    22                                       "FLAT", // Pixel doesn't flat-field properly
    23                                       "BLANK", // Pixel doesn't contain valid data
    24                                       "RANGE",// Pixel is out-of-range of linearity
    25                                       "SAT",  // Pixel is saturated
    26                                       // "LOW",  // Pixel is low
    27                                       // "CONV", // Pixel is bad after convolution with a bad pixel
    28                                       "BAD", // Pixel is low
    29                                       "BAD.WARP", // Pixel is bad after convolution with a bad pixel
    30                                       "CR",   // Pixel contains a cosmic ray
    31                                       "GHOST",// Pixel contains an optical ghost
    32                                       NULL // End marker
     11static pmConfigMaskInfo masks[] = {
     12    { "DETECTOR",  NULL,       0x00, true  },   // Something is wrong with the detector
     13    { "DARK",      "DETECTOR", 0x00, true  },   // Pixel doesn't dark-subtract properly
     14    { "FLAT",      "DETECTOR", 0x01, true  },   // Pixel doesn't flat-field properly
     15    { "BLANK",     "DETECTOR", 0x01, true  },   // Pixel doesn't contain valid data
     16    { "RANGE",     NULL,       0x00, true  },   // Pixel is out-of-range of linearity
     17    { "SAT",       "RANGE",    0x01, true  },   // Pixel is saturated
     18    { "BAD",       "RANGE",    0x01, true  },   // Pixel is low
     19    { "BAD.WARP",  NULL,       0x01, true  },   // Pixel is bad after convolution with a bad pixel
     20    { "CR",        NULL,       0x00, true  },   // Pixel contains a cosmic ray
     21    { "GHOST",     NULL,       0x00, true  },   // Pixel contains an optical ghost
     22    { "POOR.WARP", NULL,       0x00, false },   // Pixel is poor after convolution with a bad pixel
     23    // "LOW"  Pixel is low
     24    // "CONV" Pixel is bad after convolution with a bad pixel
    3325};
    34 // Fallback names in case a bad mask name is not defined
    35 static const char *fallbackMaskNames[] = { NULL, // DETECTOR
    36                                            "DETECTOR", // DARK
    37                                            "DETECTOR", // FLAT
    38                                            "DETECTOR", // BLANK
    39                                            NULL, // RANGE
    40                                            "RANGE", // SAT
    41                                            "RANGE", // LOW
    42                                            NULL, // CONV
    43                                            NULL, // CR
    44                                            NULL, // GHOST
    45 };
    46 // Default values in case a bad mask name and its fallback is not defined
    47 static const psImageMaskType defaultMask[] = { 0x00, // DETECTOR
    48                                                0x00, // DARK
    49                                                0x01, // FLAT
    50                                                0x01, // BLANK
    51                                                0x00, // RANGE
    52                                                0x01, // SAT
    53                                                0x01, // LOW
    54                                                0x01, // CONV
    55                                                0x00, // CR
    56                                                0x00  // GHOST
    57 };
    58 // Other mask names to ensure exist; these shouldn't be combined in the MASK.VALUE
    59 static const char *otherMaskNames[] = { // "POOR", // Pixel is poor after convolution with a bad pixel
    60                                         "POOR.WARP", // Pixel is poor after convolution with a bad pixel
    61                                         NULL // End marker
    62 };
    63 
    64 static bool maskSetValues(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
    65                           psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
    66                           psMetadata *source  // Source of mask bits
    67                           )
     26
     27// The functions in this file do not force the recipe or header values to be stored as the same
     28// type as psImageMaskType : they only check that the given values will fit in the space
     29// provided by psImageMaskType.  This should allow some backwards compatibility (old 8-bit
     30// masks will work with a 16-bit system), but will catch unhandled conflicts (trying to fit 16
     31// bits in 8-bits of space).
     32
     33// XXX this file does not have psError vs psWarning worked out correctly.  some of the
     34// failure modes should result in errors, not just warnings.
     35
     36// pmConfigMaskSetInMetadata examines named mask values and set the bits for maskValue and
     37// markValue.  Ensures that the below-named mask values are set, and calculates the mask value
     38// to catch all of the mask values marked as 'bad'.  Supplies the fallback name if the primary
     39// name is not found, or the default values if the fallback name is not found.
     40
     41bool pmConfigMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
     42                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
     43                               psMetadata *source  // Source of mask bits
     44    )
    6845{
    6946    PS_ASSERT_METADATA_NON_NULL(source, false);
    70 
     47   
    7148    // Ensure all the bad mask names exist, and set the value to catch all bad pixels
    7249    psImageMaskType maskValue = 0;           // Value to mask to catch all the bad pixels
    73     for (int i = 0; badMaskNames[i]; i++) {
    74         const char *name = badMaskNames[i]; // Name for mask
    75         const char *fallback = fallbackMaskNames[i]; // Fallback for mask
    76 
     50    psImageMaskType allMasks = 0;            // Value to mask to catch all masked bits (to set MARK)
     51
     52    int nMasks = sizeof (masks) / sizeof (pmConfigMaskInfo);
     53
     54    for (int i = 0; i < nMasks; i++) {
    7755        bool mdok;                      // Status of MD lookup
    78         psImageMaskType value = psMetadataLookupImageMask(&mdok, source, name); // Value of mask
     56        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, masks[i].badMaskName); // Value of mask
     57        if (!mdok) {
     58            psWarning ("problem with mask value %s\n", masks[i].badMaskName);
     59        }
     60
    7961        if (!value) {
    80             if (fallback) {
    81                 value = psMetadataLookupImageMask(&mdok, source, fallback);
    82             }
    83             if (!value) {
    84                 value = defaultMask[i];
    85             }
    86             psMetadataAddImageMask(source, PS_LIST_TAIL, name, PS_META_REPLACE, NULL, value);
    87         }
    88         maskValue |= value;
    89     }
    90 
    91     // Ensure all the other mask names exist
    92     for (int i = 0; otherMaskNames[i]; i++) {
    93         const char *name = otherMaskNames[i]; // Name for mask
    94         bool mdok;                      // Status of MD lookup
    95         psImageMaskType value = psMetadataLookupImageMask(&mdok, source, name); // Value of mask
    96         if (!value) {
    97             psMetadataAddImageMask(source, PS_LIST_TAIL, name, PS_META_REPLACE, NULL, 0x00);
    98         }
     62            if (masks[i].fallbackName) {
     63                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, masks[i].fallbackName);
     64            }
     65            if (!value) {
     66                value = masks[i].defaultMaskValue;
     67            }
     68            psMetadataAddImageMask(source, PS_LIST_TAIL, masks[i].badMaskName, PS_META_REPLACE, NULL, value);
     69        }
     70        if (masks[i].isBad) {
     71            maskValue |= value;
     72        }
     73        allMasks |= value;
    9974    }
    10075
     
    10580    int nBits = sizeof(psImageMaskType) * 8;
    10681    for (int i = 0; !markValue && (i < nBits); i++) {
    107         if (maskValue & markTrial) {
     82        if (allMasks & markTrial) {
    10883            markTrial <<= 1;
    10984        } else {
     
    131106
    132107// Get a mask value by name(s)
    133 static psImageMaskType maskGet(psMetadata *source, // Source of masks
    134                                const char *masks // Mask values to get
    135                                )
     108psImageMaskType pmConfigMaskGetFromMetadata(psMetadata *source, // Source of masks
     109                                            const char *masks // Mask values to get
     110    )
    136111{
    137112    psImageMaskType mask = 0;                // Mask value, to return
     
    141116        const char *name = names->data[i]; // Symbolic name of interest
    142117        bool mdok;                      // Status of MD lookup
    143         psImageMaskType value = psMetadataLookupImageMask(&mdok, source, name);
     118        psImageMaskType value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name);
    144119        if (!mdok) {
    145120            // Try and generate the value if we can
    146121            if (strcmp(name, "MASK.VALUE") == 0 || strcmp(name, "MARK.VALUE") == 0) {
    147                 if (!maskSetValues(NULL, NULL, source)) {
     122                if (!pmConfigMaskSetInMetadata(NULL, NULL, source)) {
    148123                    psError(PS_ERR_UNKNOWN, false, "Unable to set mask bits.");
    149124                    return 0;
    150125                }
    151                 value = psMetadataLookupImageMask(&mdok, source, name);
     126                value = psMetadataLookupImageMaskFromGeneric(&mdok, source, name);
    152127                psAssert(mdok, "Should have generated mask value");
    153128            } else {
     
    164139}
    165140
     141// lookup an image mask value by name from a psMetadata, without requiring the entry to
     142// be of type psImageMaskType, but verifying that it will fit in psImageMaskType
     143psImageMaskType psMetadataLookupImageMaskFromGeneric (bool *status, const psMetadata *md, const char *name) {
     144
     145    *status = true;
     146
     147        // select the mask bit name from the header
     148        psMetadataItem *item = psMetadataLookup (md, name);
     149        if (!item) {
     150            psWarning("Unable to find header keyword %s when parsing mask", name);
     151            *status = false;
     152            return 0;
     153        }
     154
     155        // the value may be any of the U8, U16, U32, U64 types : accept the value regardless of type size
     156        psU64 fullValue = 0;
     157        switch (item->type) {
     158          case PS_DATA_U8:
     159            fullValue = item->data.U8;
     160            break;
     161          case PS_DATA_U16:
     162            fullValue = item->data.U16;
     163            break;
     164          case PS_DATA_U32:
     165            fullValue = item->data.U32;
     166            break;
     167          case PS_DATA_U64:
     168            fullValue = item->data.U64;
     169            break;
     170            // XXX we could code this to accept Snn values, but they should not normally be used for masks
     171          default:
     172            psWarning("Mask entry %s in metadata is not of a mask type", name);
     173            *status = false;
     174            return 0;
     175        }
     176
     177        // will the incoming value fit within the current image mask type?
     178        if (fullValue > PS_MAX_IMAGE_MASK_TYPE) {
     179            psWarning("Mask entry %s in metadata is larger than allowed by the psImageMaskType", name);
     180            *status = false;
     181            return 0;
     182        }
     183        psImageMaskType value = fullValue;
     184        // XXX validate that value is a 2^n value?
     185
     186        return value;
     187}
     188
    166189// Remove from the header keywords starting with the provided string
    167 static int maskRemoveHeader(psMetadata *header, // Header from which to remove keywords
    168                             const char *start // Remove keywords that start with this string
    169                             )
     190int pmConfigMaskRemoveHeaderKeywords(psMetadata *header, // Header from which to remove keywords
     191                                     const char *start // Remove keywords that start with this string
     192    )
    170193{
    171194    psString regex = NULL;              // Regular expression for keywords
     
    183206}
    184207
     208// look up the named mask value(s) from the MASKS recipe in the config system
     209psImageMaskType pmConfigMaskGet(const char *masks, const pmConfig *config)
     210{
     211    psAssert(config, "Require configuration");
     212    PS_ASSERT_STRING_NON_EMPTY(masks, 0);
     213
     214    bool mdok;                          // Status of MD lookup
     215    psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe
     216    if (!recipe) {
     217        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     218        return 0;
     219    }
     220   
     221    psImageMaskType mask = pmConfigMaskGetFromMetadata (recipe, masks);
     222    return mask;
     223}
     224
     225bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psImageMaskType maskValue)
     226{
     227    psAssert(config, "Require configuration");
     228    PS_ASSERT_STRING_NON_EMPTY(maskName, false);
     229
     230    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     231    if (!recipe) {
     232        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     233        return false;
     234    }
     235
     236    bool status = psMetadataAddImageMask(recipe, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
     237    return status;
     238}
     239
     240
     241// replace the named masks in the recipe with values in the header:
     242// replace only the names in the header in the recipe
     243bool pmConfigMaskReadHeader(pmConfig *config, const psMetadata *header)
     244{
     245    PS_ASSERT_PTR_NON_NULL(config, false);
     246    PS_ASSERT_METADATA_NON_NULL(header, false);
     247
     248    bool status = false;
     249
     250    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     251    if (!recipe) {
     252        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     253        return false;
     254    }
     255
     256    // MASK.VALUE and MARK.VALUE aren't usually set in the recipe, but may be set in the header: create fake
     257    // versions so that it won't complain later
     258    if (!psMetadataLookup(recipe, "MASK.VALUE")) {
     259        psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MASK.VALUE", 0, "Bits to mask", 0);
     260    }
     261    if (!psMetadataLookup(recipe, "MARK.VALUE")) {
     262        psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MARK.VALUE", 0, "Bits for marking", 0);
     263    }
     264
     265    // How many mask values do we need to read?  We raise an error if this is not found,
     266    // unless the MASK.FORCE is set to true in the camera config
     267    int nMask = psMetadataLookupS32(&status, header, "MSKNUM");
     268    if (!status) {
     269        if (psMetadataLookupBool(&status, config->camera, "MASK.FORCE")) {
     270            psWarning("No mask values in header.  Assuming MASKS recipe is accurate because of MASK.FORCE");
     271            return true;
     272        }
     273        psError(PS_ERR_UNKNOWN, true, "Unable to find MSKNUM in header.");
     274        return false;
     275    }
     276
     277    // Loop over the expected number of header mask names.  For each named mask value, there
     278    // should be a pair of header keywords, one for the name and one for the value
     279    char namekey[80];                   // Keyword name for symbolic name of mask entry
     280    char valuekey[80];                  // Keyword name for value of mask entry
     281    for (int i = 0; i < nMask; i++) {
     282        snprintf(namekey,  64, "MSKNAM%02d", i);
     283        snprintf(valuekey, 64, "MSKVAL%02d", i);
     284
     285        char *name = psMetadataLookupStr(&status, header, namekey);
     286        if (!status || !name) {
     287            psWarning("Unable to find header keyword %s when parsing mask", namekey);
     288            continue;
     289        }
     290
     291        psImageMaskType headerValue = psMetadataLookupImageMaskFromGeneric (&status, header, valuekey);
     292        if (!status) {
     293            psWarning("Failed to get mask value %s from header, skipping", valuekey);
     294            continue;
     295        }           
     296
     297        // since we may read multiple mask files, we need to warn (or error?) if any of the
     298        // header mask values conflict with other header mask values; However, the original
     299        // mask values from the recipe do not need to match the header values.
     300
     301        // when we add a header mask value, we will also add the NAME.ALREADY entry; check for
     302        // the NAME.ALREADY entry to see if we have previously added this mask value from a
     303        // header.
     304
     305        psString nameAlready = NULL;    // Name of key with ".ALREADY" added
     306        psStringAppend(&nameAlready, "%s.ALREADY", name);
     307        bool already = psMetadataLookupBool(&status, recipe, nameAlready); // Already read this one?
     308
     309        bool inRecipe = false;
     310        psImageMaskType recipeValue = psMetadataLookupImageMaskFromGeneric (&inRecipe, recipe, name);
     311        if (!inRecipe) {
     312            psWarning("Mask value %s is not defined in the recipe", name);
     313        }           
     314
     315        if (already) {
     316            assert (inRecipe); // XXX makes no sense for NAME.ALREADY to be in without NAME
     317            if (recipeValue != headerValue) {
     318                psWarning("New mask header value does not match previously loaded entry: %x vs %x", headerValue, recipeValue);
     319                psMetadataAddImageMask(recipe, PS_LIST_TAIL, name, PS_META_REPLACE, "Bitmask bit value", headerValue);
     320                // XXX alternatively, error here
     321            }
     322        } else {
     323            psMetadataAddBool(recipe, PS_LIST_TAIL, nameAlready, 0, "Already read this mask value", true);
     324            psMetadataAddImageMask(recipe, PS_LIST_TAIL, name, PS_META_REPLACE, "Bitmask bit value", headerValue);
     325        }
     326
     327        psFree(nameAlready);
     328    }
     329
     330    return true;
     331}
     332
     333// write the named mask bits to the header
     334bool pmConfigMaskWriteHeader(const pmConfig *config, psMetadata *header)
     335{
     336    PS_ASSERT_PTR_NON_NULL(config, false);
     337    PS_ASSERT_METADATA_NON_NULL(header, false);
     338
     339    pmConfigMaskRemoveHeaderKeywords(header, "MSKNAM");
     340    pmConfigMaskRemoveHeaderKeywords(header, "MSKVAL");
     341    if (psMetadataLookup(header, "MSKNUM")) {
     342        psMetadataRemoveKey(header, "MSKNUM");
     343    }
     344
     345    char namekey[80];
     346    char valuekey[80];
     347
     348    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     349    if (!recipe) {
     350        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     351        return false;
     352    }
     353
     354    int nMask = 0;
     355
     356    psMetadataIterator *iter = psMetadataIteratorAlloc(recipe, PS_LIST_HEAD, NULL); // Iterator
     357    psMetadataItem *item;               // Item from iteration
     358    while ((item = psMetadataGetAndIncrement(iter))) {
     359
     360        // XXX this would give a false positive for mask which include '.ALREADY' in their names
     361        char *ptr = strstr (item->name, ".ALREADY");
     362        if (ptr) continue;
     363
     364        psU64 fullValue = 0;
     365        switch (item->type) {
     366          case PS_DATA_U8:
     367            fullValue = item->data.U8;
     368            break;
     369          case PS_DATA_U16:
     370            fullValue = item->data.U16;
     371            break;
     372          case PS_DATA_U32:
     373            fullValue = item->data.U32;
     374            break;
     375          case PS_DATA_U64:
     376            fullValue = item->data.U64;
     377            break;
     378          default:
     379            psWarning("mask recipe entry %s is not a bit value\n", item->name);
     380            continue;
     381        }
     382        assert (fullValue <= PS_MAX_IMAGE_MASK_TYPE); // this should have been asserted on read...
     383
     384        snprintf(namekey,  64, "MSKNAM%02d", nMask);
     385        snprintf(valuekey, 64, "MSKVAL%02d", nMask);
     386
     387        psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
     388        psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", fullValue);
     389        nMask++;
     390    }
     391    psFree(iter);
     392
     393    psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
     394    return true;
     395}
     396
     397
     398bool pmConfigMaskSetBits(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, const pmConfig *config)
     399{
     400    PS_ASSERT_PTR_NON_NULL(config, false);
     401
     402    psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
     403    if (!recipe) {
     404        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
     405        return false;
     406    }
     407
     408    bool status = pmConfigMaskSetInMetadata(outMaskValue, outMarkValue, recipe);
     409    return status;
     410}
     411
    185412//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    186413// FPA version of mask functions.  These are not ready to go yet.
     
    188415
    189416#if 0
     417
     418bool pmFPAMaskWriteHeader(psMetadata *header, const pmFPA *fpa)
     419{
     420    PS_ASSERT_METADATA_NON_NULL(header, false);
     421    PS_ASSERT_PTR_NON_NULL(fpa, false);
     422
     423    // clear out the header of the associated keywords:
     424    pmConfigMaskRemoveHeaderKeywords(header, "MSKNAM");
     425    pmConfigMaskRemoveHeaderKeywords(header, "MSKVAL");
     426    if (psMetadataLookup(header, "MSKNUM")) {
     427        psMetadataRemoveKey(header, "MSKNUM");
     428    }
     429
     430    char namekey[80], valuekey[80];     // Mask name and mask value header keywords
     431    int numMask = 0;                    // Number of mask entries
     432
     433    psMetadataIterator *iter = psMetadataIteratorAlloc(fpa->masks, PS_LIST_HEAD, NULL); // Iterator
     434    psMetadataItem *item;               // Item from iteration
     435    while ((item = psMetadataGetAndIncrement(iter))) {
     436        if (item->type != PS_TYPE_IMAGE_MASK) {
     437            psWarning("mask recipe entry %s is not of a mask type (%x)", item->name, item->type);
     438            continue;
     439        }
     440
     441        snprintf(namekey,  64, "MSKNAM%02d", numMask);
     442        snprintf(valuekey, 64, "MSKVAL%02d", numMask);
     443
     444        psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
     445        psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.PS_TYPE_IMAGE_MASK_DATA);
     446        numMask++;
     447    }
     448    psFree(iter);
     449
     450    return psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Number of named mask entries", numMask);
     451}
     452
    190453bool pmFPAMaskSetValues(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, pmFPA *fpa)
    191454{
     
    202465
    203466    if (fpa->masks) {
    204         return maskGet(fpa->masks, masks);
     467        return pmConfigMaskGetFromMetadata(fpa->masks, masks);
    205468    }
    206469    return pmConfigMaskGet(masks, config);
     
    295558    return true;
    296559}
    297 
    298 
    299 bool pmFPAMaskWriteHeader(psMetadata *header, const pmFPA *fpa)
    300 {
    301     PS_ASSERT_METADATA_NON_NULL(header, false);
    302     PS_ASSERT_PTR_NON_NULL(fpa, false);
    303 
    304     maskRemoveHeader(header, "MSKNAM");
    305     maskRemoveHeader(header, "MSKVAL");
    306     if (psMetadataLookup(header, "MSKNUM")) {
    307         psMetadataRemoveKey(header, "MSKNUM");
    308     }
    309 
    310     char namekey[80], valuekey[80];     // Mask name and mask value header keywords
    311     int numMask = 0;                    // Number of mask entries
    312 
    313     psMetadataIterator *iter = psMetadataIteratorAlloc(fpa->masks, PS_LIST_HEAD, NULL); // Iterator
    314     psMetadataItem *item;               // Item from iteration
    315     while ((item = psMetadataGetAndIncrement(iter))) {
    316         if (item->type != PS_TYPE_IMAGE_MASK) {
    317             psWarning("mask recipe entry %s is not of a mask type (%x)", item->name, item->type);
    318             continue;
    319         }
    320 
    321         snprintf(namekey,  64, "MSKNAM%02d", numMask);
    322         snprintf(valuekey, 64, "MSKVAL%02d", numMask);
    323 
    324         psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
    325         psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.PS_TYPE_IMAGE_MASK_DATA);
    326         numMask++;
    327     }
    328     psFree(iter);
    329 
    330     return psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Number of named mask entries", numMask);
    331 }
    332 
    333560#endif
    334 
    335 
    336 psImageMaskType pmConfigMaskGet(const char *masks, const pmConfig *config)
    337 {
    338     psAssert(config, "Require configuration");
    339     PS_ASSERT_STRING_NON_EMPTY(masks, 0);
    340 
    341     bool mdok;                          // Status of MD lookup
    342     psMetadata *recipe = psMetadataLookupMetadata(&mdok, config->recipes, "MASKS"); // The recipe
    343     if (!recipe) {
    344         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    345         return 0;
    346     }
    347     return maskGet(recipe, masks);
    348 }
    349 
    350 
    351 bool pmConfigMaskSet(const pmConfig *config, const char *maskName, psImageMaskType maskValue)
    352 {
    353     psAssert(config, "Require configuration");
    354     PS_ASSERT_STRING_NON_EMPTY(maskName, false);
    355 
    356     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    357     if (!recipe) {
    358         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    359         return false;
    360     }
    361 
    362     return psMetadataAddImageMask(recipe, PS_LIST_TAIL, maskName, PS_META_REPLACE, NULL, maskValue);
    363 }
    364 
    365 
    366 // replace the named masks in the recipe with values in the header:
    367 // replace only the names in the header in the recipe
    368 bool pmConfigMaskReadHeader(pmConfig *config, const psMetadata *header)
    369 {
    370     PS_ASSERT_PTR_NON_NULL(config, false);
    371     PS_ASSERT_METADATA_NON_NULL(header, false);
    372 
    373     bool status = false;
    374 
    375     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    376     if (!recipe) {
    377         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    378         return false;
    379     }
    380 
    381     // MASK.VALUE and MARK.VALUE aren't usually set in the recipe, but may be set in the header: create fake
    382     // versions so that it won't complain later
    383     if (!psMetadataLookup(recipe, "MASK.VALUE")) {
    384         psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MASK.VALUE", 0, "Bits to mask", 0);
    385     }
    386     if (!psMetadataLookup(recipe, "MARK.VALUE")) {
    387         psMetadataAddImageMask(recipe, PS_LIST_TAIL, "MARK.VALUE", 0, "Bits for marking", 0);
    388     }
    389 
    390     int nMask = psMetadataLookupS32(&status, header, "MSKNUM");
    391     if (!status) {
    392         if (psMetadataLookupBool(&status, config->camera, "MASK.FORCE")) {
    393             psWarning("No mask values in header.  Assuming MASKS recipe is accurate because of MASK.FORCE");
    394             return true;
    395         }
    396         psError(PS_ERR_UNKNOWN, true, "Unable to find MSKNUM in header.");
    397         return false;
    398     }
    399 
    400     char namekey[80];                   // Keyword name for symbolic name of mask entry
    401     char valuekey[80];                  // Keyword name for value of mask entry
    402     for (int i = 0; i < nMask; i++) {
    403         snprintf(namekey,  64, "MSKNAM%02d", i);
    404         snprintf(valuekey, 64, "MSKVAL%02d", i);
    405 
    406         char *name = psMetadataLookupStr(&status, header, namekey);
    407         if (!status || !name) {
    408             psWarning("Unable to find header keyword %s when parsing mask", namekey);
    409             continue;
    410         }
    411         psImageMaskType bit = psMetadataLookupImageMask(&status, header, valuekey);
    412         if (!status) {
    413             psWarning("Unable to find header keyword %s when parsing mask", namekey);
    414             continue;
    415         }
    416 
    417         // XXX validate that bit is a 2^n value?
    418 
    419         psString nameAlready = NULL;    // Name of key with ".ALREADY" added
    420         psStringAppend(&nameAlready, "%s.ALREADY", name);
    421         bool already = psMetadataLookupBool(&status, recipe, nameAlready); // Already read this one?
    422 
    423         psMetadataItem *item = psMetadataLookup(recipe, name); // Item in recipe with current value
    424         if (item && item->type != PS_TYPE_IMAGE_MASK) {
    425             psWarning("Mask recipe entry is not of a mask type (%x)", item->type);
    426             item->type = PS_TYPE_IMAGE_MASK;
    427         }
    428 
    429         if (already) {
    430             if (item && item->data.PS_TYPE_IMAGE_MASK_DATA != bit) {
    431                 psWarning("New mask recipe entry doesn't match previously loaded entry: %x vs %x",
    432                           bit, item->data.PS_TYPE_IMAGE_MASK_DATA);
    433             }
    434         } else {
    435             psMetadataAddBool(recipe, PS_LIST_TAIL, nameAlready, 0, "Already read this mask value", true);
    436         }
    437 
    438         if (!item) {
    439             psWarning("Mask recipe entry %s not in recipe\n", name);
    440             psMetadataAddImageMask(recipe, PS_LIST_TAIL, name, 0, "Bitmask bit value", bit);
    441         } else {
    442             item->data.PS_TYPE_IMAGE_MASK_DATA = bit;
    443         }
    444 
    445         psFree(nameAlready);
    446     }
    447 
    448 
    449     return true;
    450 }
    451 
    452 
    453 
    454 // write the named mask bits to the header
    455 bool pmConfigMaskWriteHeader(const pmConfig *config, psMetadata *header)
    456 {
    457     PS_ASSERT_PTR_NON_NULL(config, false);
    458     PS_ASSERT_METADATA_NON_NULL(header, false);
    459 
    460     maskRemoveHeader(header, "MSKNAM");
    461     maskRemoveHeader(header, "MSKVAL");
    462     if (psMetadataLookup(header, "MSKNUM")) {
    463         psMetadataRemoveKey(header, "MSKNUM");
    464     }
    465 
    466     char namekey[80];
    467     char valuekey[80];
    468 
    469     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    470     if (!recipe) {
    471         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    472         return false;
    473     }
    474 
    475     int nMask = 0;
    476 
    477     psMetadataIterator *iter = psMetadataIteratorAlloc(recipe, PS_LIST_HEAD, NULL); // Iterator
    478     psMetadataItem *item;               // Item from iteration
    479     while ((item = psMetadataGetAndIncrement(iter))) {
    480         if (strcmp(item->name + strlen(item->name) - strlen(".ALREADY"), ".ALREADY") == 0) {
    481             continue;
    482         }
    483 
    484         if (item->type != PS_TYPE_IMAGE_MASK) {
    485             psWarning("mask recipe entry %s is not a bit value\n", item->name);
    486             continue;
    487         }
    488 
    489         snprintf(namekey,  64, "MSKNAM%02d", nMask);
    490         snprintf(valuekey, 64, "MSKVAL%02d", nMask);
    491 
    492         psMetadataAddStr(header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
    493         psMetadataAddImageMask(header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.PS_TYPE_IMAGE_MASK_DATA);
    494         nMask++;
    495     }
    496     psFree(iter);
    497 
    498     psMetadataAddS32(header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
    499     return true;
    500 }
    501 
    502 
    503 bool pmConfigMaskSetBits(psImageMaskType *outMaskValue, psImageMaskType *outMarkValue, const pmConfig *config)
    504 {
    505     PS_ASSERT_PTR_NON_NULL(config, false);
    506 
    507     psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, "MASKS"); // The recipe
    508     if (!recipe) {
    509         psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find MASKS recipe.");
    510         return false;
    511     }
    512 
    513     return maskSetValues(outMaskValue, outMarkValue, recipe);
    514 }
  • branches/eam_branch_20081230/psModules/src/config/pmConfigMask.h

    r21079 r21143  
    44 *  @author Paul Price, IfA
    55 *
    6  *  @version $Revision: 1.4.30.1 $ $Name: not supported by cvs2svn $
    7  *  @date $Date: 2009-01-02 05:13:00 $
     6 *  @version $Revision: 1.4.30.2 $ $Name: not supported by cvs2svn $
     7 *  @date $Date: 2009-01-20 02:56:51 $
    88 *  Copyright 2007 Institute for Astronomy, University of Hawaii
    99 */
     
    1919/// @addtogroup Config Configuration System
    2020/// @{
     21
     22// structure to hold the properties of a mask value
     23typedef struct {
     24    char *badMaskName;                  // name for "bad" (i.e., mask me please) pixels
     25    char *fallbackName;                 // Fallback name in case a bad mask name is not defined
     26    psImageMaskType defaultMaskValue;   // Default value in case a bad mask name and its fallback are not defined
     27    bool isBad; // include this value as part of the MASK.VALUE entry (generically bad)
     28} pmConfigMaskInfo;
     29
     30// pmConfigMaskSetInMetadata examines named mask values and set the bits for maskValue and
     31// markValue.  Ensures that the below-named mask values are set, and calculates the mask value
     32// to catch all of the mask values marked as 'bad'.  Supplies the fallback name if the primary
     33// name is not found, or the default values if the fallback name is not found.
     34bool pmConfigMaskSetInMetadata(psImageMaskType *outMaskValue, // Value of MASK.VALUE, returned
     35                               psImageMaskType *outMarkValue, // Value of MARK.VALUE, returned
     36                               psMetadata *source  // Source of mask bits
     37  );
     38
     39
     40// Get a mask value by name(s)
     41psImageMaskType pmConfigMaskGetFromMetadata(psMetadata *source, // Source of masks
     42                                            const char *masks // Mask values to get
     43  );
     44
     45
     46// lookup an image mask value by name from a psMetadata, without requiring the entry to
     47// be of type psImageMaskType, but verifying that it will fit in psImageMaskType
     48psImageMaskType psMetadataLookupImageMaskFromGeneric (bool *status, const psMetadata *md, const char *name);
     49
     50// Remove from the header keywords starting with the provided string
     51int pmConfigMaskRemoveHeaderKeywords(psMetadata *header, // Header from which to remove keywords
     52                                     const char *start // Remove keywords that start with this string
     53  );
    2154
    2255/// Return a mask value given a list of symbolic names
Note: See TracChangeset for help on using the changeset viewer.