NB. Transform Images with distortion correction and
NB. mouse operations using the image3 addon
NB. Cliff Reiter, March 2003
NB.
NB. One can load an image via:
NB. transform_image d
NB. where d is an image filename, or an array representing an image
NB. see transform_m.html for help
NB. locale for image3 addon
coinsert 'ima3'
coinsert 'jgl2'
coclass 'ima3'
NB. default margin wh in pixels
bor_wh=:15 110
NB. path to the image3 addon library needs to be correct.
dir_sep=: PATHSEP_j_ NB. directory separator
addon_path=: jaddonspath 'image3',dir_sep
require addon_path,'image3.ijs'
require 'gl2'
TRANSFORMIMAGE=: 0 : 0
pc transformimage;
menupop "&File";
menu open "&Open" "Ctrl+o" "" "";
menu save "&Save..." "Ctrl+s" "" "";
menusep;
menu close "&Close" "" "" "";
menupopz;
menupop "&Transform";
menu rotateh "Rotate to &Horizontal" "" "" "";
menu rotatev "Rotate to &Vertical" "" "" "";
menu rotated "Rotate by &Degrees..." "" "" "";
menusep;
menu unbarrel "Remove &Barrel Distortion" "" "" "";
menu unbarrelc "Remove Barrel Distortion by &Coef..." "" "" "";
menu tiltr "Ti< to Rectangle" "" "" "";
menu balanceh "Balance Horizontal" "" "" "";
menu balancev "Balance Vertical" "" "" "";
menusep;
menu trim "&Trim" "" "" "";
menu resize "Resi&ze..." "" "" "";
menu rescale "Rescale..." "" "" "";
menupopz;
menupop "&View";
menu vselpts "&Selected Points" "" "" "";
menu vrotated "&Rotate Degrees" "" "" "";
menu vunbarrelc "&Unbarrel Coefficient" "" "" "";
menusep;
menu refresh "Re&fresh Selected Points" "" "" "";
menu clearpts "&Clear Selection" "" "" "";
menupopz;
menupop "&History";
menu back "&Back" "Ctrl+b" "" "";
menu forward "&Forward" "Ctrl+f" "" "";
menusep;
menu clearhist "&Clear History" "" "" "";
menupopz;
menupop "Hel&p";
menu help "Hel&p" "F1" "" "";
menusep;
menu about "&About" "" "" "";
menupopz;
cc win isigraph;
setxywhx win
)
to_raw_image=: 3 : 0
if. 0=#y. do. y.=.25 250 3${:a. end.
ty=.3!:0 y.
sh=.$y.
if. (ty=2)*.1=$sh do. y.=. raw_read_image y. end.
ty=.3!:0 y.
sh=.$y.
if. (ty = 4)*. 3=$sh do. y.=.y.{a.
elseif. (ty = 32)*. 2=sh do.
'p b'=.y.
if. 4=3!:0 p do. p=.p{a. end.
y.=. b{p
end.
if. 1={:$y. do. y.=.3#"1 y.end. NB. grayscale
y.
)
transformimage_run=: 3 : 0
'transform_image' transformimage_run y.
:
y.=.to_raw_image y.
tr_image_list_ima3_=:i.0
image_to_hist y.
tr_draw_image y.
)
tr_draw_image=: 3 : 0
SEL_pts_ima3_=:i.0 2
mouserect=:i.0
wh=.1 0{$y.
winm=.".wd 'qm;'
whav=.(0 1{winm)-bor_wh
if. wh *./ . <: whav
do. WH=.wh
else. WH=.<.wh*<./whav%wh end.
y.=.WH resize_image y.
xywh=.0 0,1 0{$y.
y.=.256 256 256&#.@:(a.&i.)"2 y.
y.=.,y.
wd :: 0: 'psel transformimage;'
wd :: 0: 'pclose;'
wd TRANSFORMIMAGE,(":xywh),';'
wd 'pn "Transform Image wh: ',(":wh),'";'
glmap MM_RAW
glwindowext wh
glsel 'win'
glpixels xywh,y.
glcursor IDC_CROSS
glshow ''
wd 'pas 0 0;'
wd 'pshow;'
wh
)
tr_refresh_image=:3 : 0
t=.SEL_pts_ima3_
wh=._2{.". wd 'qchildxywhx win'
glclear ''
tr_draw_image image_from_hist ''
for_xy. t do.
SEL_pts_ima3_=:SEL_pts_ima3_,xy
draw_sel_cross xy,wh
end.
glshow ''
glpaint ''
)
transformimage_refresh_button=:tr_refresh_image
transformimage_clearpts_button=:3 : 0
SEL_pts_ima3_=:i.0 2
tr_refresh_image''
)
transformimage_open_button=:3 : 0
fi=.wd 'mbopen "Open Image" "" "" "Bmp(*.bmp);Jpeg(*.jpg);Png(*.png)|*.bmp;*.jpg;*.png|All Files(*.*)|*.*"'
b=.raw_read_image fi
if. -. _1 -: b do.
image_to_hist b
tr_draw_image b
end.
)
transformimage_octrl_fkey=:transformimage_open_button
transformimage_vselpts_button=:3 : 0
wd 'mb "Selected Points" "',(,LF,.~ ": SEL_pts_ima3_ ),'"'
)
image_to_hist=: 3 : 0
tr_image_list_ima3_=:(<y.),tr_image_list_ima3_
)
image_from_hist=:3 : 0
>{.tr_image_list_ima3_
)
NB. Back button
transformimage_back_button=:3 : 0
tr_image_list_ima3_=:1|.tr_image_list_ima3_
tr_draw_image image_from_hist ''
)
transformimage_bctrl_fkey=:transformimage_back_button
NB. Forward buttons
transformimage_forward_button=:3 : 0
tr_image_list_ima3_=:_1|.tr_image_list_ima3_
tr_draw_image image_from_hist ''
)
transformimage_fctrl_fkey=:transformimage_forward_button
NB. save button
transformimage_save_button=:3 : 0
fo=.wd 'mbsave "Save Image" "" "" "Bmp(*.bmp);Jpeg(*.jpg);Png(*.png)|*.bmp;*.jpg;*.png|All Files(*.*)|*.*"'
(image_from_hist '') write_image fo
)
NB. clear history button
transformimage_clearhist_button=:3 : 0
tr_image_list_ima3_=:{.tr_image_list_ima3_
)
transformimage_sctrl_fkey=:transformimage_save_button
transformimage_win_mbldown=: 3 : 0
sd=.".sysdata
xy=.2{.sd
if. 1=7{sd do.
wh=.2 3{sd
wh add_sel_pt xy
mousetype=:0
else.
glcapture 3
mousetype=:1,xy
end.
)
transformimage_win_mblup=: 3 : 0
sd=.".sysdata
if. 1={.mousetype do.
mouserect=: (}.mousetype),4{.sd
glrgb tr_sel_color
glpen 2 1
fl=.(_1+{:mouserect)&-
gllines (0 1,0 3,2 3,2 1,0 1){(0&{,fl@(1&{),2&{,fl@(3&{))mouserect
glcapture 0
glshow ''
end.
)
mouse_to_dij=:4 : 0
'W H M N'=.x.
'x y'=.y.
y=.H-y+1
sw=. N%W
sh=. M%H
(sh*y),sw*x
)
transformimage_trim_button=: 3 : 0
if. 6=#mouserect do.
'xy XY WH'=:3 2$mouserect
b=.image_from_hist ''
whmn=.WH,2{.$b
dxy=.whmn mouse_to_dij"1 xy,:XY
b=.(>.(>./-<./) dxy){.(<.<./dxy)}.b
image_to_hist b
tr_draw_image b
mouserect=:i.0
end.
)
NB. processes resize input request
input_result_resize=:3 : 0
sz=.". y.
b=.sz resize_image image_from_hist ''
image_to_hist b
tr_draw_image b
)
transformimage_resize_button=:3 : 0
load 'jinput'
a=.conew 'jinput'
input_result=:input_result_resize
a_run__a 'Enter Resize Bounds:';'512 512';'Resize'
)
NB. processes rescale input request
input_result_rescale=:3 : 0
'sw sh'=.". y.
b=.image_from_hist ''
'H W'=.2{.$b
smoutput sw,sh
if. 1 ~: sw do.
i=.<.0.5+sw%~i.<.0.5+sw*W
b=.i{"1 2 b
end.
if. 1 ~: sh do.
i=.<.0.5+sh%~i.<.0.5+sh*H
b=.i{b
end.
image_to_hist b
tr_draw_image b
)
transformimage_rescale_button=:3 : 0
load 'jinput'
a=.conew 'jinput'
input_result=:input_result_rescale
a_run__a 'Enter WH Rescaling Factors:';'1.0 1.0';'Rescale'
)
NB. selection styles
tr_sel_color=:255 0 255
tr_sel_len=:10
tr_sel_pen=:2 1
NB. marks on image a selected point
draw_sel_cross=: 3 : 0
'x y w h'=.y.
glrgb tr_sel_color
glpen tr_sel_pen
if. tr_sel_len <<./x,y,(w-x),h-y do.
gllines (,+&(2 0*tr_sel_len))(x-tr_sel_len),h-y
gllines (,+&(0 2*tr_sel_len))x,(-tr_sel_len)+h-y
glshow ''
end.
)
add_sel_pt=:4 : 0
d=. >./"1 | y.-"1 SEL_pts_ima3_
if. *./ d>tr_sel_len do.
SEL_pts_ima3_=:SEL_pts_ima3_,y.
draw_sel_cross y.,x.
else.
i=.d i. <./d
m=.i~:i.#d
oldpt=:(i{SEL_pts_ima3_),x.
SEL_pts_ima3_=:m#SEL_pts_ima3_
tr_refresh_image ''
end.
)
NB. process Remove Barrel Distortion request
transformimage_unbarrel_button=:3 : 0
n=.#SEL_pts_ima3_
if. n=3 do.
c=.get_c ''
z=. c barrel_undistort image_from_hist ''
image_to_hist z
tr_draw_image z
else. wd 'mb "Unbarrel Error" "Unbarrel Requires 3 Selected Points"'
end.
)
NB. view unbarrel coefficient
transformimage_vunbarrelc_button=:3 : 0
if. 3=#SEL_pts_ima3_ do.
c=.get_c ''
wd 'mb "Unbarrel Coefficient" "Coef is: ',(":c),'"'
else.
wd 'mb "Unbarrel Error" "Unbarrel Requires 3 Selected Points"'
end.
)
NB. close function
transformimage_close=: 3 : 0
wd'pclose'
)
transformimage_close_button=:transformimage_close
NB. launches help file if html browser is configured
NB. and help file is in the expected directory
transformimage_help_button=:3 : 0
require addon_path,'html_gallery8.ijs'
open_html addon_path,'help',dir_sep,'transform_m.html'
)
NB. set F1 to lauch help
transformimage_f1_fkey=:transformimage_help_button
NB. The about button
transformimage_about_button=:3 : 0
z=.'Transform_m.ijs is a J script'
z=.z,:'for use with the Image3 Addon'
z=.z,'It is used to transform images in a few ways.'
z=.z,'by Cliff Reiter'
z=.z,'Lafayette College'
z=.z,'March 2003'
wd 'mb "About Transform_m" "',(,z,"1 CRLF),'"'
)
NB. transform_image d
NB. where d is an image filename, or an array representing an image
transform_image =: transformimage_run
NB. ***********************
NB. Utilities for rotations
NB. ***********************
NB. apply rotation to seminormal coordinates
sn_rot=: 4 : 0
'r t'=.10 12 o./ j./"1 y.
t=. t+x.
+. r r. t
)
NB. get angle from two points in range _1r2p1 to 1r2p1
get_sel_pts_angle=:3 : '12 o. j./(**@{.)-/SEL_pts_ima3_'
NB. radians rotate_raw_image image
rotate_raw_image=: 4 : 0
wh=.|.hw=.2{.$y.
y.=.(y.,{:a.),"_1 {:a.
cor=.,/>{;/0 0,.<:wh
x.=.2p1&|&.(+&1p1) x.
if. 1r2p1>:|x. do. t=.|x. else. t=.|1p1-|x. end.
tcor=.wh sn_to_pix t sn_rot wh pix_to_sn cor
'dw dh'=.2 1{,cor-tcor
z=.((hw+2*dh,dw),3)${:a.
for_k. (-dh)+i.({.hw)+2*dh do.
w=.j./"1 hw pix_to_sn k,.(-dw)+i. (2*dw)+{:hw
t=.x.+12 o. w
r=.10 o. w
in=.;/_1 >. hw <."1 hw sn_to_pix +.r r. t
z=.(in{y.)(dh+k)}z
end.
z
)
NB. process rotate to horizontal request
transformimage_rotateh_button=:3 : 0
if. 2~:#SEL_pts_ima3_ do. rotateh_err ''
else.
t=.get_sel_pts_angle ''
z=.t rotate_raw_image image_from_hist ''
image_to_hist z
tr_draw_image z
end.
)
NB. process rotate to vertical request
transformimage_rotatev_button=:3 : 0
if. 2~:#SEL_pts_ima3_ do. rotate_err ''
else.
t=.get_sel_pts_angle ''
t=.t-1r2p1**t
z=.t rotate_raw_image image_from_hist ''
image_to_hist z
tr_draw_image z
end.
)
NB. process Request to view line angle
transformimage_vrotated_button=:3 : 0
if. 2=#SEL_pts_ima3_ do.
a=.get_sel_pts_angle ''
wd 'mb "Rotation Angle" "Rotation Angle is: ',( ":<.0.5+a*360%2p1),' degrees"'
else.
rotate_err ''
end.
)
rotate_err=:3 : 0
wd 'mb "Rotate Error" "Two Points Should be Selected for Rotation to Vertical/Horizontal"'
)
NB. processes rotate by degrees request
input_result_rotated=:3 : 0
sz=.1r180p1* ". y.
b=.sz rotate_raw_image image_from_hist ''
image_to_hist b
tr_draw_image b
)
transformimage_rotated_button=:3 : 0
load 'jinput'
a=.conew 'jinput'
input_result=:input_result_rotated
a_run__a 'Enter Degrees to Rotate Clockwise:';'45';'Degrees to Rotate'
)
NB. ******************************************
NB. Utilities for correcting barrel distortion
NB. ******************************************
NB. radius to barrel distorted radius RD
NB. c R_to_RD y.
R_to_RD=: ] + [ * ^&3@]
NB. distorted radius to radius
NB. c RD_to_R y.
p1_temp=.1 11 39 51 16&p.
p2_temp=.1 12 48 75 36&p.
RD_to_R=: ]* (p1_temp % p2_temp)@:([**:@]) f.
NB. pixel coordinates to seminormal _1 to 1 coordinates
NB. preserving aspect ratio
NB. wh pix_to_sn ij
pix_to_sn=: 1 : 0
(y.-"1-:m.-1)%-:>./m.-1
)
NB. seminormal to pixel coordinates
NB. wh sn_to_pix xy
sn_to_pix=: 1 : 0
<.0.5+(-:m.-1)+"1 y.*"1 -:>./m.-1
)
NB. sn_to_pix=: 1 : 0
NB. [:<.@(0.5&+)(-:m.-1)"_ +"1 (-:>./m.-1)&*"1
NB. )
NB. sn_to_pix =: [: <.@(0.5&+) (-:@<:@[)+"1 ] *"1 -:@(>./)@:<:@[
NB. apply distortion to seminormal coordinates
sn_dist=: 1 : 0
'r t'=.10 12 o./ j./"1 y.
r=.m. R_to_RD r
+. r r. t
)
NB. apply undistortion to seminormal coordinates
sn_undist=: 1 : 0
'r t'=.10 12 o./ j./"1 y.
r=.m. RD_to_R r
+. r r. t
)
NB. c barrel_undistort raw_image
barrel_undistort=: 4 : 0
wh=.|.hw=.2{.$y.
und=.wh sn_to_pix@(x. sn_undist)@(wh pix_to_sn)
y.=.(y.,{:a.),"_1 {:a.
if. x.<0 do.
'dw dh'=.|und 0 0
else.
'dw dh'=.-<./und -:wh*=i.2
end.
z=.((hw+2*dh,dw),3)${:a.
dsn=. -{.-/hw pix_to_sn 0 0,:1 1
w=.j./"1 hw pix_to_sn (-dh),.(-dw)+i. (2*dw)+{:hw
for_k. (-dh)+i.({.hw)+2*dh do.
t=.12 o. w
r=.|10 o. w
r=.x. R_to_RD r
in=.;/_1 >. hw <."1 hw sn_to_pix +.r r. t
z=.(in{y.)(dh+k)}z
w=.w+dsn
end.
NB. 'one'+1
z
)
NB. tries various coefficient for undistrotion and
NB. returns a signed measure of linearity
try_c=: 3 : 0"0
wh=.m_wh ''
-/ . * (}.-"1{.)y. sn_undist"1 wh pix_to_sn SEL_pts_ima3_
)
NB. use mouse points to get c
get_c=:3 : 0
c=._0.5
h=.0.1
while. 0.0001<h do.
t=.c+h*i.11
i=.1 i:~0>(*{:)try_c t
c=.i{t
h=.0.1*h
end.
c
)
NB. processes remove barrel distrotion request
input_result_unbarrelc=:3 : 0
s=.". y.
b=.s barrel_undistort image_from_hist ''
image_to_hist b
tr_draw_image b
)
transformimage_unbarrelc_button=:3 : 0
load 'jinput'
a=.conew 'jinput'
input_result=:input_result_unbarrelc
t=.'Enter Unbarrel Coefficient',CRLF
t=.t,'Typical Value 0.1, Interesting Range _0.3 to 0.3'
if. 3=#SEL_pts_ima3_ do. c=.": get_c '' else. c=.'_0.08' end.
a_run__a t;c;'Unbarrel by Coefficient'
)
NB. ***********************************************
NB. Utilities for moving four points to a rectangle
NB. ***********************************************
bal_4=:3 : 0
s=.y. /: 2p1|12 o. j./"1 y.-"1(+/%#)y.
xa=._1|.2#_2 (+/%#)\ {."1 ]1|.s
ya=.2#_2 (+/%#)\ {:"1 s
s,:xa,.ya
)
transformimage_tiltr_button=: 3 : 0
if. 4=#SEL_pts_ima3_ do.
a=.get_tilt_a |."1 get_tilt_pts ''
b=.a trans_tilt image_from_hist ''
image_to_hist b
tr_draw_image b
else. wd 'mb "Error on Tilt" "Tilt to Rectangle needs 4 selected points"'
end.
)
m_wh=: 3 : 0 NB. mouse wh
wd 'psel transformimage'
_2{.". wd 'qchildxywhx win'
)
sn_flip1=:1 _1&*"1
get_tilt_pts=:3 : 0
wh=.m_wh ''
bal_4 sn_flip1 wh pix_to_sn SEL_pts_ima3_
)
get_tilt_a=:3 : 0
({.y.) %. (1:,],*/)"1 {: y.
)
NB. coef trans_tilt image
trans_tilt=:4 : 0
to_tilt=:((+/ . * )&x.)@:(1:,],*/)"1
wh=.|.hw=.2{.$y.
y.=.(y.,{:a.),"_1 {:a. NB. pad white edge
dh=.dw=.0
z=.((hw+2*dh,dw),3)${:a.
for_k. (-dh)+i.({.hw)+2*dh do.
in=.;/_1 >. hw <."1 hw sn_to_pix to_tilt hw pix_to_sn k,.(-dw)+i. (2*dw)+{:hw
z=.(in{y.)(dh+k)}z
end.
z
)
NB. ***********************************************
NB. Utilities for nonlinear stretching in horz/vert
NB. ***********************************************
bal_horz=:3 : 0
y=.image_from_hist ''
WH=:1 0{$y
W=:{.WH
x=./:~{."1 WH sn_to_pix (m_wh'') pix_to_sn SEL_pts_ima3_
h=.x +/ . * -:_1 1 _1 1
'x0 x1 x2 x3'=.x
p=.(x %.(x0,(x0+h),x2,x2+h)^/i.4)&p.
i=.<.0.5+p (--:W)+i.+:W
i=.((i>:0)*.i<W)#i
i{"1 2 y
)
transformimage_balanceh_button=: 3 : 0
if. 4=#SEL_pts_ima3_ do.
b=.bal_horz ''
image_to_hist b
tr_draw_image b
else. wd 'mb "Error on Tilt" "Balance Horizontal uses 4 selected points on a horizontal line"'
end.
)
bal_vert=:3 : 0
y=.image_from_hist ''
WH=:1 0{$y
H=:{:WH
x=.(H-1)-/:~{:"1 WH sn_to_pix (m_wh'') pix_to_sn SEL_pts_ima3_
h=.x +/ . * -:_1 1 _1 1
'x0 x1 x2 x3'=.x
p=.((h+x0,x2)%.1,.x1,x3)&p.
p=.((x0,(h+x0),x2,h+x2)%.1,.x,.x^2)&p.
p=.(x %.(x0,(x0+h),x2,x2+h)^/i.4)&p.
i=.<.0.5+p (--:H)+i.+:H
i=.((i>:0)*.i<H)#i
i{y
)
transformimage_balancev_button=: 3 : 0
if. 4=#SEL_pts_ima3_ do.
b=.bal_vert ''
image_to_hist b
tr_draw_image b
else. wd 'mb "Error on Tilt" "Balance Vertical uses 4 selected points on a vertical line"'
end.
)