The CImage class provides a syntax for making your scripts easier to understand when using operations involving images and numbers (also see CImage Class Methods). This is similar to operator overloading in the C++ language. CImage class math operators make it possible for a script to use expressions like the following:
ImResult = 0.08 / -(Im ^ 0.5)
Im = (Im - ImBias - ImDark) / ImFlat
All operators have class method counterparts. For example, the alternative to using the operator + would be the method Add. A primary difference between the operators and corresponding methods is that many of the operators create the result as a new CImage object, whereas the method operates on the object it is called from. The operators do not modify the original image, although the class methods may modify the CImage that calls the class method. These differences are described in the table below.
CImage operators that perform a math operation automatically create an image with floating point (double precision) data type. If you do not want to create a new image or a floating point image, use the class methods to exercise greater control over the process.
Operator Expressions
Operator | Definition | Operator Example | Script Equivalent |
Im1 + Im2 | Adds the values of two images and creates a new CImage for the result. This is equivalent to the CImage:Add method. | Im3 = Im1 + Im2 | Im3 = CImage:new( Im1 ) Im3:Add( Im2 ) |
Im1 + num | Adds a number to the image values and creates a new CImage for
the result. This is equivalent to the CImage:Add method. |
Im2 = Im1 + 0.5 | Im2 = CImage:new(Im1) Im2:Add( 0.5 ) |
Im1 - Im2 | Subtracts the values of Im2 from Im1 and creates a new CImage for the result. This is equivalent to the CImage:Sub method. | Im3 = Im1 - Im2 | Im3 = CImage:new( Im1 ) Im3:Sub( Im2 ) |
Im1 - num | Subtracts a number from the image values and creates a new CImage for the result. This is equivalent to the CImage:Sub method. | Im2 = Im1 - 0.5 | Im2 = CImage:new( Im1 ) Im2:Sub( 0.5 ) |
Im1 * Im2 | Multiplies the values of two images and creates a new CImage for the result. This is equivalent to the CImage:Mul method. | Im3 = Im1 * Im2 | Im3 = CImage:new( Im1 ) Im3:Mul( Im2 ) |
Im1 * num | Multiplies the values of an image by a number and creates a new CImage for the result. This is equivalent to the CImage:Mul method. | Im2 = Im1 * 0.5 | Im2 = CImage:new( Im1 ) Im2:Mul( 0.5 ) |
Im1 / Im2 | Divides the values of Im1 by those of Im2 and creates a new CImage for the result. This is equivalent to the CImage:Div method. | Im3 = Im1 / Im2 | Im3 = CImage:new( Im1 ) Im3:Div( Im2 ) |
Im1 / num | Divides the image values by a number and creates a new CImage for the result. This is equivalent to the CImage:Div method. | Im2 = Im1 / 0.5 | Im2 = CImage:new( Im1 ) Im2:Div( 0.5 ) |
Im1 ^ Im2 | Raises the values of Im1 to the power of Im2, pixel by pixel, and creates a new CImage for the result. This is equivalent to the CImage:Pow method. | Im3 = Im1 ^ Im2 | Im3 = CImage:new( Im1 ) Im3:Pow( Im2 ) |
Im1 ^ num | Raises the image values to a numeric power and creates a new CImage for the result. This is equivalent to the CImage:Pow method. | Im2 = Im1 ^ 0.5 | Im2 = CImage:new( Im1 ) Im2:Pow( 0.5 ) |
Im1 % Im2 | Computes the modulus (or remainder) of Im1 divided by Im2 and creates a new CImage for the result. This is equivalent to the CImage:Mod method. | Im3 = Im1 % Im2 | Im3 = CImage:new( Im1 ) Im3:Mod( Im2 ) |
Im1 % num | Computes the modulus (or remainder) of image values divided by a number and creates a new CImage for the result. This is equivalent to the CImage:Mod method. | Im2 = Im1 % 0.5 | Im2 = CImage:new( Im1 ) Im2:Mod( 0.5 ) |
-Im | Computes the unary minus of the image by negating its pixel values, creating a new CImage for the result. This is equivalent to the CImage:Chs method. | Im2 = -Im1 | Im2 = CImage:new( Im1 ) Im2:Chs() |
== | Compares two images on a pixel by pixel basis. Returns true if every pixel value in Im1 is equal to the corresponding pixel in Im2. This is equivalent to the CImage:CompareEQ method. | if Im2 == Im1 then Func() end |
if Im2:CompareEQ( Im1 ) == true then Func() end |
<= | Compares two images on a pixel by pixel basis. Returns true if every pixel value in Im1 is less than or equal to the corresponding pixel in Im2. This is equivalent to the CImage:CompareLE method. | if Im2 <= Im1 then Func() end |
if Im2:CompareLE( Im1 ) == true then Func() end |
< | Compares two images on a pixel by pixel basis. Returns true if every pixel value in Im1 is less than the corresponding pixel in Im2. This is equivalent to the CImage:CompareLT method. | if Im2 < Im1 then
Func() end |
if Im2:CompareLT( Im1 ) == true then Func() end |
Comparison between Operators and Methods
The examples above show how operators simplify complex expressions. Now compare an operator-based expression with its equivalent using class methods. Assume that a raw image and several calibration images are open in memory. The scripts below perform a typical intensity calibration and photometric adjustment.
Here is the expression using operators:
ImResult = 1.0024 * ((ImRaw - ImBiasPattern - ImDark) / ImFlatPixel / ImFlatIntensity)
Realizing the same result using class methods would use the following script:
ImRaw:SetDatatype( "double" )
Im:Sub( ImBiasPattern )
Im:Sub( ImDark )
Im:Div( ImFlatPixel )
Im:Div( ImFlatIntensity )
Im:Mul( 1.0024 )
One drawback to the operator based expression is that it may create intermediate images that are not deleted from memory until after going "out of scope", which may occur at the end of the function where they are used or ultimately, at the end of the script. For example, in evaluating the operator-based expression, Im - ImBias creates a CImage as an intermediate result. Then subtracting ImDark creates another result. Subtracting from that result to make yet another result, and so on. In fact, the expression creates 5 new instances of a CImage that are "hidden" and you can not manually delete. There is no way to avoid this. By comparison, the alternative script works by repeatedly changing the CImage Im and and does not even need to create a new image to hold the result. However, Im is altered by the method based script whereas the operators leave Im intact. If you want the method-based script to leave Im intact, simply construct a new copy of Im at the beginning, as in Im2 = CImage:new( Im ), and then call the methods from Im2. There is no work-around to these differences in behavior; so goes object-oriented programming. If you do not care that intermediate images are created, then using the expression can make your scripts far easier to understand.