Gatan | AMETEKSkip to Main Content
No options found

Change calibration units

DigitalMicrograph Script

Switch dimension calibration units in an image (demonstrate simple custom dialog).

Preview

/////////////////////////////////////////////////////////////////////
// (c) Gatan Inc.
/////////////////////////////////////////////////////////////////////
// This script will let the user change the units that an image is calibrated in.
// it handles km, m, cm, µm, nm, pm, and Å.  It will take an image calibrated in 
// any of these units and convert the calibration (and thus the scale bar also) 
// to new units.
// The script has two alternative main methods. A simple text-input version
// and a method building a custom dialog for more convenience.
/////////////////////////////////////////////////////////////////////
//	last modified 08-July-2014 BS

/*	This method, as indicated by 'number' before the method name,
	returns a numerical value corresponding to the exponent of the input units
	when given a string as input.
	e.g. supplied with cm, the method returns -2 to denote 
	the units are 10e-2m
	Note this method is called twice; once to calculate the old units 
	and also the new units.  Hence if either the entered units are not recognised
	or if the image calibration is not in known units
	then the routine will throw the unknown units error message.	*/

number GetUnitsExponent( string units )
{
	number exp
	if (units == "km")
		exp = 3
	else if (units == "m")
		exp = 0
	else if (units == "cm")
		exp = -2
	else if (units == "mm")
		exp = -3
	// Note the '||' is an OR operator
	else if (units == "µm" || units == "um" )					
		exp = -6
	else if (units == "nm")
		exp = -9
	else if (units == "Å" || units == "A")
		exp = -10
	else if (units == "pm" )
		exp = -12
	else
		Throw( "Unknown units.\nEnsure the input and image calibration are in SI units.")
	return exp
}

/*	This method, as indicated by 'string' before the method name,
	returns a string value. It replaces the 'easy' format of A and um
	by the nice Å or µm, respectively. Other unites are returned unchanged. */
	
string GetNiceUnit( string units )
{
	if (units == "um" )					
		return "µm"
	
	if (units == "A")
		return "Å"
		
	return units
}

/*	This method changes the calibration units of image 'img'
	to the units specified by the string 'newunits'
	As indicated by the use of 'void', the method doesn't return anything */

void ChangeImageUnits( image img, string newunits )
{
	//NDimen is the number of dimensions of image img
	number nDimen = img.ImageGetNumDimensions()	
	
	// Index is the dimension index number    
	// Loop nDimen times, changing the units of each dimension.
	number index 				
	for (index=0; index<nDimen; index++)       									
	{	
		// Get the existing dimension unit string for dimension 'index', denoted here as oldUnits															
		string oldUnits = img.ImageGetDimensionUnitString( index )
		
		// Call the method GetUnitsExponent to get the exponent corresponding to the inputted newUnits string 
		// and also for the exisiting old units 
		number newExp = GetUnitsExponent( newUnits )				
		number oldExp = GetUnitsExponent( oldUnits )

		// Now calulate the conversion factor 'convFactor'			
		number convFactor = 10**( oldExp-newExp )
							
		// Get the old scale 'cal' of dimension 'index'  
		number cal = img.ImageGetDimensionScale( index )
		
		// Set the scale of dimension 'index' to cal*convfactor and set the units of dimension 'index' as the string 'newUnits'			
		img.ImageSetDimensionScale( index, cal*convFactor )			
		img.ImageSetDimensionUnitString( index, GetNiceUnit(newUnits) )			
	}
}


/*	This function is the main part of the procedure, and from here
	the other functions are called (hence it is placed after the above functions).
	Again, the use of void denotes that nothing is returned when called */

void MenuChangeImageUnits()
{	
	// Grab the front image; note the use of ':=' to ensure changes		
	// to img also affects the front image by implication 
	image img := GetFrontImage()
									
	// Prompt the user to enter the string 'units'/  Note if nothing returned, the procedure ends
	string prompt = "Please enter the units for the scale bar.\n Examples: um for micron, A for Angstroms"
	string units 
	if (!GetString( prompt, units, units ))							 
		exit(0)	
		
	// Call the ChangeImageUnits method, passing in the input image and the desired units													
	ChangeImageUnits( img, units )									
}


/*	This function is a more UI based variant of the procedure above.
	It performs the same functionality, but prompts the user with a customized dialog 
	for better convenience. */

void MenuChangeImageUnitsByDialog()
{	
	// Grab the front image; note the use of ':=' to ensure changes		
	// to img also affects the front image by implication 
	image img := GetFrontImage()
									
	// Build a dialog-description tagGroup
	taggroup dlg, dlgItems
	dlg = DLGCreateDialog( "Select units", dlgItems )
	
	// Build a radio list in the dialog. Each entry has a displayed string and an 
	// according (unique) value. We simply use the value as 'index' in the list.
	// Addign the 'side' attribute formats the radio list horizontally.
	TagGroup radioListTG = DLGCreateRadioList( )
	radioListTG.DLGAddRadioItem( "km", 0 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "m", 1 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "cm", 2 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "mm", 3 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "µm", 4 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "nm", 5 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "Å", 6 ).DLGSide("Left")
	radioListTG.DLGAddRadioItem( "pm", 7 ).DLGSide("Left")
		
	// Add the radio list entry to the dialog
	dlgItems.DLGAddElement( radioListTG )
	
	// Pre-Initialize the dialog with the value of the current unit (X direction). 
	// If the radioList has an item of according value, it will be selected.
	// Otherwise no item will be selected.
	string oldXUnits = img.ImageGetDimensionUnitString( 0 )
	radioListTG.DLGValue(GetUnitsExponent(oldXUnits))
		
	// Create a dialog-object (UIframe) and initialize it with our built custom dialog
	object dialog = Alloc(UIframe).init(dlg)
	
	// Display the dialog as modal dialog (i.e. with OK/CANCEL button.)
	// If the user clicks Cancel, the method returns 0 and the script will stop
	// Changing the value in the dialog will be reflected in the value change
	// of the dialog tagGroup, i.e. the value of radioListTG will be changed.
	if ( !dialog.Pose() ) exit(0)

	// Read out the value of the radioList.
	number index = radioListTG.DLGGetValue()
	// Find the string associated with the value. 
	// Because our value is the 'index' of the whole list, we can directly
	// use it to find the according string.
	string units
	radioListTG.DLGGetNthLabel(index,units)
	
	// Call the ChangeImageUnits method, passing in the input image and the desired units													
	ChangeImageUnits( img, units )									
}


// Finally, call the MenuChangeImageUnits method to start the procedure
// Hint: Install the script in a menu with the Install Script command in the File menu

// MenuChangeImageUnits( )				// --> simple version	
MenuChangeImageUnitsByDialog( )			// --> custom dialog version