分类目录归档:IDL/ENVI

ENVI & IDL

[原] IDL关于数字值域的注意点

IDL默认方式的数字是短整型(16-bit int)。所以如下的声明方式其实是报错的:

因为,1024*32=32768,超过了短整型上限(32767),从二进制码基础可知会跳到该类型的另一头,即:

这时有两种解决办法,一种显示声明为Long(32-bit int),即数字后面跟上L:

另外一种事先声明:

idl2参见文档,记得是编译开关:1)把所有数字作为Long型 2)用中括号表示数组下标,即[]
http://www.exelisvis.com/docs/COMPILE_OPT.html

[原] IDL的逻辑判断符和位操作运算符(坑啊)

好吧,又一次被IDL坑了。怪我自己没看仔细,主要语言太多。。。
比如:
C系列的逻辑判断符是 && || !
Delphi的逻辑判断符是AND OR NOT
写在这里,起警示作用:
IDL的逻辑判断符是这样的:&& || ~
IDL的位操作符是这样的:AND OR NOT XOR
以前写判断都是 if … and … then …
所以从来没注意and原来是(Bitwise AND),not原来是(Bitwise NOT)
好吧,因为以前的判断基本都是逻辑组合(即 if ID gt 2 and ID lt 5 then…)为主,所以基本两个的结果是一样的,没出过问题。
坑来了:
id = -2
if not id then …
(not -2) equals 1
所以,以后IDL逻辑判断全部要用 && || ~

[原] 如何在数组中查找定位最接近的数值

这个需求一般是查询一个look-up-table,比如数据定标表,假设有如下一个数组(实际数组比这大很多,只是为了举例):
现在要找 1.5 最接近的数值:

我一开始用的是先把数组sort,然后用二分法查找(代码不贴了,很简单)
后来一想IDL应该有内置支持这种查找吧,发现有 Value_Locate 方法,可以解决问题。
但是缺点很明显,需要先sort
后来找到这里:Locating a Value in an Array
我稍微改进了一下,因为Min支持 /ABSOLUTE 参数:

[转] 如何高效地编写IDL代码 Tips & Thicks

适合所有IDL使用者好好看看:
Tips & Tricks for Efficient IDL Programming
尤其是3、5、9、10条:
3、Try to avoid IF statements within loops. When an IF statement appears in the middle of a loop with each element of an array in a conditional, the loop can be eliminated most of the time by using logical array expressions.

Slow:
for i = 0L, n_elements(data)-1L do $
if (data[i] le 30) then $
data[i] = 30

Faster:
dex = where(data le 30, count)
if (count gt 0) then data[dex] = 30

Even faster:
data = ((data gt 30) * data) + ((data le 30) * 30)

Fastest:
data = data > 30

5、Access large arrays by memory order. Arrays in IDL are column-major order. The important thing to remember is that IDL indexes arrays as [column, row]. The upper left-hand element of a matrix is considered to be [0,0]. This is the format used by FORTRAN, and is traditionally associated with image processing because it keeps all the elements of a single image scanline together. In contrast C and Visual Basic use row-major order and indexes its data as [row,column].

When an array is larger than or close to the working set size (the amount of physical memory available for the process) it should be accessed in memory order, meaning access it by accessing rows first.
for x = 0, 511 do for y = 0, 511 do arr[x, y] = ….
is very inefficient because to read the first column 250,000 bytes of data must be read into physical memory. This process must be repeated for each column, requiring the entire array to be read and written almost 512 times. By exchanging the two FOR loops the computing time can be reduced by a factor of 50:
for y = 0, 511 do for x = 0, 511 do arr[x, y] = ….

9. Use of the TEMPORARY function minimizes memory use when performing operations on large arrays. TEMPORARY reassigns to a new variable the memory referred to by its argument, deleting the old variable reference in the process (though the reassignment may be to a variable that reuses the original name). Assume that A is a large array. To add 1 to each element of A this is one coding option:
A = A + l
This statement creates a new array for the result of the addition and assigns the result to A before freeing the old allocation of A. Therefore, this operation needs 2*sizeof(A) of memory to perform the operation. The statement
A = temporary(A) + 1
needs no additional space.

10. Try not to use “*” for array indexing on the left hand side of a statement. Instead, use “0.” For instance, for the array
B = intarr(200, 200, 3)
it is much slower to use the following notation
B[*,*,1] = insertData
than to use
B[0,0,1] = insertData
The first notation is inefficient because the IDL interpreter will allocate/build a 200 x 200 long integer array of subscript indexes to substitute for the wildcard token. The latter notation does not need an array of subscripts; it performs direct copy to memory. (Note that ‘insertData’ must fit in the 200 x 200 x 2 memory space that defines the borders of the subarray that starts at ‘B[0,0,1]’ in order to avoid an array-out-of-bounds error.)

[原] IDL的格式化字符串太让人faint了

也许跟FORTRAN差不多,那也是我为什么讨厌FORTRAN最大的原因

比如我要输出 YY-MM-DD hh_mm_ss 的时间格式:

OMG…..Orz……

[原] IDL剪贴板绘图在其他语言调用下失效的bug

