
GUI for setting image scale using cursors

tony
Mon, 10/26/2020 - 11:28 am
Often I want to quickly plot my data over an image of a plot from some reference source. Various packages already exist that have some kind interface for setting the dimension scaling of a graph image so that the image plot axes are registered with the graph window axes. This is a stand-alone piece of code to make it easy to set the image scaling interactively, by positioning cursors and typing in the desired values for the cursor positions.
How to use it:
- Use the "Load, Display and Scale Image..." menu item to load an image file, or
- Load an image of a graph (with linear axes) into Igor
- Display the image using Windows > New > Image Plot...
- Right click on image in plot and select "Set Image Scale"
- Position a pair of cursors at high and low values for each axis and type desired cursor values into the corresponding SetVariable controls
- Right click and select "Done with Set Image Scale" to finish
#pragma rtGlobals=3
#pragma ModuleName=ImageScaleGUI
#pragma version=1.2
// GUI for setting image scaling using cursors
// how to use:
// create a new image plot
// right click and select 'Set Image Scale'
// position cursors and enter desired values for cursor positions
// right click and select 'Done with Set Image Scale'
menu "TracePopup", dynamic
ImageScaleGUI#ImageTraceMenu(), /Q, ImageScaleGUI#ScaleImageInGraph()
end
menu "Load Waves"
"Load, Display and Scale Image...", /Q, ImageScaleGUI#LoadAndScaleImage()
end
static function LoadAndScaleImage()
ImageLoad
if(v_flag==0)
return 0
endif
Display
AppendImage $S_fileName
SetAxis/A/R left
ScaleImageInGraph()
end
static function /T ImageTraceMenu()
if (WinType("")!=1)
return "" // don't do anything if Igor is just rebuilding the menu
endif
ControlInfo SetVarA
if(v_flag!=0)
return "Done with Set Image Scale"
endif
// figure out graph and trace names
GetLastUserMenuInfo
return SelectString(strlen(ImageNameList(s_graphname, ";")) > 0, "", "Set Image Scale")
end
static function ScaleImageInGraph()
ControlInfo SetVarA
if(v_flag!=0) // SetVar exists, clean up
SetWindow kwTopWin hook(setscaleGUI)=$""
KillControl SetVarA; KillControl SetVarB; KillControl SetVarC; KillControl SetVarD
Cursor /K A; Cursor /K B; Cursor /K C; Cursor /K D
return 1
endif
string strImage=StringFromList(0, ImageNameList("", ";"))
wave wImage=ImageNameToWaveRef("", strImage)
variable hSize=DimSize(wImage, 0), vSize=DimSize(wImage,1)
// vertical hairs for X cursors
Cursor /N=1/S=2/I/H=2/C=(65535,0,0)/p A $strImage 0.1*hSize, 0.2*vSize
Cursor /N=1/S=2/I/H=2/C=(65535,0,0)/p B $strImage 0.9*hSize, 0.2*vSize
// horizontal hairs for Y cursors
Cursor /N=1/S=2/I/H=3/C=(0,65535,0)/p C $strImage 0.2*hSize, 0.9*vSize
Cursor /N=1/S=2/I/H=3/C=(0,65535,0)/p D $strImage 0.2*hSize, 0.1*vSize
string info=ImageInfo("", strImage, 0)
string strXaxis=StringByKey("XAXIS",info)
string strYaxis=StringByKey("YAXIS",info)
STRUCT Point pt
Make /free/T csr={"A","B","C","D"}
int i
for(i=0;i<4;i+=1)
SetVariable $"SetVar"+csr[i] title="", value=_NUM: i<2 ? xcsr($csr[i]) : vcsr($csr[i])
SetVariable $"SetVar"+csr[i] limits={-Inf,Inf,0}, size={40,10}, fsize=14, Proc=ImageScaleGUI#Rescale
SetVariable $"SetVar"+csr[i] valueColor=(65535*(i<2),65535*(i>1),0)
endfor
SetWindow kwTopWin hook(setscaleGUI)=ImageScaleGUI#ImgHook, hookevents=4
// enter ImgHook function with resize event to reposition setvars
STRUCT WMWinHookStruct s
s.eventcode=6
ImgHook(s)
end
static function ImgHook(STRUCT WMWinHookStruct &s)
string info, strXaxis, strYaxis
switch (s.eventcode)
case 6:
case 7:
case 8:
info=ImageInfo("", s.traceName, 0)
strXaxis=StringByKey("XAXIS",info)
strYaxis=StringByKey("YAXIS",info)
if(s.eventcode==7) // cursormoved
if(GrepString(s.cursorName,"[A-D]")==0)
return 0
endif
// keep axis coordinates within bounds of axes
variable ptX, ptY
GetAxis /Q $strXaxis
ptX=max(xcsr($s.cursorName), min(V_Min,V_Max))
ptX=min(ptX, max(V_Min,V_Max))
GetAxis /Q $strYaxis
ptY=max(vcsr($s.cursorName), min(V_Min,V_Max))
ptY=min(ptY, max(V_Min,V_Max))
STRUCT Point pt
pt.h=PixelFromAxisVal("", strXaxis, ptX)
pt.v=PixelFromAxisVal("", strYaxis, ptY)
variable val=GrepString(s.cursorName,"[AB]") ? xcsr($s.cursorName) : vcsr($s.cursorName)
SetVariable $"SetVar"+s.cursorName value=_NUM:val, pos={pt.h-20,pt.v-10}, disable=0
break
endif
// reposition or disable setvars when window is resized
s.eventCode=7 // prepare to reenter this function with cursormoved eventcode
Make /free/T csr={"A","B","C","D"}
int i
for(i=0;i<4;i+=1)
s.cursorName=csr[i]
variable csrpos = i>1 ? vcsr($s.cursorName) : xcsr($s.cursorName)
GetAxis /Q $SelectString(i>1, strXaxis, strYaxis)
if(csrpos>min(v_max,v_min) && csrpos<max(v_max,v_min))
ImgHook(s)
else
SetVariable $"setvar"+(s.cursorName) disable=1
endif
endfor
endswitch
return 0
end
static function Rescale(STRUCT WMSetVariableAction &s)
if(s.eventCode!=8)
return 0
endif
string strImage=StringFromList(0, ImageNameList("", ";"))
wave wImage=ImageNameToWaveRef("", strImage)
int isX = GrepString((s.ctrlName), "[AB]"), autoscale=1
string strAxis, info, flags
info=ImageInfo("", strImage, 0)
strAxis=StringByKey(SelectString(isX, "YAXIS", "XAXIS"),info)
info=AxisInfo("", strAxis)
flags=StringByKey("SETAXISFLAGS", info)
variable indexMin, indexMax
if(GrepString(flags, "/")==0)
GetAxis /Q $strAxis
indexMin=scaleToIndex(wImage, V_min, 1-isX)
indexMax=scaleToIndex(wImage, V_max, 1-isX)
autoscale=0
endif
variable ValAC, ValBD, delta, offset, oldDelta
ControlInfo $SelectString(isX, "SetVarC", "SetVarA")
ValAC=V_Value
ControlInfo $SelectString(isX, "SetVarD", "SetVarB")
ValBD=V_Value
delta = isX ? (ValBD-ValAC)/(pcsr(B)-pcsr(A)) : (ValBD-ValAC)/(qcsr(D)-qcsr(C))
offset = isX ? ValAC - delta*pcsr(A) : ValAC - delta*qcsr(C)
oldDelta = DimDelta(wImage, 1-isX)
if(isX)
SetScale /P x, offset, delta , wImage
else
SetScale /P y, offset, delta , wImage
endif
if(autoscale==0)
v_min=IndexToScale(wImage, indexMin, 1-isX)
v_max=IndexToScale(wImage, indexMax, 1-isX)
if(v_min>v_max)
SetAxis /R $strAxis v_min, v_max
else
SetAxis $strAxis v_min, v_max
endif
endif
if(sign(oldDelta)!=sign(delta))
// switch the axis limits so that image is not flipped
if(GrepString(flags, "/R"))
SetAxis /A $strAxis
elseif(GrepString(flags, "/A"))
SetAxis /A/R $strAxis
endif
endif
return 0
end
#pragma ModuleName=ImageScaleGUI
#pragma version=1.2
// GUI for setting image scaling using cursors
// how to use:
// create a new image plot
// right click and select 'Set Image Scale'
// position cursors and enter desired values for cursor positions
// right click and select 'Done with Set Image Scale'
menu "TracePopup", dynamic
ImageScaleGUI#ImageTraceMenu(), /Q, ImageScaleGUI#ScaleImageInGraph()
end
menu "Load Waves"
"Load, Display and Scale Image...", /Q, ImageScaleGUI#LoadAndScaleImage()
end
static function LoadAndScaleImage()
ImageLoad
if(v_flag==0)
return 0
endif
Display
AppendImage $S_fileName
SetAxis/A/R left
ScaleImageInGraph()
end
static function /T ImageTraceMenu()
if (WinType("")!=1)
return "" // don't do anything if Igor is just rebuilding the menu
endif
ControlInfo SetVarA
if(v_flag!=0)
return "Done with Set Image Scale"
endif
// figure out graph and trace names
GetLastUserMenuInfo
return SelectString(strlen(ImageNameList(s_graphname, ";")) > 0, "", "Set Image Scale")
end
static function ScaleImageInGraph()
ControlInfo SetVarA
if(v_flag!=0) // SetVar exists, clean up
SetWindow kwTopWin hook(setscaleGUI)=$""
KillControl SetVarA; KillControl SetVarB; KillControl SetVarC; KillControl SetVarD
Cursor /K A; Cursor /K B; Cursor /K C; Cursor /K D
return 1
endif
string strImage=StringFromList(0, ImageNameList("", ";"))
wave wImage=ImageNameToWaveRef("", strImage)
variable hSize=DimSize(wImage, 0), vSize=DimSize(wImage,1)
// vertical hairs for X cursors
Cursor /N=1/S=2/I/H=2/C=(65535,0,0)/p A $strImage 0.1*hSize, 0.2*vSize
Cursor /N=1/S=2/I/H=2/C=(65535,0,0)/p B $strImage 0.9*hSize, 0.2*vSize
// horizontal hairs for Y cursors
Cursor /N=1/S=2/I/H=3/C=(0,65535,0)/p C $strImage 0.2*hSize, 0.9*vSize
Cursor /N=1/S=2/I/H=3/C=(0,65535,0)/p D $strImage 0.2*hSize, 0.1*vSize
string info=ImageInfo("", strImage, 0)
string strXaxis=StringByKey("XAXIS",info)
string strYaxis=StringByKey("YAXIS",info)
STRUCT Point pt
Make /free/T csr={"A","B","C","D"}
int i
for(i=0;i<4;i+=1)
SetVariable $"SetVar"+csr[i] title="", value=_NUM: i<2 ? xcsr($csr[i]) : vcsr($csr[i])
SetVariable $"SetVar"+csr[i] limits={-Inf,Inf,0}, size={40,10}, fsize=14, Proc=ImageScaleGUI#Rescale
SetVariable $"SetVar"+csr[i] valueColor=(65535*(i<2),65535*(i>1),0)
endfor
SetWindow kwTopWin hook(setscaleGUI)=ImageScaleGUI#ImgHook, hookevents=4
// enter ImgHook function with resize event to reposition setvars
STRUCT WMWinHookStruct s
s.eventcode=6
ImgHook(s)
end
static function ImgHook(STRUCT WMWinHookStruct &s)
string info, strXaxis, strYaxis
switch (s.eventcode)
case 6:
case 7:
case 8:
info=ImageInfo("", s.traceName, 0)
strXaxis=StringByKey("XAXIS",info)
strYaxis=StringByKey("YAXIS",info)
if(s.eventcode==7) // cursormoved
if(GrepString(s.cursorName,"[A-D]")==0)
return 0
endif
// keep axis coordinates within bounds of axes
variable ptX, ptY
GetAxis /Q $strXaxis
ptX=max(xcsr($s.cursorName), min(V_Min,V_Max))
ptX=min(ptX, max(V_Min,V_Max))
GetAxis /Q $strYaxis
ptY=max(vcsr($s.cursorName), min(V_Min,V_Max))
ptY=min(ptY, max(V_Min,V_Max))
STRUCT Point pt
pt.h=PixelFromAxisVal("", strXaxis, ptX)
pt.v=PixelFromAxisVal("", strYaxis, ptY)
variable val=GrepString(s.cursorName,"[AB]") ? xcsr($s.cursorName) : vcsr($s.cursorName)
SetVariable $"SetVar"+s.cursorName value=_NUM:val, pos={pt.h-20,pt.v-10}, disable=0
break
endif
// reposition or disable setvars when window is resized
s.eventCode=7 // prepare to reenter this function with cursormoved eventcode
Make /free/T csr={"A","B","C","D"}
int i
for(i=0;i<4;i+=1)
s.cursorName=csr[i]
variable csrpos = i>1 ? vcsr($s.cursorName) : xcsr($s.cursorName)
GetAxis /Q $SelectString(i>1, strXaxis, strYaxis)
if(csrpos>min(v_max,v_min) && csrpos<max(v_max,v_min))
ImgHook(s)
else
SetVariable $"setvar"+(s.cursorName) disable=1
endif
endfor
endswitch
return 0
end
static function Rescale(STRUCT WMSetVariableAction &s)
if(s.eventCode!=8)
return 0
endif
string strImage=StringFromList(0, ImageNameList("", ";"))
wave wImage=ImageNameToWaveRef("", strImage)
int isX = GrepString((s.ctrlName), "[AB]"), autoscale=1
string strAxis, info, flags
info=ImageInfo("", strImage, 0)
strAxis=StringByKey(SelectString(isX, "YAXIS", "XAXIS"),info)
info=AxisInfo("", strAxis)
flags=StringByKey("SETAXISFLAGS", info)
variable indexMin, indexMax
if(GrepString(flags, "/")==0)
GetAxis /Q $strAxis
indexMin=scaleToIndex(wImage, V_min, 1-isX)
indexMax=scaleToIndex(wImage, V_max, 1-isX)
autoscale=0
endif
variable ValAC, ValBD, delta, offset, oldDelta
ControlInfo $SelectString(isX, "SetVarC", "SetVarA")
ValAC=V_Value
ControlInfo $SelectString(isX, "SetVarD", "SetVarB")
ValBD=V_Value
delta = isX ? (ValBD-ValAC)/(pcsr(B)-pcsr(A)) : (ValBD-ValAC)/(qcsr(D)-qcsr(C))
offset = isX ? ValAC - delta*pcsr(A) : ValAC - delta*qcsr(C)
oldDelta = DimDelta(wImage, 1-isX)
if(isX)
SetScale /P x, offset, delta , wImage
else
SetScale /P y, offset, delta , wImage
endif
if(autoscale==0)
v_min=IndexToScale(wImage, indexMin, 1-isX)
v_max=IndexToScale(wImage, indexMax, 1-isX)
if(v_min>v_max)
SetAxis /R $strAxis v_min, v_max
else
SetAxis $strAxis v_min, v_max
endif
endif
if(sign(oldDelta)!=sign(delta))
// switch the axis limits so that image is not flipped
if(GrepString(flags, "/R"))
SetAxis /A $strAxis
elseif(GrepString(flags, "/A"))
SetAxis /A/R $strAxis
endif
endif
return 0
end

Forum

Support

Gallery
Igor Pro 8
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More
Edited snippet to add a menu item that I find useful, and fixed some annoyances related to changing axis values after rescale.
December 1, 2020 at 09:21 am - Permalink