snibgo's ImageMagick pages

Colours to matrix and polynomials

What -color-matrix or -function Polynomial will make one image look like another?

When we have two same-sized images with corresponding pixels, so there is a colour transformation but no geometric transformation, we can calculate the parameters for "-color-matrix" or "-function Polynomial" that approximate the transformation.

The method assumes the transformation is global rather than local, eg the entire image has been shifted towards red, rather than one part shifted towards red and another part towards blue.

Other methods for transforming images include:

Methods on this pages are generalisations of "gain and bias".

Scripts on this page assume that the version of ImageMagick in %IM7DEV% has been built with various process modules. See Process modules.

References

The method

IM's "-color-matrix" and "-function Polynomial" operations have mathematical definitions: each channel of each output pixel is calculated from a formula that has the channels of the corresponding input pixel and a list of numbers. We use these operations by supplying the list of numbers, so IM can calculate the output pixels.

This method operates the reverse process: given the input and output pixels, it calculates the list of numbers.

How does it do this? There is one equation per channel per pixel, with known channel values and unknown numbers in the list, but we know the same numbers are used in all the equations. So we have a bunch of simultaneous equations that can be solved for all the unknowns, which gives us the list of numbers. We often have more equations than unknowns, so we find the unknowns that minimizes the sum-of-squared-errors.

Why do we want this? We might have a set of input images that we want to normalise to a common standard. For example, time-lapse photos of a building site that we want to make into a movie. Or aerial photos that we want to join together. Or photos of an object taken under different lighting conditions. The same matrix or polynomial is then applied to any image for which we want the same transformation.

Before giving the method details, we will play with IM's colour matrix and polynomial to see how they work.

The following descriptions assume the three colour channels are RGB, but they could be Lab or YIQ or any other three-channel colorspace.

IM's colour matrix

IM's operation "-color-matrix" calculates new pixels as the sum of a DC offset plus the colour components each multiplied by a factor. Hence, it provides for cross-feed between channels.

For RGB with offsets, we use a 6x6 matrix. The six columns and rows are the five channels (R, G, B, K, A) and an offset. "K" is the black channel of CMYK, and we don't use this. The top three rows specify the red, green and blue outputs. The bottom three rows are constant, and we don't usually want to change colours according to alpha, or to change alpha according to colours, so we have only 12 important values:

a,b,c,0,0,d,
e,f,g,0,0,h,
i,j,k,0,0,m,
0,0,0,1,0,0,
0,0,0,0,1,0,
0,0,0,0,0,1

