PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/octave-forge/extra/gnuplot/inst/myimage.m

#
Objective C | 516 lines | 451 code | 65 blank | 0 comment | 112 complexity | a82cbcec0546b8f9e34411b3891d4f86 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, GPL-3.0, LGPL-3.0
  1. ## im2 = myimage (im,...) - Make im viewable by normalizing greylevels and more
  2. ##
  3. ## Scales the values of im so that they range in [0,255]. The smallest element
  4. ## of im (or range(1), if the "range" option is used) is mapped to zero, and the
  5. ## largest (or range(2)) is mapped to 255.
  6. ##
  7. ## If both dimensions are less than 180,
  8. ##
  9. ## If the save option is not used, and nargout is 0, then im2 will be displayed,
  10. ## rather than returned. NaN and Inf pixels become black or, if the image is
  11. ## saved as a .png or .gif, transparent.
  12. ##
  13. ## OPTIONS:
  14. ## --------
  15. ## "range", [min,max] : Graylevel range to be mapped to 0:255.
  16. ## Default:[min(im(:)),max(im(:))]
  17. ## "qrange", [minq,maxq]: Map quantiles between minq and maxq to 0 and 255.
  18. ## "minsz", [Rows,Cols] : Minimum dims of im2. im will be scale by an integral
  19. ## factor so that at least one of its dimensions matches
  20. ## minsz. Default: [180 180]
  21. ## "scl", scl : Scale image size up (scl>1) or down (scl<1)
  22. ## "invert" : Invert image (black becomes white and vice versa).
  23. ##
  24. ## "is_col" : Color image, consecutive rows being R, G and B.
  25. ## "colormap", : Convert greylevel image to a 'rainbow' colormap
  26. ##
  27. ## "show_range" : Place a graylevel scale below image.
  28. ## "scale_sz",sz : Width of graylevel scale. Implies show_range.
  29. ##
  30. ## "text", [x,y], str : Annotate image with str, at position x,y, with size sz
  31. ## "text", [x,y,sz],str
  32. ## "line", [x,y,x,y,R,G,B,W] or
  33. ## "line", [x,y,x,y,R,G,B] or
  34. ## "line", [x,y,x,y,C,W] or
  35. ## "line", [x,y,x,y,C] or
  36. ## "line", [x,y,x,y]
  37. ##
  38. ## "save", filename : Save im2 in filename.
  39. ## "display", yesno : Display im2 or not. Default: False iff save requested
  40. ## or nargout!=0.
  41. ##
  42. ## EXAMPLES: type "demo myimage" to run the examples below
  43. ## ---------
  44. ## myimage (randn(3,3), "show_range")
  45. ## myimage (rand(9,3), "is_col")
  46. ## myimage (randn(32,32), "minsz",[32,50])
  47. ## myimage (ones(64,1)*linspace(0,1,256), "colormap")
  48. ## myimage (linspace(0,3,256)'*ones(1,64), "range",[3 1])
  49. ## myimage (zeros(200,200), "text",[10,20],">> 1 + pi\nans = 4.1416\n>>")
  50. ##
  51. ## im = kron (ones(4), kron (eye(2),ones(10)));
  52. ## im += ones (80,1)*linspace(0,1/2,80);
  53. ## myimage (im,"text",[11,5],"Hello","text", [10,30,30],"world")
  54. ##
  55. ## FIXME: scl < 1 seems to be buggy
  56. ### Author Etienne Grossmann <etienne@isr.ist.utl.pt>
  57. function im = myimage (im, varargin)
  58. ##viewer = "qiv"; # If I need to display image
  59. ##viewer = "feh";
  60. ##viewer = "display";
  61. viewer = "eog";
  62. is_col = 0;
  63. invert = 0;
  64. sameScale = 1; # Use same greylevel scale for R, G and B
  65. show_range = 0;
  66. scale_sz = 0;
  67. vrange = [];
  68. qrange = [];
  69. minsz = 180;
  70. maxsz = 640;
  71. colormap = 0;
  72. filename = 0;
  73. text = {};
  74. line = {};
  75. do_show = !nargout;
  76. dont_wait = "";
  77. roi = [];
  78. scl = nan;
  79. if nargin > 1
  80. cnt = 1;
  81. # For compat w/ old style
  82. if ! ischar (varargin{cnt}), is_col = varargin{cnt++}; end
  83. while cnt <= length (varargin)
  84. opt = varargin{cnt++};
  85. if ! ischar (opt)
  86. error ("Expecting option name, got a %s",typeinfo(opt))
  87. endif
  88. switch opt
  89. case "scl", scl = varargin{cnt++};
  90. case "ROI", roi = varargin{cnt++};
  91. case "save", filename = varargin{cnt++};
  92. case "range", vrange = varargin{cnt++};
  93. case "qrange", qrange = varargin{cnt++};
  94. case "minsz", minsz = varargin{cnt++};
  95. case "do_show", do_show = varargin{cnt++};
  96. case "viewer", viewer = varargin{cnt++}; do_show = 1;
  97. case "display", viewer = "display"; do_show = 1;
  98. case "gimp", viewer = "gimp"; do_show = 1; dont_wait = "&";
  99. case "qiv", viewer = "qiv"; do_show = 1; dont_wait = "&";
  100. if cnt<=length(varargin) && isnumeric(varargin{cnt})
  101. printf ("Warning: option 'display' now takes no arg\n");
  102. end
  103. case "invert", invert = 1;
  104. case "is_col", is_col = 1;
  105. case "colormap", colormap = 1;
  106. if cnt<=length(varargin) && isnumeric(varargin{cnt})
  107. colormap = varargin{cnt++};
  108. if columns (colormap) != 3
  109. error ("colormap's optional argument has %i != 3 columns", columns(colormap));
  110. end
  111. colormap /= max (colormap(:));
  112. end
  113. case "show_range", show_range = 1;
  114. case "scale_sz", show_range = 1; scale_sz = varargin{cnt++};
  115. case "circle", circle = {circle{:},varargin{cnt++}};
  116. case "line", line = {line{:},varargin{cnt++}};
  117. case "text", text = {text{:},varargin{cnt+[0,1]}}; cnt += 2;
  118. otherwise error ("Unknown option '%s'", opt);
  119. endswitch
  120. endwhile
  121. endif
  122. if ischar(im), im = imread (im); endif
  123. if length(size(im)) == 3, # 3D-array to 2D matrix of interlaced R,G,B
  124. is_col = 1;
  125. ##im = reshape
  126. ##([im(:,:,1)(:),im(:,:,2)(:),im(:,:,3)(:)]',size(im)(1:2).*[3,1]);
  127. im = reshape (reshape(im,prod(size(im))/3,3)',size(im)(1:2).*[3,1]);
  128. endif
  129. [R,C] = size(im);
  130. im(!isfinite(im)) = nan;
  131. R0 = R; C0 = C;
  132. if prod (size (maxsz)) == 1, maxsz = maxsz*[1 1]; endif
  133. if isnan (scl) && ((R>maxsz(1)*(1+2*is_col)) || (C>maxsz(2)))
  134. scl = ceil (max (R/(maxsz(1)*(1+is_col*2)), C/maxsz(2)))
  135. end
  136. if !isnan (isnan (scl)) && scl > 1
  137. if is_col
  138. im = im([1:3*scl:R;2:3*scl:R;3:3*scl:R],1:scl:C);
  139. else
  140. im = im(1:scl:R,1:scl:C);
  141. endif
  142. [R,C] = size(im);
  143. endif
  144. if prod (size (minsz)) == 1, minsz = minsz*[1 1]; endif
  145. if isnan (scl) && ((R<minsz(1)*(1+is_col*2)) && C<minsz(2))
  146. scl = 1 / ceil(min (minsz(1)*(1+is_col*2)/R, minsz(2)/C));
  147. end
  148. if !isnan (isnan (scl)) && scl < 1
  149. ## printf ("Scaling up by %i\n",scl);
  150. scl0 = round (1/scl);
  151. if is_col
  152. im = reshape ([kron(im(1:3:end,:), ones (scl0))(:),\
  153. kron(im(2:3:end,:), ones (scl0))(:),\
  154. kron(im(3:3:end,:), ones (scl0))(:)]', R*scl0,C*scl0);
  155. else
  156. im = kron (im, ones (scl0));
  157. endif
  158. [R,C] = size(im);
  159. end
  160. if isnan (scl)
  161. scl = 1;
  162. end
  163. if ! isempty (qrange)
  164. if length (qrange) != 2
  165. qrange = sort ([qrange, 1-qrange]);
  166. end
  167. vrange = qnt (im(:),qrange);
  168. end
  169. ## Set imin (maps to 0), imax (maps to 255) and irng ( = imax - imin)
  170. if ! isempty (vrange)
  171. if prod (size (vrange)) == 2
  172. imin = vrange(1);
  173. imax = vrange(2);
  174. irng = vrange(2) - vrange(1);
  175. elseif prod (size (vrange)) == 6
  176. if rows (vrange) == 2, vrange = vrange'; end
  177. imin = vrange(1:3);
  178. imax = vrange(4:6);
  179. irng = imax - imin;
  180. else
  181. error ("range should have 2 or 6 elements; got %s",\
  182. sprintf("%i x ",size(vrange))(1:end-3));
  183. end
  184. else
  185. if !is_col || sameScale
  186. imin = min (im(:));
  187. imax = max (im(:));
  188. irng = imax - imin;
  189. else
  190. imin = min (reshape (im,3,R*C/3)');
  191. imax = max (reshape (im,3,R*C/3)');
  192. irng = imax - imin;
  193. endif
  194. end
  195. if any (irng) < 0
  196. error ("Range ( %s) is not positive",sprintf("%f ",irng));
  197. endif
  198. ##length(unique(im))
  199. if !is_col || sameScale
  200. im-=imin;
  201. if irng
  202. im .*= 255/irng;
  203. else
  204. im += min (1, max (imin/255,0));
  205. endif
  206. else
  207. for j = 1:3, im(j:3:R,:) -= imin(j); endfor
  208. for j = 1:3
  209. if irng(j)
  210. im(j:3:R,:) .*= 255/irng(j);
  211. else
  212. im(j:3:R,:) += min (1,max (imin(j)/255,0));
  213. endif
  214. endfor
  215. endif
  216. im(im<0) = 0;
  217. im(im>255) = 255;
  218. if (invert), im = 255 - im; end
  219. if !isempty (roi)
  220. roi *= scl;
  221. #size(im)
  222. #[min(im(:)),max(im(:))]
  223. highlight = 64;
  224. im(roi(2):roi(4),roi(1):roi(3)) += highlight;
  225. im .*= 255/(255+highlight);
  226. #size(im)
  227. #[min(im(:)),max(im(:))];
  228. endif
  229. if show_range && !is_col
  230. # Assume graylevel
  231. ## scale_C, scale_R : size of scale image
  232. if scale_sz
  233. scale_C = max (128, scale_sz);
  234. else
  235. scale_C = min (max (128, C), 256);
  236. endif
  237. scale_R = 2*round (12*scale_C/128);
  238. # Image w/ room for image and scale below
  239. scale_im0 = ones(scale_R/2,1)*linspace(0,255,scale_C);
  240. if invert, scale_im0 = 255 - scale_im0; end
  241. scale_im = [255+zeros(scale_R/2,scale_C);\
  242. scale_im0];
  243. tn = [tempname(),".pgm"];
  244. if imin && abs(log10(abs(imin)))>5, ado = sprintf ("%.3g",imin);
  245. else ado = sprintf ("%.3f",imin);
  246. endif
  247. if imin && abs(log10(abs(imax)))>5, aup = sprintf ("%.3g",imax);
  248. else aup = sprintf ("%.3f",imax);
  249. endif
  250. roundBy = 0.01;
  251. if irng > 1-2*roundBy;
  252. if abs (imin-round(imin)) < roundBy, ado = num2str(round(imin)); endif
  253. if abs (imax-round(imax)) < roundBy, aup = num2str(round(imax)); endif
  254. endif
  255. psz = round(8*scale_C/128);
  256. ado = sprintf ("-annotate +%i+%i \"%s\"",\
  257. 2,\
  258. psz,\
  259. ado);
  260. aup = sprintf ("-annotate +%i+%i \"%s\"",\
  261. scale_C-length(aup)*round(5*psz/10)-3,\
  262. psz,\
  263. aup);
  264. imwrite (tn, uint8 (scale_im),[aup; ado; sprintf("-pointsize %i",psz)]);
  265. scale_im = imread (tn);
  266. unlink (tn);
  267. pC = max (scale_C, C);
  268. padded_im = 255*ones (R+scale_R,pC);
  269. padded_im(1:R,floor((pC-C)/2)+(1:C)) = im;
  270. padded_im(R+1:R+scale_R,floor((pC-scale_C)/2)+(1:scale_C)) = \
  271. double (scale_im);
  272. im = padded_im;
  273. endif
  274. if colormap && !is_col
  275. sz = size (im);
  276. if prod (size (colormap)) == 1
  277. colormap = rainbow()(end:-1:1,:);
  278. end
  279. ncol = rows (colormap);
  280. cmap = 255*interp1 ((1:ncol),colormap,linspace(1,ncol,256))';
  281. nanpix = isnan (im);
  282. im(nanpix) = 0; # Dummy value, replacement is done below
  283. im = reshape (cmap (:,1+floor(im(:))),3*sz(1),sz(2));
  284. if show_range # Get the text back in bw
  285. im(3*R+(1:3*scale_R),1:floor((pC-scale_C)/2)) = 255;
  286. im(3*R+(1:3*scale_R),floor((pC+scale_C)/2):end) = 255;
  287. im(3*R+(1:3*scale_R/2),floor((pC-scale_C)/2)+(1:scale_C)) = \
  288. kron (double (scale_im(1:scale_R/2,:)),ones(3,1));
  289. endif
  290. nanpix = !!reshape ([1;1;1]*nanpix(:)', size(im));
  291. im(nanpix) = nan;
  292. is_col = 1;
  293. endif
  294. #imin
  295. #imax
  296. #length(unique(im))
  297. assert (all (im(:) >= 0 | isnan (im(:))));
  298. assert (all (im(:) <= 255 | isnan (im(:))));
  299. # Process text annotation commands
  300. wopts = "";
  301. i = 1;
  302. while i < length (text)
  303. if !isnumeric (text{i}),
  304. error ("Arg of type '%s' where numeric required, in 'text' option",\
  305. typeinfo(text{i}));
  306. end
  307. if length (text{i}) != 2 && length (text{i}) != 3
  308. error ("Position argument has size %s (should have 2 or 3 elements)",\
  309. sprintf("%i x ",size(text{i})(1:end-3)));
  310. endif
  311. if !ischar (text{i+1}),
  312. error ("Arg of type '%s' where string required, in 'text' option",\
  313. typeinfo(text{i+1}));
  314. endif
  315. if !length (text{i+1}), i+=2; continue; endif
  316. ptsz = floor (C0/16); # Size of text characters (in orig image)
  317. if length (text{i}) == 3, ptsz = text{i}(3); endif
  318. # Height and Width of text box
  319. tmp = [1, text{i+1} == "\n"];
  320. if tmp(end), tmp = tmp(1:end-1); endif
  321. tmp = cumsum (tmp);
  322. tmp = loop_add (zeros(1,max(tmp)),tmp);
  323. txtsz = [length(tmp),max(tmp)-1];
  324. # Choose a color, white, gray or black according
  325. # to histogram of image in bounding box.
  326. txtbb = (text{i}([2,1,2,1])(:)' + [-txtsz(1),0,0,txtsz(2)] * ptsz/2) * scl;
  327. txtbb = round (txtbb);
  328. txtbb = min (txtbb, size(im)([1 2 1 2]));
  329. txtbb = max (txtbb, 1);
  330. bbh = hist (im(txtbb(1):txtbb(3),txtbb(2):txtbb(4))(:),[55,127,200]);
  331. bbh = 0.98*bbh + 0.01*bbh([1 1 2]) + 0.01*bbh([2 3 3]);
  332. [dummy,tmp] = min (bbh);
  333. ##im(txtbb(1):txtbb(3),txtbb(2):txtbb(4)) = 0;
  334. fillColorStr = {"-fill \"#000000\" ",\
  335. "-fill \"#A0A0A0\" ",\
  336. "-fill \"#ffffff\" "}{tmp};
  337. wopts = [wopts, fillColorStr];
  338. wopts = [wopts, sprintf("-pointsize %i ",ptsz*scl)];
  339. #wopts = [wopts, sprintf("-annotate +%i+%i \"%s\" ",text{i}(1:2),text{i+1})];
  340. wopts = [wopts, sprintf("-draw \"text %i,%i '%s'\" ",scl*text{i}(1:2),text{i+1})];
  341. i += 2;
  342. endwhile # EOF loop thru text annotation commands
  343. i = 1;
  344. while i <= length (line)
  345. ll = line{i}(:);
  346. lll = length(ll);
  347. if !isnumeric (ll)
  348. error ("%ith 'line' argument is of type '%s', not numeric",\
  349. i, typeinfo(line{i}));
  350. endif
  351. if lll < 4
  352. error ("%ith 'line' argument has %i elements, 4 at least are needed",\
  353. i, lll);
  354. endif
  355. if lll > 8
  356. error ("%ith 'line' argument has %i elements, 8 at most are taken",\
  357. i, lll)
  358. endif
  359. rgb = [nan,nan,nan];
  360. wid = nan;
  361. switch lll
  362. case 4, # All defaults
  363. case 5, rgb = ll(5)*[1 1 1]; # x,y,x,y,c
  364. # x,y,x,y,c, w
  365. case 6, rgb = ll(5)*[1 1 1]; wid = ll(6);
  366. case 7, rgb = ll(5:7)';
  367. case 8, rgb = ll(5:7)'; wid = ll(8);
  368. endswitch
  369. if all (!isnan (ll(1:4))) # Don't bother for nans
  370. if !isnan (wid),
  371. wopts = [wopts, sprintf("-stroke-width %i ",wid)];
  372. endif
  373. if all(!isnan (rgb)),
  374. wopts = [wopts, sprintf("-fill \"#%02x%02x%02x\" ",rgb)];
  375. endif
  376. wopts = [wopts, sprintf("-draw \"line %i,%i %i,%i\" ",ll(1:4))];
  377. else
  378. printf ("myimage: Hey, there's some 'nan' in the %i'th line argument\n",i);
  379. endif
  380. i++;
  381. #wopts
  382. endwhile # EOF loop thru lines
  383. nanmask = isnan(im);
  384. im(nanmask) = 0;
  385. # Do I need to use libmagick to save and
  386. # display, or because save was requested, or to
  387. # annotate image.
  388. if do_show || filename || length(wopts)
  389. # If I save, should I do sthing for transparency?
  390. nanmaskfile = "";
  391. if filename && any (nanmask(:))\
  392. && (strcmp (filename(end-3:end), ".png")\
  393. || strcmp (filename(end-3:end), ".gif"))
  394. nanmaskfile = "tmp-mask.pgm"
  395. imwrite (nanmaskfile, uint8 (255*!nanmask));
  396. ##myimage (nanmask);
  397. endif
  398. if !is_col
  399. if !filename, filename = "tmp.pgm"; endif
  400. imwrite (filename, uint8 (im), wopts);
  401. else
  402. if !filename, filename = "tmp.ppm"; endif
  403. RC3 = prod (size(im));
  404. RC = size(im)./[3 1];
  405. imwrite (filename, \
  406. reshape(uint8 (im(1:3:RC3)),RC),\
  407. reshape(uint8 (im(2:3:RC3)),RC),\
  408. reshape(uint8 (im(3:3:RC3)),RC),\
  409. wopts);
  410. end
  411. # If there's transparency, do a separate call to convert
  412. if length(nanmaskfile)
  413. ["convert ",filename," ",\
  414. "tmp-mask.pgm -quality 100 +matte -compose CopyOpacity ",\
  415. filename]
  416. system (["cp ",filename," tmp-im.png"])
  417. system (["convert ",filename," ",\
  418. "tmp-mask.pgm -quality 100 +matte -compose CopyOpacity ",\
  419. filename]);
  420. endif
  421. if do_show
  422. [o,s] = system ([viewer, " ",filename," ",dont_wait]);
  423. if s
  424. error("%s exited w/ status %im after \
  425. outputing<<EOF\n%s\nEOF\n",viewer,s,o);
  426. endif
  427. endif
  428. # If I annotated image, annotation is now in
  429. # file, but not in im, so I load im from file
  430. if length(wopts) && nargout
  431. im = imread (filename);
  432. assert (all (im(:) >= 0));
  433. assert (all (im(:) <= 255));
  434. end
  435. end
  436. assert (all (im(:) >= 0));
  437. assert (all (im(:) <= 255));
  438. if !nargout, clear im; endif
  439. endfunction
  440. %!demo
  441. %!
  442. %! myimage (randn(3,3), "show_range")
  443. %! myimage (rand(9,3), "is_col")
  444. %! myimage (randn(32,32), "minsz",[32,50])
  445. %! myimage (ones(64,1)*linspace(0,1,256), "colormap")
  446. %! myimage (linspace(0,3,256)'*ones(1,64), "range",[3 1])
  447. %! myimage (zeros(200,200), "text",[10,20],">> 1 + pi\nans = 4.1416\n>>")
  448. %!
  449. %! im = kron (ones(4), kron (eye(2),ones(10)));
  450. %! im += ones (80,1)*linspace(0,1/2,80);
  451. %! myimage (im,"text",[11,5],"Hello","text", [10,30,30],"world")