Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

264 linhas
8.1 KiB

  1. import os
  2. import argparse
  3. import lxml.etree as ET
  4. import subprocess
  5. import flirimageextractor
  6. import cv2
  7. import numpy as np
  8. from pathlib import Path
  9. from wand.image import Image
  10. from osgeo import gdal
  11. from osgeo import osr
  12. arg_parser = argparse.ArgumentParser(description='Export SVG composition of FLIR images as TIFF with thermo layer')
  13. arg_parser.add_argument('Input',
  14. metavar='input_svg',
  15. type=str,
  16. help='Path to the input SVG file cotaining xlinks to FLIR images')
  17. arg_parser.add_argument('Output',
  18. metavar='output_tiff',
  19. type=str,
  20. help='Output filename')
  21. args = arg_parser.parse_args()
  22. dirname = os.path.dirname(__file__)
  23. INPUT_PATH = os.path.join(dirname, args.Input)
  24. INPUT_DIR = os.path.split(INPUT_PATH)[0]
  25. TEMP_MAP_THERMALPNG_SVG_PATH = os.path.join(INPUT_DIR, 'map_thermalpng.svg')
  26. TEMP_MAP_THERMALPNG_PATH = os.path.join(INPUT_DIR, 'map_thermalpng.png')
  27. TEMP_MAP_PREVIEW_PATH = os.path.join(INPUT_DIR, 'map_preview.png')
  28. THERMALPNG_DIR = 'thermalpngs'
  29. OUTPUT_PATH = os.path.join(dirname, args.Output)
  30. def make_thermalpng_tiles():
  31. """
  32. Extract thermal infomration as greyscale PNG-16 (temp * 1000 to retain some decimals)
  33. and save the png tiles
  34. """
  35. Path(os.path.join(INPUT_DIR, THERMALPNG_DIR)).mkdir(parents=True, exist_ok=True)
  36. png_output_dir = os.path.join(INPUT_DIR, THERMALPNG_DIR)
  37. for root_path, directories, file in os.walk(os.path.join(dirname, INPUT_DIR)):
  38. for file in file:
  39. if(file.endswith(".jpg")):
  40. print('Extracting thermal info from ' + file)
  41. full_filepath = os.path.join(root_path, file)
  42. flir = flirimageextractor.FlirImageExtractor()
  43. flir.process_image(full_filepath)
  44. thermal_img_np = flir.thermal_image_np
  45. multiplied_image = cv2.multiply(thermal_img_np, 1000)
  46. output_file_path = os.path.join(png_output_dir, file + '.thermal.png')
  47. print(output_file_path)
  48. cv2.imwrite(output_file_path, multiplied_image.astype(np.uint16))
  49. def make_thermalpng_svg():
  50. """
  51. replaces the image paths with the thermal pngs
  52. and creates new SVG file
  53. """
  54. # print("svg_file")
  55. # print(dir(svg_file))
  56. tree = ET.parse(INPUT_PATH)
  57. root = tree.getroot()
  58. # print(ET.tostring(root))
  59. # tile_rows = root.xpath('//image', namespaces={'n': "http://www.w3.org/2000/svg"})
  60. # print(dir(root))
  61. tile_elements = root.xpath('//*[@class="thermal_image"]')
  62. linkattrib ='{http://www.w3.org/1999/xlink}href'
  63. for tile in tile_elements:
  64. tile.attrib[linkattrib] = os.path.join(THERMALPNG_DIR, tile.attrib[linkattrib] + '.thermal.png')
  65. # newxml = ET.tostring(tree, encoding="unicode")
  66. # print(newxml)
  67. # return newxml
  68. with open(TEMP_MAP_THERMALPNG_SVG_PATH, 'wb') as f:
  69. tree.write(f, encoding='utf-8')
  70. return tree
  71. def make_thermalpng():
  72. """
  73. exports the SVG canvas as Gray_16 PNG
  74. """
  75. command = [
  76. '/snap/bin/inkscape',
  77. '--pipe',
  78. '--export-type=png',
  79. '--export-png-color-mode=Gray_16'
  80. ],
  81. input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb")
  82. output_file = open(TEMP_MAP_THERMALPNG_PATH, "wb")
  83. completed = subprocess.run(
  84. *command,
  85. cwd=INPUT_DIR, # needed for reative image links
  86. stdin=input_file,
  87. stdout=output_file
  88. )
  89. return completed
  90. def make_thermalpreview():
  91. """
  92. exports the preview image
  93. """
  94. command = [
  95. '/snap/bin/inkscape',
  96. '--pipe',
  97. '--export-type=png',
  98. '--export-png-color-mode=Gray_8'
  99. ],
  100. input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb")
  101. output_file = open(TEMP_MAP_PREVIEW_PATH, "wb")
  102. completed = subprocess.run(
  103. *command,
  104. cwd=INPUT_DIR, # needed for reative image links
  105. stdin=input_file,
  106. stdout=output_file
  107. )
  108. return completed
  109. # def make_thermalpreview():
  110. # """
  111. # exports the preview image
  112. # """
  113. # command = [
  114. # '/snap/bin/inkscape',
  115. # '--pipe',
  116. # '--export-type=png',
  117. # '--export-png-color-mode=Gray_8'
  118. # ]
  119. # input_file = open(TEMP_MAP_THERMALPNG_SVG_PATH, "rb")
  120. # output_file = open(TEMP_MAP_PREVIEW_PATH, "wb")
  121. # completed = subprocess.run(
  122. # *command,
  123. # cwd=INPUT_DIR, # needed for reative image links
  124. # stdin=input_file,
  125. # stdout=output_file
  126. # )
  127. # return completed
  128. def get_thermal_numpy_array():
  129. # input_file = open(TEMP_MAP_THERMALPNG_PATH, "rb")
  130. image = cv2.imread(TEMP_MAP_THERMALPNG_PATH, cv2.IMREAD_ANYDEPTH)
  131. image_float = image.astype(np.float32)
  132. image_float_normalized = cv2.divide(image_float, 1000)
  133. print(image_float_normalized[1000][905])
  134. # cv2.imshow("OpenCV Image Reading", image)
  135. return image_float_normalized
  136. def get_used_tiles_relpaths():
  137. """
  138. outputs an array of all used tile filenames in the input SVG
  139. (relative filepaths like they appear in the svg.)
  140. """
  141. images = []
  142. tree = ET.parse(INPUT_PATH)
  143. root = tree.getroot()
  144. tile_elements = root.xpath('//*[@class="thermal_image"]')
  145. linkattrib ='{http://www.w3.org/1999/xlink}href'
  146. for tile in tile_elements:
  147. images.append(tile.attrib[linkattrib])
  148. return images
  149. def deg_coordinates_to_decimal(coordStr):
  150. coordArr = coordStr.split(', ')
  151. calculatedCoordArray = []
  152. for calculation in coordArr:
  153. calculationArr = calculation.split('/')
  154. calculatedCoordArray.append(int(calculationArr[0]) / int(calculationArr[1]))
  155. degrees = calculatedCoordArray[0]
  156. minutes = calculatedCoordArray[1]
  157. seconds = calculatedCoordArray[2]
  158. decimal = (degrees + (minutes * 1/60) + (seconds * 1/60 * 1/60))
  159. # print(decimal)
  160. return decimal
  161. def read_coordinates_from_tile(filename):
  162. full_filepath = os.path.join(INPUT_DIR, filename)
  163. with Image(filename=full_filepath) as image:
  164. for key, value in image.metadata.items():
  165. if key == 'exif:GPSLatitude':
  166. # print('latstr', value)
  167. lat = deg_coordinates_to_decimal(value) # lat -> Y vertical
  168. if key == 'exif:GPSLongitude':
  169. # print('lonstr', value)
  170. lon = deg_coordinates_to_decimal(value) # lon -> X horizontal
  171. if key == 'exif:GPSImgDirection':
  172. direction = value.split('/')
  173. print(int(direction[0])/int(direction[1])/2, ' ', (value))
  174. return [lat, lon]
  175. def get_coordinate_boundaries():
  176. image_names = get_used_tiles_relpaths()
  177. coordinates = {
  178. 'lat': [],
  179. 'lon': []
  180. }
  181. for filename in image_names:
  182. tile_coordinates = read_coordinates_from_tile(filename)
  183. coordinates['lat'].append(tile_coordinates[0])
  184. coordinates['lon'].append(tile_coordinates[1])
  185. boundaries = {
  186. 'xmin': min(coordinates['lon']),
  187. 'xmax': max(coordinates['lon']),
  188. 'ymin': min(coordinates['lat']),
  189. 'ymax': max(coordinates['lat']),
  190. }
  191. return boundaries
  192. def make_geotiff_image():
  193. thermal_numpy_array = get_thermal_numpy_array()
  194. # coordinates of all tiles
  195. geo_bound = get_coordinate_boundaries()
  196. print('boundaries', geo_bound)
  197. np_shape = thermal_numpy_array.shape
  198. image_size = (np_shape[0], np_shape[1])
  199. # set geotransform
  200. nx = image_size[0]
  201. ny = image_size[1]
  202. xres = (geo_bound['xmax'] - geo_bound['xmin']) / float(nx)
  203. yres = (geo_bound['ymax'] - geo_bound['ymin']) / float(ny)
  204. geotransform = (geo_bound['xmin'], xres, 0, geo_bound['ymax'], 0, -yres)
  205. # create the 3-band raster file
  206. dst_ds = gdal.GetDriverByName('GTiff').Create(OUTPUT_PATH, ny, nx, 1, gdal.GDT_Float32)
  207. dst_ds.SetGeoTransform(geotransform) # specify coords
  208. srs = osr.SpatialReference() # establish encoding
  209. res = srs.SetWellKnownGeogCS( "WGS84" ) # WGS84 lat/long
  210. dst_ds.SetProjection(srs.ExportToWkt()) # export coords to file
  211. dst_ds.GetRasterBand(1).WriteArray(thermal_numpy_array) # write thermal-band to the raster
  212. dst_ds.FlushCache() # write to disk
  213. # make_thermalpng_tiles()
  214. # make_thermalpng_svg()
  215. # make_thermalpreview()
  216. # make_thermalpng()
  217. make_geotiff_image()
  218. # dataset = gdal.Open("working_result_example.tif", gdal.GA_ReadOnly)
  219. # print(dir(dataset))
  220. # print(dataset.GetMetadata_List())