i.oif.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: i.oif
  5. # AUTHOR(S): Markus Neteler 21.July 1998
  6. # Updated for GRASS 5.7 by Michael Barton 2004/04/05
  7. # Converted to Python by Glynn Clements
  8. # Customised by Nikos Alexandris 04. August 2013
  9. # Customised by Luca Delucchi Vienna Code Sprint 2014
  10. # PURPOSE: calculates the Optimum Index factor of all band combinations
  11. # for LANDSAT TM 1,2,3,4,5,7
  12. # COPYRIGHT: (C) 1999,2008 by the GRASS Development Team
  13. #
  14. # This program is free software under the GNU General Public
  15. # License (>=v2). Read the file COPYING that comes with GRASS
  16. # for details.
  17. #
  18. # Ref.: Jensen: Introductory digital image processing 1996, p.98
  19. #############################################################################
  20. #% Module
  21. #% description: Calculates Optimum-Index-Factor table for spectral bands
  22. #% keyword: imagery
  23. #% keyword: multispectral
  24. #% keyword: statistics
  25. #% End
  26. #% option G_OPT_R_INPUTS
  27. #% end
  28. #% option G_OPT_F_OUTPUT
  29. #% description: Name for output file (if omitted or "-" output to stdout)
  30. #% required: no
  31. #% end
  32. #% Flag
  33. #% key: g
  34. #% description: Print in shell script style
  35. #% End
  36. #% Flag
  37. #% key: s
  38. #% description: Process bands serially (default: run in parallel)
  39. #% End
  40. import sys
  41. import os
  42. from grass.script.utils import parse_key_val
  43. from grass.script import core as grass
  44. # i18N
  45. import gettext
  46. gettext.install('grassmods', os.path.join(os.getenv("GISBASE"), 'locale'))
  47. def oifcalc(sdev, corr, k1, k2, k3):
  48. grass.debug(_("Calculating OIF for combination: %s, %s, %s" % (k1, k2,
  49. k3)), 1)
  50. # calculate SUM of Stddeviations:
  51. ssdev = [sdev[k1], sdev[k2], sdev[k3]]
  52. numer = sum(ssdev)
  53. # calculate SUM of absolute(Correlation values):
  54. scorr = [corr[k1, k2], corr[k1, k3], corr[k2, k3]]
  55. denom = sum(map(abs, scorr))
  56. # Calculate OIF index:
  57. # Divide (SUM of Stddeviations) and (SUM of Correlation)
  58. return numer / denom
  59. def perms(bands):
  60. n = len(bands)
  61. for i in range(0, n - 2):
  62. for j in range(i + 1, n - 1):
  63. for k in range(j + 1, n):
  64. yield (bands[i], bands[j], bands[k])
  65. def main():
  66. shell = flags['g']
  67. serial = flags['s']
  68. bands = options['input'].split(',')
  69. if len(bands) < 4:
  70. grass.fatal(_("At least four input maps required"))
  71. output = options['output']
  72. # calculate the Stddev for TM bands
  73. grass.message(_("Calculating standard deviations for all bands..."))
  74. stddev = {}
  75. if serial:
  76. for band in bands:
  77. grass.verbose("band %d" % band)
  78. s = grass.read_command('r.univar', flags='g', map=band)
  79. kv = parse_key_val(s)
  80. stddev[band] = float(kv['stddev'])
  81. else:
  82. # run all bands in parallel
  83. if "WORKERS" in os.environ:
  84. workers = int(os.environ["WORKERS"])
  85. else:
  86. workers = len(bands)
  87. proc = {}
  88. pout = {}
  89. # spawn jobs in the background
  90. n = 0
  91. for band in bands:
  92. proc[band] = grass.pipe_command('r.univar', flags='g', map=band)
  93. if n % workers is 0:
  94. # wait for the ones launched so far to finish
  95. for bandp in bands[:n]:
  96. if not proc[bandp].stdout.closed:
  97. pout[bandp] = proc[bandp].communicate()[0]
  98. proc[bandp].wait()
  99. n = n + 1
  100. # wait for jobs to finish, collect the output
  101. for band in bands:
  102. if not proc[band].stdout.closed:
  103. pout[band] = proc[band].communicate()[0]
  104. proc[band].wait()
  105. # parse the results
  106. for band in bands:
  107. kv = parse_key_val(pout[band])
  108. stddev[band] = float(kv['stddev'])
  109. grass.message(_("Calculating Correlation Matrix..."))
  110. correlation = {}
  111. s = grass.read_command('r.covar', flags='r', map=[band for band in bands],
  112. quiet=True)
  113. # We need to skip the first line, since r.covar prints the number of values
  114. lines = s.splitlines()
  115. for i, row in zip(bands, lines[1:]):
  116. for j, cell in zip(bands, row.split(' ')):
  117. correlation[i, j] = float(cell)
  118. # Calculate all combinations
  119. grass.message(_("Calculating OIF for all band combinations..."))
  120. oif = []
  121. for p in perms(bands):
  122. oif.append((oifcalc(stddev, correlation, *p), p))
  123. oif.sort(reverse=True)
  124. grass.verbose(_("The Optimum Index Factor analysis result "
  125. "(best combination shown first):"))
  126. if shell:
  127. fmt = "%s,%s,%s:%.4f\n"
  128. else:
  129. fmt = "%s, %s, %s: %.4f\n"
  130. if not output or output == '-':
  131. for v, p in oif:
  132. sys.stdout.write(fmt % (p + (v,)))
  133. else:
  134. outf = open(output, 'w')
  135. for v, p in oif:
  136. outf.write(fmt % (p + (v,)))
  137. outf.close()
  138. if __name__ == "__main__":
  139. options, flags = grass.parser()
  140. main()