(For clarity, I don't use the letter "L".)

When we know the values of a..m, each output R',G',B' is then calculated from the corresponding input R,G,B:

R' = R*a + G*b + B*c + d
G' = R*e + G*f + B*g + h
B' = R*i + G*j + B*k + m
A' = A

If we use only the diagonal elements a,f,k and the offsets d,h,m, setting other values to zero, we have the equivalent of the gain and bias method, where a,f,k are the gain multipliers and d,h,m are the bias offsets.

Examples:

Identity matrix.

%IMG7%magick ^
  toes.png ^
  -color-matrix ^
1,0,0,0,0,0,^
0,1,0,0,0,0,^
0,0,1,0,0,0,^
0,0,0,1,0,0,^
0,0,0,0,1,0,^
0,0,0,0,0,1 ^
  c2mp_cm1.png
c2mp_cm1.pngjpg

Swap red and green channels.

%IMG7%magick ^
  toes.png ^
  -color-matrix ^
0,1,0,0,0,0,^
1,0,0,0,0,0,^
0,0,1,0,0,0,^
0,0,0,1,0,0,^
0,0,0,0,1,0,^
0,0,0,0,0,1 ^
  c2mp_cm2.png
c2mp_cm2.pngjpg
%IMG7%magick ^
  toes.png ^
  -color-matrix ^
1,0.25,0,0,0,-0.25,^
0,1,0,0,0,0,^
0,0,1,0,0,0,^
0,0,0,1,0,0,^
0,0,0,0,1,0,^
0,0,0,0,0,1 ^
  c2mp_cm3.png
c2mp_cm3.pngjpg
%IMG7%magick ^
  toes.png ^
  -color-matrix ^
1.1,0.25,0,0,0,-0.1,^
0.1,1,0.1,0,0,-0.2,^
-0.1,0,1,0,0,0,^
0,0,0,1,0,0,^
0,0,0,0,1,0,^
0,0,0,0,0,1 ^
  c2mp_cm4.png
c2mp_cm4.pngjpg

How do we get the 12 numbers a..m from two images? If the images each have N pixels, then we have N input values for each of R, G and B, and N output values for each of R', G' and B'. This gives us 3*N simultaneous equations that can be solved by Gauss-Jordan elimination.

For example, suppose an input pixel is RGB=(10%,20%,30%) and the corresponding output pixel is R'G'B'=(21%,22%,14%). This gives us three equations:

21 = 10*a + 20*b + 30*c + d
22 = 10*e + 20*f + 30*g + h
14 = 10*i + 20*j + 30*k + m

For this pair of pixels, the terms are (10,20,30,1), and the results are (21,22,14).

Four pairs of pixels would supply 12 simultaneous equations, so we could solve for the 12 unknowns a..m. If we have more than four pixels, the problem is over-determined and there may be no exact solution. But we can find a solution that minimizes the squared errors.

The output in each channel depends on the input in every channel, so we can't represent the transformation by simple "in versus out" curves.

Constraint: no cross-feed

We may wish to prevent the solution from cross-feeding between channels. The solution then has only six important values, gain a,f,k and bias d,h,m:

a,0,0,0,0,d,
0,f,0,0,0,h,
0,0,k,0,0,m,
0,0,0,1,0,0,
0,0,0,0,1,0,
0,0,0,0,0,1

The equations are:

R' = R*a + d
G' = G*f + h
B' = B*k + m
A' = A

The equations are fully independent; they have no elements in common. Hence they are solved as three independent problems.

This is simple linear regression. The output in each channel depends on the input of that channel only, so we can represent the transformation by three simple curves (which are all straight lines):

set sMAT=^
1.1,0,0,0,0,-0.1,^
0,0.9,0,0,0,-0.2,^
0,0,1,0,0,0,^
0,0,0,1,0,0,^
0,0,0,0,1,0,^
0,0,0,0,0,1

%IMG7%magick ^
  toes.png ^
  -color-matrix %sMAT% ^
  c2mp_cm4.png

%IMG7%magick ^
  -size 1x256 gradient: -rotate 90 ^
  -color-matrix %sMAT% ^
  c2mp_cmgr4.png

call %PICTBAT%graphLineCol ^
  c2mp_cmgr4.png . . 0
c2mp_cm4.pngjpg c2mp_cmgr4_glc.png

Constraint: gain only

Constraining to just the gain can be useful. The solution then has only three important values, a,d,f:

a,0,0,0,0,0,
0,f,0,0,0,0,
0,0,k,0,0,0,
0,0,0,1,0,0,
0,0,0,0,1,0,
0,0,0,0,0,1

The equations are:

R' = R*a
G' = G*f
B' = B*k
A' = A

Again, the equations are fully independent, so they are solved as three independent problems.

A bias-only method is also possible, but doesn't seem useful.

IM's polynomial

IM's operation -function polynomial is closely related to -colour-matrix. We can apply a different polynomial to each channel, and that is how we will use it. There is no cross-channel mixing. Each output channel value is the sum of the input raised to a number of integer powers, each multipled by a coefficient.

If u is the input value normalised to typically between 0.0 to 1.0, and the polynomial is degree n, then the output u' is...

u' = an*un + an-1*un-1 + ... + a1*u + a0

Given a number of inputs u and corresponding outputs u', the module calculates the coefficients a0 ... an. The number of terms, and number of coefficients, is (n+1). We have one set of coefficients per channel, for a total of 3*(n+1) coefficients.

A polynomial of degree zero adds a constant value (a bias-only operation). A polynomial of degree one multiplies, then adds a constant value (a linear polynomial; a gain and bias operation). Polynomials of degree two are called quadratic; of degree three are called cubic. Higher degrees describe more complex transfer curves. A polynomial degree n can be used to transform an image of n pixels to any other image.

For example:

Set R' = -0.3*R2 + 0.8*R + 0.2, etc.

set sPOLY=^
  -channel R -function Polynomial -0.3,0.8,0.2 ^
  -channel G -function Polynomial 0.8,-0.1 ^
  -channel B -function Polynomial 0.4

%IMG7%magick ^
  toes.png ^
  %sPOLY% ^
  +channel ^
  c2mp_pol1.png
c2mp_pol1.pngjpg

By applying the same operations to a gradient, we can get a transfer curve for each channel.

Set R' = -0.3*R2 + 0.8*R + 0.2, etc.

%IMG7%magick ^
  -size 1x256 gradient: -rotate 90 ^
  %sPOLY% ^
  +channel ^
  c2mp_polgr1.png

call %PICTBAT%graphLineCol ^
  c2mp_polgr1.png . . 0
c2mp_polgr1_glc.png

So, we can create a polynomial for each channel, and tweak a photo so its colour patches roughly match those of a reference. Higher degrees of polynomials will match the patches more closely, until perfection when the degree equals the number of patches. But this comes at a price: with higher degrees, the curve becomes increasingly eratic at colours other than the patches. In practice, degrees above three do not seem useful, and degree two is often sufficient.

Example photos

set imgA=toes.png
toes.pngjpg
set imgB=toes_x.jpg
toes_x.jpg

The process module cols2mat

When we have two same-sized images, "-process cols2mat" calculates the 12 numbers a..m and hence the 6x6 colour matrix, or the polynomial of required degree, that best transforms the first image to the second.

Option Description
Short
form
Long form
m string method string Method for calculating the matrix, one of:
    Cross include cross-channel multipliers (12 terms);
    NoCross exclude cross-channel multipliers (6 terms);
    NoCrossPoly polynomial without cross-channel (3*degreePoly+3 terms);
    GainOnly include only this-channel multipliers (3 terms).
Default = Cross.
d integer degreePoly integer For method NoCrossPoly, degree of polynomial.
For example: degree 3 gives v' = a*v3 + b*v2 + c*v + d.
Default: 2.
w number weightLast number Weight for last line of image.
For example: more than 1.0 (eg 10, 100) to give greater weight to last line,
between 0.0 and 1.0 to give less weight.
Default: 1.0.
wa weightAlpha Multiplies weight by product of the pixel alphas.
x noTrans Don't replace images with transformation.
string file string Write text data (the colour matrix) to stderr or stdout.
Default = stderr.
v verbose Write some text output to stderr.
version Write version information to stdout.

The module needs two or three input images. The first two inputs must be the same size as each other. It replaces all the inputs with a single output image. It calculates the colour matrix or polynomial from the first two inputs. If there are only two inputs, the output is the first transformed by the colour matrix or polynomial. If there are three inputs then the output is the third transformed by the colour matrix or polynomial.

For the weightAlpha option, see Weighting by alpha below.

The noTrans option will leave the image list unchanged. For applications that don't need a transformed image, it saves some time.

The inputs must have three colour chanels, representing RGB, L*a*b*, YIQ or whatever. For RGB images, I use it with sRGB colorspace, but I expect it will work with any profiled 3-channel colorspace.

Typically the first two inputs are small, for example 6x4 pixels. But they can be any size, provided they are the same size and the pixels correspond. It takes about four seconds to process a pair of 35 MP images.

For the NoCrossPoly method, the text output is three lists of polynomial coefficients. For the other methods, the text output is a single list of numbers in the 6x6 matrix. (A more general polynomial with cross-channel terms is possible, but IM has no operation for this.)

By default the calculation gives equal weight to all the input pixels, but a different weight may be applied to the last row on input pixels, and the weight may be multiplied by the product of the alphas.

Extracting the matrix

The calculated 6x6 color matrix is sent as text to stderr or stdout, in a line that starts with "c2matrix=". The 36 numbers are separated by commas, with no spaces.

For example:

%IM7DEV%magick ^
  %imgA% ^
  %imgB% ^
  -precision 9 ^
  -process 'cols2mat f stdout' ^
  c2mp_m1.png 
c2mp_m1.pngjpg
c2matrix=1.8136873,-0.417894393,0.374689493,0,0,-0.362733056,-0.0860060676,1.72129904,-0.0694160492,0,0,-0.231379744,0.173499106,-0.19861703,1.69508299,0,0,-0.378856359,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Warning: may clip Red shadows
Warning: may clip Red highlights
Warning: may clip Green shadows
Warning: may clip Green highlights

We can put the matrix into an environment variable like this:

set mymatrix=
for /F "usebackq tokens=1,2 delims==" %%A in (`%IM7DEV%magick ^
  %imgA% ^
  %imgB% ^
  -precision 9 ^
  -process 'cols2mat noTrans f stdout' ^
  NULL:`) do (
  if "%%A"=="c2matrix" set mymatrix=%%B
)
if "%mymatrix%"=="" goto error

echo mymatrix=%mymatrix% 
mymatrix=1.8136873,-0.417894393,0.374689493,0,0,-0.362733056,-0.0860060676,1.72129904,-0.0694160492,0,0,-0.231379744,0.173499106,-0.19861703,1.69508299,0,0,-0.378856359,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1 

Extracting the polynomial

For example:

%IM7DEV%magick ^
  %imgA% ^
  %imgB% ^
  -precision 9 ^
  -process 'cols2mat method NoCrossPoly f stdout' ^
  c2mp_p1.png 
c2mp_p1.pngjpg
PolyRed=-2.10505152,4.19656686,-1.00894437
Warning: may clip Red shadows
Warning: may clip Red highlights
PolyGreen=-0.343882818,1.89691195,-0.305446549
Warning: may clip Green shadows
Warning: may clip Green highlights
PolyBlue=0.459346856,1.27933004,-0.298628025
Warning: may clip Blue shadows
Warning: may clip Blue highlights

We can put the polynomial coefficients into environment variables like this:

set mypolyr=
for /F "usebackq tokens=1,2 delims==" %%A in (`%IM7DEV%magick ^
  %imgA% ^
  %imgB% ^
  -precision 9 ^
  -process 'cols2mat method NoCrossPoly noTrans f stdout' ^
  NULL:`) do (
  if "%%A"=="PolyRed" set mypolyr=%%B
  if "%%A"=="PolyGreen" set mypolyg=%%B
  if "%%A"=="PolyBlue" set mypolyb=%%B
)
if "%mypolyr%"=="" goto error

echo mypolyr=%mypolyr% 
echo mypolyg=%mypolyg% 
echo mypolyb=%mypolyb% 
mypolyr=-2.10505152,4.19656686,-1.00894437 
mypolyg=-0.343882818,1.89691195,-0.305446549 
mypolyb=0.459346856,1.27933004,-0.298628025 

We can show the polynomials on a graph:

%IMG7%magick ^
  -size 1x256 gradient: -rotate 90 ^
  -channel R -function Polynomial %mypolyr% ^
  -channel G -function Polynomial %mypolyg% ^
  -channel B -function Polynomial %mypolyb% ^
  +channel ^
  c2mp_polygr.png

call %PICTBAT%graphLineCol ^
  c2mp_polygr.png . . 0
c2mp_polygr_glc.png

Testing the matrix

We test a round trip: now we know the matrix that most closely transforms imgA to imgB, we can apply the matrix to imgA and the result should be close to imgB.

%IMG7%magick ^
  %imgA% ^
  -color-matrix %mymatrix% ^
  %imgB% ^
  -metric RMSE ^
  -format %%[distortion] ^
  -compare ^
  info: 
0.0632554

We also test a case where the inputs are equal. This should create the identity matrix, which has one in the diagonal elements and zero elsewhere.

%IM7DEV%magick ^
  %imgA% ^
  ( +clone ) ^
  -process 'cols2mat noTrans f stdout' ^
  NULL: 
c2matrix=1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1

Another test, where each component is multiplied and added to:

%IM7DEV%magick ^
  %imgA% ^
  ( +clone -evaluate Multiply 0.95 -evaluate Add 10%% ) ^
  -process 'cols2mat noTrans f stdout' ^
  NULL: 
c2matrix=0.95,6.0394223e-13,2.6113502e-12,0,0,0.1,-5.4439919e-14,0.95,2.5774529e-12,0,0,0.1,1.1124435e-12,1.6980861e-13,0.95,0,0,0.1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Warning: may clip Red highlights
Warning: may clip Green highlights

Limited arithmetic precision has prevented the cross-channel multipliers from being exactly zero. "method NoCross" will calculate the solution with zeros in those positions.

%IM7DEV%magick ^
  %imgA% ^
  ( +clone -evaluate Multiply 0.95 -evaluate Add 10%% ) ^
  -process 'cols2mat method NoCross noTrans f stdout' ^
  NULL: 
c2matrix=0.95,0,0,0,0,0.1,0,0.95,0,0,0,0.1,0,0,0.95,0,0,0.1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Warning: may clip Red highlights
Warning: may clip Green highlights

For some cases, the module will not find a unique solution, usually because the problem is under-constrained (there are fewer simultaneous equations than unknowns). For example:

%IM7DEV%magick ^
  xc:Red ^
  xc:Blue ^
  -process 'cols2mat noTrans f stdout' ^
  NULL: 
cols2mat: no solution found

No output line starts with "c2matrix=". Scripts should check for this condition.

(In fact, two solutions are possible: the blue output is the red input multiplied by one, or the blue output is set to an offset of one. Each of these solutions has an infinite number of variations.)

What matrix will make a larger image entirely blue?

%IM7DEV%magick ^
  %imgA% ^
  ( +clone -fill Blue -colorize 100 ) ^
  -process 'cols2mat noTrans f stdout' ^
  NULL: 
c2matrix=0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1

A single solution is found: the blue output is set to an offset of one, with no channel multipliers.

Testing the polynomial

We test a round trip: now we know the polynomials that most closely transforms c2mp_ph1_mat.png to c2mp_ph4_mat.png, we can apply them to c2mp_ph1_mat.png and the result should be close to c2mp_ph4_mat.png.

%IMG7%magick ^
  %imgA% ^
  -channel R -function Polynomial %mypolyr% ^
  -channel G -function Polynomial %mypolyg% ^
  -channel B -function Polynomial %mypolyb% ^
  +channel ^
  %imgB% ^
  -metric RMSE ^
  -format %%[distortion] ^
  -compare ^
  info: 
0.0477719

We also test a case where the inputs are equal. This should create polynomials with one in the v1 elements and zero elsewhere.

%IM7DEV%magick ^
  %imgA% ^
  ( +clone ) ^
  -process 'cols2mat method NoCrossPoly d 1 noTrans f stdout' ^
  NULL: 
PolyRed=1,0
PolyGreen=1,0
PolyBlue=1,0
%IM7DEV%magick ^
  %imgA% ^
  ( +clone ) ^
  -process 'cols2mat method NoCrossPoly d 2 noTrans f stdout' ^
  NULL: 
PolyRed=1.110223e-16,1,5.5511151e-17
PolyGreen=0,1,0
PolyBlue=0,1,0
%IM7DEV%magick ^
  %imgA% ^
  ( +clone ) ^
  -process 'cols2mat method NoCrossPoly d 3 noTrans f stdout' ^
  NULL: 
PolyRed=-1.8605756e-15,3.3492796e-15,1,3.398451e-16
PolyGreen=0,0,1,0
PolyBlue=0,0,1,0

As before, a unique solution may not be found:

%IM7DEV%magick ^
  xc:Red ^
  xc:Blue ^
  -process 'cols2mat method NoCrossPoly noTrans f stdout' ^
  NULL: 
cols2mat: no solution found

No output line starts with "PolyRed=" etc. Scripts should check for this condition.

What polynomials will make a larger image entirely blue?

%IM7DEV%magick ^
  %imgA% ^
  ( +clone -fill Blue -colorize 100 ) ^
  -process 'cols2mat method NoCrossPoly noTrans f stdout' ^
  NULL: 
PolyRed=0,0,0
PolyGreen=0,0,0
PolyBlue=0,0,1

A single solution is found: the blue output is set to an offset of one, with no channel multipliers.

Weighting by alpha

The weightAlpha option calculates the solution of the simultaneous equations weighted by the product of the alphas of the input and output pixels. So if either pixel is entirely transparent, that pixel will be disregarded for the purpose of calculating the matrix or polynomial.

(Note that weightAlpha doesn't assume that pixel colours are calculated from alpha, nor that alpha is calculated. That would treat alpha like the colour channels, and I haven't included that in the module. I might in the future.)

toes_holed.png

toes_holed.png

Copy the hole to toes_x.jpg

%IMG7%magick ^
  toes_x.jpg ^
  toes_holed.png ^
  -compose CopyOpacity -composite ^
  -background Black -alpha Background ^
  toes_x_holed.png
toes_x_holed.png

What colour matrix makes the grass of toes.png look like the grass of toes_x_holed.png?

%IM7DEV%magick ^
  toes.png ^
  toes_x_holed.png ^
  -process 'cols2mat f stdout' ^
  c2mp_th1.png 
c2mp_th1.pngjpg
c2matrix=-0.62713194,1.9866906,-1.2680442,0,0,0.069961819,-1.4615194,2.9325759,-1.4897024,0,0,0.20511958,-0.65773008,1.1757757,-0.41449264,0,0,0.045947247,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Warning: may clip Red highlights
Warning: may clip Green highlights

Oops. Most of toes_x_holed.png is (transparent) black, so the matrix is heavily influenced by this. We can eliminate the transparent pixels from the calculation by using the weightAlpha option:

%IM7DEV%magick ^
  toes.png ^
  toes_x_holed.png ^
  -process 'cols2mat weightAlpha f stdout' ^
  c2mp_th2.png 
c2mp_th2.pngjpg
c2matrix=2.4829447,-0.13992561,0.063649543,0,0,-0.67242755,-0.12718404,1.6265641,0.10697504,0,0,-0.23135687,0.067065836,0.16431625,1.5729776,0,0,-0.46285413,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1
Warning: may clip Red shadows
Warning: may clip Red highlights
Warning: may clip Green shadows
Warning: may clip Green highlights

Even when both inputs are in the range 0 to 100%, the transformed output can be outside that range. If the image is saved to an integer format, values will be automatically clamped (aka clipped). If HDRI is used, pixels can be brought within gamut by "-clamp" or "-auto-level".

set FMT=^
red: %%[fx:minima.r] to %%[fx:maxima.r]\n^
green: %%[fx:minima.g] to %%[fx:maxima.g]\n^
blue: %%[fx:minima.b] to %%[fx:maxima.b]\n

%IM7DEV%magick ^
  toes.png ^
  toes_x_holed.png ^
  -process 'cols2mat weightAlpha' ^
  -format "%FMT%" ^
  +write info: ^
  c2mp_th3.png 
red: -0.46074721 to 1.7434018
green: -0.14116973 to 1.2328533
blue: -0.42654275 to 1.2380592
c2mp_th3.pngjpg
%IM7DEV%magick ^
  toes.png ^
  toes_x_holed.png ^
  -process 'cols2mat weightAlpha' ^
  -auto-level ^
  -format "%FMT%" ^
  +write info: ^
  c2mp_th4.png 
red: 0 to 1
green: 0.14498906 to 0.76836933
blue: 0.015518218 to 0.77073119
c2mp_th4.pngjpg

As in the Wolf reference, the module could be run for a pair of opaque inputs, then the difference between the output and second input is negated and used as the opacity for the first input of a re-run, and iterate until stability is reached. Thus outliers would count less towards a solution.

Future

Polynomials with cross-channel terms could be created, eg:

R' = R2*d + G2*e + B2*f + R*G*g + G*B*h + B*R*i + R*a + G*b + B*c + j

IM has no built-in operator to process these, so that would also need to be written.

We could "regard alpha". This could calculate and use alpha in the same way as the colour channels.

We might have an option to save the colour matrix as a 6x6 image. Then another module can apply it to images. And another can do maths: concatenation.

Option to add zero and 100% for matrix calculation?

Can we use the Jump method to determine the best degree for polynomials?


All images on this page were created by the commands shown, using:

%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenCL 
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193231332)
%IM7DEV%magick -version
Version: ImageMagick 7.1.0-20 Q32-HDRI x86_64 2021-12-29 https://imagemagick.org
Copyright: (C) 1999-2021 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules OpenMP(4.5) 
Delegates (built-in): bzlib cairo fontconfig fpx freetype jbig jng jpeg lcms ltdl lzma pangocairo png raqm rsvg tiff webp wmf x xml zip zlib
Compiler: gcc (11.2)

Source file for this web page is col2mp.h1. To re-create this web page, execute "procH1 col2mp".


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.1 9-Nov-2017.

Page created 04-Aug-2022 17:46:32.

Copyright © 2022 Alan Gibson.