ProSEM In Action

Scripts - Using Multiple Recipes in One Project

Summary:

While most projects examine one type of image, so that a single recipe can apply to all images in that project, there are occasions where a mixture of image content or conditions, combined with a desire to keep the analysis of all images together, would make it useful to be able to apply different recipes to different images in the same project. This can be achieved with ProSEM's python scripting.

There must be some identifiable criterion that can be used to distinguish which recipe should be used on which images. The examples here show:

    • Using a pattern design identifier encoded in the image filename to use different recipes on images of different designs
    • Using the image pixel size from the image metadata to use different recipes on images of different magnifications

Demonstrates:

    • Using Scripts to measure images
    • Loading and running saved Recipes from a script
    • Evaluating filename content or image metadata to make decisions within scripts

Download:

This downloadable archive contains complete scripts for the examples which are shown below. For details on how to install and use these scripts, see How to Use Scripts Downloaded from this Website.

Note that these scripts will require some editing to customize the details for your specific images, file locations, recipes, and criteria.  See the notes below and the comments inside each script for more details.

Demonstration Script: Selective Recipes Using Filename Matching

This script measures a set of images where the recipe to be used depends on string matching within the file name -- in this example, the use different recipes on images with different designs, specifically with different pattern densities. For example, if the filename contains: "DEN_025" then the recipe named "DEN_025" will be run on that image.

Shown here is the active portion of the script, which loops through each defined recipe, and runs that recipe on any image in the project with a filename containing the selection string. The downloadable archive above contains complete scripts, though before use, it will be necessary to edit the script to update the recipe path, recipe names, and filename match strings.  

RecipePath = r"C:\Users\someone\ProSEM_Recipes"

# This list hold tuple pairs:   Recipe Name , Match String
	Recipes = [ ("ZEP_DEN_000","DEN_000"),
            ("ZEP_DEN_025","DEN_025"),
            ("ZEP_DEN_050","DEN_050"),
            ("ZEP_DEN_075","DEN_075"),
            ("ZEP_DEN_100","DEN_100"),
            ]

    print("Number of Recipes to test and possibly apply: ",len(Recipes))
    print("Number of Images to possibly measure:",len(prosem))

    recipeCount = 0
    for RecipeName,RecipeMatch in Recipes:
        recipeCount += 1
        ThisRecipe = os.path.join(RecipePath, RecipeName + '.mpr')
        print("Recipe {0}/{1}: {2!r}...".format(recipeCount,len(Recipes),RecipeName))
        prosem.load_recipe(ThisRecipe)
        for image in prosem:
            if re.search(RecipeMatch,image.label):        # is the match string in this image filename?
                print("   Image: {0!r}...".format(image.label))
                prosem.apply_recipe(image)

    print("Done.", file=sys.stderr)
    return True    # must return True so that the new measurements will be passed back into the interactive ProSEM instance.

Notes

  • If an image filename matches more than one search string in "Recipes" dictionary define, then this script will run multiple recipes on that image. The main handling loop could be modified to not run any recipe on an image which has already been measured, though this check would check for either measurements made on an image before the script, or by an earlier recipe in this script.

        ...
        prosem.load_recipe(ThisRecipe)
        for image in prosem:
            if len(image) > 1:    # don't measure again if this image already has measurements.
                if re.search(RecipeMatch,image.label):        # is the match string in this image filename?
                    print("   Image: {0!r}...".format(image.label))
                    prosem.apply_recipe(image)
        ...
  • For any images which don't match any of the search strings, this script will not run any recipe on those images. It would also be easy to add another loop just after this one to check for any images which still have no measurements, and run a 'default' recipe on those images.

Demonstration Script: Selective Recipe Using Image Metadata

This script measures a set of images where some images within the project are captured at different magnifications. Which recipe to apply is determined by checking the SEM magnification of the image, which is obtained from the image metadata. Whenever working with Image Metadata, the exact metadata tags used by the SEM software must be used, including identical case and any included punctuation marks. Use the Image Information panel to see the available metadata tags for the selected image. If this panel is not visible, enable it in ProSEM's View menu.

Note: care should be used in analyzing results from images captured using different conditions. The video signal content of the image depends strongly on the imaging conditions, and images of the same structure captured at different imaging conditions will likely measure differently.

# This list hold tuple pairs:   Recipe Name , Magnification
# These recipes much be in the directory pointed to by RecipePath
Recipes = [ ("EBET018 dot array 16kx","16000"),
            ("EBET018 dot array 30kx","30000")
            ]

RecipePath = prosem.base

metadataKey = '$CM_MAG'         # the metadata key to match the value above; must match exactly, including case
                                # the metadata keys available depend on the SEM software and settings. 

toleranceMagnification = 0.05   # if the magnification matches within this tolerance, then that recipe is used.
                                #  0.05 = 5% of mag total range, so +/- 2.5% above or below.

if len(prosem) == 0:
    print ('There are no images in this project.')
    return

# check that recipes exist first...
for RecipeName,RecipeMag in Recipes:
    ThisRecipe = os.path.join(RecipePath, RecipeName + '.mpr')
    recipesOK = True
    if not os.path.isfile(ThisRecipe):  #does the recipe file exist in the right place?
        print("\nError:\nRecipe: {}\nnot found at: {}".format(RecipeName,RecipePath))
        recipesOK = False
if not recipesOK:
    return

for image in prosem:
    if len(image) > 0:
        print('Image {}:  Already has stored measurements. Image not remeasured.'.format(image.label))
        continue     # go on to the next image
    try:        # use try/except to catch any errors that happen trying to get the metadata value, most probably that it just isn't there.
        thisMag = float(image.metadata[metadataKey])   # get the magnification, and convert it to a floating point number
    except:
        print ('Image {}:  Metadata item not found: {}.  Image not measured. '. format(image.label,metadataKey))
        continue     # go on to the next image
    for RecipeName,RecipeMag in Recipes:   # loop through the recipe, load and run the first one that matches
        testCriterion = (abs(float(RecipeMag) - thisMag)/ float(RecipeMag)) <= toleranceMagnification
        if (abs(float(RecipeMag) - thisMag)/ float(RecipeMag)) <= toleranceMagnification:
            print('Image {}:  Measuring with recipe: {}'.format(image.label,RecipeName))
            ThisRecipe = os.path.join(RecipePath, RecipeName + '.mpr')
            prosem.load_recipe(ThisRecipe)
            prosem.apply_recipe(image)
            break        # only run the first matching recipe, so once measured, go on to next image. 
    if len(image) == 0:
        print('Image {}:  No matching criterion for image mag: {} found.  Image not measured.'.format(image.label,thisMag))
print("Done.", file=sys.stderr)
return True    # must return True so that the new measurements will be passed back into the interactive ProSEM instance.

Notes

To demonstrate some additional techniques, this script has a few elements beyond the more simple example above:

  • Error checking that each defined recipe exists in the specified location
  • Recipes are assumed to be in the same folder as the ProSEM project, which is the location of the first image if the project has not yet been saved.
  • Checks if an image already has stored measurements; if so, the image is not re-measured.
  • The main processing loop is inverted compared to the above example. Rather than looping through all recipes and checking all images for a Match, this example loops through all images just once, but checks recipes until one that matches the specified criterion within the given tolerance is found. For small projects, there is likely no noticeable difference in execution speeds, but for projects with many images, this arrangement will execute faster.