diff --git a/StkAutomation/Python/General_Utilities/README.md b/StkAutomation/Python/General_Utilities/README.md index 7574ca81..8aaf16ba 100644 --- a/StkAutomation/Python/General_Utilities/README.md +++ b/StkAutomation/Python/General_Utilities/README.md @@ -220,3 +220,17 @@ This script reformats the data exported from AEDT HFSS into a *.rcs file. STK ca * Licenses: N/A * Other Scripts: N/A * Scenario: N/A + +--- + +## [applyMinElevation2StkAzElMask.py](applyMinElevation2StkAzElMask.py) + +This script takes an STK-generated Az/El mask file (*.aem) and applies a minimum elevation angle to it. Any az/el pairs that have an elevation lower than the minEl input value shall be set to minEl. The resulting Az/El mask file is then written to a new *.aem file. + +### Dependencies + +* Licenses: N/A +* Other Scripts: N/A +* Scenario: N/A + +--- \ No newline at end of file diff --git a/StkAutomation/Python/General_Utilities/applyMinElevation2StkAzElMask.py b/StkAutomation/Python/General_Utilities/applyMinElevation2StkAzElMask.py new file mode 100644 index 00000000..339be784 --- /dev/null +++ b/StkAutomation/Python/General_Utilities/applyMinElevation2StkAzElMask.py @@ -0,0 +1,53 @@ +""" +This script takes an STK-generated Az/El mask file (*.aem) and applies +a minimum elevation angle to it. Any az/el pairs that have an elevation +lower than the minEl input value shall be set to minEl. The resulting +Az/El mask file is then written to a new *.aem file. +""" + +inFilePath = 'Facility1.aem' +outFilePath = 'Facility1_modified.aem' +minEl = 5.0 # deg + +readingData = False +with open(inFilePath, 'r') as inFile: + # Read input STK AEM file + inFileList = list(inFile) + + with open(outFilePath, 'w') as outFile: + # Write output header + i = 0 + while len(inFileList[i].strip().split()) != 3: + outFile.write(inFileList[i]) + i+=1 + + # Begin writing data + while i < len(inFileList): + # Read azimuth block header + azimuth = float(inFileList[i].strip().split()[0]) + azData = [] + i+=1 + + # Read azimuth block data + dataLine = inFileList[i].strip().split() + while len(dataLine) == 2: + el = float(dataLine[0]) + r = float(dataLine[1]) + # Handle case where terrain mask elevation is lower than minimum specified elevation + if el < minEl and (len(inFileList[i+1].strip().split()) == 0 or float(inFileList[i+1].strip().split()[0]) > minEl): + azData.append((minEl, r)) + # Handle case where terrain mask elevation is higher than minimum specified elevation + elif el > minEl: + azData.append((el, r)) + # Read next azimuth data line + i+=1 + dataLine = inFileList[i].strip().split() + + # Done parsing azimuth block, write azimuth header and data block to file + outFile.write(f'{azimuth} {azData[-1][0]} {len(azData)}\n') + for line in azData: + outFile.write(f'{line[0]} {line[1]}\n') + outFile.write('\n') + + # Next azimuth block to read + i+=1 \ No newline at end of file diff --git a/StkAutomation/Python/Scenario_Analysis/README.md b/StkAutomation/Python/Scenario_Analysis/README.md index cd1ffb3e..96f2d924 100644 --- a/StkAutomation/Python/Scenario_Analysis/README.md +++ b/StkAutomation/Python/Scenario_Analysis/README.md @@ -78,4 +78,16 @@ Currently the "Percent Satisfied" report for a voluemtric object in STK reports * Scenario: N/A * Third-Party Libraries: Numpy +--- + +## [eoirRawImages2Video](eoirRawImages2Video.py) + +This script will create a normalized video from a file directory containing *.txt raw sensor scenes from EOIR. Specify the folder containing raw sensor outputs, a normalized folder to place normalized images, and an output video name. The normalized video will be placed in the parent directory of the output folder for normalized images as an mp4 file. You can specify a desired gamma scaling and video FPS as well. + +### Dependencies + +* Licenses: N/A +* Other Scripts: N/A +* Scenario: N/A + --- \ No newline at end of file diff --git a/StkAutomation/Python/Scenario_Analysis/eoirRawImages2Video.py b/StkAutomation/Python/Scenario_Analysis/eoirRawImages2Video.py new file mode 100644 index 00000000..6990f4d0 --- /dev/null +++ b/StkAutomation/Python/Scenario_Analysis/eoirRawImages2Video.py @@ -0,0 +1,93 @@ +import glob +import os +import pandas as pd +import numpy as np +from PIL import Image +import cv2 + +def normalizeFrameSequence(inputFolder, outputFolder, k = 0.3): + # Suggested gamma encoding k + # Linear (k=1),Cubic Root(k=1/3), Square transformation(k=2) + # Linear just converts pixel counts to the range 0 to 255 + # Cubic Root suppresses the bright spots and enhances the dark spots + # Square suppresses the dark spots and enhances the bright spots + + # Get all raw files + os.chdir(inputFolder) + rawFiles = [] + for file in glob.glob("*.txt"): + rawFiles.append(file) + + # Get global min and max to normalize + globalMax = float('-inf') + for file in rawFiles: + print(f'Processing {file}') + with open(file, 'r') as f: + for line in f: + lineNums = [float(num) for num in line.split()] + globalMax = max(globalMax, max(lineNums)) + + # Set max bound with gamma encoding + os.chdir(outputFolder) + maxBound = globalMax ** k + for index, file in enumerate(rawFiles): + # Read image, then clip to 0, then apply gamma, then normalize, then write to file + print(f'Writing normalized {file}') + data = pd.read_csv(os.path.join(inputFolder, file), sep= '\\s+', header=None).clip(lower=0) ** k + normalizedData = data/maxBound*255 # Max value of 255 for uint8 + imageArray = normalizedData.values.astype(np.uint8) + image = Image.fromarray(imageArray) + image.save(f'normalizedFrame_{index:06d}.jpg') + +def images2Video(imageFolder, videoName, fps): + # Get video frames + os.chdir(imageFolder) + files = [] + for file in os.listdir("."): + files.append(file) + numImages = len(files) + + # Find mean image size to resize + print('Computing video frame size') + mean_width = 0 + mean_height = 0 + for file in files: + im = Image.open(file) + width, height = im.size + mean_width += width + mean_height += height + mean_width = int(mean_width / numImages) + mean_height = int(mean_height / numImages) + + # Must resize to consistent size for cv2 video writer + print('Resizing images') + for file in files: + im = Image.open(file) + imResize = im.resize((mean_width, mean_height), Image.Resampling.LANCZOS) + imResize.save(file) + + # Write video + print('Writing video') + frame = cv2.imread(files[0]) + height, width, _ = frame.shape + video = cv2.VideoWriter(os.path.join(os.path.dirname(imageFolder), videoName+'.mp4'), cv2.VideoWriter.fourcc(*'avc1'), fps, (width, height)) + for file in files: + print(file) + video.write(cv2.imread(file)) + cv2.destroyAllWindows() + video.release() + +def main(): + # INPUTS + rawFolder = 'C:\\RAW' + normalizedFolder = 'C:\\Compressed' + videoName = 'EOIR_Video' + fps = 10 + + # Run + normalizeFrameSequence(rawFolder, normalizedFolder, k=1) + images2Video(normalizedFolder, videoName, fps) + print('Done') + +if __name__ == "__main__": + main() \ No newline at end of file