i.colors.enhance.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #!/usr/bin/env python
  2. ############################################################################
  3. #
  4. # MODULE: i.colors.enhance (former i.landsat.rgb)
  5. #
  6. # AUTHOR(S): Markus Neteler, original author
  7. # Hamish Bowman, scripting enhancements
  8. # Converted to Python by Glynn Clements
  9. #
  10. # PURPOSE: create pretty RGBs: the trick is to remove outliers
  11. # using percentiles (area under the histogram curve)
  12. #
  13. # COPYRIGHT: (C) 2006, 2008, 2012-2014 by the GRASS Development Team
  14. #
  15. # This program is free software under the GNU General Public
  16. # License (>=v2). Read the file COPYING that comes with GRASS
  17. # for details.
  18. #
  19. # TODO: implement better brightness control
  20. #############################################################################
  21. #%module
  22. #% description: Performs auto-balancing of colors for RGB images.
  23. #% keyword: imagery
  24. #% keyword: RGB
  25. #% keyword: satellite
  26. #% keyword: colors
  27. #%end
  28. #%option G_OPT_R_INPUT
  29. #% key: red
  30. #% description: Name of red channel
  31. #%end
  32. #%option G_OPT_R_INPUT
  33. #% key: green
  34. #% description: Name of green channel
  35. #%end
  36. #%option G_OPT_R_INPUT
  37. #% key: blue
  38. #% description: Name of blue channel
  39. #%end
  40. #%option
  41. #% key: strength
  42. #% type: double
  43. #% description: Cropping intensity (upper brightness level)
  44. #% options: 0-100
  45. #% answer : 98
  46. #% required: no
  47. #%end
  48. #%flag
  49. #% key: f
  50. #% description: Extend colors to full range of data on each channel
  51. #% guisection: Colors
  52. #%end
  53. #%flag
  54. #% key: p
  55. #% description: Preserve relative colors, adjust brightness only
  56. #% guisection: Colors
  57. #%end
  58. #%flag
  59. #% key: r
  60. #% description: Reset to standard color range
  61. #% guisection: Colors
  62. #%end
  63. #%flag
  64. #% key: s
  65. #% description: Process bands serially (default: run in parallel)
  66. #%end
  67. import sys
  68. import grass.script as gscript
  69. from grass.pygrass.raster import RasterRow
  70. # i18N
  71. import os
  72. import gettext
  73. gettext.install('grassmods', os.path.join(os.getenv("GISBASE"), 'locale'))
  74. try:
  75. # new for python 2.6, in 2.5 it may be easy_install'd.
  76. import multiprocessing as mp
  77. do_mp = True
  78. except:
  79. do_mp = False
  80. def get_percentile(map, percentiles):
  81. # todo: generalize for any list length
  82. val1 = percentiles[0]
  83. val2 = percentiles[1]
  84. values = '%s,%s' % (val1, val2)
  85. s = gscript.read_command('r.quantile', input=map,
  86. percentiles=values, quiet=True)
  87. val_str1 = s.splitlines()[0].split(':')[2]
  88. val_str2 = s.splitlines()[1].split(':')[2]
  89. return (float(val_str1), float(val_str2))
  90. # wrapper to handle multiprocesses communications back to the parent
  91. def get_percentile_mp(map, percentiles, conn):
  92. # Process() doesn't like storing connection parts in
  93. # separate dictionaries, only wants to pass through tuples,
  94. # so instead of just sending the sending the pipe we have to
  95. # send both parts then keep the one we want. ??
  96. output_pipe, input_pipe = conn
  97. input_pipe.close()
  98. result = get_percentile(map, percentiles)
  99. gscript.debug('child (%s) (%.1f, %.1f)' % (map, result[0], result[1]))
  100. output_pipe.send(result)
  101. output_pipe.close()
  102. def set_colors(map, v0, v1):
  103. rules = ''.join(["0% black\n", "%f black\n" % v0,
  104. "%f white\n" % v1, "100% white\n"])
  105. gscript.write_command('r.colors', map=map, rules='-', stdin=rules,
  106. quiet=True)
  107. def main():
  108. red = options['red']
  109. green = options['green']
  110. blue = options['blue']
  111. brightness = options['strength']
  112. full = flags['f']
  113. preserve = flags['p']
  114. reset = flags['r']
  115. global do_mp
  116. if flags['s']:
  117. do_mp = False
  118. check = True
  119. for m in [red, green, blue]:
  120. if not RasterRow(m).exist():
  121. check = False
  122. gscript.warning("Raster map <{}> not found ".format(m))
  123. if not check:
  124. gscript.fatal("At least one of the input raster map was not found")
  125. # 90 or 98? MAX value controls brightness
  126. # think of percent (0-100), must be positive or 0
  127. # must be more than "2" ?
  128. if full:
  129. for i in [red, green, blue]:
  130. gscript.run_command('r.colors', map=i, color='grey', quiet=True)
  131. sys.exit(0)
  132. if reset:
  133. for i in [red, green, blue]:
  134. gscript.run_command('r.colors', map=i, color='grey255', quiet=True)
  135. sys.exit(0)
  136. if not preserve:
  137. if do_mp:
  138. gscript.message(_("Processing..."))
  139. # set up jobs and launch them
  140. proc = {}
  141. conn = {}
  142. for i in [red, green, blue]:
  143. conn[i] = mp.Pipe()
  144. proc[i] = mp.Process(target=get_percentile_mp,
  145. args=(i, ['2', brightness],
  146. conn[i],))
  147. proc[i].start()
  148. gscript.percent(1, 2, 1)
  149. # collect results and wait for jobs to finish
  150. for i in [red, green, blue]:
  151. output_pipe, input_pipe = conn[i]
  152. (v0, v1) = input_pipe.recv()
  153. gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1))
  154. input_pipe.close()
  155. proc[i].join()
  156. set_colors(i, v0, v1)
  157. gscript.percent(1, 1, 1)
  158. else:
  159. for i in [red, green, blue]:
  160. gscript.message(_("Processing..."))
  161. (v0, v1) = get_percentile(i, ['2', brightness])
  162. gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1))
  163. set_colors(i, v0, v1)
  164. else:
  165. all_max = 0
  166. all_min = 999999
  167. if do_mp:
  168. gscript.message(_("Processing..."))
  169. # set up jobs and launch jobs
  170. proc = {}
  171. conn = {}
  172. for i in [red, green, blue]:
  173. conn[i] = mp.Pipe()
  174. proc[i] = mp.Process(target=get_percentile_mp,
  175. args=(i, ['2', brightness],
  176. conn[i],))
  177. proc[i].start()
  178. gscript.percent(1, 2, 1)
  179. # collect results and wait for jobs to finish
  180. for i in [red, green, blue]:
  181. output_pipe, input_pipe = conn[i]
  182. (v0, v1) = input_pipe.recv()
  183. gscript.debug('parent (%s) (%.1f, %.1f)' % (i, v0, v1))
  184. input_pipe.close()
  185. proc[i].join()
  186. all_min = min(all_min, v0)
  187. all_max = max(all_max, v1)
  188. gscript.percent(1, 1, 1)
  189. else:
  190. for i in [red, green, blue]:
  191. gscript.message(_("Processing..."))
  192. (v0, v1) = get_percentile(i, ['2', brightness])
  193. gscript.debug("<%s>: min=%f max=%f" % (i, v0, v1))
  194. all_min = min(all_min, v0)
  195. all_max = max(all_max, v1)
  196. gscript.debug("all_min=%f all_max=%f" % (all_min, all_max))
  197. for i in [red, green, blue]:
  198. set_colors(i, all_min, all_max)
  199. # write cmd history:
  200. mapset = gscript.gisenv()['MAPSET']
  201. for i in [red, green, blue]:
  202. if gscript.find_file(i)['mapset'] == mapset:
  203. gscript.raster_history(i)
  204. if __name__ == "__main__":
  205. options, flags = gscript.parser()
  206. main()