Introduction
Imatest IT (Industrial Testing) is a set of Application Programming Interfaces (APIs) that allow developers to access Imatest’s powerful image quality analysis tools in their own custom applications.
Imatest IT is available for 64-bit Windows, MacOS and Linux, and includes libraries for use with C, C++, Python, Objective-C, .NET (Windows only – including C# and Visual Basic), and LabVIEW. IT also contains standalone executables that can be called from a command line or script. The API libraries perform the exact same calculations as the corresponding GUI-based Imatest Master modules.
Imatest IT is a complete package that includes the module libraries, support documentation, sample code, and complete applications that interface with the modules.
Although Imatest IT operates independently of Imatest Master, we strongly recommend that IT users have at least one Master installation on site. Imatest Ultimate Edition, which includes both IT and Image Master Edition at a significant discount, is the ideal option for most users. As you will see in Step 2 below, setting up your test configuration, an integral part of any IT application, is much easier using Master.
Imatest IT Modules
Imatest IT contains sixteen image analysis modules:
SFR – measures MTF and related results from manually-specified slanted edges | SFRplus – measures MTF, lateral chromatic aberration, distortion, tonal response, and much more using Imatest’s highly-automated SFRplus chart and module |
Star – measures MTF and lateral chromatic aberration from a Siemens star chart (usually sinusoidal) | Colorcheck – measures color accuracy, noise, tonal response, and more from a 24-patch X-Rite Colorchecker |
Stepchart – measures tonal response, gamma, noise, and more from a grayscale stepchart | Wedge – measures MTF using hyperbolic wedges, found in the ISO 12233:2000 and eSFR ISO chart |
OIS – measures the efficacy of image stabilization | Uniformity – measures image uniformity, color shading, and hot/dead pixels from a flat field image |
Distortion – measures distortion using a grid or checkerboard pattern | eSFR ISO – measures MTF, color accuracy, noise, and tonal response using an enhanced ISO 12233:2014 chart |
Blemish – measures visually-significant blemishes from a flat field image | Dot Pattern – measures distortion and lateral chromatic aberration from a dot grid pattern (I3A CPIQ-compliant) |
Multitest – analyzes images of a large variety of test charts for color accuracy, tonal response, noise, SNR (Signal-to-Noise Ratio) and ISO sensitivity | Checkerboard – measures MTF, lateral chromatic aberration, and distortion using a checkerboard target |
Random – Module that measures texture quality using the spilled coins or random (spatially-invariant) chart | SFRreg – measures MTF and lateral chromatic aberration using one or more automatically-detected SFRreg targets |
Log FC – measures the effects of signal processing (MTF as a function of spatial frequency and contrast) using a Log Frequency-Contrast chart | Arbitrary Charts – measure a wide array of image quality factors from a chart design unsupported elsewhere in Imatest (including your own custom design). |
Using Imatest IT
As illustrated in this graphic, working with Imatest IT is a four-step process. Each of these steps is outlined in detail in this article.
Step 1: Prepare Test Environment and Capture Test Targets
Inputs: None
Outputs: Test Image(s)
Imatest’s analysis modules require correctly framed and properly lit images of test targets. Once your test environment is properly set up, capture images of the required test targets for the modules you will be using.
Step 2: Configure INI File w/ Test Image(s)
Inputs: Test Image(s)
Outputs: INI File(s)
Using a sampling of the test images captured in Step 1, use Imatest Master to analyze the image files, choosing the options required for your application, and setting the Regions of Interest (ROIs) for your charts. Once everything is ready, export the INI file and keep it with your application source files.
In Imatest you can use the Save ini file for button in the Imatest IT settings window to save an ini file with only the needed sections.
Step 3: Integrate and Call Imatest IT Modules
Inputs: Test Image(s), INI File(s)
Outputs: Analysis Results
Code your application using your preferred programming language and call the module functions with your images and INI file.
Step 4: Process the Results
Inputs: Analysis Results
Outputs: Whatever you need
Load the analysis results and use them however you wish.
Installing Imatest IT
If you have not already downloaded Imatest IT, you can do so on the download page.
Next, follow the installation instructions found here.
After Imatest IT has successfully installed, you will need to activate it on your computer. Follow these instructions to activate your node-locked or floating license. If the computer running Imatest IT does not have an internet connection, you can also choose to activate it offline.
Post Installation Tasks
Linux Only – Updating the LD_LIBRARY_PATH
On Linux computers, several paths need to be appended to the LD_LIBRARY_PATH environment variable. To do this, you will need to edit your ~/.bashrc (or similar) file, and include these lines:
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/Imatest/v2020.2/IT/bin export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/Imatest/v2020.2/IT/libs/library/cpp export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/MATLAB/MATLAB_Runtime/v98/runtime/glnxa64 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/MATLAB/MATLAB_Runtime/v98/bin/glnxa64 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/MATLAB/MATLAB_Runtime/v98/sys/os/glnxa64 export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/MATLAB/MATLAB_Runtime/v98/sys/opengl/lib/glnxa64
For more information on editing environment variables, see this article.
macOS Only – Updating DYLD_LIBRARY_PATH
On macOS computers, several paths need to be appended to the DYLD_LIBRARY_PATH environment variable.
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/Applications/Imatest/IT/v2020.2/bin export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/Applications/Imatest/IT/v2020.2/libs/library/cpp export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/Applications/MATLAB/MATLAB_Runtime/v98/runtime/maci64 export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH}:/Applications/MATLAB/MATLAB_Runtime/v98/bin/maci64
(Optional) – Reducing Startup Time w/ the MCR Cache
The first time you use the Imatest IT libraries, they must be unpacked to a temporary directory. This can take several seconds, depending on your system. In some use cases, this can happen on every use, especially if you are using the Imatest IT Acquisition Library.
To prevent the repeated unpacking of the IT libraries, you need to set two more environment variables: MCR_CACHE_ROOT and MCR_CACHE_SIZE. The MCR_CACHE_ROOT variable tells the Matlab Runtime where to extract the Imatest IT libraries. Setting it to a specific location that has write access for all users ensures that this cache will not be deleted by the operating system when it cleans up temporary files. The MCR_CACHE_SIZE variable is the size, in bytes, that the Matlab Runtime cache is allowed to grow to before other libraries are deleted. To keep Imatest IT running at top performance, it should be set to at least 900000000, and will result in much faster startup times for Imatest IT for some users.
Follow the instructions here to add these variables to your environment.
Windows
Variable Name | Value |
---|---|
MCR_CACHE_ROOT | C:\ProgramData\Imatest\mcr_cache\2020.2\IT |
MCR_CACHE_SIZE | 900000000 |
Linux
Variable Name | Value |
---|---|
MCR_CACHE_ROOT | /var/lib/imatest/mcr_cache/2020.2/IT |
MCR_CACHE_SIZE | 900000000 |
macOS
Variable Name | Value |
---|---|
MCR_CACHE_ROOT | $HOME/imatest/mcr_cache/2020.2/IT |
MCR_CACHE_SIZE | 900000000 |
Note that for macOS you will need to create this folder.
Other Additional Installation Steps
Select your preferred interface below to see detailed instructions.
In order for your application to interface with the Imatest IT C or C++ DLLs, your system needs to know where to find them.
There are two ways to make the Imatest IT C or C++ DLLs available to the system:
- Add the library’s directory to your system’s PATH or LD_LIBRARY_PATH variable (recommended).
- Copy the DLLs to the same directory as your application.
Adding to the PATH or LD_LIBRARY_PATH variable
Add the following directory to your system’s PATH (Windows) or LD_LIBRARY_PATH (Linux) variable, depending on which interface you will be using. For instructions on how to do this, see Editing System Environment Variables.
Note: Linux users may already have completed this step by following the Additional Installation Steps above, if you are using the C++ library.
In order for your application to interface with the Imatest IT C or C++ DLLs, your system needs to know where to find them.
There are two ways to make the Imatest IT C or C++ DLLs available to the system:
- Add the library’s directory to your system’s PATH or LD_LIBRARY_PATH variable (recommended).
- Copy the DLLs to the same directory as your application.
Adding to the PATH or LD_LIBRARY_PATH variable
Add the following directory to your system’s PATH (Windows) or LD_LIBRARY_PATH (Linux) variable, depending on which interface you will be using. For instructions on how to do this, see Editing System Environment Variables.
Note: Linux users may already have completed this step by following the Additional Installation Steps above, if you are using the C++ library.
Operating System | Variable Name | Value |
---|---|---|
Windows | PATH | C:\Program Files\Imatest\v2020.2\IT\libs\library\c |
Linux | LD_LIBRARY_PATH | /usr/local/Imatest/v2020.2/IT/libs/library/c |
Operating System | Variable Name | Value |
---|---|---|
Windows | PATH | C:\Program Files\Imatest\v2020.2\IT\libs\library\cpp |
Linux | LD_LIBRARY_PATH | /usr/local/Imatest/v2020.2/IT/libs/library/cpp |
macOS | DYLD_LIBRARY_PATH | /Applications/Imatest/IT/v2020.2/libs/library/cpp |
Copying the Imatest IT DLLs
If you prefer not to change your PATH or LD_LIBRARY_PATH variables, you can also reference the Imatest IT DLLs by copying them to the same directory as your project’s executable.
Visual Studio users can automate this process by adding a Post-Build Event.
- In the Solution Explorer, right-click on the project and select Properties.
- Under Configuration Properties and Build Events, choose Post-Build Event.
- Add the following to the Command Line box:
[shell]
copy /Y "C:\Program Files\Imatest\v2020.2\IT\libs\library\c\imatest_library.dll" ";$(TargetDir)"
[/shell] - Repeat these steps for each configuration in your project.
Now, the imatest_library.dll file will be copied to your project’s target directory automatically and will be able to be loaded by your application.
Copying the Imatest IT DLLs
If you prefer not to change your PATH or LD_LIBRARY_PATH variables, you can also reference the Imatest IT DLLs by copying them to the same directory as your project’s executable.
Visual Studio users can automate this process by adding a Post-Build Event.
- In the Solution Explorer, right-click on the project and select Properties.
- Under Configuration Properties and Build Events, choose Post-Build Event.
- Add the following to the Command Line box:
[shell]
copy /Y "C:\Program Files\Imatest\v2020.2\IT\libs\library\cpp\imatest_library.dll" "$(TargetDir)"
[/shell] - Repeat these steps for each configuration in your project.
Now, the imatest_library.dll file will be copied to your project’s target directory automatically and will be able to be loaded by your application.
In order for your application to interface with the Imatest IT C++ libraries using Objective-C/C++, your system needs to know where to find them.
There are two ways to make the Imatest IT C++ libraries available to the system:
- Add the library’s directory to your system’s DYLD_LIBRARY_PATH variable.
- Copy the libraries to the same directory as your application.
Adding to the DYLD_LIBRARY_PATH variable
Add the following folder paths to your system’s DYLD_LIBRARY_PATH variable, depending on which interface you will be using. For instructions on how to do this, see Editing System Environment Variables.
Operating System | Variable Name | Value |
---|---|---|
macOS | DYLD_LIBRARY_PATH | /Applications/Imatest/IT/v2020.2/libs/library/cpp |
macOS | DYLD_LIBRARY_PATH | /Applications/Imatest/IT/v2020.2/bin |
Copying the Imatest IT Libraries
If you prefer not to change your DYLD_LIBRARY_PATH variable, you can also reference the Imatest IT libraries by copying them to the same directory as your project’s executable.
XCode users can automate this process by adding a Copy File and a Run Script Build Phase
- In the project editor, select your application’s target and then go to the Build Phases pane.
- Go to the Editor menu and then select Add Build Phase:Add Copy Files Build Phase.
- In the Copy Files phase, set the Destination to Products Directory.
- Click the + icon and then click the Add Other… button.
- Navigate /Applications/Imatest/IT/v2020.2/libs/library/cpp/, select libImatest.dylib, press Open and then press Finish.
- In the Copy Files phase, deselect Copy Sign On Copy.
- Repeat the process for /Applications/Imatest/IT/v2020.2/bin/ShaferFilechck.dylib.
- In the Run Script phase add
install_name_tool -change @loader_path/libImatest.dylib @rpath/libImatest.dylib ${TARGET_BUILD_DIR}/${WRAPPER_NAME}/Contents/MacOS/${TARGETNAME}
The Imatest IT Python Interface is shipped as a Python module. Before referencing it in your scripts, you will need to install it using Python’s package manager. This must be done on the command line, and requires Administrator access. If you don’t know how to open a Command Prompt with Administrator privileges in Windows, see this helpful article.
Note: Imatest IT only supports Python versions 2.7, 3.6 and 3.7.
First, navigate to the Imatest IT Python library directory.
Windows
[shell]
cd C:\Program Files\Imatest\v2020.2\IT\libs\library\python\
[/shell]
Linux
[shell]
cd /usr/local/Imatest/v2020.2/IT/libs/library/python
[/shell]
macOS
[shell]
cd /Applications/Imatest/IT/v2020.2/libs/library/python
[/shell]
Next, run the following command to install the Imatest IT Python module:
Windows (assuming you are running Python 2.7 installed in C:\Python27\)
[shell]
C:\Python27\python.exe setup.py install
[/shell]
Linux
[shell]
sudo python setup.py install
[/shell]
macOS
[shell]
sudo -H python setup.py install
[/shell]
You will now be able to reference Imatest IT in your Python scripts using the import statement.
There are no more additional installation steps required to use the Imatest IT .NET libraries.
To simplify calling the Imatest IT EXE programs from the command line or a script file, the Imatest IT bin directory should be part of your PATH environment variable.
Windows In Windows, this is done automatically during installation, but if you are getting errors like “sfr.exe is not recognized as an internal or external command, operable program or batch file” when trying to run the EXE programs, you may need to manually add the bin directory to your PATH environment variable.
Follow these instructions and add C:\Program Files\Imatest\v2020.2\IT\bin to the system PATH variable. You will need to open a new command window for the change to take effect.
To simplify calling the Imatest IT EXE programs from the command line or a script file, the Imatest IT bin directory should be part of your PATH environment variable.
Linux On Linux systems, you will need to manually add $PATH:/usr/local/Imatest/v2020.2/IT/bin to the PATH variable. See these instructions .
macOS On macOS systems, you will need to manually add $PATH:/Applications/Imatest/IT/v2020.2/bin to the PATH variable. See these instructions .
Step 1: Prepare Test Environment and Capture Test Targets
Imatest’s analysis modules require correctly framed and properly lit images of test targets to produce accurate results. For information on setting up your image testing environment, see this article.
Imatest offers a wide range of test charts to improve the accuracy of your image analysis.
Step 2: Configure INI File with Test Image(s)
In addition to the test image, the other important input for Imatest IT module functions is the INI configuration file, which contains settings that describe the input image (such as the ROI [region of interest]), analysis details, and output file locations. Before using Imatest IT in your application, you will need to configure one or more INI files for your specific testing needs.
Creating an INI File with Imatest Master
Imatest IT-specific INI File Settings
To configure Imatest IT-specific settings, choose Settings, then IT & Pass/Fail Settings… from the main window menu bar. For a detailed explanation of the IT-specific settings found in this window, see this article. After you have made your changes, click OK.
Image Analysis INI File Settings
Once you have an image file of your test target that matches the framing and dimensions of the tests you will run using Imatest IT, analyze it using Imatest Master with the module you require. Be sure the image has the same pixel count as the images to be used in your production environment.
Repeat the tests with different settings until you have the results you require.
Exporting the INI File
Once you have configured the IT settings to meet your requirements– including the Region of Interest (ROI), calculation details, output file and folder locations– you can go back to the main Imatest window, and choose INI File Settings then Save Settings… from the menu bar. Choose a location for the INI file and give it a useful name. This file name will be the second input parameter when calling Imatest IT module functions.
In Imatest you can use the Save ini file for button in the Imatest IT settings window to save an ini file with only the needed sections.
You can create a file to control up to four modules by selecting the module in each of the boxes on the left, then pressing Save ini file for. The ini section(s) for the module ([sfr] and [sfrreg] in the above example) is included, along with [imatest], [api], [dcraw], [rdraw], and [sqf] and [visnoise], where appropriate.
Step 3: Integrate and Call Imatest IT Modules
Now that your test images and INI files have been prepared, you can integrate your application and analyze the images using Imatest IT’s module functions.
Select your preferred interface below to see detailed instructions.
Windows (Visual Studio) Project Setup
First, you need to configure your project to be able to find the Imatest IT and b Runtime libraries. To do this, right click on the project and choose Properties. Add the following include directories in the sections under Configuration Properties:
Category | Property | Value |
---|---|---|
C/C++ / General | Additional Include Directories | C:\Program Files\MATLAB\MATLAB Runtime\v98\extern\include C:\Program Files\Imatest\v2020.2\IT\libs\library\c |
Linker / General | Additional Include Directories | C:\Program Files\MATLAB\MATLAB Runtime\v98\extern\lib\win64\microsoft C:\Program Files\Imatest\v2020.2\IT\libs\library\c |
Linker / Input | Additional Dependencies | mclmcrrt.lib imatest_library.lib |
Note: Imatest only supports 64-bit architectures. You must use the x64 platform configuration when using Imatest IT in your projects. You may need to manually add this platform configuration to your project first. For information on how to do this, see this article.
macOS
Note: For macOS the Imatest IT C library must be used from an Objective-C wrapper. Please see the Objective-C documentation for details.
Initializing the Imatest IT Library
Now that your project references are set up, the next step is to include the imatest_library.h header file. Add this line to the top of your source file:
[cpp]
#include "imatest_library.h"
[/cpp]
Next, initialize the MATLAB Runtime application state by calling mclInitializeApplication(const char **options, int count). Most users can ignore the options and count parameters; just pass in NULL and 0, respectively. The function will return 0 if successful, allowing you to trap errors and handle them gracefully. This should only be called once during the life of your application.
[cpp]
#include "imatest_library.h"
int main()
{
if (!mclInitializeApplication(NULL,0))
{
printf("Error: could not initialize application properly.\n");
return -1001;
}
/// …
}
[/cpp]
The last initialization step is to call imatest_libraryInitialize(). This will prepare the Imatest IT library for use. The function also returns 0 if it is successful.
[cpp]
#include "imatest_library.h"
int main()
{
if (!mclInitializeApplication(NULL,0))
{
printf("Error: could not initialize the MATLAB Runtime properly.\n");
return -1001;
}
if(!imatest_libraryInitialize())
{
printf("Error: could not initialize the Imatest IT library properly.\n");
return -1002;
}
/// …
}
[/cpp]
Calling the Imatest IT C Library Interface
Now that the MATLAB Runtime and Imatest IT library are all ready to go, the next step is the prepare the arguments that will be passed into the IT module functions. Each of the IT modules has the same method signature (with the exception of OIS). In this example, we will use the sfr function. The signature for the SFR module function looks like this:
[cpp]
bool mlfSfr_shell(int nargout, mxArray** nret, mxArray* inputFile, mxArray* rootDir, mxArray* inputKeys, mxArray* opMode, mxArray* varargin);
[/cpp]
The Imatest IT C library encapsulates all input and output arguments inside mxArray types. This is a generic pointer type that can represent any data type. See below for more information on using mxArrays.
The Imatest IT C library parameters are listed here:
Parameter Name | Data Type | Description |
---|---|---|
nargout | int |
The number of expected output arguments. This will always be 1 for the JSON result string. |
&nret | mxArray** [const char*] |
The output object, which will be a string wrapped in an mxArray. |
inputFile | mxArray* [const char*] |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the rootDir parameter. |
rootDir | mxArray* [const char*] |
Directory containing your INI file. If you do not pass a file path in as the first item in the varargin parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
inputKeys | mxArray* [const char*] |
This value should always be the string “JSON”. XML output has been deprecated. |
opMode | mxArray* [const char*] |
String containing one of the following operation codes, which tells Imatest IT how to analyze your image(s), and how to read the values contained in the varargin parameter. If you are supplying your own full path to an INI file, and it is the first item in the varargin collection, then use one of these values: -7, -8, -10, or -17. If your INI file is named imatest-v2.ini and resides in the directory passed in as rootDir, then use one of these values: -5, -6, -9, and -15. The different opCode values direct how Imatest IT will behave. For more information on the different op modes supported by Imatest IT, see this article. |
varargin | mxArray* [multiple const char*] |
This is a catch all array structure for other parameters required by the various opModes. The contents of this array depend on which op mode you are using, and on how many images you will be processing. For information on how to populate this array, see here. |
Working with mxArrays
The Imatest IT C library receives and returns data via mxArray pointers. The MATLAB Runtime provides helper methods for allocating, interacting with, and deallocating mxArray structures.
Most of the Imatest IT C library input parameters (with the exception of varargin and raw image data passed in when using direct read mode) are strings (const char*) wrapped as mxArrays. You can create these mxArray pointers by using the mxCreateString(const char *str) function.
Before your program terminates, you must deallocate all of your mxArray pointers using the mxDestroyArray(mxArray *pm) function, and then set the pointers to NULL.
Here is an example of the typical lifecycle of an mxArray string parameter:
[cpp]
// Declare the pointer variable
mxArray *inputFile = NULL;
// Initialize the mxArray with a string
inputFile = mxCreateString("C:\\Program Files\\Imatest\\v2020.2\\IT\\samples\\images\\sfr_example.jpg");
// Make calls to Imatest IT library
// …
// Destroy the mxArray
mxDestroyArray(inputFile);
inputFile = NULL;
[/cpp]
The varargin parameter is a Matlab Cell Array containing zero or more additional input parameters, depending on the op mode. To initialize this parameter, use the mxCreateCellMatrix(int rows, int columns) function. You should create the varargin cell array with the exact number of cells required for your op mode. The rows parameter should always be 1, and the columns parameter should be the number of parameters you will be supplying.
You can then set the individual cells using mxSetCell(mxArray *array, int index, mxArray *value), where array is the varargin pointer, index is a zero-based index, and value is an mxArray pointer to the value being added to the array.
The varargin parameter is deallocated in the same way as other mxArrays, and you should not deallocate the individual cells of the array.
[cpp]
mxArray *varargin = NULL, *iniFile = NULL, *inputFile2 = NULL;
iniFile = mxCreateString("C:\\Program Files\\Imatest\\v2020.2\\IT\\samples\\cpp\\Imatest_INI\\imatest-v2.ini");
inputFile2 = mxCreateString("C:\\Program Files\\Imatest\\v2020.2\\IT\\samples\\images\\sfr_example.jpg");
varargin = mxCreateCellMatrix(1, 2);
mxSetCell(varargin, 0, iniFile);
mxSetCell(varargin, 1, inputFile2);
// …
mxDestroyArray(varargin);
[/cpp]
Calling Imatest IT Modules
Now that the library is initialized, and all of the input parameters are set up, it is time to call the Imatest IT analysis function. This example uses the SFR module, but the same code can be used to call the rest of the Imatest modules (with the exception of OIS, which has different inputs).
The first parameter will always be 1, and the second is a reference to an mxArray* pointer that will contain the JSON output of the analysis. If the function returns false, it means an error has occurred. Check the stdout and stderr streams for details on what went wrong, and see the section Error Handling below for information on handling errors gracefully.
When the call is successful, the JSON output will reside inside the outputJSON pointer. You can extract the string using the mxArrayToString(const mxArray *array_ptr) function.
[cpp]
if (!mlfSfr_shell(1, &outputJSON, inputFile, rootDir, inputKeys, opMode, varargin))
{
printf("*** Error calling SFR. Check output messages for details. ***\n");
}
else
{
jsonOutput = mxArrayToString(outputJSON);
printf(jsonOutput);
}
[/cpp]
When you are finished making calls to the Imatest IT C library, you then need to make three more function calls to terminate the library and the MATLAB Runtime.
[cpp]
mlfIt_terminate();
imatest_libraryTerminate();
mclTerminateApplication();
[/cpp]
Windows (Visual Studio) Project Setup
First, you need to configure your project to be able to find the Imatest IT and MATLAB Runtime libraries. To do this, right click on the project and choose Properties. Add the following include directories in the sections under Configuration Properties:
Category | Property | Value |
---|---|---|
C/C++ / General | Additional Include Directories | C:\Program Files\MATLAB\MATLAB Runtime\v98\extern\include C:\Program Files\Imatest\v2020.2\IT\libs\library\cpp |
Linker / General | Additional Include Directories | C:\Program Files\MATLAB\MATLAB Runtime\v98\extern\lib\win64\microsoft C:\Program Files\Imatest\v2020.2\IT\libs\library\cpp |
Linker / Input | Additional Dependencies | mclmcrrt.lib imatest_library.lib |
Note: Imatest only supports 64-bit architectures. You must use the x64 platform configuration when using Imatest IT in your projects. You may need to manually add this platform configuration to your project first. For information on how to do this, see this article.
macOS
Note: For macOS the Imatest IT C++ library must be used from an Objective-C wrapper. Please see the Objective-C documentation for details.
Initializing the Imatest IT Library
Now that your project references are set up, the next step is to include the imatest_library.h header file. Add this line to the top of your source file:
[cpp]
#include "imatest_library.h"
[/cpp]
Next, initialize the MATLAB Runtime application state by calling mclInitializeApplication(const char **options, int count). Most users can ignore the options and count parameters; just pass in NULL and 0, respectively. The function will return 0 if successful, allowing you to trap errors and handle them gracefully.
[cpp]
#include "imatest_library.h"
int main()
{
if (!mclInitializeApplication(NULL,0))
{
std::cerr << "Error: could not initialize the MATLAB Runtime properly." << std::endl;
return -1001;
}
/// …
}
[/cpp]
The last initialization step is to call imatest_libraryInitialize(). This will prepare the Imatest IT library for use. The function also returns 0 if it is successful.
[cpp]
#include "imatest_library.h’
int main()
{
if (!mclInitializeApplication(NULL,0))
{
std::cerr << "Error: could not initialize the MATLAB Runtime properly." << std::endl;
return -1001;
}
if(!imatest_libraryInitialize())
{
std::cerr << "Error: could not initialize the Imatest IT library properly." << std::endl;
return -1002;
}
/// …
}
[/cpp]
Calling the Imatest IT C++ Library Interface
Now that the MATLAB Runtime and Imatest IT library are all ready to go, the next step is the prepare the arguments that will be passed into the IT module functions. Each of the IT modules has the same method signature (with the exception of OIS). In this example, we will use the sfr function. The signature for the SFR module function looks like this:
[cpp]
void sfr_shell(int nargout, mwArray& nret, const mwArray& inputFile, const mwArray& rootDir, const mwArray& inputKeys, const mwArray& opMode, const mwArray& varargin);
[/cpp]
The Imatest IT C++ library encapsulates all input and output arguments inside mwArray objects. This is a generic wrapper class that can represent any data type. See below for more information on using mwArrays.
The Imatest IT C++ library parameters are listed here:
Parameter Name | Data Type | Description |
---|---|---|
nargout | int |
The number of expected output arguments. This will always be 1 for the JSON result string. |
nret | mwArray& [const char*] |
The output object, which will be a string wrapped in an mwArray object. |
inputFile | mwArray& [const char*] |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the rootDir parameter. |
rootDir | mwArray& [const char*] |
Directory containing your INI file. If you do not pass a file path in as the first item in the varargin parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
inputKeys | mwArray& [const char*] |
This value should always be the string “JSON”. XML output has been deprecated. |
opMode | mwArray& [const char*] |
String containing one of the following operation codes, which tells Imatest IT how to analyze your image(s), and how to read the values contained in the varargin parameter. If you are supplying your own full path to an INI file, and it is the first item in the varargin collection, then use one of these values: -7, -8, -10, or -17. If your INI file is named imatest-v2.ini and resides in the directory passed in as rootDir, then use one of these values: -5, -6, -9, and -15. The different opCode values direct how Imatest IT will behave. For more information on the different op modes supported by Imatest IT, see this article. |
varargin | mwArray& [multiple const char*] |
This is a catch all array structure for other parameters required by the various op modes. The contents of this array depend on which op mode you are using, and on how many images you will be processing. For information on how to populate this array, see here. |
Working with mwArrays
The Imatest IT C++ library receives and returns data via mwArray objects. Unlike the C library, the C++ library’s mwArray class is object-oriented, and also takes care of allocating and deallocating automatically. There is no need to manually destroy the mwArray objects.
Most of the Imatest IT C++ library input parameters (with the exception of varargin and raw image data passed in when using direct read mode) are strings (const char*) wrapped as mwArray objects. You can create these mwArray pointers by passing a const char* into the constructor.
[cpp]
mwArray opMode("-5");
[/cpp]
The varargin parameter is a Matlab Cell Array containing zero or more additional input parameters, depending on the opMode. To initialize this parameter, use the mwArray(int num_rows, int num_cols, mxClassID mxID) constructor, passing 1 for num_rows, the number of extra arguments required as num_cols, and the constant mxCELL_CLASS as mxID. The num_cols value should be the exact number of cells required for your op mode. See this article for more information on populating the varargin parameter.
You can then set the individual cells using the mwArray object’s Get(int row, int column) and Set(const mwArray& arr) methods. Note that the row and column parameters are 1-based indexes.
[cpp]
/// Set the first cell of varargin to be the iniFilePath
varargin.Get(1,1).Set(iniFilePath);
[/cpp]
Calling Imatest IT Modules
Now that the library is initialized, and all of the input parameters are set up, it is time to call the Imatest IT analysis function. This example uses the SFR module, but the same code can be used to call the rest of the Imatest modules (with the exception of OIS, which has different inputs).
The first parameter will always be 1, and the second is a reference to an uninitialized mwArray variable that will contain the JSON output of the analysis. If the function throw an exception, it means an error has occurred. Check the exception messages and stdout and stderr streams for details on what went wrong. See the section on Error Handling below for more information on catching and handling exceptions gracefully.
When the call is successful, the JSON output will reside inside the outputJSON pointer. You can extract the string by calling the mwArray.ToString() method, then converting that result to a const char*. Note that you must declare the mwString variable separately for this to work.
[cpp]
sfr_shell(1, outputJSON, inputFile, rootDir, inputKeys, opMode, varargin)
mwString mwStr = outputJSON.ToString();
const char* strOutputJSON = (const char*)mwStr;
std::cout << strOutputJSON << std::endl;
[/cpp]
When you are finished making calls to the Imatest IT C++ library, you then need to make three more function calls to terminate the library and the Matlab Runtime.
[cpp]
it_terminate();
imatest_libraryTerminate();
mclTerminateApplication();
[/cpp]
XCode Project Setup
First, you need to configure your project to be able to find the Imatest IT and MATLAB Runtime libraries. To do this, in the project editor, go to Build Settings and add the follow paths and linker flags:
Category | Property | Value |
---|---|---|
Search Paths | Header Search Paths | /Applications/Imatest/IT/v2020.2/libs/library/cpp /Applications/MATLAB/MATLAB_Runtime/v98/extern/include |
Search Paths | Library Search Paths | /Applications/Imatest/IT/v2020.2/libs/library/cpp /Applications/MATLAB/MATLAB_Runtime/v98/runtime/maci64 |
Linking | Other Linker Flags | -lmwmclmcrrt -lImatest |
Note: Imatest only supports the x86_64 architecture.
Next, in the General pane,
- Go to the Linked Frameworks and Libraries section
- Click the + button
- Click the Add Other… button
- Navigate to /Applications/Imatest/IT/v2020.2/libs/library/cpp
- select libImatest.dylib and click Open.
- Add Cocoa.Framework in a similar fashion if it has not been added.
Adding Symbolic Breakpoints to XCode projects
When the MATLAB Runtime initializes it emits SIGSEGV and SIGBUS. The MATLAB Runtime will properly handle this issue on its own if left to do so. The easiest way deal with this in XCode is to set symbolic break points and add commands that instruct the debugger to ignore these signals. Without these commands, the debugger will break on those signals when the MATLAB Runtime initializes and runs.
- Go to Debug:Break Points:Create Symbolic Breakpoint.
- In the Symbol field, type NSApplicationMain
- Set the Action dropdown to ‘Debugger Command’
- In the command field enter
process handle --pass true --stop false --notify true SIGSEGV
- Check ‘Automatically continue after evaluating’
- Repeat steps 1-5 adding another symbolic with the following command
process handle --pass true --stop false --notify true SIGBUS
Initializing the Imatest IT Library
Now that your project references are set up, the next step is to include the libImatest.h header file. Add these lines after your other includes and imports:
[objc] #define HRESULT HRESULT_MATLAB #include "libImatest.h" #include "mclmcrrt.h" #include "mclcppclass.h" #undef HRESULT [/objc]
Note that mclmcrrt.h defines HRESULT, which is also defined by Cocoa headers, so we use the preprocessor to redefine HRESULT in mclmcrrt.h and dependent header files to resolve the conflict.
Next, initialize the MATLAB Runtime application state by calling mclInitializeApplication(const char **options, int count). Most users can ignore the options and count parameters; just pass in NULL and 0, respectively. The function will return 0 if successful, allowing you to trap errors and handle them gracefully. This should only be called once during the life of your application. The last initialization step is to call libImatestInitialize(). This will prepare the Imatest IT library for use. The function also returns 0 if it is successful. Since in Cocoa all non-GUI methods cannot run on the main thread, detach a thread to run the method. The methods below are added to the AppDelegate class for the UI.
[objc] - (void) applicationWillFinishLaunching:(NSNotification *)aNotification { NSLog(@"Processing applicationWillFinishLaunching event"); [NSThread detachNewThreadSelector:@selector(initApp:) toTarget:self withObject:nil]; } - (void)initApp:(id)param { @autoreleasepool { NSLog(@"Executing initialization thread..."); mclmcrInitialize(); if (!mclInitializeApplication(NULL,0)) { NSString *stringError = [NSString stringWithCString:mclGetLastErrorMessage() encoding:NSMacOSRomanStringEncoding]; NSLog(@"Initializing the MATLAB Runtime failed"); NSLog(@"%@", stringError); return; } NSLog(@"Initializing Imatest IT library"); if (!libImatestInitialize() { NSString *stringError = [NSString stringWithCString:mclGetLastErrorMessage() encoding:NSMacOSRomanStringEncoding]; NSLog(@"Initializing the IT library failed"); libImatestPrintStackTrace(); NSLog(@"%@", stringError); return; } NSLog(@"Initialized"); } } [/objc]
Calling the Imatest IT C++ Library Interface
Now that the MATLAB Runtime and Imatest IT library are all ready to go, the next step is the prepare the arguments that will be passed into the IT module functions. Each of the IT modules has the same method signature (with the exception of OIS). In this example, we will use the sfrplus function. The signature for the SFR module function looks like this:
[cpp]
void sfrplus_shell(int nargout, mwArray& nret, const mwArray& inputFile, const mwArray& rootDir, const mwArray& inputKeys, const mwArray& opMode, const mwArray& varargin);
[/cpp]
The Imatest IT C++ library encapsulates all input and output arguments inside mwArray objects. This is a generic wrapper class that can represent any data type. See below for more information on using mwArrays.
The Imatest IT C++ library parameters are listed here:
Parameter Name | Data Type | Description |
---|---|---|
nargout | int |
The number of expected output arguments. This will always be 1 for the JSON result string. |
nret | mwArray& [const char*] |
The output object, which will be a string wrapped in an mwArray object. |
inputFile | mwArray& [const char*] |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the rootDir parameter. |
rootDir | mwArray& [const char*] |
Directory containing your INI file. If you do not pass a file path in as the first item in the varargin parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
inputKeys | mwArray& [const char*] |
This value should always be the string “JSON”. XML output has been deprecated. |
opMode | mwArray& [const char*] |
String containing one of the following operation codes, which tells Imatest IT how to analyze your image(s), and how to read the values contained in the varargin parameter. If you are supplying your own full path to an INI file, and it is the first item in the varargin collection, then use one of these values: -7, -8, -10, or -17. If your INI file is named imatest-v2.ini and resides in the directory passed in as rootDir, then use one of these values: -5, -6, -9, and -15. The different opCode values direct how Imatest IT will behave. For more information on the different op modes supported by Imatest IT, see this article. |
varargin | mwArray& [multiple const char*] |
This is a catch all array structure for other parameters required by the various op modes. The contents of this array depend on which op mode you are using, and on how many images you will be processing. For information on how to populate this array, see here. |
Working with mwArrays
The Imatest IT C++ library receives and returns data via mwArray objects. Unlike the C library, the C++ library’s mwArray class is object-oriented, and also takes care of allocating and deallocating automatically. There is no need to manually destroy the mwArray objects.
Most of the Imatest IT C++ library input parameters (with the exception of varargin and raw image data passed in when using direct read mode) are strings (const char*) wrapped as mwArray objects. You can create these mwArray pointers by passing a const char* into the constructor.
[cpp]
mwArray opMode("-5");
[/cpp]
The varargin parameter is a Matlab Cell Array containing zero or more additional input parameters, depending on the opMode. To initialize this parameter, use the mwArray(int num_rows, int num_cols, mxClassID mxID) constructor, passing 1 for num_rows, the number of extra arguments required as num_cols, and the constant mxCELL_CLASS as mxID. The num_cols value should be the exact number of cells required for your op mode. See this article for more information on populating the varargin parameter.
You can then set the individual cells using the mwArray object’s Get(int row, int column) and Set(const mwArray& arr) methods. Note that the row and column parameters are 1-based indexes.
[cpp]
/// Set the first cell of varargin to be the iniFilePath
varargin.Get(1,1).Set(iniFilePath);
[/cpp]
Calling Imatest IT Modules
Now that the library is initialized, and all of the input parameters are set up, it is time to call the Imatest IT analysis function. This example uses the SFR module, but the same code can be used to call the rest of the Imatest modules (with the exception of OIS, which has different inputs).
The first parameter will always be 1, and the second is a reference to an uninitialized mwArray variable that will contain the JSON output of the analysis. If the function throw an exception, it means an error has occurred. Check the exception messages and stdout and stderr streams for details on what went wrong. See the section on Error Handling below for more information on catching and handling exceptions gracefully.
When the call is successful, the JSON output will reside inside the outputJSON mwArray.
[objc] - (void)postTest: (id)param { @autoreleasepool { try{ // Declare and initialize outputJSON, fileParam, pathParam, keysParam, modeParam, and varargin mwArray's NSLog(@"Running test."); sfrplus_shell(1, outputJSON, fileParam, pathParam, keysParam, modeParam, varargin); // Process JSON returned in outputJSON mwArray } catch (mwException ex){ NSLog(@"Error"); NSLog(@"%s", ex.what()); ex.print_stack_trace(); } } } - (void)runTest { // Start a new thread to run sfrplus_shell() [NSThread detachNewThreadSelector:@selector(postTest:) toTarget:self withObject:nil]; } [/objc]
The JSON string returned in outputJSON has UTF-16 encoding. This can be converted to a NSString with the following
[objc] auto numel = outputJSON.NumberOfElements(); std::u16string buffer(numel+1, 0); outputJSON.GetCharData(&buffer[0], numel); char* data = (char*)buffer.data(); unsigned long size = buffer.size()*sizeof(char16_t); NSString* jsonString =[[NSString alloc] initWithBytes:data length:size encoding:NSUTF16LittleEndianStringEncoding]; [/objc]
When you are finished making calls to the Imatest IT C++ library, you then need to make three more function calls (it_terminate(), libImatestTerminate(), and mclTerminateApplication) to terminate the library and the Matlab Runtime.
[objc] - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { [NSThread detachNewThreadSelector:@selector(terminateApp:) toTarget:self withObject:sender]; return NSTerminateLater; } -(void)terminateApp:(NSApplication *)theApplication { NSLog(@"Executing termination thread"); it_terminate(); libImatestTerminate(); mclTerminateApplication(); [theApplication replyToApplicationShouldTerminate: YES]; } [/objc]
Note: Imatest only supports 64-bit architectures. You must use the 64-bit version of Python when using Imatest IT.
Calling the Imatest IT Python Interface
At the top of your script file, include this line to import the ImatestLibrary class from the imatest.it module:
[python]
from imatest.it import ImatestLibrary
[/python]
Next, create an instance of the ImatestLibrary class. Behind the scenes, the ImatestLibrary constructor will start up the Matlab MCR Runtime and load all the IT libraries into memory. This will take a few seconds the first time you run it, but should be faster on subsequent runs, especially if you have set your system’s environment variables to the recommended values as described above.
[python]
from imatest.it import ImatestLibrary
imatestLib = ImatestLibrary()
[/python]
Now that the Matlab MCR and Imatest IT library are all ready to go, the next step is the prepare the arguments that will be passed into the IT module functions. Each of the IT modules has the same method signature (with the exception of OIS). In this example, we will use the sfr function. The signature for the SFR module function looks like this:
[python]
sfr(input_file=None, root_dir=None, op_mode=None, ini_file=None, raw_data=None, json_args=None)
[/python]
The Imatest IT Python library parameters are listed here:
Parameter Name | Data Type | Description |
---|---|---|
input_file | string or list |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the root_dir parameter. |
root_dir | string |
Directory containing your INI file. If you do not pass a file path in as the ini_file parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
op_mode | string |
String containing one of the following operation codes, which tells Imatest IT how to analyze your image(s), or if you are using Direct Read mode. Valid values for the op_mode parameter are found in constants of the ImatestLibrary class: ImatestLibrary.OP_MODE_SEPARATE, ImatestLibrary.OP_MODE_SIGNAL_AVERAGE, ImatestLibrary.OP_MODE_TEMPORAL, and ImatestLibrary.OP_MODE_DIRECT_READ. For more information on the different op modes supported by Imatest IT, see this article. |
ini_file | string (optional) |
If you want to use an INI file that is not named imatest-v2.ini, you will need to supply the path to the file as the ini_file parameter. |
raw_data | string (optional) |
The raw image data. Only used when using OP_MODE_DIRECT_READ. For more information on direct read mode, see this article. |
json_args | string (optional) |
A JSON string containing metadata about how to interpret the image in the raw_data parameter. Only used when using OP_MODE_DIRECT_READ. For more information on direct read mode, see this article. |
Calling Imatest IT Modules
Now that the library is initialized, and all of the input parameters are set up, it is time to call the Imatest IT analysis function. This example uses the SFR module, but the same code can be used to call the rest of the Imatest modules (with the exception of OIS, which has different inputs).
It’s easiest to call the sfr using named parameters, as shown below. An exception will be thrown if something goes wrong – you should catch it and handle it gracefully. Check the exception message and stdout and stderr streams for details on what went wrong, and see the Error Handling section below for more information on gracefully handling exceptions.
When the call is successful, the function will return a string containing JSON-encoded output.
[python]
from imatest.it import ImatestLibrary
import json
imatestLib = ImatestLibrary()
result = imatestLib.sfr(input_file=input_file,
root_dir=root_dir,
op_mode=ImatestLibrary.OP_MODE_SEPARATE,
ini_file=ini_file)
print(result)
[/python]
When you are finished making calls to the Imatest IT Python library, you then need to call terminate_library() to unload the library and the Matlab Runtime.
[python]
imatestLib.terminate_library();
[/python]
Running the Imatest IT Python library on macOS
Note: Due to a limitation in how the IT Python library is constructed, you must call any python code via the mwpython.sh script provided by Mathworks at /Applications/MATLAB/MATLAB_Runtime/v98/bin. It is recommended that you set the PYTHON_HOME environment variable if you wish to use a particular python interpreter. Also, the only supported means to call mwpython is to call a script directly (not a module using the -m flag in python). For example
[bash]
export PATH=/Applications/MATLAB/MATLAB_Runtime/v98/bin:$PATH
export PYTHON_HOME=/Library/Frameworks/Python.framework/Versions/3.7
mwpython some_script.py
[/bash]
Windows (Visual Studio) Project Setup
To use the Imatest IT .NET libraries in your Visual Studio project, first you need to add a reference to the library DLL in your project.
Once your project is created in Visual Studio, right click on the References section of the Solution Explorer and choose Add Reference….
In the Reference Manager window, choose Browse on the left-hand side, then click the Browse… button at the bottom.
Navigate to the .NET library directory of your Imatest IT installation (by default, C:\Program Files\Imatest\v2020.2\IT\libs\library\.NET\), choose Imatest.IT.dll, and click the Add button.
Note: You do not need to add the IT.dll reference to your project.
Click OK to close the Reference Manager window.
Note: Imatest only supports 64-bit architectures. You must use the x64 platform when running .NET applications. The Any CPU platform will throw runtime errors.
Calling the Imatest IT .NET Interface
[csharp]
using Imatest.IT;
[/csharp]
[vbnet]
Imports Imatest.IT
[/vbnet]
Next, create an instance of the Imatest.IT.Library class. Behind the scenes, the Imatest.IT.Library constructor will start up the Matlab MCR Runtime and load all the IT libraries into memory. This will take a few seconds the first time you run it, but should be faster on subsequent runs, especially if you have set your system’s environment variables to the recommended values as described above.
Imatest.IT.Library implements the IDisposable interface, and we recommend that you wrap your library instance inside of a using statement to ensure that the Dispose() method is called properly. The Dispose() method cleans up the Matlab Runtime, and also releases your floating license seat, if you are using a floating license.
[csharp]
using Imatest.IT;
class Program
{
static void Main(string[] args)
{
using (Library itLib = new Library())
{
// ….
}
}
}
[/csharp]
Imatest.IT.Library implements the IDisposable interface, and we recommend that you wrap your library instance inside of a Using statement to ensure that the Dispose() method is called properly. The Dispose() method cleans up the Matlab Runtime, and also releases your floating license seat, if you are using a floating license.
[vbnet]
Imports Imatest.IT
Module Program
Sub Main()
Using itLib = New Library()
‘ …
End Using
End Sub
End Module
[/vbnet]
Now that the Matlab MCR and Imatest IT library are all ready to go, the next step is the prepare the arguments that will be passed into the IT module functions. Each of the IT modules has the same overloaded method signatures (with the exception of OIS). In this example, we will use the SFR.JSON methods. The signatures for the SFR module function looks like this:
[csharp]
string SFR.JSON(string rootDir, string inputFile, OperationMode opMode)
string SFR.JSON(string rootDir, IEnumerable<string> inputFiles, OperationMode opMode)
string SFR.JSON(string rootDir, string inputFile, OperationMode opMode, string iniFilePath)
string SFR.JSON(string rootDir, IEnumerable<string> inputFiles, OperationMode opMode, string iniFilePath)
string SFR.JSON(string rootDir, byte[] inputBytes, DirectReadOptions directReadOptions)
string SFR.JSON(string rootDir, byte[] inputBytes, DirectReadOptions directReadOptions, string iniFilePath)
[/csharp]
[vbnet]
SFR.JSON(String rootDir, String inputFile, OperationMode opMode) As String
SFR.JSON(String rootDir, IEnumerable(Of String) inputFiles, OperationMode opMode) As String
SFR.JSON(String rootDir, String inputFile, OperationMode opMode, String iniFilePath) As String
SFR.JSON(String rootDir, IEnumerable(Of String) inputFiles, OperationMode opMode, String iniFilePath) As String
SFR.JSON(String rootDir, Byte() inputBytes, DirectReadOptions directReadOptions) As String
SFR.JSON(String rootDir, Byte() inputBytes, DirectReadOptions directReadOptions, String iniFilePath) As String
[/vbnet]
The Imatest IT .NET library parameters are listed here:
Parameter Name | Data Type | Description |
---|---|---|
rootDir | string |
Directory containing your default INI file. If you do not pass a file path in as optional the iniFile parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
inputFile | string |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the rootDir parameter. |
inputFiles | IEnumerable<string> |
A list of image file paths. Full path names may be used (and are recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If relative path names are used, the path is relative to your calling program, not the value of the rootDir parameter. |
opMode | OperationMode |
Enum value for one of the available operation modes, which tells Imatest IT how to analyze your image(s). Valid values for the opMode parameter are: OperationMode.Separate, OperationMode.SignalAverage, and OperationMode.Temporal. For more information on the different op modes supported by Imatest IT, see this article. |
iniFile | string (optional) |
If you want to use an INI file that is not named imatest-v2.ini, you will need to supply the path to the file as the iniFile parameter. |
inputBytes | byte[], ushort[], or uint[] (optional) |
The raw image data. Only used if you are passing in image data directly using Direct Read Mode. For more information on direct read mode, see this article. |
directReadOptions | DirectReadOptions (optional) |
A an object containing metadata about how to interpret the image in the inputBytes parameter. Only used when using Direct Read Mode. For more information on direct read mode, see this article. |
Parameter Name | Data Type | Description |
---|---|---|
rootDir | String |
Directory containing your default INI file. If you do not pass a file path in as optional the iniFile parameter, then Imatest IT will use a file named imatest-v2.ini found in this directory as your INI configuration. |
inputFile | String |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program, not the value of the rootDir parameter. |
inputFiles | IEnumerable(Of String) |
A list of image file paths. Full path names may be used (and are recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If relative path names are used, the path is relative to your calling program, not the value of the rootDir parameter. |
opMode | OperationMode |
Enum value for one of the following operation codes, which tells Imatest IT how to analyze your image(s). Valid values for the opMode parameter are: OperationMode.Separate, OperationMode.SignalAverage, and OperationMode.Temporal. For more information on the different op modes supported by Imatest IT, see this article. |
iniFile | String (optional) |
If you want to use an INI file that is not named imatest-v2.ini, you will need to supply the path to the file as the iniFile parameter. |
inputBytes | Byte(), UShort(), or UInteger() (optional) |
The raw image data. Only used if you are passing in image data directly using Direct Read Mode. For more information on direct read mode, see this article. |
directReadOptions | DirectReadOptions (optional) |
A an object containing metadata about how to interpret the image in the inputBytes parameter. Only used when using Direct Read Mode. For more information on direct read mode, see this article. |
Calling Imatest IT Modules
Now that the library is initialized, and all of the input parameters are set up, it is time to call the Imatest IT analysis function. This example uses the SFR module, but the same code can be used to call the rest of the Imatest modules (with the exception of OIS, which has different inputs).
We recommend always wrapping your Imatest IT calls in try/catch blocks. If anything goes wrong, an Exception will be thrown. You should handle these exceptions gracefully. Check the exception message for details on what went wrong, and see the section on Error Handling below for more information.
When the call is successful, the function will return a string containing JSON-encoded output.
[csharp]
using Imatest.IT;
class Program
{
static void Main(string[] args)
{
using (Library itLib = new Library())
{
try {
string result = itLib.SFR.JSON(rootDir, inputFile, OperationMode.Separate, iniFilePath);
} catch (Exception ex) {
Console.Out.WriteLine(ex.Message);
}
}
}
}
[/csharp]
[vbnet]
Imports Imatest.IT
Module Program
Sub Main()
Using itLib = New Library()
Try
Dim result = itLib.SFR.JSON(rootDir, imagePath, OperationMode.Separate, iniFilePath)
Catch ex As Exception
Console.Out.WriteLine(ex.Message)
End Try
End Using
End Sub
End Module
[/vbnet]
Calling the Imatest IT EXE Interface
The Imatest IT EXE Library can be called using Windows or Linux script files. We recommend making sure that the IT bin directory is in your PATH variable. On Windows, this should already happen when Imatest IT is installed. You may need to add to your path manually on Linux. For more information on viewing and editing system environment variables, see this article.
All Imatest IT EXE executables accept the following arguments (except for OIS, which uses different inputs):
[sourcecode language="plain"] sfr.exe op-mode input-file bin-directory ini-file [result-directory] [other-images ...] [/sourcecode]
The Imatest IT EXE library parameters are listed here:
Parameter Name | Description |
---|---|
op_mode |
One of the following operation codes, which tells Imatest IT how to analyze your image(s). Valid values for the op_mode parameter are: -1 (Separate Analysis), -11 (Signal Average Analysis), and -12 (Temporal Noise Analysis). For more information on the different op modes supported by Imatest IT, see this article. |
input-file |
Image file path. A full path name may be used (and is recommended), such as “C:\Program Files\Imatest\v2020.2\IT\samples\images\sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program. |
bin-directory |
The location of the Imatest IT bin directory. By default, this will be “C:\Program Files\Imatest\v2020.2\IT\bin”. |
ini-file |
The full path to the INI configuration file you will be using. |
result-directory |
The directory where Imatest IT’s output files will be written to. |
other-images |
The path(s) to other images that will be analyzed besides the initial input-file image. |
Calling Imatest IT Modules
Imatest IT EXE modules are called using the command line, or in .bat files.
Note: You should not include a trailing ‘\’ when passing in directory names, otherwise you may get an error (see here).
[shell]
sfr.exe "-1" "C:\ImatestSamples\sfr_example.jpg" "C:\Program Files\Imatest\v2020.2\IT\bin" "C:\ImatestSamples\imatest-v2.ini" "C:\ImatestSamples\Results"
[/shell]
When the module is finished running, the result files will be written to the result-directory folder (in this case, C:\ImatestSamples\Results).
Calling the Imatest IT EXE Interface
The Imatest IT EXE Library can be called using macOS or Linux Bash script files. We recommend making sure that the IT bin directory is in your PATH variable. You may need to add to your path manually on macOS and Linux. For more information on viewing and editing system environment variables, see this article.
All Imatest IT EXE executables accept the following arguments (except for OIS, which uses different inputs):
[sourcecode language="plain"] ./run_sfr.sh op-mode input-file bin-directory ini-file [result-directory] [other-images ...] [/sourcecode]
The Imatest IT EXE library parameters are listed here:
Parameter Name | Description |
---|---|
op_mode |
One of the following operation codes, which tells Imatest IT how to analyze your image(s). Valid values for the op_mode parameter are: -1 (Separate Analysis), -11 (Signal Average Analysis), and -12 (Temporal Noise Analysis). For more information on the different op modes supported by Imatest IT, see this article. |
input-file |
Image file path. A full path name may be used (and is recommended), such as “/Applications/Imatest/IT/v2020.2/samples/images/sfr_example.jpg”. If a relative path name is used, the path is relative to your calling program. |
bin-directory |
The location of the Imatest IT bin directory. By default, this will be “/Applications/Imatest/IT/v2020.2/bin” on macOS, and “/usr/local/Imatest/v2020.2/IT/bin” on Linux. |
ini-file |
The full path to the INI configuration file you will be using. |
result-directory |
The directory where Imatest IT’s output files will be written to. |
other-images |
The path(s) to other images that will be analyzed besides the initial input-file image. |
Calling Imatest IT Modules
Imatest IT EXE modules are called using the command line with the .sh files.
Note: You should not include a trailing ‘\’ when passing in directory names, otherwise you may get an error (see here).
[shell]
./run_sfr.sh "-1" "$HOME/ImatestSamples/sfr_example.jpg" "/Applications/Imatest/IT/v2020.2/bin" "$HOME/ImatestSamples/imatest-v2.ini" "$HOME/ImatestSamples/Results"
[/shell]
When the module is finished running, the result files will be written to the result-directory folder (in this case, $HOME/ImatestSamples/Results).
Step 4: Process the Results
The Imatest IT module functions output their results as JSON, XML, and CSV formatted text files. The C, C++, Python, and .NET libraries also return results as a JSON formatted string to the calling program.
Using the JSON Result in Code
Imatest IT’s JSON result string, which is returned to the calling program, can be parsed and processed using third party JSON libraries. A list of JSON libraries for several languages can be found at json.org.
The result strings are packaged as nested property/value objects, and the first property is always [module]Results, as seen in this excerpt from an SFRplus call:
{ "sfrplusResults": { "version": "Imatest 4.5.14 SFRplus", "title": "sfrplus_example.jpg", "number_of_regions": [5], "HeightPxls": [2592], "WidthPxls": [3888], "pixels_per_inch": [0], "pixels_per_mm": [0], "um_per_pixel": [0], "CPIQ": { "sfrComputerMonitor": { "acutance": [0.8444,0.8406,0.7965,0.8583,0.8579], "qualityLoss": [0.1755,0.2173,0.9715,0.06028,0.06267] }, "sfrPhoneDisplay": { "acutance": [0.8785,0.8747,0.8268,0.8938,0.8935], "qualityLoss": [-0.005023,-0.00252,0.4007,0.00336,0.00336] }, "sfrUHDTVDisplay": { "acutance": [0.8287,0.8253,0.7708,0.8466,0.8463], "qualityLoss": [0.3724,0.4224,1.621,0.1535,0.1569] }, "sfrSmallPrint": { "acutance": [0.6816,0.6807,0.6678,0.6852,0.6859], "qualityLoss": [4.755,4.791,5.328,4.606,4.577] }, "sfrLargePrint": { "acutance": [0.8654,0.8671,0.8646,0.8658,0.8672], "qualityLoss": [0.02288,0.01626,0.02633,0.02126,0.01574] } }, "mtfPeak": [1.023,1.007,1,1.045,1.036], "mtf50": [0.3389,0.3426,0.3089,0.3512,0.3523], "mtf50p": [0.3365,0.3419,0.3089,0.3461,0.3482], ... } }
Note: If you analyze multiple files in a single call, only the last file’s results will be returned to the calling program. The others will be written to output files in the Results directory.
If you find that a result you need is missing from the returned JSON, please contact us and we can add it in the next minor release of Imatest IT.
Imatest IT Output Files
Imatest IT also writes its results to text files, which are formatted in XML, CSV, and JSON. By default, these files are written to a Results folder in the same folder as the images themselves. You can change the location by using Imatest Master to change your INI configuration settings, in the Auto mode settings for the modules you will be using:
Performance Tip: If you do not need some or all of the output files, you can disable them using the same Auto mode settings window. This will make your Imatest IT calls run a little faster. Just uncheck each of the outputs that you do not require.
Error Handling
Select your preferred interface below to see the best ways to handle errors using Imatest IT.
In the Imatest C library, if an error occurs within one of the analysis module functions, a false result will be returned. You can then use the mlfGetExceptionID(int nargout, mxArray** errID, mxArray** errName) function to extract an Error ID and Error Name, which map into the Imatest IT Exception Hierarchy.
To make handling these exceptions easier, Imatest IT includes an optional header file, imatest_exception_IDs.h, which maps each of the Error IDs to an enum. To include this header file, add #include “imatest_exception_ids.h” to your source file. You can read more about the Exception Hierarchy here.
Here is an example of how you can catch and gracefully handle exceptions using the Imatest IT C Library:
[cpp]
int retVal;
mxArray *errorID = NULL, *errorName = NULL;
enum ImatestExceptionIDs errorCode;
const char* errorNameStr;
…
if (!mlfSfr_shell(nargout, &amp;amp;amp;amp;amp;outputJSON, inputFile, rootDir, inputKeys, opMode, varargin))
{
if (mlfGetExceptionID(2, &amp;amp;amp;amp;amp;errorID, &amp;amp;amp;amp;amp;errorName))
{
errorCode = (enum ImatestExceptionIDs)mxGetScalar(errorID);
printf("*** Error ID: %d\n", errorCode);
switch (errorCode)
{
case kImatestFileNotFoundException:
printf("File not found exception.\n");
break;
case kBadFramingException:
printf("Bad framing exception.\n");
break;
default:
errorNameStr = mxArrayToString(mxGetCell(errorName, 0));
printf("*** Unexpected Error: %s\n", errorNameStr);
break;
}
mxDestroyArray(errorID);
mxDestroyArray(errorName);
retVal = errorCode;
}
else {
printf("*** Unknown Error.\n");
retVal = -1005;
}
}
else
{
retVal = 0;
…
}
[/cpp]
In the Imatest C++ library, if an error occurs within one of the analysis module functions, an mwException will be thrown. If you catch the exception, then you can use the getExceptionID(int nargout, mwArray& errID, mwArray& errName) function to extract an Error ID and Error Name, which map into the Imatest IT Exception Hierarchy.
To make handling these exceptions easier, Imatest IT includes an optional header file, imatest_exception_IDs.h, which maps each of the Error IDs to an enum. To include this header file, add #include “imatest_exception_ids.h” to your source file. You can read more about the Exception Hierarchy here.
Here is an example of how you can catch and gracefully handle exceptions using the Imatest IT C++ Library:
[cpp]
try
{
sfr_shell(1, outputJSON, inputFile, rootDir, inputKeys, opMode, varargin)
}
catch (const mwException&amp;amp;amp;amp;amp; e)
{
mwArray mwErrorID, mwErrorName;
mwString mwErrorNameStr;
getExceptionID(2, mwErrorID, mwErrorName);
int err = (int)mwErrorID;
switch (err)
{
case imatest::kImatestFileNotFoundException:
std::cerr &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; "*** File was not found. Check the file path." &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; std::endl;
break;
case imatest::kBadFramingException:
std::cerr &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; "*** Image is not framed correctly." &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; std::endl;
break;
default:
mwErrorNameStr = mwErrorName.Get(1,1).ToString();
std::cerr &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; "*** Unexpected Error: " &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; mwErrorNameStr &amp;amp;amp;amp;lt;&amp;amp;amp;amp;lt; std::endl;
break;
}
retVal = err;
}
[/cpp]
In the Imatest C++ library, if an error occurs within one of the analysis module functions, an mwException will be thrown. If you catch the exception, then you can use the getExceptionID(int nargout, mwArray& errID, mwArray& errName) function to extract an Error ID and Error Name, which map into the Imatest IT Exception Hierarchy.
To make handling these exceptions easier, Imatest IT includes an optional header file, imatest_exception_IDs.h, which maps each of the Error IDs to an enum. To include this header file, add #include “imatest_exception_ids.h” to your source file. You can read more about the Exception Hierarchy here.
Here is an example of how you can catch and gracefully handle exceptions using the Imatest IT C++ Library with Objective-C++:
[objc] - (void)postTest: (id)param { @autoreleasepool { try{ // Declare and initialize outputJSON, fileParam, pathParam, keysParam, modeParam, and varargin mwArray's NSLog(@"Running test."); sfrplus_shell(1, outputJSON, fileParam, pathParam, keysParam, modeParam, varargin); // Process JSON returned in outputJSON mwArray } catch (mwException ex) { mwArray mwErrorID, mwErrorName; mwString mwErrorNameStr; getExceptionID(2, mwErrorID, mwErrorName); int err = (int)mwErrorID; switch (err) { case imatest::kImatestFileNotFoundException: NSLog(@"*** File was not found. Check the file path."); break; case imatest::kBadFramingException: NSLog(@"*** Image is not framed correctly."); break; default: mwErrorNameStr = mwErrorName.Get(1,1).ToString(); NSLog(@"*** Unexpected Error: %s", (const char*)mwErrorNameStr); break; } retVal = err; } } } - (void)runTest { // Start a new thread to run sfrplus_shell() [NSThread detachNewThreadSelector:@selector(postTest:) toTarget:self withObject:nil]; } [/objc]
In the Imatest Python library, if an error occurs within one of the analysis module functions, an ImatestException will be thrown. If you catch the exception, then you can get more information about using the error_id, error_name, and message properties.
Here is an example of how you can catch and gracefully handle exceptions using the Imatest IT Python Library. You can use the constants on the ImatestException class to handle certain error types in different ways. In this example, an ImatestException will be thrown because all floating license seats are currently being used:
[python]
from imatest.it import ImatestLibrary, ImatestException
…
try:
result = imatestLib.sfr(input_file=input_file,
root_dir=root_dir,
op_mode=ImatestLibrary.OP_MODE_SEPARATE,
ini_file=ini_file)
except ImatestException as ex:
if iex.error_id == ImatestException.FloatingLicenseException:
print("All floating license seats are in use. Exit Imatest on another computer and try again.")
elif iex.error_id == ImatestException.LicenseException:
print("License Exception: " + iex.message)
else:
print("*** Error calling sfr: %s" % (iex.message, ))
[/python]
In the Imatest .NET library, if an error occurs within one of the analysis module functions, an Exception will be thrown. If you catch the exception, then you can get more information about it by calling the ImatestLibrary.GetLastException() and ImatestLibrary.GetExceptionName() methods.
Here is an example of how you can catch and gracefully handle exceptions using the Imatest IT .NET Library:
[csharp]
try
{
string result = itLib.SFRplus.JSON(rootDir, imagePath, OperationMode.Separate, iniFile);
}
catch (Exception ex)
{
ImatestException iex = lib.GetLastException();
string errorName = lib.GetExceptionName();
if (iex == ImatestException.FloatingLicenseException)
{
Console.Out.WriteLine("All floating license seats are in use. Exit Imatest on another computer and try again.");
}
else if (iex == ImatestException.LicenseException)
{
Console.Out.WriteLine("License Exception: {0}: {1}", errorName, ex.Message);
}
else
{
Console.Out.WriteLine("An error has occurred:");
Console.Out.WriteLine(ex.Message);
}
}
[/csharp]
[vbnet]
Try
Dim result = itLib.SFR.JSON(rootDir, imagePath, OperationMode.Separate, iniFile)
Catch ex As Exception
Dim iex As ImatestException = library.GetLastException()
Dim errorName As String = library.GetExceptionName()
If iex = ImatestException.FloatingLicenseException Then
Console.Out.WriteLine("All floating license seats are in use. Exit Imatest on another computer and try again.")
ElseIf iex = ImatestException.LicenseException Then
Console.Out.WriteLine("License Exception: {0}: {1}", errorName, ex.Message)
Else
Console.Out.WriteLine("An error has occurred:")
Console.Out.WriteLine(ex.Message)
End If
End Try
[/vbnet]
In the Imatest EXE library, if an error occurs within one of the analysis module functions, the return code from the executable will be -1 instead of 0. If you are calling the executable from a batch script, you can check what the return code was to determine if an exception occurred or not.
Here is an example of how you can test for an exception using the Imatest IT EXE Library:
[shell]
sfr.exe "-1" "’C:\ImatestSamples\sfr_example.jpg’" "’C:\Program Files\Imatest\v2020.2\IT\bin’" "’C:\ImatestSamples\imatest-v2.ini’" "’C:\ImatestSamples\Results’"
if %ERRORLEVEL% neq 0 (
echo ‘*** Error calling sfr. Check output for details.’
)
[/shell]
In the Imatest EXE library, if an error occurs within one of the analysis module functions, the return code from the executable will be -1 instead of 0. If you are calling the executable from a batch script, you can check what the return code was to determine if an exception occurred or not.
Here is an example of how you can test for an exception using the Imatest IT EXE Library:
[shell]
./run_sfr.sh "-1" "$HOME/ImatestSamples/sfr_example.jpg" "/Applications/Imatest/IT/v2020.2/bin" "$HOME/ImatestSamples/imatest-v2.ini" "$HOME/ImatestSamples/Results"
if [ "$?" -ne "0" ]
echo ‘*** Error calling sfr. Check output for details.’
fi
[/shell]
Sample Code
Imatest IT ships with several example projects in C++, Objective-C (macOS only), Python, C#, and Visual Basic. You can find them in the samples folder of your IT installation, along with example images of Imatest test charts that can be used for each of IT’s analysis modules.
Imatest IT for Windows also comes with a sample GUI application that demonstrates integrating the IT .NET libraries in a full-featured GUI application. Using the example images provided in the samples folder, you can experiment with the different analysis modules. It also provides a simple way to interact with the Imatest Acquisition Library. Using this app, you can quickly connect and test any of the supported image capture devices and make sure they are working, without writing any code. The full source code for this app is included in the .NET C# samples folder.The available log levels are:
Advanced Topics
Direct Read Mode and Reading RAW Images
Images can be passed directly into Imatest IT as byte arrays using Direct Read Mode. The images can be processed RGB or RAW. Direct Read Mode is generally much faster than passing in image file paths, since the data is already in memory and does not need to be read from disk. Although it does require more initial setup effort, if your application is speed-critical or high-volume, we strongly recommend using Direct Read Mode.
For detailed instructions on using Imatest IT’s Direct Read Mode, see this article.
Using the Imatest Image Acquisition Library
Images can be directly acquired in your application from supported devices using the Imatest IT Acquisition Library (C, C++, and .NET only).
For more information on the C and C++ version of the Acquisition Library, see this article. For the .NET version, see this article.
Using Pass/Fail Metrics
Pass/Fail results are included in the JSON results for those modules that support it (Blemish, Colorcheck, Distortion, Multitest, SFR, SFRplus, eSFR-ISO, Random, Star, Stepchart, and Uniformity). If you have configured Pass/Fail criteria, and included the Pass/Fail file in your INI file, then the tests will be run, and the results will be included as a separate JSON object called “passfail”.
For more information on implementing Pass/Fail in Imatest, see this article.
Logging Levels and Redirecting Output
By default, the Imatest IT modules print some information to the standard output or console. Logging levels control the nature of the output (to standard out and to log file) and may be selected by INI file control or from the Settings menu on the main window of Imatest Master.
If your application does not have a console, or you want to store this output in another way, it is possible to redirect the standard out and standard error outputs.
Select your preferred interface below to see detailed instructions.
[cpp]
int stdOutHandler(const char* str)
{
// Record output
…
return strlen(str);
}
int stdErrHandler(const char* str)
{
// Record output
…
return strlen(str);
}
if (!imatest_libraryInitializeWithHandlers(stdErrHandler, stdOutHandler))
{
…
[/cpp]
[cpp]
int stdOutHandler(const char* str)
{
// Record output
…
return strlen(str);
}
int stdErrHandler(const char* str)
{
// Record output
…
return strlen(str);
}
if (!imatest_libraryInitializeWithHandlers(stdErrHandler, stdOutHandler))
{
…
[/cpp]
[cpp]
int stdOutHandler(const char* str)
{
// Record output
…
return strlen(str);
}
int stdErrHandler(const char* str)
{
// Record output
…
return strlen(str);
}
if (!libImatestInitializeWithHandlers(stdErrHandler, stdOutHandler))
{
…
[/cpp]
[python]
import StringIO
std_out = StringIO.StringIO()
std_err = StringIO.StringIO()
libImatest = ImatestLibrary(stdout=out_file, stderr=err_file)
# Call library methods …
print std_out.getvalue()
print std_err.getvalue()
std_out.close()
std_err.close()
[/python]
[csharp]
StringWriter stdOut = new StringWriter();
StringWriter stdErr = new StringWriter();
Console.SetOut(stdOut);
Console.SetError(stdErr);
…
string stdOutText = stdOut.ToString();
string stdErrText = stdErr.ToString();
stdOut.Close();
stdErr.Close();
[/csharp]
[vbnet]
Dim stdOut As New StringWriter()
Dim stdErr As New StringWriter()
Console.SetOut(stdout)
Console.SetError(stderr)
…
Dim stdOutStr As String = stdOut.ToString()
Dim stdErrStr As String = stdErr.ToString()
stdOut.Close()
stdErr.Close()
[/vbnet]
[shell]
sfr.exe "-1" "C:\ImatestSamples\sfr_example.jpg" "C:\Program Files\Imatest\v2020.2\IT\bin" "C:\ImatestSamples\imatest-v2.ini" "C:\ImatestSamples\Results" &amp;amp;amp;amp;gt; "C:\ImatestSamples\Results\sfr_output.log" 2&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;1
[/shell]
will redirect stdout and stderr streams to “C:\ImatestSamples\Results\sfr_output.log”.
[shell]
./run_sfr.sh "-1" "$HOME/ImatestSamples/sfr_example.jpg" "/Applications/Imatest/IT/v2020.2/bin" "$HOME/ImatestSamples/imatest-v2.ini" "$HOME/ImatestSamples/Results" &amp;amp;amp;amp;gt; "$HOME/ImatestSamples/Results/sfr_output.log" 2&amp;amp;amp;amp;gt;&amp;amp;amp;amp;amp;1
[/shell]
will redirect stdout and stderr streams to “$HOME/ImatestSamples/Results/sfr_output.log”.
Advanced: Asynchronous Programming with Imatest IT .NET
With the Imatest IT .NET library, you can easily use write asynchronous module calls in your custom applications using the .NET Framework’s async and await keywords along with Imatest IT .NET’s JSONAsync() methods.
Making these simple changes can have dramatic effect on the responsiveness of applications, especially if they are GUI-based. To see the difference in action, run the Imatest IT .NET Sample Application found at C:\Program Files\Imatest\v2020.2\IT\samples\.NET\ImatestITSampleProject\ImatestITSampleProject.exe and try both the Run and Run Async buttons. You will notice the application appears to freeze when using the non-async version, but is fully responsive when using the async methods.
Altering Existing Imatest IT .NET Code to be Asynchronous
There are only three changes that need to be made to convert single-threaded code into asynchronous code.:
- Add an async modifier to the signature in which the asynchronous code will be called.
- Add the await in front of the Imatest IT method call.
- Change the Imatest IT method call to use the new Async version.
Below is a code snippet of synchronous code making a simple call to the SFRPlus module:
[csharp]
protected void TestImage()
{
using (Library lib = new Library())
{
string rootDir = @"C:\ImatestSamples\";
string imagePath = @"C:\ImatestSamples\sfrplus_example.jpg";
// Call Imatest IT library with JSON output
string result = lib.SFRplus.JSON(rootDir, imagePath, OperationMode.Separate);
Console.Out.WriteLine(result);
}
}
[/csharp]
Below is the same code that has been converted to call the SFRplus module asynchronously:
[csharp]
protected async void TestImage()
{
using (Library lib = new Library())
{
string rootDir = @"C:\ImatestSamples\";
string imagePath = @"C:\ImatestSamples\sfrplus_example.jpg";
// Call Imatest IT library with JSON output
string result = await lib.SFRplus.JSONAsync(rootDir, imagePath, OperationMode.Separate);
// Continue other operations that do not rely on the result value of the test
Console.Out.WriteLine(result);
}
}
[/csharp]
Initializing the Imatest IT .NET Libraries Asynchronously
The Imatest IT .NET and Imatest Acquisition Library classes have static CreateAsync() methods that can be called using the await keyword:
[csharp]
public async void InitializeApplication()
{
/// Inside application initialization code
/// The await keyword will automatically start a new thread to initialize the library,
/// while code in the main thread continues to execute until the itLib object is
/// actually used.
Library itLib = await Library.CreateAsync();
/// Continue initializing the rest of the application while the background thread
/// initializes the rest of the application
…
/// The main thread will wait here until the secondary thread is completed and the
/// Library.CreateAsync() method has returned a Library object.
await itLib.SFRplus.JSONAsync(rootDir, inputFile, OperationMode.Separate);
/// At this point only the main thread is running
}
[/csharp]
Parallel Processing
Imatest IT now allows you to analyze several different images in parallel,
using the new parallel_analyzer function.
To use the parallel_analyzer, first create a list of analysis tasks that need to be run. Each task will be assigned to a different parallel process. The number of available concurrent processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer cores if you need.
The parallel_analyzer_shell() C++ interface
The signature of the parallel_analyzer_shell() function is as follows:
[cpp]
parallel_analyzer_shell(int nargout, mwArray&amp;amp;amp;amp;amp; results, const mwArray&amp;amp;amp;amp;amp; tasks, const mwArray&amp;amp;amp;amp;amp; iniFileName, const mwArray&amp;amp;amp;amp;amp; runParallel, const mwArray&amp;amp;amp;amp;amp; numWorkers);
[/cpp]
Parameter Name | Data Type | Description |
nargout | int | The number of expected output arguments. This will be set to 1. |
results | mwArray& [const char*] | The serialized JSON object array wrapped in a mwArray |
tasks | const mwArray& [mxSTRUCT_CLASS] | The array of analysis tasks to run. For further information see below. |
iniFileName | const mwArray& [const char*] | The path for the Imatest INI file used for analysis |
runParallel | const mwArray& [bool] | A boolean set to true if parallel analysis is desired, otherwise set to false for serial operation. |
numWorkers | const mwArray& [int] | The number of child processes to spawn. |
The tasks array is a mwArray of ClassID mxSTRUCT_CLASS. This data type has named fields, as with C++ structs. Each element of the task array has these fields:
input – The supplied image in the form of file path(s) or numeric array(s)
analysisID – An integer that tells IT which module to run. The allowed values are defined in the ImatestAnalysisIDs enum (see <IT installation root>\libs\library\cpp\Imatest_analysis_ids.h):
imatest::BLEMISH_ANALYSIS_ID
imatest::CHECKERBOARD_ANALYSIS_ID
imatest::COLORCHECK_ANALYSIS_ID
imatest::DISTORTION_ANALYSIS_ID
imatest::DOTPATTERN_ANALYSIS_ID
imatest::ESFRISO_ANALYSIS_ID
imatest::MULTITEST_ANALYSIS_ID
imatest::RANDOM_ANALYSIS_ID
imatest::SFR_ANALYSIS_ID
imatest::SFRPLUS_ANALYSIS_ID
imatest::SFRREG_ANALYSIS_ID
imatest::STAR_ANALYSIS_ID
imatest::UNIFORMITY_ANALYSIS_ID
imatest::WEDGE_ANALYSIS_ID
jsonMetaData – Image meta data in the form of serialized JSON object string. This field only needs to be filled when numeric arrays are being supplied.
An example of the creation of the tasks array for four image files is available in the parallel_analyzer sample project (<IT installation root>\samples\cpp\parallel_analyzer\main.cpp). In this example, the tasks array is created with
[cpp]
mwSize numRows = 4; // There are 4 images to test
mwSize numCols = 1;
int numFields = 3;
const char* fieldNames[] = {"input\0", "analysisID\0", "jsonMetadata\0"};
mwArray tasks(numRows, numCols, numFields, fieldNames);
[/cpp]
To supply values to the individual tasks, we make use of the Get(const char* fieldName, int numIndices, int index1, …) accessor for mxSTRUCT_CLASS mwArrays:
[cpp]
// define the first task
tasks.Get("input", 1, 1).Set(mwArray(".\\sfrplus_example.jpg"));
tasks.Get("analysisID", 1, 1).Set(sfrplusID);
// define the second task
tasks.Get("input", 1, 2).Set(mwArray(".\\blemish_example.jpg"));
tasks.Get("analysisID", 1, 2).Set(blemishID);
//define the third task
tasks.Get("input", 1, 3).Set(mwArray(".\\colorcheck_example.jpg"));
tasks.Get("analysisID", 1, 3).Set(colorcheckID);
//define the fourth task
tasks.Get("input", 1, 4).Set(mwArray(".\\esfriso_example.jpg"));
tasks.Get("analysisID", 1, 4).Set(esfrisoID);
[/cpp]
It is important to note that this array is 1-indexed.
Creation of the remaining inputs is simpler; we use the mwArray contructors for scalar numeric values and strings.
[cpp]
mwArray iniFileName("..\\Imatest_INI\\imatest-v2.ini");
mwArray runParallel(true);
mwArray numWorkers(2);
[/cpp]
Lastly, we call parallel_analyzer_shell() with the inputs.
[cpp]
mwArray out;
parallel_analyzer_shell(1, out, tasks, iniFileName, runParallel, numWorkers);
[/cpp]
The results will be returned in the out mwArray, which contains a JSON encoded string that can be parsed into an object array with one result object per task. Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property.
In addition to the parallel_analyzer sample, IT also includes a C++ sample project that implements parallel processing using the Boost.Interprocess Library (<IT installation root>\samples\cpp\CPP_parallel_test_project). More information can be found in this article.
To use the parallel_analyzer, first create a list of analysis tasks that need to be run. Each task will be assigned to a different parallel process. The number of available concurrent processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer cores if you need.
The parallel_analyzer_shell() C++ interface
The signature of the parallel_analyzer_shell() function is as follows:
[cpp]
parallel_analyzer_shell(int nargout, mwArray&amp;amp;amp;amp;amp; results, const mwArray&amp;amp;amp;amp;amp; tasks, const mwArray&amp;amp;amp;amp;amp; iniFileName, const mwArray&amp;amp;amp;amp;amp; runParallel, const mwArray&amp;amp;amp;amp;amp; numWorkers);
[/cpp]
Parameter Name | Data Type | Description |
nargout | int | The number of expected output arguments. This will be set to 1. |
results | mwArray& [const char*] | The serialized JSON object array wrapped in a mwArray |
tasks | const mwArray& [mxSTRUCT_CLASS] | The array of analysis tasks to run. For further information see below. |
iniFileName | const mwArray& [const char*] | The path for the Imatest INI file used for analysis |
runParallel | const mwArray& [bool] | A boolean set to true if parallel analysis is desired, otherwise set to false for serial operation. |
numWorkers | const mwArray& [int] | The number of child processes to spawn. |
The tasks array is a mwArray of ClassID mxSTRUCT_CLASS. This data type has named fields, as with C++ structs. Each element of the task array has these fields:
input – The supplied image in the form of file path(s) or numeric array(s)
analysisID – An integer that tells IT which module to run. The allowed values are defined in the ImatestAnalysisIDs enum (see <IT installation root>/libs/library/cpp/Imatest_analysis_ids.h):
imatest::BLEMISH_ANALYSIS_ID
imatest::CHECKERBOARD_ANALYSIS_ID
imatest::COLORCHECK_ANALYSIS_ID
imatest::DISTORTION_ANALYSIS_ID
imatest::DOTPATTERN_ANALYSIS_ID
imatest::ESFRISO_ANALYSIS_ID
imatest::MULTITEST_ANALYSIS_ID
imatest::RANDOM_ANALYSIS_ID
imatest::SFR_ANALYSIS_ID
imatest::SFRPLUS_ANALYSIS_ID
imatest::SFRREG_ANALYSIS_ID
imatest::STAR_ANALYSIS_ID
imatest::UNIFORMITY_ANALYSIS_ID
imatest::WEDGE_ANALYSIS_ID
jsonMetaData – Image meta data in the form of serialized JSON object string. This field only needs to be filled when numeric arrays are being supplied.
An example of the creation of the tasks array for four image files is available in the parallel_analyzer sample project (<IT installation root>\samples\cpp\parallel_analyzer\main.cpp). In this example, the tasks array is created with
[cpp]
mwSize numRows = 4; // There are 4 images to test
mwSize numCols = 1;
int numFields = 3;
const char* fieldNames[] = {"input\0", "analysisID\0", "jsonMetadata\0"};
mwArray tasks(numRows, numCols, numFields, fieldNames);
[/cpp]
To supply values to the individual tasks, we make use of the Get(const char* fieldName, int numIndices, int index1, …) accessor for mxSTRUCT_CLASS mwArrays:
[cpp]
// define the first task
tasks.Get("input", 1, 1).Set(mwArray(".\\sfrplus_example.jpg"));
tasks.Get("analysisID", 1, 1).Set(sfrplusID);
// define the second task
tasks.Get("input", 1, 2).Set(mwArray(".\\blemish_example.jpg"));
tasks.Get("analysisID", 1, 2).Set(blemishID);
//define the third task
tasks.Get("input", 1, 3).Set(mwArray(".\\colorcheck_example.jpg"));
tasks.Get("analysisID", 1, 3).Set(colorcheckID);
//define the fourth task
tasks.Get("input", 1, 4).Set(mwArray(".\\esfriso_example.jpg"));
tasks.Get("analysisID", 1, 4).Set(esfrisoID);
[/cpp]
It is important to note that this array is 1-indexed.
Creation of the remaining inputs is simpler; we use the mwArray contructors for scalar numeric values and strings.
[cpp]
mwArray iniFileName("..\\Imatest_INI\\imatest-v2.ini");
mwArray runParallel(true);
mwArray numWorkers(2);
[/cpp]
Lastly, we call parallel_analyzer_shell() with the inputs.
[cpp]
mwArray out;
parallel_analyzer_shell(1, out, tasks, iniFileName, runParallel, numWorkers);
[/cpp]
The results will be returned in the out mwArray, which contains a JSON encoded string that can be parsed into an object array with one result object per task. Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property.
To use the parallel_analyzer, first create a list of analysis tasks that need to be run. Each task will be assigned to a different parallel process. The number of available concurrent processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer cores if you need.
The task file
In the stand-alone executable version of parallel_analyzer, the list of tasks is supplied in the form of a JSON encoded file. In this JSON file, the list of tasks is represented by a JSON object array, where each individual task is an object within that array. For each task the following fields need to be defined:
input – The supplied image in the form of file path(s) or numeric array(s)
analysisID – An integer that tells IT which module to run. The allowed values are defined below:
Module | Value |
Blemish | 1 |
Checkerboard | 2 |
Colorcheck | 3 |
Distortion | 4 |
Dotpattern | 5 |
eSFRiso | 6 |
Multitest | 7 |
Random | 8 |
SFR | 9 |
SFRplus | 10 |
SFRreg | 11 |
Star | 12 |
Uniformity | 13 |
Wedge | 14 |
jsonMetaData – Image meta data in the form of serialized JSON object. This field only needs to be filled when numeric arrays are being supplied.
As an example, suppose that there are two files named blemish_example.jpg and sfrplus_example.jpg in the current working directory that need to be analyzed by the Blemish and SFRplus modules, respectively. The contents of this tasks file is then
[plain]
[
{
"input": "blemish_example.jpg",
"analysisID": 1,
"jsonMetadata": ""
},
{
"input": "sfrplus_example.jpg",
"analysisID": 10,
"jsonMetadata": ""
}
]
[/plain]
The parallel_analyzer_exe interface
The signature of the parallel_analyze executable is as follows:
[plain]
parallel_analyzer_exe taskFileName iniFileName runParallel numWorkers [-o|–output_filename &amp;amp;amp;amp;lt;filename&amp;amp;amp;amp;gt;]
[/plain]
The required inputs are
taskFileName: The path to the JSON task file (see the Task File section below).
iniFileName: The path to the Imatest INI file
runParallel: A boolean value that is 1 if the user wants parallel processing and 0 if serial processing is desired.
numWorkers: An integer value indicating the number of child processes to invoke for analysis. The maximum value is the number of physical cores.
with remaining optional input
-o|–output_filename <filename>: Supply the full file path for the file into which the results are saved. Note that either ‘-o’ or ‘–output_filename’ can be used. If this optional input is not supplied, the results are saved to a file named ‘results_<current date and time>.json’.
Continuing the above example, suppose that the task file (tasks.json) from above is in our Documents folder with the two image files and our INI file (imatest-v2.ini). The call to run the two tasks in parallel on two processes would be
[shell]
cd %HOMEPATH%\Documents
C:\Program Files\Imatest\v2020.2\IT\bin\parallel_analyzer_exe.exe tasks.json imatest-v2.ini 1 2
[/shell]
The results will be saved to a JSON encoded file in the form of a JSON object array with one result object per task. Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property.
To use the parallel_analyzer, first create a list of analysis tasks that need to be run. Each task will be assigned to a different parallel process. The number of available concurrent processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer cores if you need.
The task file
In the stand-alone executable version of parallel_analyzer, the list of tasks is supplied in the form of a JSON encoded file. In this JSON file, the list of tasks is represented by a JSON object array, where each individual task is an object within that array. For each task the following fields need to be defined:
input – The supplied image in the form of file path(s) or numeric array(s)
analysisID – An integer that tells IT which module to run. The allowed values are defined below:
Module | Value |
Blemish | 1 |
Checkerboard | 2 |
Colorcheck | 3 |
Distortion | 4 |
Dotpattern | 5 |
eSFRiso | 6 |
Multitest | 7 |
Random | 8 |
SFR | 9 |
SFRplus | 10 |
SFRreg | 11 |
Star | 12 |
Uniformity | 13 |
Wedge | 14 |
jsonMetaData – Image meta data in the form of serialized JSON object. This field only needs to be filled when numeric arrays are being supplied.
As an example, suppose that there are two files named blemish_example.jpg and sfrplus_example.jpg in the current working directory that need to be analyzed by the Blemish and SFRplus modules, respectively. The contents of this tasks file is then
[plain]
[
{
"input": "blemish_example.jpg",
"analysisID": 1,
"jsonMetadata": ""
},
{
"input": "sfrplus_example.jpg",
"analysisID": 10,
"jsonMetadata": ""
}
]
[/plain]
The parallel_analyzer_exe interface
The signature of the parallel_analyze executable is as follows:
[plain]
./run_parallel_analyzer.sh taskFileName iniFileName runParallel numWorkers [-o|–output_filename &amp;amp;amp;amp;lt;filename&amp;amp;amp;amp;gt;]
[/plain]
The required inputs are
taskFileName: The path to the JSON task file (see the Task File section below).
iniFileName: The path to the Imatest INI file
runParallel: A boolean value that is 1 if the user wants parallel processing and 0 if serial processing is desired.
numWorkers: An integer value indicating the number of child processes to invoke for analysis. The maximum value is the number of physical cores.
with remaining optional input
-o|–output_filename <filename>: Supply the full file path for the file into which the results are saved. Note that either ‘-o’ or ‘–output_filename’ can be used. If this optional input is not supplied, the results are saved to a file named ‘results_<current date and time>.json’.
Continuing the above example, suppose that the task file (tasks.json) from above is in our Documents folder with the two image files and our INI file (imatest-v2.ini). The call on macOS to run the two tasks in parallel on two processes would be
[shell]
cd ~/Documents
/Applications/Imatest/IT/v2020.2/bin/run_parallel_analyzer.sh ./tasks.json ./imatest-v2.ini 1 2
[/shell]
And on Linux the command would be
[shell]
cd ~/Documents
/usr/local/Imatest/v2020.2/IT/bin/run_parallel_analyzer.sh ./tasks.json ./imatest-v2.ini 1 2
[/shell]
The results will be saved to a JSON encoded file in the form of a JSON object array with one result object per task. Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property.
Imatest IT allows you to analyze several different images in parallel, using the new parallel_analyzer function.
To use the parallel_analyzer, first create a list of analysis tasks that need to be run. Each task will be assigned to a different parallel process. The number of available concurrent processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer cores if you need.
To create an analysis task, use the new_parallel_task function:
[python]
ImatestLibrary.new_parallel_task(image_files=None, image_data=None, analysis_type=None, image_data_meta_data=None)
[/python]
Parameter Name | Data Type | Description |
---|---|---|
image_files | str or list of strs | Either a file path to an image, or a list of file paths |
image_data | str/bytes or array.array (numerical) | If you are providing raw image data, use this argument, which is either the read value of the image in str (Python 2.7) or bytes (Python 3.6, 3.7) form. If using image_data, you must include the image_data_meta_data argument, which you can get by calling ImatestLibrary.build_json_args() |
analysis_type | enum | A flag telling Imatest IT which module to run. Valid values are constants on the ImatestLibrary class: ImatestLibrary.BLEMISH_ANALYSIS ImatestLibrary.CHECKERBOARD_ANALYSIS ImatestLibrary.COLORCHECK_ANALYSIS ImatestLibrary.DISTORTION_ANALYSIS ImatestLibrary.DOTPATTERN_ANALYSIS ImatestLibrary.ESFRISO_ANALYSIS ImatestLibrary.MULTITEST_ANALYSIS ImatestLibrary.RANDOM_ANALYSIS ImatestLibrary.SFR_ANALYSIS ImatestLibrary.SFRPLUS_ANALYSIS ImatestLibrary.SFRREG_ANALYSIS ImatestLibrary.STAR_ANALYSIS ImatestLibrary.UNIFORMITY_ANALYSIS ImatestLibrary.WEDGE_ANALYSIS |
image_data_meta_data | dict | A dict object containing the direct read meta data, used to help interpret the raw byte data, and obtained by calling ImatestLibrary.build_json_args(). Required if using the image_data argument, not needed if using image_files. |
add each of your tasks to a list, then call ImatestLibrary.parallel_analyser, passing in the path to your INI file, True for run_parallel, and the number of worker processes you’d like to use:
[python]
ini_file = r’C:\images\ini_file\imatest-v2.ini’
tasks = []
tasks.append(library.new_parallel_task(image_files=r’C:\images\sfrplus_0123.jpg’, analysis_type=ImatestLibrary.SFRPLUS_ANALYSIS))
tasks.append(library.new_parallel_task(image_files=[r’C:\images\blemish_0001.jpg’, r’C:\images\blemish_0002.jpg’, r’C:\images\blemish_0003.jpg’], analysis_type=ImageLibrary.BLEMISH_ANALYSIS))
….
result = library.parallel_analyzer(tasks=tasks, ini_file=ini_file, run_parallel=True, num_workers=4)
[/python]
The result will be a JSON encoded string that can be parsed into an array of result objects using json.loads(result). Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property:
[python]
resultArr = json.loads(result)
for task_result in result_arr:
if task_result[‘errorID’]:
# Gracefully handle the error
else:
result_data = task_result[‘data’]
# Process the results in the result_data dictionary
[/python]
Imatest IT allows you to analyze several different images in parallel, using the new ParallelAnalyzer.Execute() method.
To use the ParallelAnalyzer, first create a List of ImatestTasks objects that contain images to be analyzed. Each task will be assigned to a different parallel process. The number of available concurrent worker processes depends on how many cores your machine has, though you can tell Imatest IT to use fewer workers if you need.
To create an ImatestTask, use one of the overloaded ImatestTask.Create() methods:
[csharp]
public static ImatestTask Create(string imageFilePath, ImatestModule module);
public static ImatestTask Create(IEnumerable&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; imageFilePaths, ImatestModule module);
public static ImatestTask Create(byte[] imageData, ImatestModule module, DirectReadOptions imageMetaData);
public static ImatestTask Create(UInt16[] imageData, ImatestModule module, DirectReadOptions imageMetaData);
public static ImatestTask Create(UInt32[] imageData, ImatestModule module, DirectReadOptions imageMetaData);
[/csharp]
[vbnet]
Public Shared Function Create(imageFilePath As String, [module] As ImatestModule) As ImatestTask
Public Shared Function Create(imageFilePaths As IEnumerable(Of String), [module] As ImatestModule) As ImatestTask
Public Shared Function Create(imageData() As Byte, [module] As ImatestModule, imageMetaData As DirectReadOptions) As ImatestTask
Public Shared Function Create(imageData() As UShort, [module] As ImatestModule, imageMetaData As DirectReadOptions) As ImatestTask
Public Shared Function Create(imageData() As UInteger, [module] As ImatestModule, imageMetaData As DirectReadOptions) As ImatestTask
[/vbnet]
Parameter Name | Data Type | Description |
---|---|---|
imageFilePath | string | A file path to an image |
imageFilePaths | IEnumerable<string> | A collection of file paths to images |
imageData | byte[], UInt16[], UInt32[] | Raw image data (if you are using direct read mode) |
module | enum (ImatestLibrary) | A flag telling Imatest IT which module to run. Valid values are contained in the ImatestModule enum: ImatestModule.Blemish ImatestModule.Checkerboard ImatestModule.Colorcheck ImatestModule.Distortion ImatestModule.DotPattern ImatestModule.eSFRISO ImatestModule.Multitest ImatestModule.Random ImatestModule.SFR ImatestModule.SFRplus ImatestModule.SFRreg ImatestModule.Star ImatestModule.Uniformity ImatestModule.Wedge |
imageMetaData | DirectReadOptions | An instance of the DirectReadOptions class that contains image meta data, used to help interpret the raw byte data. |
Add each of your tasks to a collection of type ImatestTask, then call Library.ParallelAnalyzer.Execute(), passing in the path to your INI file for iniFilePath, true for runInParallel, and the number of worker processes you’d like to use:
[csharp]
string inFile = "C:\\images\\ini_file\\imatest-v2.ini";
List&amp;amp;amp;amp;lt;ImatestTask&amp;amp;amp;amp;gt; lstTasks = new List&amp;amp;amp;amp;lt;ImatestTask&amp;amp;amp;amp;gt;();
lstTasks.Add(ImatestTask.Create("C:\\images\\sfrplus_0123.jpg", ImatestModule.SFRplus));
lstTasks.Add(ImatestTask.Create(new List&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt;() { "C:\\image\\blemish_0001.jpg", "C:\\images\\blemish_0002.jpg", "C:\\images\\blemish_0003.jpg" }, ImatestModule.Blemish));
….
string result = library.ParallelAnalyzer.Execute(lstTasks, iniFile, true, 2);
[/csharp]
[vbnet]
Dim iniFilePath As String
Dim lstTasks As New List(Of ImatestTask)()
Dim result As String
iniFilePath = "C:\\images\\ini_file\\imatest-v2.ini"
lstTasks.Add(ImatestTask.Create("C:\\images\\sfrplus_0123.jpg", ImatestModule.SFRplus))
lstTasks.Add(ImatestTask.Create("C:\\image\\blemish_0001.jpg" ImatestModule.Blemish))
List&amp;amp;amp;amp;lt;ImatestTask&amp;amp;amp;amp;gt; lstTasks = new List&amp;amp;amp;amp;lt;ImatestTask&amp;amp;amp;amp;gt;();
lstTasks.Add(ImatestTask.Create("C:\\images\\sfrplus_0123.jpg", ImatestModule.SFRplus));
lstTasks.Add(ImatestTask.Create(new List&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt;() { "C:\\image\\blemish_0001.jpg", "C:\\images\\blemish_0002.jpg", "C:\\images\\blemish_0003.jpg" }, ImatestModule.Blemish));
….
result = library.ParallelAnalyzer.Execute(lstTasks, iniFilePath, True, 4)
[/vbnet]
The result will be a JSON encoded string that can be parsed into an array of result objects using any .NET JSON library. Each result object has this form:
[plain]
{
"data": {
"dateRun": "18-Sep-2017 10:26:59",
"ini_file_name": "C:\\images\\ini_file\\imatest-v2.ini",
"ini_time_size": "18-Sep-2017 10:26:45 21822B MD5 = ac109f86b635bd5b4344d252969e64a7",
"version": "Imatest 5.0.0 SFRplus",
"title": "sfrplus_0123.jpg",
"image_path_name": "C:\\images\\sfrplus_0123.jpg",
…
},
"errorID": "",
"errorMessage": "",
"errorReport": ""
}
[/plain]
If any exceptions occurred during processing, they will be reported in the errorID, errorMessage, and errorReport properties. While handling your results, you should always check whether the errorID property is empty or not before working with the data property.
Arbitrary Charts Module
Imatest IT now allows you to call the Arbitrary Charts module in using the new arbitrary_charts functions. For more information on the Arbitrary Charts modules, see this article.
[cpp]
arbitrary_charts_shell(int nargout, mwArray&amp;amp;amp;amp;amp; output, const mwArray&amp;amp;amp;amp;amp; inputData, const mwArray&amp;amp;amp;amp;amp; chartFile, const mwArray&amp;amp;amp;amp;amp; iniFile, const mwArray&amp;amp;amp;amp;amp; averageMode, const mwArray&amp;amp;amp;amp;amp; optionsJson);
[/cpp]
where the parameters are defined in the following table:
nargoutintAlways set this to 1. This parameter indicates the number of desired outputs.
Parameter Name | Data Type | Description |
---|---|---|
output | mwArray(const char*) | This will contains the results in the form of a JSON-encoded UTF-16 string. |
inputData | mwArray | The input image data. This can be in the form of a single image file path, a mwArray of type mxCELL_CLASS containing multiple image paths, or a mwArray of type mxCELL_CLASS containing numeric arrays. |
chartFile | mwArray(const char*) | The file path to the chart definition file (see https://www.imatest.com/docs/arbitrary-charts/definitions/). |
iniFile | mwArray(const char*) | The file path to the INI file. |
averageMode | mwArray(int) || mwArray(const char*) | This parameter allows you to specify whether if groups of files are averaged (averageMode == 1) or not (averageMode == 0). |
optionsJson | mwArray(const char*) | This parameter is a JSON-encoded string that contains descriptive meta-data for the image. See below for more information. |
To begin, declare the iniFileParam and chartFileParam variables and supply the fully-qualified paths to INI and chart definition files.
[objc] - (void)runTest: (id)param { @autoreleasepool { try{ mwArray iniFileParam("/some/folder/imatest-v2.ini"); mwArray chartFileParm("/some/folder/chart_definition.json"); [/objc]
Next the images need to be supplied either as one or more image files, or as image data arrays. If you want to supply more than one image file at a time you will need to first construct an mwArray of type mxCELL_CLASS. For example, if you had three images inputDataParam would be constructed as follows:
[objc] mwArray inputDataParam(3, 1, mxCELL_CLASS); inputDataParam.Get(1, 1).Set(mwArray("/some/folder/image1.jpg")); inputDataParam.Get(1, 2).Set(mwArray("/some/folder/image2.jpg")); inputDataParam.Get(1, 3).Set(mwArray("/some/folder/image3.jpg")); [/objc]
Alternatively, if you had only a single image file, you can construct inputDataParam by passing the image file path directly to the mwArray constructor
[objc] mwArray inputDataParam("/some/folder/image.jpg"); [/objc]
If you are supplying more than one image, you can specify whether the images should be averaged (averageMode == 1) or analyzed separately (averageMode == 0) using the averageModeParam, which can be set to contain a numeric value or a string such as
[objc] mwArray averageModeParam("0"); [/objc]
The remaining parameter to construct is optionsJson. The JSON properties defined in the optionsJson parameter are defined in the table below.
Option Name | Data Type | Required? | Description |
---|---|---|---|
width | int | image data arrays only | The width of the image in pixels. |
height | int | image data arrays only | The height of the image in pixels. |
encoding | string | Yes | The data encoding format of the image data. For now the options are (case-insensitive):’intensity’, ‘sRGB’, ‘adobe_rgb’, ‘wide_gamut_rgb’, ‘pro_photo_rgb’, ‘apple_rgb’, ‘colormatch’, ‘rec_709_full’, ‘rec_709_legal’, ‘rec_2020_full’, ‘rec_2020_legal’, ‘aces’. Use ‘intensity’ for 1-channel grayscale data, while the others are for standard RGB encodings. |
fileroot | string | image data arrays only | The file path to the source image file. |
extension | string | image data arrays only | The file extension to the source image file. |
serial_number | string | No | A string containing the serial number. |
part_number | string | No | A string containing the part number. |
crop_borders | double array | No | A 1 x 4 double array indicating the crop borders ( [Left Top Right Bottom] ). |
lens_to_chart_distance_cm | double | No | The lens to chart distance in cm. |
chart_height_cm | double | No | The chart height in cm. |
In this example, image files are being supplied, so we are only required to supply the image encoding, for example:
[objc] mwArray optionsJsonParam("{\"encoding\":\"sRGB\"}"); [/objc]
Lastly, we call arbitrary_charts_shell and supply the parameters that have been constructed
[objc] // Call the library function mwArray output arbitrary_charts_shell(1, output, inputDataParam, chartFileParm, iniFileParam, averageModeParam, optionsJsonParam); // Extract the JSON-encoded string. // Note that the mwArray contains only UTF-16 strings, which we must load into an NSString auto numel = out.NumberOfElements(); std::u16string buffer(numel+1, 0); out.GetCharData(&amp;amp;amp;amp;amp;buffer[0], numel); char* data = (char*)buffer.data(); unsigned long size = buffer.size()*sizeof(char16_t); NSString* jsonString =[[NSString alloc] initWithBytes:data length:size encoding:NSUTF16LittleEndianStringEncoding]; // Process results } catch (mwException ex){ NSLog(@"Error"); NSLog(@"%s", ex.what()); ex.print_stack_trace(); } } } [/objc]
The result will be a JSON-encoded string of this form:
[plain]
{
"Info": {
"Timestamp": "04-Oct-2017 09:09:08",
"Version": "Imatest 5.1.0.25883 Alpha ",
"Build": "2017-10-03",
"Calculation_time_seconds": [44.36107732]
},
"Results_array_sources": "C:\\images\\P1858_combination_chart_example.jpg",
"Results": {
…
}
}
[/plain]
First, create an image options dictionary by calling ImatestLibrary.get_arbitrary_charts_options():
[python]
ImatestLibrary.get_arbitrary_charts_options(self, width=None, height=None, encoding=None, filename=None, extension=None, pixel_size=None)
[/python]
Parameter Name | Data Type | Description |
---|---|---|
width | int | Image width (in pixels) |
height | int | Image height (in pixels) |
encoding | str | The pixel encoding (i.e., “srgb”, “intensity”) |
filename | str | (direct read only) The name of the file, used for results file names. |
extension | str | (direct read only) The extension key used to decode the direct read image bytes, as configured in the Read Raw screen of Imatest Master. |
pixel_size | enum | (direct read only) The pixel size of the direct read image. Use one of these constants: ImatestLibrary.PIXEL_SIZE_8_BIT_UNSIGNED ImatestLibrary.PIXEL_SIZE_16_BIT_UNSIGNED ImatestLibrary.PIXEL_SIZE_32_BIT_UNSIGNED |
Once you have the options object, you can then call the one of the arbitrary_charts functions:
[python]
ImatestLibrary.arbitrary_charts_separate(self, image_files=None, image_data=None, chart_file=None, ini_file=None, options=None)
ImatestLibrary.arbitrary_charts_signal_average(self, image_files=None, image_data=None, chart_file=None, ini_file=None, options=None)
[/python]
The arbitrary_charts_separate function will analyze multiple inputs separately, while the arbitrary_charts_signal_average function will combine two images’ results into a single signal averaged result.
Parameter Name | Data Type | Description |
---|---|---|
image_files | str or list of strs | Either a file path to an image, or a list of file paths |
image_data | str/bytes or array.array (numerical) | If you are providing raw image data, use this argument, which is either the read value of the image in str (Python 2.7) or bytes (Python 3.6, 3.7) form. If using image_data, you must include the required parameters into the ImatestLibrary.get_arbitrary_charts_options() method |
chart_file | str | The path to the chart definition file. |
ini_file | str | The path to the INI file. |
options | dict | The dict object returned by calling ImatestLibrary.get_arbitrary_charts_options(). |
The result will be a JSON-encoded string, which can be converted to a dict using json.loads(), of this form:
[plain]
{
"Info": {
"Timestamp": "04-Oct-2017 09:09:08",
"Version": "Imatest 5.1.0.25883 Alpha ",
"Build": "2017-10-03",
"Calculation_time_seconds": [44.36107732]
},
"Results_array_sources": "C:\\images\\P1858_combination_chart_example.jpg",
"Results": {
…
}
}
[/plain]
First, create an ArbitraryChartOptions object:
[csharp]
ArbitraryChartOptions arbChartOptions = new ArbitraryChartOptions();
arbChartOptions.Encoding = ImageEncoding.sRGB;
arbChartOptions.Width = 1296;
arbChartOptions.Height = 808;
[/csharp]
[vbnet]
Dim arbChartOptions As ArbitraryChartOptions
arbChartOptions = new ArbitraryChartOptions()
arbChartOptions.Encoding = ImageEncoding.sRGB
arbChartOptions.Width = 1296
arbChartOptions.Height = 808
[/vbnet]
Property Name | Data Type | Description |
---|---|---|
Width | int | Image width (in pixels) |
Height | int | Image height (in pixels) |
encoding | enum (ImageEncoding) | The pixel encoding: ImageEncoding.sRGB ImageEncoding.Intensity |
Filename | string | (direct read only) The name of the file, used for results file names. |
Extension | string | (direct read only) The extension key used to decode the direct read image bytes, as configured in the Read Raw screen of Imatest Master. |
Once you have the ArbitraryChartOptions object, you can then call the one of the ArbitraryCharts methods:
[csharp]
public string Separate(string inputFile, string chartFile, string iniFile, ArbitraryChartOptions options);
public string Separate(IEnumerable&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; inputFiles, string chartFile, string iniFile, ArbitraryChartOptions options);
public string Separate(byte[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public string Separate(ushort[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public string Separate(uint[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SeparateAsync(string inputFile, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SeparateAsync(IEnumerable&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; inputFiles, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SeparateAsync(byte[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SeparateAsync(ushort[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SeparateAsync(uint[] imageData, string chartFile, string iniFile, ArbitraryChartOptions options);
public string SignalAverage(IEnumerable&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; inputFiles, string chartFile, string iniFile, ArbitraryChartOptions options);
public Task&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; SignalAverageAsync(IEnumerable&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; inputFiles, string chartFile, string iniFile, ArbitraryChartOptions options);
[/csharp]
[vbnet]
Public Function Separate(inputFile As String, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function Separate(inputFiles As IEnumerable(Of String), chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function Separate(imageData() As Byte, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function Separate(imageData() As UShort, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function Separate(imageData() As UInteger, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function SeparateAsync(inputFile As String, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
Public Function SeparateAsync(inputFiles As IEnumerable(Of String), chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
Public Function SeparateAsync(imageData() As Byte, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
Public Function SeparateAsync(imageData() As UShort, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
Public Function SeparateAsync(imageData() As UInteger, chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
Public Function SignalAverage(inputFiles As IEnumerable(Of String), chartFile As String, iniFile As String, options As ArbitraryChartOptions) As String
Public Function SignalAverageAsync(inputFiles As IEnumerable(Of String), chartFile As String, iniFile As String, options As ArbitraryChartOptions) As Task(Of String)
[/vbnet]
The ArbitraryCharts.Separate methods will analyze multiple inputs separately, while the ArbitraryCharts.SignalAverage method will combine two images’ results into a single signal averaged result.
Parameter Name | Data Type | Description |
---|---|---|
inputFile(s) | string or IEnumberable | Either a file path to an image, or a list of file paths |
imageData | byte[], UInt16[], UInt32[] | Raw image data (if you are using direct read mode) |
chartFile | str | The path to the chart definition file. |
iniFile | str | The path to the INI file. |
options | dict | The ArbitraryChartOptions object. |
The result will be a JSON-encoded string, which can be parsed using any .NET JSON library, of this form:
[plain]
{
"Info": {
"Timestamp": "04-Oct-2017 09:09:08",
"Version": "Imatest 5.1.0.25883 Alpha ",
"Build": "2017-10-03",
"Calculation_time_seconds": [44.36107732]
},
"Results_array_sources": "C:\\images\\P1858_combination_chart_example.jpg",
"Results": {
…
}
}
[/plain]