private void startConvertingNextFile() { //skip conversion if output file already exists if (File.Exists(filesToConvert[conversionFilesConverted].outputFilename) == true && conversionSkipAlreadyConvertedFiles == true) { string ENVIFileNameOnly = Path.GetFileName(filesToConvert[conversionFilesConverted].outputFilename); printNotification(ENVIFileNameOnly + " already exists. Skipping."); bw_FileConversionComplete(); //can't work on this file, so mark as finished return; } //skip conversion if IMD file cannot be found string NITFFileNameOnly = Path.GetFileName(filesToConvert[conversionFilesConverted].NITFFilename); if (File.Exists(filesToConvert[conversionFilesConverted].IMDTarFilename) == false) { printNotification("No IMD/Tar file for " + NITFFileNameOnly + ". Skipping.", Color.Red); bw_FileConversionComplete(); //can't work on this file, so mark as finished return; } //everything ok to start conversion of the next file printNotification("Converting " + NITFFileNameOnly); //set parameters to pass to converter WVConversionSettings conversionSettings = new WVConversionSettings(); conversionSettings.inputNITFFilename = filesToConvert[conversionFilesConverted].NITFFilename; conversionSettings.inputIMDTarFilename = filesToConvert[conversionFilesConverted].IMDTarFilename; conversionSettings.outputFilename = filesToConvert[conversionFilesConverted].outputFilename; conversionSettings.outputType = conversionOutputDataType; conversionSettings.scaleFactor = conversionOutputScaleFactor; conversionSettings.applyFineTuningCal = conversionApplyFineTuningCal; //convert the file convertNITFToENVI(conversionSettings); }
public static void CalibrateImage(WVConversionSettings conversionSettings) { string inputFilename = conversionSettings.inputNITFFilename; string inputIMDFilename = conversionSettings.inputIMDTarFilename; string outputFilename = conversionSettings.outputFilename; string outputHeaderFilename = outputFilename + ".hdr"; DataType outputType = conversionSettings.outputType; double scaleFactor = conversionSettings.scaleFactor; //open the input file Dataset ds = Gdal.Open(inputFilename, Access.GA_ReadOnly); if (ds == null) { throw new Exception("Can't open " + inputFilename); //stop if file could not be opened properly } //get GDAL driver for this file type Driver drv = ds.GetDriver(); if (drv == null) { throw new Exception("Can't get driver for reading."); //stop if driver could not be found for this file } //get image raster info // GDAL reads image in blocks, so get their size & how many int width = ds.RasterXSize; int height = ds.RasterYSize; int nBands = ds.RasterCount; int blockXSize, blockYSize; ds.GetRasterBand(1).GetBlockSize(out blockXSize, out blockYSize); int nImageXBlocks = (int)Math.Ceiling((double)width / blockXSize); int nImageYBlocks = (int)Math.Ceiling((double)height / blockYSize); DataType inputDataType = ds.GetRasterBand(1).DataType; int bytesPerSample = getBytesInSampleType(inputDataType); //note on cache size // default cache size is ~41MB // read buffer must be less than cache size for improved speed // appears that gdal can read images using multi-threading with 1 core decoding each block. // This works well as long as all currently needed blocks fit within the cache. // all bands for a block appear to be decoded at once // reading by block appears better because if we barely overrun the GDAL cache size the time doubles, // whereas if reading by row all blocks intersecting the row must be read every time a row is read (far slower) //set GDAL cache to encompass one row of image blocks for all bands (plus a little extra) OSGeo.GDAL.Gdal.SetCacheMax(nImageXBlocks * blockXSize * blockYSize * nBands * bytesPerSample + 50000000); //parse band info from IMD file string IMDTarFilename = inputIMDFilename; string[] IMDLines; if (IMDTarFilename.Substring(IMDTarFilename.Length - 4, 4).ToLower().Equals(".imd")) { IMDLines = File.ReadAllLines(IMDTarFilename); } else { IMDLines = Regex.Split(TarFileExtraction.getIMDFromTar(IMDTarFilename), "\r\n|\r|\n"); } BandInfo[] bandInfos = parseBandInfoFromIMD(IMDLines); //fine-tuning calibration info double[] fineTuneGains = new double[bandInfos.Length]; double[] fineTuneOffsets = new double[bandInfos.Length]; //set default values to make no changes for (int i = 0; i < bandInfos.Length; i++) { fineTuneGains[i] = 1; } //get fine-tune info if specified if (conversionSettings.applyFineTuningCal == true) { getFineTuneFactors(bandInfos, fineTuneGains, fineTuneOffsets); } //create new envi header file createENVIHeader(outputHeaderFilename, inputFilename, ds, bandInfos, outputType, scaleFactor); BinaryWriter bw = new BinaryWriter(new FileStream(outputFilename, FileMode.Create)); //report start of work if (conversionSettings.worker != null) { conversionSettings.worker.ReportProgress(0); } //convert images one row of blocks at a time int bytesPerOutputSample = getBytesInSampleType(outputType); for (int ys = 0; ys < nImageYBlocks; ys++) { //allocate buffer to store one band of data for one block row int rowHeight = (ys < nImageYBlocks - 1) ? blockYSize : (height - ys * blockYSize); byte[] inputBuffer = new byte[width * rowHeight * bytesPerSample]; double[][] dBuffer = new double[rowHeight][]; byte[] outputBuffer = new byte[width * rowHeight * bytesPerOutputSample]; for (int band = 1; band <= nBands; band++) { //read data System.Runtime.InteropServices.GCHandle handle = System.Runtime.InteropServices.GCHandle.Alloc(inputBuffer, System.Runtime.InteropServices.GCHandleType.Pinned); IntPtr pointer = handle.AddrOfPinnedObject(); ds.GetRasterBand(band).ReadRaster(0, ys * blockYSize, width, rowHeight, pointer, width, rowHeight, ds.GetRasterBand(1).DataType, 0, 0); handle.Free(); //convert raw input data to double precision for (int y = 0; y < rowHeight; y++) { dBuffer[y] = new double[width]; } convertByteArrayToDouble2D(dBuffer, inputBuffer, inputDataType); //calibrate for (int y = 0; y < rowHeight; y++) { for (int x = 0; x < width; x++) { dBuffer[y][x] = (fineTuneGains[band - 1] * dBuffer[y][x] * (bandInfos[band - 1].absCalFactor / bandInfos[band - 1].effectiveBandwidth) + fineTuneOffsets[band - 1]) / 10 * scaleFactor; } } //convert calibrated info to output data type convertDouble2DToByteArray(dBuffer, outputBuffer, outputType); //save calibrated data to output file long bToIndex = ((long)(band - 1) * width * height + ys * blockYSize * width + 0) * bytesPerOutputSample; bw.Flush(); bw.BaseStream.Seek(bToIndex, SeekOrigin.Begin); bw.Write(outputBuffer); //stop processing if work cancelled if (conversionSettings.worker != null && conversionSettings.worker.CancellationPending == true) { //stop writing to the file bw.Close(); //try to delete incomplete output files File.Delete(outputFilename); File.Delete(outputHeaderFilename); //stop processing return; } //report progress if (conversionSettings.worker != null) { conversionSettings.worker.ReportProgress((int)(((double)ys * nBands + band - 1 + 1) / (nImageYBlocks * nBands) * 100)); } } } //close output file bw.Close(); }
//BACKGROUND THREAD HANDLING //starts background thread to work on conversion private void convertNITFToENVI(WVConversionSettings conversionSettings) { conversionSettings.worker = bw; bw.RunWorkerAsync(conversionSettings); }
//parse inputs and attempt conversion of a file private static void runConvertCommand(Lookup <string, CommandArgField> lup) { //parse required input parameters string inputFilename = lup["-input"].ToArray()[0].parameters[0]; string outputFilename = lup["-output"].ToArray()[0].parameters[0]; //parse optional input parameters int outputdatatype = (lup.Contains("-outputdatatype") == true) ? int.Parse(lup["-outputdatatype"].ToArray()[0].parameters[0]) : 12; DataType outputType; if (outputdatatype == 4) { outputType = DataType.GDT_Float32; } else if (outputdatatype == 12) { outputType = DataType.GDT_UInt16; } else { throw new Exception("Unhandled output type. Only 4 (Float32) and 12 (UInt16) supported."); } double scaleFactor = (lup.Contains("-scalefactor") == true) ? double.Parse(lup["-scalefactor"].ToArray()[0].parameters[0]) : 1; string imdFilename; if (lup.Contains("-imd") == true) { imdFilename = lup["-imd"].ToArray()[0].parameters[0]; } else { imdFilename = Path.GetDirectoryName(inputFilename) + "\\" + Path.GetFileNameWithoutExtension(inputFilename) + ".imd"; if (File.Exists(imdFilename) == false) { imdFilename = Path.GetDirectoryName(inputFilename) + "\\" + Path.GetFileNameWithoutExtension(inputFilename) + ".tar"; } } bool applyFineTuningCal = (lup.Contains("-applyfinetuningcalibration") == true) ? bool.Parse(lup["-applyfinetuningcalibration"].ToArray()[0].parameters[0]) : true; //setup background processing thread handler BackgroundWorker bw = new BackgroundWorker(); bw.WorkerReportsProgress = true; bw.WorkerSupportsCancellation = true; bw.DoWork += new DoWorkEventHandler(bw_DoWork); bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged); //set parameters to pass to converter WVConversionSettings conversionSettings = new WVConversionSettings(); conversionSettings.inputNITFFilename = inputFilename; conversionSettings.inputIMDTarFilename = imdFilename; conversionSettings.outputFilename = outputFilename; conversionSettings.outputType = outputType; conversionSettings.scaleFactor = scaleFactor; conversionSettings.applyFineTuningCal = applyFineTuningCal; conversionSettings.worker = bw; //start calibration in the background thread bw.RunWorkerAsync(conversionSettings); //wait for background processing to finish while (bw.IsBusy == true) { Thread.Sleep(100); } }