Files
cms_thermo_active/ThermoCamUtils/ImageData.cs
T

690 lines
23 KiB
C#

using Flir.Atlas.Image;
using Flir.Atlas.Live.Device;
using Flir.Atlas.Live.Discovery;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
namespace ThermoCamUtils
{
/// <summary>
/// Classe gestione aree di memoria immagini (thermo, trasformate, ...)
/// </summary>
public class ImageData
{
#region Protected Fields
protected const string colorPath = "images\\colored";
protected const string currName = "_last";
protected const string dataFormat = "dat";
protected const string dataPath = "images\\data";
protected const string imgFormat = "jpg";
protected const string thermPath = "images\\original";
protected const string transPath = "images\\transformed";
protected string dirDataTemp = "";
protected string dirImgColor = "";
protected string dirImgGrTra = "";
protected string dirImgOrigi = "";
protected string fileColorPath = "";
protected string fileDataPath = "";
protected string fileGrTraPath = "";
protected string fileOrigiPath = "";
/// <summary>
/// Ultimi Dati letti x temperature
/// </summary>
protected TemperatureData lastFlirData = new TemperatureData();
/// <summary>
/// Stopwatch x benchmarking
/// </summary>
protected Stopwatch sw = new Stopwatch();
#endregion Protected Fields
#region Public Fields
public static readonly string BASE_PATH = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
/// <summary>
/// Array completo immagine
/// </summary>
public List<MeasurePoint> AllPoints = new List<MeasurePoint>();
/// <summary>
/// Statistiche esecuzione task
/// </summary>
public ExecTime ExTime = new ExecTime();
/// <summary>
/// Ultimo punto acquisito
/// </summary>
public Point lastPoint = new Point();
/// <summary>
/// Ultima temp letta da FLIR
/// </summary>
public double lastReadTemp = 0;
/// <summary>
/// Ultimo range di temperature osservato
/// </summary>
public Range<double> lastTempRange = new Range<double>(0, 5000);
#endregion Public Fields
#region Public Constructors
/// <summary>
/// Setup oggetto e variabili
/// </summary>
public ImageData()
{
// setup folder varie
dirDataTemp = $"{BASE_PATH}\\{dataPath}";
dirImgColor = $"{BASE_PATH}\\{colorPath}";
dirImgOrigi = $"{BASE_PATH}\\{thermPath}";
dirImgGrTra = $"{BASE_PATH}\\{transPath}";
checkLocadOutDir();
}
#endregion Public Constructors
#region Public Events
public event EventHandler eh_CameraConnected;
public event EventHandler<Flir.Atlas.Live.ConnectionStatusChangedEventArgs> eh_CameraConnStatusChanged;
public event EventHandler eh_CameraDisposed;
#endregion Public Events
#region Private Properties
private bool IsDirty { get; set; }
#endregion Private Properties
#region Protected Properties
protected Point[] _reticolo { get; set; }
#endregion Protected Properties
#region Public Properties
/// <summary>
/// Ultima immagine ricolorata e trasformata (perspective)
/// </summary>
public Bitmap ColorTransf { get; set; }
/// <summary>
/// conf corrente applicata
/// </summary>
public ThermoCamConf currConf { get; set; } = new ThermoCamConf();
/// <summary>
/// Ultima bitmap disegnata (con punti)
/// </summary>
public Bitmap Decorated { get; set; }
/// <summary>
/// Ultima immagine post trasformazione (perspective)
/// </summary>
public Bitmap GrayTransf { get; set; }
/// <summary>
/// Ultima bitmap acquisita
/// </summary>
public Bitmap Origin { get; set; }
/// <summary>
/// Ultima immagine recuperata
/// </summary>
public ThermalImage Thermal { get; set; }
#endregion Public Properties
#region Private Methods
private void Camera_ConnectionStatusChanged(object sender, Flir.Atlas.Live.ConnectionStatusChangedEventArgs e)
{
if (eh_CameraConnStatusChanged != null)
{
eh_CameraConnStatusChanged(this, e);
}
}
private void checkLocadOutDir()
{
// verifico esistenza directory
if (!Directory.Exists(dirDataTemp))
{
Directory.CreateDirectory(dirDataTemp);
}
if (!Directory.Exists(dirImgColor))
{
Directory.CreateDirectory(dirImgColor);
}
if (!Directory.Exists(dirImgOrigi))
{
Directory.CreateDirectory(dirImgOrigi);
}
if (!Directory.Exists(dirImgGrTra))
{
Directory.CreateDirectory(dirImgGrTra);
}
}
private void drawPoint(Color currColor, Point currPoint)
{
try
{
// disegno!
using (Graphics gr = Graphics.FromImage(Decorated))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
Point[] crsPoints = new Point[4];
for (int i = 0; i < 4; i++)
{
crsPoints[i] = currPoint;
}
crsPoints[0].X = crsPoints[0].X - 4;
crsPoints[1].X = crsPoints[1].X + 4;
crsPoints[2].Y = crsPoints[2].Y - 4;
crsPoints[3].Y = crsPoints[3].Y + 4;
using (Pen thick_pen = new Pen(currColor, 1))
{
gr.DrawLine(thick_pen, crsPoints[0], crsPoints[1]);
gr.DrawLine(thick_pen, crsPoints[2], crsPoints[3]);
}
}
}
catch (Exception exc)
{ }
}
private void Image_Changed(object sender, Flir.Atlas.Image.ImageChangedEventArgs e)
{
IsDirty = true;
}
#endregion Private Methods
#region Protected Methods
/// <summary>
/// se ho una immagine thermo --> reticolo punti x misura (griglia completa...)
/// </summary>
protected Point[] getReticolo()
{
Point[] answ = _reticolo;
if (answ == null)
{
if (Thermal != null)
{
int i = 0;
answ = new Point[Thermal.Size.Width * Thermal.Size.Height];
for (int y = 0; y < Thermal.Size.Height; y++)
{
for (int x = 0; x < Thermal.Size.Width; x++)
{
answ[i] = new Point() { X = x, Y = y };
i++;
}
}
_reticolo = answ;
}
}
return answ;
}
/// <summary>
/// Calcola valore R ponderato dato un punto + intorno
/// </summary>
/// <param name="reqPoint"></param>
/// <returns></returns>
protected int getRSmooth(Point reqPoint)
{
int answ = 0;
if (Origin != null)
{
// solo se il punto è entro limiti immagine --> 1 pixel entro bordo
if (reqPoint.X > 0 && reqPoint.X < Origin.Width)
{
if (reqPoint.Y > 0 && reqPoint.Y < Origin.Height)
{
int rgbValMain = Origin.GetPixel(lastPoint.X, lastPoint.Y).R;
int rgbValN = Origin.GetPixel(lastPoint.X, lastPoint.Y - 1).R;
int rgbValNO = Origin.GetPixel(lastPoint.X - 1, lastPoint.Y - 1).R;
int rgbValO = Origin.GetPixel(lastPoint.X - 1, lastPoint.Y).R;
int rgbValSO = Origin.GetPixel(lastPoint.X - 1, lastPoint.Y + 1).R;
int rgbValS = Origin.GetPixel(lastPoint.X, lastPoint.Y + 1).R;
int rgbValSE = Origin.GetPixel(lastPoint.X + 1, lastPoint.Y + 1).R;
int rgbValE = Origin.GetPixel(lastPoint.X + 1, lastPoint.Y).R;
int rgbValNE = Origin.GetPixel(lastPoint.X + 1, lastPoint.Y - 1).R;
// calcolo valore ponderato
answ = (int)Math.Round((double)(1 * rgbValMain + 1 * (rgbValN + rgbValO + rgbValS + rgbValE) + rgbValNO + rgbValSO + rgbValSE + rgbValNE) / 10, 0);
}
}
}
return answ;
}
#endregion Protected Methods
#region Public Methods
/// <summary>
/// Effettua calcolo immagini target
/// </summary>
public void calculateTarget()
{
if (Thermal != null)
{
try
{
// genero immagine BN
sw.Restart();
var pTransf = new PerspectiveTransform(currConf.OrigPoints.Coords, currConf.DestPoints.Coords);
var transfImg = pTransf.convertImage(Origin, currConf.TargetSize.X, currConf.TargetSize.Y);
GrayTransf = transfImg;
sw.Stop();
ExTime.recordData("ImageTransf", sw.ElapsedMilliseconds);
sw.Restart();
var rTrasf = new ReColorize(currConf.TargetRange.Min, currConf.TargetRange.Max);
// ora calcolo ricolorazione da immagine originale
var colImg = rTrasf.process(Origin, lastFlirData.Values);
// e faccio la stessa trasformazione di riscalatura
var transfColImg = pTransf.convertImage(colImg, currConf.TargetSize.X, currConf.TargetSize.Y);
ColorTransf = transfColImg;
sw.Stop();
ExTime.recordData("ImageColor", sw.ElapsedMilliseconds);
}
catch (Exception exc)
{
}
}
}
public void ConnectCamera(CameraDeviceInfo cameraDeviceInfo)
{
DisposeCamera();
switch (cameraDeviceInfo.SelectedStreamingFormat)
{
case ImageFormat.FlirFileFormat:
IRCam.ThermoCamera = new ThermalCamera();
break;
case ImageFormat.Argb:
IRCam.ThermoCamera = new VideoOverlayCamera();
break;
default:
throw new ArgumentOutOfRangeException();
}
IRCam.ThermoCamera.ConnectionStatusChanged += Camera_ConnectionStatusChanged;
IRCam.ThermoCamera.GetImage().Changed += Image_Changed;
IRCam.ThermoCamera.Connect(cameraDeviceInfo);
#if false
if (IRCam.ThermoCamera.Recorder == null && _recorder != null)
{
_recorder.Dispose();
_recorder = null;
}
if (_recorder != null)
{
if (!_recorder.IsDisposed)
_recorder.Initialize(IRCam.ThermoCamera);
}
recorderToolStripMenuItem.Enabled = IRCam.ThermoCamera.Recorder != null;
#endif
if (eh_CameraConnected != null)
{
eh_CameraConnected(this, new EventArgs());
}
}
public void DisconnectCamera()
{
if (IRCam.ThermoCamera == null) return;
IRCam.ThermoCamera.Disconnect();
}
public void DisposeCamera()
{
if (eh_CameraDisposed != null)
{
eh_CameraDisposed(this, new EventArgs());
}
if (IRCam.ThermoCamera == null) return;
IRCam.ThermoCamera.ConnectionStatusChanged -= Camera_ConnectionStatusChanged;
IRCam.ThermoCamera.GetImage().Changed -= Image_Changed;
IRCam.ThermoCamera.Dispose();
}
public void drawCrossAtPoints()
{
if (Thermal != null)
{
// ricopio immagine "Pulita"
initImageFromFile();
sw.Restart();
// se ho dei punti x trasformazione --> disegno
if (currConf.OrigPoints.curr > 0)
{
foreach (var item in currConf.OrigPoints.Coords)
{
drawPoint(Color.Green, item);
}
}
// se ho punto acquisizione temp --> disegno!
if (currConf.MeasPoints.Count > 0)
{
foreach (var item in currConf.MeasPoints)
{
// disegno!
drawPoint(Color.Blue, item.Coords);
}
}
sw.Stop();
ExTime.recordData("AddPoints", sw.ElapsedMilliseconds);
}
}
/// <summary>
/// effettua salvataggio files (immagini + misure)
/// </summary>
/// <returns></returns>
public bool fileLoad(string fileName)
{
double minTemp = 5000;
double maxTemp = 0;
bool answ = false;
if (string.IsNullOrEmpty(fileName))
{
// uso last...
fileName = currName;
}
// setup nomi files
fileDataPath = $"{dirDataTemp}\\{fileName}.{dataFormat}";
fileColorPath = $"{dirImgColor}\\{fileName}.{imgFormat}";
fileOrigiPath = $"{dirImgOrigi}\\{fileName}.{imgFormat}";
fileGrTraPath = $"{dirImgGrTra}\\{fileName}.{imgFormat}";
// se trovo i files...
if (File.Exists(fileOrigiPath))
{
try
{
// carico oggetto FLIR
using (var flirImg = new ThermalImageFile(fileOrigiPath))
{
//Thermal = new ThermalImageFile(filePath);
Thermal = (ThermalImage)flirImg;
Thermal.TemperatureUnit = TemperatureUnit.Celsius;
Thermal.Scale.IsAutoAdjustEnabled = true;
}
// carico DIRETTAMENTE da file le immagini iniziali da generare...
using (Image loadedImg = Image.FromFile(fileOrigiPath))
{
Origin = (Bitmap)loadedImg.Clone();
Decorated = (Bitmap)loadedImg.Clone();
}
// carico il file delle temperature
string rawData = File.ReadAllText(fileDataPath);
if (!string.IsNullOrEmpty(rawData))
{
lastFlirData = JsonConvert.DeserializeObject<TemperatureData>(rawData);
// calcolo min/Max
foreach (var item in lastFlirData.Values)
{
if (item < minTemp)
{
minTemp = item;
}
if (item > maxTemp)
{
maxTemp = item;
}
}
lastTempRange = new Range<double>(minTemp, maxTemp);
}
}
catch (Exception exc)
{ }
}
return answ;
}
/// <summary>
/// effettua salvataggio files (immagini + misure)
/// </summary>
/// <returns></returns>
public string fileSave()
{
string answ = "";
try
{
// x sicurezza check directory...
checkLocadOutDir();
// setup nomi files
fileDataPath = $"{dirDataTemp}\\{currName}.{dataFormat}";
fileColorPath = $"{dirImgColor}\\{currName}.{imgFormat}";
fileOrigiPath = $"{dirImgOrigi}\\{currName}.{imgFormat}";
fileGrTraPath = $"{dirImgGrTra}\\{currName}.{imgFormat}";
// salvo thermo!
Thermal.Scale.IsAutoAdjustEnabled = true;
Thermal.SaveSnapshot(fileOrigiPath);
// salvo trasformata
GrayTransf.Save(fileGrTraPath);
// salvo colorata
ColorTransf.Save(fileColorPath);
// salvo conf thermo
string rawData = JsonConvert.SerializeObject(lastFlirData, Formatting.None);
File.WriteAllText(fileDataPath, rawData);
// copia immagine con nome univoco da rendere a libreria x eventuale salvataggio in area PROD del nome immagine associato...
string uniqueName = $"{DateTime.Now:yyyyMMdd_HHmmss}";
File.Copy(fileOrigiPath, fileOrigiPath.Replace(currName, uniqueName));
File.Copy(fileColorPath, fileColorPath.Replace(currName, uniqueName));
File.Copy(fileGrTraPath, fileGrTraPath.Replace(currName, uniqueName));
File.Copy(fileDataPath, fileDataPath.Replace(currName, uniqueName));
answ = uniqueName;
}
catch (Exception exc)
{ }
return answ;
}
/// <summary>
/// Recupera temperature coi 2 metodi da FLIR e da B/N
/// </summary>
/// <param name="readTemp"></param>
public void getTemperatures(bool readTemp)
{
if (Thermal != null)
{
lastReadTemp = 0;
if (readTemp)
{
try
{
sw.Restart();
foreach (var item in currConf.MeasPoints)
{
// recupero da ARRAY in memoria delle ultime letture fatte...
lastReadTemp = lastFlirData.Values[item.Coords.X + Thermal.Size.Width * item.Coords.Y];
//lastReadTemp = Thermal.GetValueAt(item.Coords).Value;
}
sw.Stop();
ExTime.recordData("GetPoints", sw.ElapsedMilliseconds);
}
catch (Exception exc)
{ }
}
}
}
/// <summary>
/// Init iniziale immagini
/// </summary>
public void initImageFromFile()
{
if (Origin != null)
{
Decorated = (Bitmap)Origin.Clone();
}
}
/// <summary>
/// Init iniziale immagini
/// </summary>
public void initImagesFromThermo()
{
if (Thermal != null)
{
Origin = (Bitmap)Thermal.Image.Clone();
Decorated = (Bitmap)Thermal.Image.Clone();
}
}
/// <summary>
/// recupero valore statistica richiesta
/// </summary>
/// <param name="statName"></param>
/// <returns></returns>
public double lastStatTime(string statName)
{
double answ = -1;
if (ExTime.Stats.ContainsKey(statName))
{
try
{
answ = ExTime.Stats[statName];
}
catch
{ }
}
return answ;
}
/// <summary>
/// Effettua al lettura di tutte el temperature e le salva nell'oggetto in memoria
/// </summary>
public void readAllTemperatures()
{
sw.Restart();
// richiedo tutte!
var allData = Thermal.GetValues(getReticolo());
/// riduco info a 1 decimale
double[] floatData = Array.ConvertAll(allData, x => Math.Round(x, 2));
// salvo oggetto unico
lastFlirData = new TemperatureData()
{
ArraySize = new Size()
{
X = Thermal.Size.Width,
Y = Thermal.Size.Height
},
ScanOrder = "YX",
Values = floatData
};
sw.Stop();
ExTime.recordData("GetAllTemperatures", sw.ElapsedMilliseconds);
}
/// <summary>
/// Salvo il punto di misura selezionato
/// </summary>
/// <param name="addOnEnd"></param>
public void saveMeasurePoint(bool addOnEnd)
{
// se NO devo accodare resetto...
if (!addOnEnd)
{
currConf.MeasPoints = new List<MeasurePoint>();
}
MeasurePoint newPoint = new MeasurePoint()
{
Id = currConf.MeasPoints.Count,
Coords = lastPoint,
Temperature = 0
};
currConf.MeasPoints.Add(newPoint);
}
/// <summary>
/// recupera immagine effettuando eventuale salvataggio
/// </summary>
/// <param name="doSave"></param>
public string takePicture(bool doSave)
{
string answ = "";
sw.Restart();
if (!IsDirty) return answ;
IsDirty = false;
if (IRCam.ThermoCamera == null) return answ;
IRCam.ThermoCamera.GetImage().EnterLock();
try
{
Thermal = (ThermalImage)IRCam.ThermoCamera.GetImage();
Thermal.TemperatureUnit = TemperatureUnit.Celsius;
Thermal.Scale.IsAutoAdjustEnabled = true;
lastTempRange = new Range<double>(Thermal.Scale.Range.Minimum, Thermal.Scale.Range.Maximum);
// salvo img locale
Origin = Thermal.Image;
Decorated = Thermal.Image;
// recupero le temperature...
readAllTemperatures();
//verifico se devo salvare...
if (doSave)
{
answ = fileSave();
}
}
catch (Exception exception)
{
Trace.TraceError(exception.Message);
}
finally
{
IRCam.ThermoCamera.GetImage().ExitLock();
}
sw.Stop();
ExTime.recordData("ImageAcquisition", sw.ElapsedMilliseconds);
return answ;
}
#endregion Public Methods
}
}