经过运行剪贴板监视器程序,我确认这是IDL的bug:如果用VC等其他语言调用IDL绘图,IDL并不能通过IDLgrClipboard对象将绘图结果保存到系统剪贴板(而在IDL的编辑器环境下运行,剪贴板是能得到绘图结果的)。
下面是英文描述:
IDLgrClipboard not works in callable mode (I use VC++ to execute IDL procedure to draw some plots, and copy the result to system clipboard). After running a system-clipboard-viewer-tool, I conclude it must be a bug (I tested with IDL6.2, IDL7.0).

It works well under IDL-workbench, but when call from VC++, everything else goes OK except clipboard is empty.

解决办法:只好制定FILENAME参数,将结果保存到文件:
Finally, I have no choise but to save the drawing to a file, and it works:

[原] 自定义IDL调色板指南

IDL的调色板功能很好很强大,以至于我还没琢磨透到底怎么调。。。。

不过一般都是用自己定义的调色板,就讲讲怎么往IDL里加入自己的调色板:
(加了以后在系统内LOADCT的时候,就能直接读取自定义的调色板,非常方便)

IDL提供了 MODIFYCT 命令用来更改或加入系统的预定义调色板:

Itab是索引值,0-40是系统的,一般都要41开始
Name是命名,32个字符内
R、G、B就是256长度的BYTE(单字节正数)数组
File是文件名,如果不制定就操作默认的(resouce目录的color1.tbl)

实际发现File指定了其他文件名,MODIFYCT会出错。看了源码,发现
MODIFYCT并没有处理文件读取错误(不存在)的异常。(不知道是不是IDL7.0的问题)

IDL也没有公开colortable的文件格式。不过我把MODIFYCT的源码结合color1.tbl
分析了一下,得到IDL的colortable文件格式:

总数 + R 256 + G 256 + B 256 + …. + 32长度名称(在文件末尾)

例(如果有两个表):[2][R..R][G..G][B..B][R..R][G..G][B..B][名称1][名称2]

这样就可以自己输出调色板文件了,不需要用IDL的默认文件(防止多用户冲突)。
之后可以用 LOADCT, 0, FILE=’mytable.tbl’ 动态载入

附C语言输出调色板文件代码:

[原] IDL的数组存储是行顺序,下标引用是列在前

IDL的数组在内存中存储还是以行顺序的,只是多维下标引用的时候列为先。即:

A=
[r r r]
[g g g]
[b b b]

在内存中是 rrrgggbbb(和C是一样的!fortran是rgbrgbrgb)

而引用的时候列在前:(C是行在前!)

A[0,0] A[1,0] A[2,0]
A[0,1] A[1,1] A[2,1]
A[0,2] A[1,2] A[2,2]

三维的情况和C也一样(注意,IDL和C唯一的差别就是IDL的下标列在前,然后是行);存储结构一致也就意味着C里的多维数组内存块可以直接丢到IDL里处理。其实我觉得IDL在下标上太小白了,干嘛不和C保持一致?某IDL大牛说:之所以下标在前,是为了更直观的知道X方向上有几个、Y方向上有几个。比如:A[3, 2],X方向有3个,Y方向有2个(2行3列):Is IDL column-major or row-major?

某本书(似乎国内的书都不认真写 – -)说IDL是列顺序的,这是不对的。可以拿三维数据做简单试验(也便于对下标引用理解):

[原] IDL 7.0测试截图

IDL的功能非常强大(尤其是画三维图上,等我文章出来再帖过),支持多操作系统。
Grads可以实现的IDL都能实现,IDL能实现的Grads不一定能。
只不过我们系里熟悉Grads的多一些,如果想用IDL,可能自己要多费点力气。
IDL7.0的编辑器基于eclipse,如果写过java的应该非常熟悉这个编辑器。比IDL6自带的编辑器好多了,确实非常方便。
下面是我简单的测试截图(为了图小一点,编辑器拖得比较小):

Splash画面:
idl_0.jpg
欢迎画面:
idl_1.jpg
编辑器(有语法提示,按F1可在IDE里嵌入帮助,见下图):
idl_2.jpg
测试plot(右侧是嵌入的帮助)。中间是plot的默认结果,支持很多参数,效果可以改:
idl_3.jpg

[转]ENVI使用小技巧:如何在“快速制图”中正常显示经纬度格网字体?

由于中国用户使用的基本上全部是中文系统,所以在进行“快速制图”操作过程中会出现经纬度格网字体不能正常显示(经纬度符号显示为“?”)。
通过以下操作可以解决这个问题:
方法一:通过修改“envi. cfg”文件解决
1. 找到ENVI的安装目录下的“envi. cfg”文件,并以记事本的方式打开。路径为:\\RSI\IDL*\products\envi*\menu。
2. 将“DEGREE SYMBOL = 32”拷到envi. Cfg文件中。
3. 重新启动ENVI即可。
方法二:直接在“快速制图”中修改
1. 启动ENVI。
2. 通过“File -> Open Image File’ dialog”选择ENVI自带的实例数据“bhtmref.img
3. 将波段1、2、3分别赋给红、绿、蓝通道,彩色合成显示在ENVI主图像窗口中选择“File -> QuickMap -> New QuickMap…”打开“快速制图”工具。
4. 在“Default QuickMap Layout”对话框中点击“OK”选取默认值。
5. 在“QuickMap Image Selection”对话框中点击“OK”选择全部图像。
6. 在“QuickMap Parameters”对话框中,将“Gridlines”项的“Font”通过下拉列表重新选择为“Hershey Font-> Roman1”即可。点击“Apply”,查看经纬度格网字体已经可以被正常显示。