private void BuildHeader(Header header, Exposure exposure, Dictionary<string, object> metadata, long maxValue) { // Set BZERO to half of bitness (32768 for 16-bit) header.AddValue("BZERO", 0.5 * maxValue, ""); header.AddValue("BSCALE", (double)1, ""); header.AddValue("DATAMIN", 0.0, ""); header.AddValue("DATAMAX", (double)exposure.MaxDepth, ""); header.AddValue("CBLACK", (double)exposure.PixelMinValue, ""); header.AddValue("CWHITE", (double)exposure.PixelMaxValue, ""); header.AddValue("SWCREATE", "DSImager", ""); if (metadata != null) { foreach (var entry in metadata) { if (entry.Value is int) header.AddValue(entry.Key, (int)entry.Value, ""); if (entry.Value is bool) header.AddValue(entry.Key, (bool)entry.Value, ""); if (entry.Value is double) header.AddValue(entry.Key, (double)entry.Value, ""); if (entry.Value is string) header.AddValue(entry.Key, (string)entry.Value, ""); if (entry.Value is long) header.AddValue(entry.Key, (long)entry.Value, ""); } } }
public void Save(Exposure exposure, string filename, Dictionary<string, object> metadata) { Fits fits = new Fits(); int[] dimensions = new[] { exposure.Height, exposure.Width }; // choose the type from calculating the bitness from the exposure maxdepth long a = 0, bits = -1; while (a < exposure.MaxDepth) a = (int)Math.Pow(2.0, ++bits); Array pixels; if (bits <= 16) { pixels = ConvertToShort(exposure.Pixels); } else { pixels = exposure.Pixels; } var data = ArrayFuncs.Curl(pixels, dimensions); var hdu = FitsFactory.HDUFactory(data); // Write the headers. BuildHeader(hdu.Header, exposure, metadata, a); fits.AddHDU(hdu); if (!filename.EndsWith(".fits")) filename += ".fits"; BufferedFile bf = new BufferedFile(filename, FileAccess.ReadWrite, FileShare.None); fits.Write(bf); bf.Close(); }
public void Save(Exposure exposure, string filename) { Save(exposure, filename, null); }
private void OnExposureCompleted(bool successful, Exposure exposure) { if (!ExposureVisualProcessingSettings.AutoStretch) { var min = ExposureVisualProcessingSettings.StretchMin; var max = ExposureVisualProcessingSettings.StretchMax; // No auto stretch, make sure we don't have initial conditions // (default min/max), if values are non-default then apply stretch. if (!(min == 0 && (max == -1 || max == exposure.MaxDepth))) { if (max == -1) max = exposure.MaxDepth; exposure.SetStretch(min, max); } } else { exposure.SetStretch(); } if (CurrentImagingSession != null && CurrentImagingSession.SaveOutput) { try { SaveExposureToDisk(exposure, CurrentImageSequence.FileFormat); } catch (Exception e) { _logService.LogMessage(new LogMessage(this, LogEventCategory.Error, "Unable to save exposure to disk! Exception raised: " + e.Message)); } } if (OnImagingComplete != null) OnImagingComplete(successful, exposure); }
private void SaveExposureToDisk(Exposure exposure, string format) { var ff = _imageIoService.WritableFileFormats.Where(wff => wff.Id == format).FirstOrDefault(); if(ff == null) throw new ArgumentException("File format '" + format + "' was invalid, no writer for that file format found.", "format"); var writer = _imageIoService.GetImageWriter(ff); var fname = CurrentImagingSession.GenerateFilename(CurrentImageSequence); var path = CurrentImagingSession.OutputDirectory; if (string.IsNullOrEmpty(path)) { if (!string.IsNullOrEmpty(_systemEnvironment.UserPicturesDirectory)) { path = Path.Combine(_systemEnvironment.UserPicturesDirectory, "DSImager-session-" + CurrentImagingSession.Name.ToFilenameString()); } else { path = Path.Combine(_systemEnvironment.UserHomeDirectory, "DSImager-session-" + CurrentImagingSession.Name.ToFilenameString()); } } if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } var filename = Path.Combine(path, fname); writer.Save(exposure, filename); _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, "Exposure saved to disk: " + filename)); }
private void HandleCanceledImagingOperation(bool successful, Exposure exposure) { // Canceling seems to leave the buffer in a questionable state: the next // frame is usually broken (tested on Atik 414EX). Therefore take one "garbage frame" // so that the next frame taken won't be a disappointment. _cameraService.OnExposureCompleted -= HandleCanceledImagingOperation; _cameraService.TakeExposure(0, true, true); }
/// <summary> /// Starts exposuring. /// No camera parameters given, ie. the Camera parameters must have already been set. /// ImagingService should do that part - this method just starts the exposure and /// runs an exposure cycle and handles the different states and such. /// </summary> /// <param name="duration">The exposure duration, in seconds</param> /// <param name="isCalibrationFrame">If the frame is a calibration frame, set to true</param> /// <param name="garbageFrame">If we consider this a "garbage frame", ie. this frame is taken for cleanup purposes. /// No events will be triggered by this frame.</param> /// <returns> /// Did exposuring succeed or fail. Note: upon stopping exposure, /// the return value is true (exposure data is still saved). Upon aborting, the value is false. /// </returns> public async Task<bool> TakeExposure(double duration, bool isCalibrationFrame = false, bool garbageFrame = false) { _isExposuring = true; if (garbageFrame) { _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, "Taking a cleanup frame")); } else _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, string.Format("Starting new exposure: {0:F}s", duration))); if (Camera.CameraState != CameraStates.cameraIdle) { _logService.LogMessage(new LogMessage(this, LogEventCategory.Warning, "Camera is not in idle state, unable to start a new exposure.")); return false; } var metadata = new ExposureMetaData() { BinX = Camera.BinX, BinY = Camera.BinY, ExposureTime = duration }; if (OnExposureStarted != null && !garbageFrame) OnExposureStarted(duration); Camera.StartExposure(duration, !isCalibrationFrame); if (OnExposureProgressChanged != null && !garbageFrame) OnExposureProgressChanged(0, duration, ExposurePhase.Exposuring); var startTime = DateTime.Now; TimeSpan currentDuration = TimeSpan.Zero; while (!Camera.ImageReady && (Camera.CameraState != CameraStates.cameraExposing || Camera.CameraState != CameraStates.cameraReading)) { await Task.Delay(200); currentDuration = DateTime.Now - startTime; if (OnExposureProgressChanged != null && !garbageFrame) OnExposureProgressChanged(currentDuration.TotalSeconds, duration, ExposurePhase.Exposuring); } // Done, download the image. if (Camera.ImageReady) { if (garbageFrame) { _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, "Cleanup frame taken")); _isExposuring = false; return true; } if (OnExposureProgressChanged != null) OnExposureProgressChanged(currentDuration.TotalSeconds, duration, ExposurePhase.Downloading); _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, "Exposure ready, downloading...")); int[,] imgArr = (int[,])Camera.ImageArray; int imageW = imgArr.GetLength(0); int imageH = imgArr.GetLength(1); // BlockCopy doesn't work here because the output row/column order is wrong. // We really want the data as a single dimensional array and this is not // the most efficient way to do it but will have to suffice until // I find a more efficient way. int[] pixelArr = new int[imgArr.GetLength(0) * imgArr.GetLength(1)]; for (int y = 0; y < imageH; y++) { for (int x = 0; x < imageW; x++) { pixelArr[y * imageW + x] = imgArr[x, y]; } } Exposure exposure = new Exposure(imageW, imageH, pixelArr, Camera.MaxADU, false); metadata.ExposureTime = Camera.LastExposureDuration; metadata.ExposureEndTime = DateTime.Now; exposure.MetaData = metadata; _exposure = exposure; _isExposuring = false; _logService.LogMessage(new LogMessage(this, LogEventCategory.Informational, "Exposure done.")); if (OnExposureCompleted != null) OnExposureCompleted(true, exposure); return true; } // The exposure was aborted and image could not be retrieved. else { _logService.LogMessage(new LogMessage(this, LogEventCategory.Warning, "Exposure done but image not ready, exposure must have been aborted.")); _isExposuring = false; if (OnExposureCompleted != null && !garbageFrame) OnExposureCompleted(false, null); return false; } }