Display as HSB
DigitalMicrograph Script
Display complex image as color encoded HSB image (phase = color, modulus = brightness).
Preview
/////////////////////////////////////////////////////////////////////
// (c) Gatan Inc.
/////////////////////////////////////////////////////////////////////
// This script displays a complex image encoded as colour-image, using
// HUE values for the phase and BRIGHTNESS for the modulus value.
// The script is split into multiple methods which may be installed as
// a library for use elsewhere
// There are methods for single number conversion and equivalent methods
// using images as parameters.
//
// RGB -> HSL algorithm by:
// "Fundamentals of Interactive Computer Graphics"
// by Foley and van Dam (c 1982, Addison-Wesley). Chapter 17
/////////////////////////////////////////////////////////////////////
// last modified 31-July-2015 BS
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Methods to convert RGB values into HSL values */
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
void RGB2HSL(number R, number G, number B, number &H, number &S, number &L)
{
H = 0; S = 0; L = 0;
// STEP 1: Convert the RGB values to the range 0-1
// RGB images are 0.255 integer. Convert to 0..1 float,
R = R/255; ; G = G/255; B = B/255;
if ((r<0)||(r>1)) Throw("Error in RGB->HSL")
if ((g<0)||(g>1)) Throw("Error in RGB->HSL")
if ((b<0)||(b>1)) Throw("Error in RGB->HSL")
// STEP 2: Find min and max values of R, B, G
number minCol = minimum(R,G,B)
number maxCol = maximum(R,G,B)
if (minCol>maxCol) Throw("Error in RGB->HSL")
// STEP 3: L=(minCol+maxCol)/2
L = (minCol+maxCol)/2
// STEP 4a: Calculate S
// L< 0.5 ==> S=maxCol-minCol)/(maxCol+minCol)
// L>=0.5 ==> S=maxCol-minCol)/(2-maxCol-minCol)
if (L<0.5) S=(maxCol-minCol)/(maxCol+minCol)
else S=(maxCol-minCol)/(2-maxCol-minCol)
// STEP 4b: Test for gray-value (S=0). This is the case for minCol=maxCol. Set H=0 as well (is undefined)
if (minCol==maxCol) S=0
// STEP 5: Calculate H based on which color is maxCol
// If R=maxcolor, H = (G-B)/(maxcolor-mincolor)
// If G=maxcolor, H = 2.0 + (B-R)/(maxcolor-mincolor)
// If B=maxcolor, H = 4.0 + (R-G)/(maxcolor-mincolor)
if (R==maxCol) H= (G-B)/(maxCol-minCol)
else if (G==maxCol) H= 2 + (B-R)/(maxCol-minCol)
else if (B==maxCol) H= 4 + (R-G)/(maxCol-minCol)
if (minCol==maxCol) H= 0
if (H<0) H+=6
if (H>6) H-=6
H = H/6
// Rescale to the 0..255 range
L=L*255; S=S*255; H=H*255;
H=round(H); S=round(S); L=round(L);
if ((H<0||H>255)) Throw("Error in RGB->HSL")
if ((S<0||S>255)) Throw("Error in RGB->HSL")
if ((L<0||L>255)) Throw("Error in RGB->HSL")
}
rgbNumber RGB2HSL(rgbnumber RGBnum)
{
number r=red(RGBnum)
number g=green(RGBnum)
number b=blue(RGBnum)
number h,s,l
RGB2HSL(r,g,b,h,s,l)
return rgb(h,s,l)
}
void RGB2HSL(image R, image G, image B, image &H, image &S, image &L)
{
R.ConvertToFloat()
G.ConvertToFloat()
B.ConvertToFloat()
H = r*0; S = r*0; L = r*0
// STEP 1: Convert the RGB values to the range 0-1
// RGB images are 0.255 integer. Convert to 0..1 float,
R = R/255; ; G = G/255; B = B/255;
if (sum(tert(r<0||r>1,1,0))!=0) Throw("Error in RGB->HSL")
if (sum(tert(g<0||g>1,1,0))!=0) Throw("Error in RGB->HSL")
if (sum(tert(b<0||b>1,1,0))!=0) Throw("Error in RGB->HSL")
// STEP 2: Find min and max values of R, B, G
image minCol = minimum(R,G,B)
image maxCol = maximum(R,G,B)
if (sum(tert(minCol>maxCol,1,0))!=0) Throw("Error in RGB->HSL")
// STEP 3: L=(minCol+maxCol)/2
L = (minCol+maxCol)/2
// STEP 4a: Calculate S
// L< 0.5 ==> S=maxCol-minCol)/(maxCol+minCol)
// L>=0.5 ==> S=maxCol-minCol)/(2-maxCol-minCol)
S = tert(L<0.5,(maxCol-minCol)/(maxCol+minCol),(maxCol-minCol)/(2-maxCol-minCol))
// STEP 4b: Test for gray-value (S=0). This is the case for minCol=maxCol. Set H=0 as well (is undefined)
S = tert(minCol==maxCol,0,S)
// STEP 5: Calculate H based on which color is maxCol
// If R=maxcolor, H = (G-B)/(maxcolor-mincolor)
// If G=maxcolor, H = 2.0 + (B-R)/(maxcolor-mincolor)
// If B=maxcolor, H = 4.0 + (R-G)/(maxcolor-mincolor)
h=0
H = tert(R==maxCol, (G-B)/(maxCol-minCol),H)
H = tert(G==maxCol,2 + (B-R)/(maxCol-minCol),H)
H = tert(B==maxCol,4 + (R-G)/(maxCol-minCol),H)
H = tert(minCol==maxCol,0,H)
H=tert(H<0,H+6,tert(H>6,H-6,H) )
H = H/6
// Rescale to the 0..255 range
L=L*255; S=S*255; H=H*255;
H=round(H); S=round(S); L=round(L);
H.SetName("H");S.SetName("S");L.SetName("L");
if (sum(tert(H<0||H>255,1,0)!=0)) Throw("Error in RGB->HSL")
if (sum(tert(S<0||S>255,1,0)!=0)) Throw("Error in RGB->HSL")
if (sum(tert(L<0||L>255,1,0)!=0)) Throw("Error in RGB->HSL")
}
RGBimage RGB2HSL(rgbimage RGBin)
{
image R = RGBin.red()
image G = RGBin.green()
image B = RGBin.blue()
image H=r*0;
image S=r*0;
image L=r*0;
RGB2HSL(R,G,B,H,S,L)
return rgb(H,S,L)
}
RGBimage RGB2HSL(image Rin, image Gin, image Bin)
{
return RGB2HSL(RGB(Rin,Gin,Bin))
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Methods to convert HSL values into RGB values */
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
void HSL2RGB(number H, number S, number L, number &R, number &G, number &B)
{
R = 0; G = 0; B = 0;
// STEP 1: Convert the input values to the range 0-1
// RGB images are 0.255 integer. Convert to 0..1 float,
H = H/255; ; S = S/255; L = L/255;
// Step 2: Test L and compute temp. values
// If L < 0.5, temp2=L*(1.0+S)
// If L >= 0.5, temp2=L+S - L*S
number temp2
if (L<0.5) temp2 = L*(1+S)
else temp2 = L+S-L*S
number temp1 = 2.0*L - temp2
// Step 3: compute R
number temp3=H+1/3
if (temp3>1) temp3-=1;
if (temp3<0) temp3+=1;
if (6.0*temp3 < 1 ) R = temp1+(temp2-temp1)*6.0*temp3
else if (2.0*temp3 < 1 ) R = temp2
else if (3.0*temp3 < 2 ) R = temp1+(temp2-temp1)*(2/3-temp3)*6.0
else R = temp1
// Step 4: compute G
temp3=H
if (temp3>1) temp3-=1;
if (temp3<0) temp3+=1;
if (6.0*temp3 < 1 ) G = temp1+(temp2-temp1)*6.0*temp3
else if (2.0*temp3 < 1 ) G = temp2
else if (3.0*temp3 < 2 ) G = temp1+(temp2-temp1)*(2/3-temp3)*6.0
else G = temp1
// Step 5: compute B
temp3=H-1/3
if (temp3>1) temp3-=1;
if (temp3<0) temp3+=1;
if (6.0*temp3 < 1 ) B = temp1+(temp2-temp1)*6.0*temp3
else if (2.0*temp3 < 1 ) B = temp2
else if (3.0*temp3 < 2 ) B = temp1+(temp2-temp1)*(2/3-temp3)*6.0
else B = temp1
// Step 6: if S=0 (gray) all R,G,B = L
if (S==0)
{
R=L;
G=L;
B=L;
}
// Scale back to 0..255
R=R*255; G=G*255; B=B*255;
R=round(R); G=round(G); B=round(B);
if ((R<0||R>255)) Throw("Error in HSL->RGB")
if ((G<0||G>255)) Throw("Error in HSL->RGB")
if ((B<0||B>255)) Throw("Error in HSL->RGB")
}
rgbNumber HSL2RGB(rgbNumber HSLnum)
{
number h=red(HSLnum)
number s=green(HSLnum)
number l=blue(HSLnum)
number r,g,b
HSL2RGB(h,s,l,r,g,b)
return rgb(r,g,b)
}
void HSL2RGB(image H, image S, image L,image &R, image &G, image &B)
{
H.ConvertToFloat()
S.ConvertToFloat()
L.ConvertToFloat()
R = H*0; G = H*0; B = H*0;
// STEP 1: Convert the input values to the range 0-1
// RGB images are 0.255 integer. Convert to 0..1 float,
H = H/255; ; S = S/255; L = L/255;
// Step 2: Test L and compute temp. values
// If L < 0.5, temp2=L*(1.0+S)
// If L >= 0.5, temp2=L+S - L*S
image temp2 = tert(L<0.5,L*(1+S),L+S-L*S)
image temp1 = 2.0*L - temp2
// Step 3: compute R
image temp3=H+1/3
temp3=tert(temp3>1,temp3-1,tert(temp3<0,temp3+1,temp3))
image Ch1 = temp1+(temp2-temp1)*6.0*temp3
image Ch2 = temp2
image Ch3 = temp1+(temp2-temp1)*(2/3-temp3)*6.0
image Ch4 = temp1
R = tert( 6.0*temp3 < 1 , Ch1, \
tert( 2.0*temp3 < 1 , Ch2, \
tert( 3.0*temp3 < 2 , Ch3, \
Ch4 )))
// Step 4: compute G
temp3=H
temp3=tert(temp3>1,temp3-1,tert(temp3<0,temp3+1,temp3))
Ch1 = temp1+(temp2-temp1)*6.0*temp3
Ch2 = temp2
Ch3 = temp1+(temp2-temp1)*((2.0/3.0)-temp3)*6.0
Ch4 = temp1
G = tert( 6.0*temp3 < 1 , Ch1, \
tert( 2.0*temp3 < 1 , Ch2, \
tert( 3.0*temp3 < 2 , Ch3, \
Ch4 )))
// Step 5: compute B
temp3=H-1/3
temp3=tert(temp3>1,temp3-1,tert(temp3<0,temp3+1,temp3))
Ch1 = temp1+(temp2-temp1)*6.0*temp3
Ch2 = temp2
Ch3 = temp1+(temp2-temp1)*((2.0/3.0)-temp3)*6.0
Ch4 = temp1
B = tert( 6.0*temp3 < 1 , Ch1, \
tert( 2.0*temp3 < 1 , Ch2, \
tert( 3.0*temp3 < 2 , Ch3, \
Ch4 )))
// Step 6: if S=0 (gray) all R,G,B = L
image bGray = tert(S==0,1,0)
R = L*bGray+R*!bGray
G = L*bGray+G*!bGray
B = L*bGray+B*!bGray
// Scale back to 0..255
R=R*255; G=G*255; B=B*255;
R=round(R); G=round(G); B=round(B);
R.SetName("R");G.SetName("G");B.SetName("B");
if (sum(tert(R<0||R>255,1,0)!=0)) Throw("Error in HSL->RGB")
if (sum(tert(G<0||G>255,1,0)!=0)) Throw("Error in HSL->RGB")
if (sum(tert(B<0||B>255,1,0)!=0)) Throw("Error in HSL->RGB")
}
RGBimage HSL2RGB(rgbimage HSLin)
{
image H = HSLin.red()
image S = HSLin.green()
image L = HSLin.blue()
image R=H*0;
image G=H*0;
image B=H*0;
HSL2RGB(H,S,L,R,G,B)
return RGB(R,G,B)
}
RGBimage HSL2RGB(image Hin, image Sin, image Lin)
{
return HSL2RGB(RGB(Hin,Sin,Lin))
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Methods to create RGB color images out of complex images, */
/* using phase & modulus represented as HUE and BRIGHTNESS */
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
RGBimage ComplexAsHSL(compleximage in,number Rmin, number Rmax, number Pmin, number Pmax, number HUEstart)
{
realimage PhiImg = phase(in) // this returns [-Pi , Pi]
realimage Rimg = modulus(in)
realimage sat=Rimg*0+1
// Do a mapping of regions. Only represent R map [Rmin,Rmax] = [0,1]
// result("\n map ["+min( Rimg)+","+max( Rimg)+"] to ["+rMin+","+rMax+"]")
RImg = tert(RImg<rMin,rMin,RImg)
RImg = tert(RImg>rMax,rMax,RImg)
RImg-=rMin;
RImg*=1/(rMax-rMin)
// Do a mapping of regions. Only represent Phi map [Phimin,Phimax] = [0,1]
// result("\n map ["+min(PhiImg)+","+max(PhiImg)+"] to ["+pMin+","+pMax+"]")
PhiImg = tert(PhiImg<pMin,pMin,PhiImg)
PhiImg = tert(PhiImg>pMax,pMax,PhiImg)
PhiImg-=pMin;
PhiImg*=1/(pMax-pMin)
PhiImg+=HUEstart
While (sum(tert(PhiImg>1,1,0))>0) PhiImg-=tert(PhiImg>1,1,0)
While (sum(tert(PhiImg<0,1,0))>0) PhiImg+=tert(PhiImg<0,1,0)
Rimg*=255; PhiImg*=255; sat=255;
return HSL2RGB(RGB(PhiImg,sat,Rimg))
}
RGBimage ComplexAsHSL(compleximage in, number HUEstart)
{
realimage PhiImg = phase(in)
realimage Rimg = modulus(in)
return ComplexAsHSL(in,min(Rimg),max(Rimg),min(PhiImg),max(PhiImg),HUEstart)
}
RGBimage ComplexAsHSL(compleximage in)
{
realimage PhiImg = phase(in)
realimage Rimg = modulus(in)
return ComplexAsHSL(in,min(Rimg),max(Rimg),min(PhiImg),max(PhiImg),0)
}
RGBimage ComplexAsHSL(compleximage in, number Pmin, number Pmax, number HUEstart)
{
realimage PhiImg = phase(in) // this returns [-Pi , Pi]
realimage Rimg = modulus(in)
return ComplexAsHSL(in,min(Rimg),max(Rimg),pMin,pMax,HUEstart)
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Methods to create a scaled RGB color images out of complex images including a color legend. */
/* using phase & modulus represented as HUE and BRIGHTNESS */
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
Component ComplexAsHSLlegend(number SHOW, number sx, number sy, number Rmin, number Rmax, number Pmin, number Pmax, number HUEstart)
{
imagedocument imgDoc
imgDoc=NewImageDocument("Legend")
image Pimg,Rimg
Rimg:=RealImage("R",4,sx,sy) = icol/sx*(Rmax-Rmin)+Rmin
Pimg:=RealImage("P",4,sx,sy) = irow/sy*(2*Pi())-Pi()
compleximage c
c=complex(Rimg,Pimg).rect()
RGBimage legend = ComplexAsHSL(c,Rmin,Rmax,Pmin,Pmax,HUEstart)
Component doc = imgDoc.ImageDocumentAddImageDisplay(legend,4)
number size=sy/15
string str
str=" -Pi -"
component Comp
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(0,0,1.0,0.5,1,1)
str=" +Pi -"
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(0,sy,1.0,0.5,1,1)
str="|"
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(0,sy,0.5,0,1,1)
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(0,sy,0.5,-1,1,1)
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(sx,sy,0.5,0,1,1)
str=""+rmin
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(0,sy,0.5,-2,1,1)
str=""+rmax
Comp=NewTextAnnotation(0,0,str,size)
doc.ComponentAddChildAtBeginning(comp)
Comp.ComponentPositionAroundPoint(sx,sy,0.5,-1,1,1)
if (show) imgDoc.ImageDocumentClone(1).ImageDocumentShow()
component outComp=imgDoc.ImageDocumentGetRootComponent().ComponentGetChild(0)
return outComp
}
imagedocument ComplexAsHSLwithLegend(compleximage in, number HUEstart)
{
realimage PhiImg = phase(in)
realimage Rimg = modulus(in)
number sx,sy
number lx=50
number ly=200
in.getsize(sx,sy)
RGBimage out = ComplexAsHSL(in,min(Rimg),max(Rimg),min(PhiImg),max(PhiImg),HUEstart)
imagedocument iDoc=NewImageDocument("")
Component comp = iDoc.ImageDocumentAddImageDisplay(out,4)
Component legComp = ComplexAsHSLlegend(0,lx,ly,min(Rimg),max(Rimg),min(PhiImg),max(PhiImg),HUEstart)
comp.ComponentAddChildAtEnd(legComp)
ImageDocument finalDoc = idoc.ImageDocumentClone(1)
comp = finalDoc.ImageDocumentGetRootComponent().ComponentGetChild(0).ComponentGetChild(0)
number rat=min(sx/lx,sy/ly)*0.75
comp.ComponentTransformCoordinates(sx*1.2,sy*0.1,rat,rat)
return finalDoc
}
imagedocument ComplexAsHSLwithLegend(compleximage in, number Pmin, number Pmax, number HUEstart)
{
realimage PhiImg = phase(in)
realimage Rimg = modulus(in)
number sx,sy
number lx=50
number ly=200
in.getsize(sx,sy)
RGBimage out = ComplexAsHSL(in,min(Rimg),max(Rimg),pMin,pMax,HUEstart)
imagedocument iDoc=NewImageDocument("")
Component comp = iDoc.ImageDocumentAddImageDisplay(out,4)
Component legComp = ComplexAsHSLlegend(0,lx,ly,min(Rimg),max(Rimg),pMin,pMax,HUEstart)
comp.ComponentAddChildAtEnd(legComp)
ImageDocument finalDoc = idoc.ImageDocumentClone(1)
comp = finalDoc.ImageDocumentGetRootComponent().ComponentGetChild(0).ComponentGetChild(0)
number rat=min(sx/lx,sy/ly)*0.75
comp.ComponentTransformCoordinates(sx*1.2,sy*0.1,rat,rat)
return finalDoc
}
imagedocument ComplexAsHSLwithLegend(compleximage in,number Rmin, number Rmax, number Pmin, number Pmax, number HUEstart)
{
realimage PhiImg = phase(in) // this returns [-Pi , Pi]
realimage Rimg = modulus(in)
realimage sat=Rimg*0+1
number sx,sy
number lx=50
number ly=200
in.getsize(sx,sy)
// Do a mapping of regions. Only represent R map [Rmin,Rmax] = [0,1]
// result("\n map ["+min( Rimg)+","+max( Rimg)+"]to ["+rMin+","+rMax+"]")
RImg = tert(RImg<rMin,rMin,RImg)
RImg = tert(RImg>rMax,rMax,RImg)
RImg-=rMin;
RImg*=1/(rMax-rMin)
// Do a mapping of regions. Only represent Phi map [Phimin,Phimax] = [0,1]
//result("\n map ["+min(PhiImg)+","+max(PhiImg)+"]to ["+pMin+","+pMax+"]")
PhiImg = tert(PhiImg<pMin,pMin,PhiImg)
PhiImg = tert(PhiImg>pMax,pMax,PhiImg)
PhiImg-=pMin;
PhiImg*=1/(pMax-pMin)
PhiImg+=HUEstart
While (sum(tert(PhiImg>1,1,0))>0) PhiImg-=tert(PhiImg>1,1,0)
While (sum(tert(PhiImg<0,1,0))>0) PhiImg+=tert(PhiImg<0,1,0)
Rimg*=255; PhiImg*=255; sat=255;
image out= HSL2RGB(RGB(PhiImg,sat,Rimg))
imagedocument iDoc=NewImageDocument("")
Component comp = iDoc.ImageDocumentAddImageDisplay(out,4)
Component legComp = ComplexAsHSLlegend(0,lx,ly,rMin,Rmax,pMin,pMax,HUEstart)
comp.ComponentAddChildAtEnd(legComp)
ImageDocument finalDoc = idoc.ImageDocumentClone(1)
finalDoc.ImageDocumentSetName( "Complex color coded with legend, Phase = HUE, Mod = brightness" )
comp = finalDoc.ImageDocumentGetRootComponent().ComponentGetChild(0).ComponentGetChild(0)
number rat=min(sx/lx,sy/ly)*0.75
comp.ComponentTransformCoordinates(sx*1.2,sy*0.1,rat,rat)
return finalDoc
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/* Application test methods */
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
Void TestComplexImageAsHUE()
{
Image P:=RealImage("Phase",4,512,512)=sin((irow+iradius)/500*Pi())
Image M:=RealImage("Modulus",4,512,512)=iradius+icol
ComplexImage C = Complex(M,P).rect()
RGBImage HUEImg := ComplexAsHSL(c,0)
HUEImg.SetName( "Complex colorcoded, Phase = HUE, Mod = brightness" )
C.SetName( "Complex" )
P.SetName( "Phase")
M.SetName( "Mod")
HUEImg.ShowImage()
C.ShowImage()
ImageDocument HUEImgWithLegend =ComplexAsHSLwithLegend( C, 100, 500, 0, PI(), 0 )
HUEImgWithLegend.ImageDocumentShow()
}
TestComplexImageAsHUE()