Merge remote-tracking branch 'CMS/develop' into develop

This commit is contained in:
=
2021-02-18 18:40:39 +01:00
30 changed files with 2705 additions and 2189 deletions
+89 -72
View File
@@ -8,42 +8,47 @@ namespace ThermalImageStreamerDemo
{
public partial class DiscoveryForm : Form
{
public string CameraName { get; set; } = "";
public bool doAutoConnect
{
get
{
return !string.IsNullOrEmpty(CameraName);
}
}
#region Private Fields
private Discovery _discovery;
#endregion Private Fields
#region Public Constructors
public DiscoveryForm()
{
InitializeComponent();
}
private void DiscoveryForm_Load(object sender, EventArgs e)
#endregion Public Constructors
#region Public Properties
public string CameraAddress { get; set; } = "";
public string CameraName { get; set; } = "";
public bool doAutoConnect
{
Start();
timerAutoconnect.Start();
get
{
return (!string.IsNullOrEmpty(CameraAddress) || !string.IsNullOrEmpty(CameraName));
}
}
private void DiscoveryForm_FormClosing(object sender, FormClosingEventArgs e)
{
Stop();
}
/// <summary>
/// Camera selezionata
/// </summary>
public CameraDeviceInfo SelectedCameraDevice { get; set; }
private void listViewDevices_MouseDoubleClick(object sender, MouseEventArgs e)
{
SelectCameraFromListCtrl();
DialogResult = DialogResult.OK;
Close();
}
#endregion Public Properties
void _discovery_DeviceError(object sender, DeviceErrorEventArgs e)
#region Private Methods
private static void DisposeDiscovery(Object context)
{
BeginInvoke((Action)(() => ShowError(e.ErrorMessage)));
var discovery = (Discovery)context;
discovery.Dispose();
}
private static void ShowError(string message)
@@ -51,26 +56,19 @@ namespace ThermalImageStreamerDemo
MessageBox.Show(message);
}
void _discovery_DeviceLost(object sender, CameraDeviceInfoEventArgs e)
private void _discovery_DeviceError(object sender, DeviceErrorEventArgs e)
{
BeginInvoke((Action)(() => RemoveDevice(e.CameraDevice)));
BeginInvoke((Action)(() => ShowError(e.ErrorMessage)));
}
void _discovery_DeviceFound(object sender, CameraDeviceInfoEventArgs e)
private void _discovery_DeviceFound(object sender, CameraDeviceInfoEventArgs e)
{
BeginInvoke((Action)(() => AddDevice(e.CameraDevice)));
}
private void RemoveDevice(CameraDeviceInfo cameraDeviceInfo)
private void _discovery_DeviceLost(object sender, CameraDeviceInfoEventArgs e)
{
foreach (ListViewItem item in listViewDevices.Items)
{
var device = item.Tag as CameraDeviceInfo;
if (device != null && device.DeviceIdentifier == cameraDeviceInfo.DeviceIdentifier)
{
listViewDevices.Items.Remove(item);
}
}
BeginInvoke((Action)(() => RemoveDevice(e.CameraDevice)));
}
private void AddDevice(CameraDeviceInfo cameraDeviceInfo)
@@ -103,18 +101,60 @@ namespace ThermalImageStreamerDemo
item.Tag = info;
listViewDevices.Items.Add(item);
}
}
/// <summary>
/// Camera selezionata
/// </summary>
public CameraDeviceInfo SelectedCameraDevice { get; set; }
static void DisposeDiscovery(Object context)
private void buttonSelect_Click(object sender, EventArgs e)
{
var discovery = (Discovery)context;
discovery.Dispose();
SelectCameraFromListCtrl();
DialogResult = DialogResult.OK;
Close();
}
private void DiscoveryForm_FormClosing(object sender, FormClosingEventArgs e)
{
Stop();
}
private void DiscoveryForm_Load(object sender, EventArgs e)
{
Start();
timerAutoconnect.Start();
}
private void listViewDevices_MouseDoubleClick(object sender, MouseEventArgs e)
{
SelectCameraFromListCtrl();
DialogResult = DialogResult.OK;
Close();
}
private void listViewDevices_SelectedIndexChanged(object sender, EventArgs e)
{
var items = listViewDevices.SelectedItems;
buttonSelect.Enabled = items.Count != 0;
}
private void RemoveDevice(CameraDeviceInfo cameraDeviceInfo)
{
foreach (ListViewItem item in listViewDevices.Items)
{
var device = item.Tag as CameraDeviceInfo;
if (device != null && device.DeviceIdentifier == cameraDeviceInfo.DeviceIdentifier)
{
listViewDevices.Items.Remove(item);
}
}
}
private void SelectCameraFromListCtrl()
{
var items = listViewDevices.SelectedItems;
if (items.Count <= 0) return;
var lv = items[0];
var device = lv.Tag as CameraDeviceInfo;
SelectedCameraDevice = device;
DialogResult = DialogResult.OK;
Close();
}
private void Start()
@@ -131,9 +171,9 @@ namespace ThermalImageStreamerDemo
// _discovery.Start(Interface.Usb);
// or with a combination
// _discovery.Start(Interface.Network | Interface.Usb);
// _discovery.Start(Interface.Network | Interface.Usb);
// Start discovery, scan on all interfaces.
// Start discovery, scan on all interfaces.
// This requires that Bonjour and the Pleora drivers are installed, see the Atlas web page for more information.
_discovery.Start();
}
@@ -149,30 +189,6 @@ namespace ThermalImageStreamerDemo
_discovery = null;
}
private void buttonSelect_Click(object sender, EventArgs e)
{
SelectCameraFromListCtrl();
DialogResult = DialogResult.OK;
Close();
}
void SelectCameraFromListCtrl()
{
var items = listViewDevices.SelectedItems;
if (items.Count <= 0) return;
var lv = items[0];
var device = lv.Tag as CameraDeviceInfo;
SelectedCameraDevice = device;
DialogResult = DialogResult.OK;
Close();
}
private void listViewDevices_SelectedIndexChanged(object sender, EventArgs e)
{
var items = listViewDevices.SelectedItems;
buttonSelect.Enabled = items.Count != 0;
}
private void timerAutoconnect_Tick(object sender, EventArgs e)
{
timerAutoconnect.Stop();
@@ -181,7 +197,7 @@ namespace ThermalImageStreamerDemo
{
foreach (ListViewItem item in listViewDevices.Items)
{
if(item.Text == CameraName)
if (item.Text == CameraName)
{
item.Selected = true;
SelectCameraFromListCtrl();
@@ -192,5 +208,6 @@ namespace ThermalImageStreamerDemo
timerAutoconnect.Start();
}
#endregion Private Methods
}
}
}
+36 -89
View File
@@ -34,7 +34,6 @@
this.disconnectToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cameraToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.recorderToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.toolStripConnectionStatus = new System.Windows.Forms.ToolStripStatusLabel();
this.progBar = new System.Windows.Forms.ToolStripProgressBar();
@@ -44,15 +43,14 @@
this.chkSaveAll = new System.Windows.Forms.CheckBox();
this.btnLoad = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.lblTempRGB = new System.Windows.Forms.Label();
this.lblMaxTemp = new System.Windows.Forms.Label();
this.lblMinTemp = new System.Windows.Forms.Label();
this.label6 = new System.Windows.Forms.Label();
this.txtMaxScale = new System.Windows.Forms.TextBox();
this.label7 = new System.Windows.Forms.Label();
this.txtMinScale = new System.Windows.Forms.TextBox();
this.chkReadTemp = new System.Windows.Forms.CheckBox();
this.lblReadTemp = new System.Windows.Forms.Label();
this.chkRevProc = new System.Windows.Forms.CheckBox();
this.chkParallel = new System.Windows.Forms.CheckBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.label5 = new System.Windows.Forms.Label();
this.txtBC = new System.Windows.Forms.TextBox();
@@ -75,8 +73,6 @@
this.lblImgB = new System.Windows.Forms.Label();
this.lblImgC = new System.Windows.Forms.Label();
this.chkShowOrig = new System.Windows.Forms.CheckBox();
this.lblMinTemp = new System.Windows.Forms.Label();
this.lblMaxTemp = new System.Windows.Forms.Label();
this.menuStrip1.SuspendLayout();
this.statusStrip1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.pBoxA)).BeginInit();
@@ -132,20 +128,11 @@
//
// cameraToolStripMenuItem
//
this.cameraToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.recorderToolStripMenuItem});
this.cameraToolStripMenuItem.Enabled = false;
this.cameraToolStripMenuItem.Name = "cameraToolStripMenuItem";
this.cameraToolStripMenuItem.Size = new System.Drawing.Size(60, 20);
this.cameraToolStripMenuItem.Text = "Camera";
//
// recorderToolStripMenuItem
//
this.recorderToolStripMenuItem.Name = "recorderToolStripMenuItem";
this.recorderToolStripMenuItem.Size = new System.Drawing.Size(130, 22);
this.recorderToolStripMenuItem.Text = "Recorder...";
this.recorderToolStripMenuItem.Click += new System.EventHandler(this.recorderToolStripMenuItem_Click);
//
// statusStrip1
//
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
@@ -193,8 +180,6 @@
this.panelCmd.Controls.Add(this.chkSaveAll);
this.panelCmd.Controls.Add(this.btnLoad);
this.panelCmd.Controls.Add(this.groupBox3);
this.panelCmd.Controls.Add(this.chkRevProc);
this.panelCmd.Controls.Add(this.chkParallel);
this.panelCmd.Controls.Add(this.groupBox2);
this.panelCmd.Controls.Add(this.groupBox1);
this.panelCmd.Controls.Add(this.checkLive);
@@ -229,36 +214,46 @@
//
this.groupBox3.Controls.Add(this.lblMaxTemp);
this.groupBox3.Controls.Add(this.lblMinTemp);
this.groupBox3.Controls.Add(this.lblTempRGB);
this.groupBox3.Controls.Add(this.label6);
this.groupBox3.Controls.Add(this.txtMaxScale);
this.groupBox3.Controls.Add(this.label7);
this.groupBox3.Controls.Add(this.txtMinScale);
this.groupBox3.Controls.Add(this.chkReadTemp);
this.groupBox3.Controls.Add(this.lblReadTemp);
this.groupBox3.Location = new System.Drawing.Point(8, 333);
this.groupBox3.Location = new System.Drawing.Point(8, 269);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(175, 175);
this.groupBox3.Size = new System.Drawing.Size(175, 119);
this.groupBox3.TabIndex = 5;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Temperature";
//
// lblTempRGB
// lblMaxTemp
//
this.lblTempRGB.AutoSize = true;
this.lblTempRGB.ForeColor = System.Drawing.SystemColors.ButtonHighlight;
this.lblTempRGB.Location = new System.Drawing.Point(89, 41);
this.lblTempRGB.MinimumSize = new System.Drawing.Size(80, 0);
this.lblTempRGB.Name = "lblTempRGB";
this.lblTempRGB.Size = new System.Drawing.Size(80, 13);
this.lblTempRGB.TabIndex = 15;
this.lblTempRGB.Text = "? °C";
this.lblTempRGB.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.lblMaxTemp.AutoSize = true;
this.lblMaxTemp.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.lblMaxTemp.Location = new System.Drawing.Point(89, 42);
this.lblMaxTemp.MinimumSize = new System.Drawing.Size(80, 0);
this.lblMaxTemp.Name = "lblMaxTemp";
this.lblMaxTemp.Size = new System.Drawing.Size(80, 13);
this.lblMaxTemp.TabIndex = 17;
this.lblMaxTemp.Text = "? °C";
this.lblMaxTemp.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// lblMinTemp
//
this.lblMinTemp.AutoSize = true;
this.lblMinTemp.ForeColor = System.Drawing.SystemColors.ControlText;
this.lblMinTemp.Location = new System.Drawing.Point(7, 42);
this.lblMinTemp.MinimumSize = new System.Drawing.Size(80, 0);
this.lblMinTemp.Name = "lblMinTemp";
this.lblMinTemp.Size = new System.Drawing.Size(80, 13);
this.lblMinTemp.TabIndex = 16;
this.lblMinTemp.Text = "? °C";
//
// label6
//
this.label6.AutoSize = true;
this.label6.Location = new System.Drawing.Point(7, 135);
this.label6.Location = new System.Drawing.Point(7, 91);
this.label6.Name = "label6";
this.label6.Size = new System.Drawing.Size(57, 13);
this.label6.TabIndex = 13;
@@ -266,17 +261,18 @@
//
// txtMaxScale
//
this.txtMaxScale.Location = new System.Drawing.Point(92, 132);
this.txtMaxScale.Location = new System.Drawing.Point(92, 88);
this.txtMaxScale.Name = "txtMaxScale";
this.txtMaxScale.Size = new System.Drawing.Size(77, 20);
this.txtMaxScale.TabIndex = 12;
this.txtMaxScale.Text = "60";
this.txtMaxScale.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
this.txtMaxScale.TextChanged += new System.EventHandler(this.txtMaxScale_TextChanged);
//
// label7
//
this.label7.AutoSize = true;
this.label7.Location = new System.Drawing.Point(7, 108);
this.label7.Location = new System.Drawing.Point(7, 64);
this.label7.Name = "label7";
this.label7.Size = new System.Drawing.Size(54, 13);
this.label7.TabIndex = 11;
@@ -284,12 +280,13 @@
//
// txtMinScale
//
this.txtMinScale.Location = new System.Drawing.Point(92, 105);
this.txtMinScale.Location = new System.Drawing.Point(92, 61);
this.txtMinScale.Name = "txtMinScale";
this.txtMinScale.Size = new System.Drawing.Size(77, 20);
this.txtMinScale.TabIndex = 10;
this.txtMinScale.Text = "0";
this.txtMinScale.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
this.txtMinScale.TextChanged += new System.EventHandler(this.txtMinScale_TextChanged);
//
// chkReadTemp
//
@@ -313,42 +310,18 @@
this.lblReadTemp.Text = "? °C";
this.lblReadTemp.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// chkRevProc
//
this.chkRevProc.AutoSize = true;
this.chkRevProc.Checked = true;
this.chkRevProc.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkRevProc.Location = new System.Drawing.Point(8, 514);
this.chkRevProc.Name = "chkRevProc";
this.chkRevProc.Size = new System.Drawing.Size(100, 17);
this.chkRevProc.TabIndex = 11;
this.chkRevProc.Text = "Rev processing";
this.chkRevProc.UseVisualStyleBackColor = true;
//
// chkParallel
//
this.chkParallel.AutoSize = true;
this.chkParallel.Checked = true;
this.chkParallel.CheckState = System.Windows.Forms.CheckState.Checked;
this.chkParallel.Location = new System.Drawing.Point(8, 533);
this.chkParallel.Name = "chkParallel";
this.chkParallel.Size = new System.Drawing.Size(112, 17);
this.chkParallel.TabIndex = 10;
this.chkParallel.Text = "Bitmap Marshalled";
this.chkParallel.UseVisualStyleBackColor = true;
//
// groupBox2
//
this.groupBox2.Controls.Add(this.label5);
this.groupBox2.Controls.Add(this.txtBC);
this.groupBox2.Controls.Add(this.label1);
this.groupBox2.Controls.Add(this.txtAB);
this.groupBox2.Location = new System.Drawing.Point(8, 214);
this.groupBox2.Location = new System.Drawing.Point(8, 187);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(175, 76);
this.groupBox2.TabIndex = 5;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "target";
this.groupBox2.Text = "Target";
//
// label5
//
@@ -396,12 +369,12 @@
this.groupBox1.Controls.Add(this.lblOrigC);
this.groupBox1.Controls.Add(this.lblOrigB);
this.groupBox1.Controls.Add(this.chkPointSetup);
this.groupBox1.Location = new System.Drawing.Point(8, 122);
this.groupBox1.Location = new System.Drawing.Point(8, 91);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(175, 90);
this.groupBox1.TabIndex = 4;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "origin";
this.groupBox1.Text = "Origin";
//
// btnReset
//
@@ -565,29 +538,7 @@
this.chkShowOrig.TabIndex = 12;
this.chkShowOrig.Text = "Show Original";
this.chkShowOrig.UseVisualStyleBackColor = true;
//
// lblMinTemp
//
this.lblMinTemp.AutoSize = true;
this.lblMinTemp.ForeColor = System.Drawing.SystemColors.ControlText;
this.lblMinTemp.Location = new System.Drawing.Point(7, 67);
this.lblMinTemp.MinimumSize = new System.Drawing.Size(80, 0);
this.lblMinTemp.Name = "lblMinTemp";
this.lblMinTemp.Size = new System.Drawing.Size(80, 13);
this.lblMinTemp.TabIndex = 16;
this.lblMinTemp.Text = "? °C";
//
// lblMaxTemp
//
this.lblMaxTemp.AutoSize = true;
this.lblMaxTemp.ForeColor = System.Drawing.SystemColors.ControlLightLight;
this.lblMaxTemp.Location = new System.Drawing.Point(89, 67);
this.lblMaxTemp.MinimumSize = new System.Drawing.Size(80, 0);
this.lblMaxTemp.Name = "lblMaxTemp";
this.lblMaxTemp.Size = new System.Drawing.Size(80, 13);
this.lblMaxTemp.TabIndex = 17;
this.lblMaxTemp.Text = "? °C";
this.lblMaxTemp.TextAlign = System.Drawing.ContentAlignment.TopRight;
this.chkShowOrig.CheckedChanged += new System.EventHandler(this.chkShowOrig_CheckedChanged);
//
// MainForm
//
@@ -637,7 +588,6 @@
private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem discoveryToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem cameraToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem recorderToolStripMenuItem;
private System.Windows.Forms.StatusStrip statusStrip1;
private System.Windows.Forms.ToolStripStatusLabel toolStripConnectionStatus;
private System.Windows.Forms.ToolStripMenuItem disconnectToolStripMenuItem;
@@ -667,15 +617,12 @@
private System.Windows.Forms.Label lblImgC;
private System.Windows.Forms.ToolStripProgressBar progBar;
private System.Windows.Forms.ToolStripStatusLabel lblStats;
private System.Windows.Forms.CheckBox chkParallel;
private System.Windows.Forms.CheckBox chkRevProc;
private System.Windows.Forms.GroupBox groupBox3;
private System.Windows.Forms.Label label6;
private System.Windows.Forms.TextBox txtMaxScale;
private System.Windows.Forms.Label label7;
private System.Windows.Forms.TextBox txtMinScale;
private System.Windows.Forms.Label lblPoint;
private System.Windows.Forms.Label lblTempRGB;
private System.Windows.Forms.CheckBox chkShowOrig;
private System.Windows.Forms.Button btnReset;
private System.Windows.Forms.Button btnLoad;
+130 -488
View File
@@ -22,67 +22,19 @@ namespace ThermalImageStreamerDemo
private readonly Timer _timerRefreshUi = new Timer();
#if false
private Camera IRCam.ThermoCamera;
#endif
private RecorderForm _recorder;
#endregion Private Fields
#region Protected Fields
protected const string colorPath = "images\\Color";
protected const string confFileName = "ThermoConf.json";
protected const string currImgFile = "ThermalData.jpg";
protected const string thermPath = "images\\Therm";
/// <summary>
/// Ultimo range di temperature osservato
/// </summary>
protected Range<double> _lastTempRange = new Range<double>(-999, 5000);
protected int currPoint = -1;
/// <summary>
/// Contenitore oggetti Image x FlirCam
/// Classe gestione ThermoCam (oggetti Image, metodi processing...) x FlirCam
/// </summary>
protected ImageData ImgData = new ImageData();
#if false
protected double lastCalcTemp = 0;
protected Point ImgData.lastPoint = new Point();
protected double lastReadTemp = 0;
#endif
protected double msLastCam = 0;
protected double msLastCol = 0;
protected double msLastMsr = 0;
protected double msLastPts = 0;
protected double msLastTra = 0;
protected Point refTempPoint = new Point();
protected Stopwatch sw = new Stopwatch();
protected TCContr ThermoCamCont = new TCContr();
#endregion Protected Fields
#region Public Fields
// Config File Names
public static readonly string BASE_PATH = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
#endregion Public Fields
#region Public Constructors
public MainForm()
@@ -90,8 +42,20 @@ namespace ThermalImageStreamerDemo
InitializeComponent();
_timerRefreshUi.Interval = 100;
_timerRefreshUi.Tick += _timerRefreshUi_Tick;
_timerRefreshUi.Start();
// collego eventi ImgData
ThermoCamCont.eh_CameraConnected += ImgData_eh_CameraConnected;
ThermoCamCont.eh_CameraDisposed += ImgData_eh_CameraDisposed;
ThermoCamCont.eh_CameraConnStatusChanged += ImgData_eh_CameraConnStatusChanged;
// cerco se ho un set di parametri già impostati...
tryReloadConf();
ThermoCamCont.tryReloadConf();
// avvio l'autoconnessione
if (!string.IsNullOrEmpty(ThermoCamCont.currConf.CameraName))
{
discoveryCamera();
}
// sistemo le conf temp
setRangeTemp();
// calcolo i currConf.destPoints
updateDestPt();
}
@@ -100,8 +64,6 @@ namespace ThermalImageStreamerDemo
#region Private Properties
private bool IsDirty { get; set; }
private bool liveView
{
get
@@ -118,44 +80,18 @@ namespace ThermalImageStreamerDemo
#region Protected Properties
protected string confPath
{
get
{
// se esiste il file... path assoluto
string answ = confFileName;
if (!Path.IsPathRooted(answ))
{
answ = BASE_PATH + "\\" + confFileName;
}
return answ;
}
}
protected ThermoCamConf currConf
{
get
{
return ImgData.currConf;
}
set
{
ImgData.currConf = value;
}
}
protected int dimX
{
get
{
int answ = 100;
int.TryParse(txtAB.Text, out answ);
currConf.TargetSize.X = answ;
ThermoCamCont.currConf.TargetSize.X = answ;
return answ;
}
set
{
currConf.TargetSize.X = value;
ThermoCamCont.currConf.TargetSize.X = value;
txtAB.Text = $"{value}";
}
}
@@ -166,61 +102,40 @@ namespace ThermalImageStreamerDemo
{
int answ = 100;
int.TryParse(txtBC.Text, out answ);
currConf.TargetSize.Y = answ;
ThermoCamCont.currConf.TargetSize.Y = answ;
return answ;
}
set
{
currConf.TargetSize.Y = value;
ThermoCamCont.currConf.TargetSize.Y = value;
txtBC.Text = $"{value}";
}
}
/// <summary>
/// Ultimo range di temperature osservato
/// </summary>
protected Range<double> lastTempRange
{
get
{
return _lastTempRange;
}
set
{
_lastTempRange = value;
lblMinTemp.Text = $"{value.Minimum:N2}";
lblMaxTemp.Text = $"{value.Maximum:N2}";
}
}
protected double maxScale
protected double maxRangeTemp
{
get
{
double answ = 1000;
double.TryParse(txtMaxScale.Text, out answ);
currConf.TargetRange.Max = answ;
return answ;
}
set
{
currConf.TargetRange.Max = value;
txtMaxScale.Text = $"{value:N0}";
}
}
protected double minScale
protected double minRangeTemp
{
get
{
double answ = 0;
double.TryParse(txtMinScale.Text, out answ);
currConf.TargetRange.Min = answ;
return answ;
}
set
{
currConf.TargetRange.Min = value;
txtMinScale.Text = $"{value:N0}";
}
}
@@ -277,18 +192,12 @@ namespace ThermalImageStreamerDemo
#region Private Methods
private void _recorder_SelectedFileMouseDoubleClick(object sender, SelectedFileEventArgs e)
{
var playback = new PlaybackForm(e.FilePath);
playback.Show();
}
private void _timerRefreshUi_Tick(object sender, EventArgs e)
{
// se è in live view --> continuo
if (liveView)
{
takePicture(saveEnabled);
ThermoCamCont.takePicture(saveEnabled);
processImage();
refreshDisplay();
}
@@ -302,53 +211,31 @@ namespace ThermalImageStreamerDemo
private void btnLoad_Click(object sender, EventArgs e)
{
string dirPath = $"{BASE_PATH}\\{thermPath}";
string filePath = $"{dirPath}\\{currImgFile}";
if (File.Exists(filePath))
{
try
{
ImgData.Thermal = new ThermalImageFile(filePath);
ImgData.Thermal.TemperatureUnit = TemperatureUnit.Celsius;
ImgData.Thermal.Scale.IsAutoAdjustEnabled = true;
// carico DIRETTAMENTE da file...
ImgData.Origin = (Bitmap)Image.FromFile(filePath);
ImgData.Decorated = (Bitmap)Image.FromFile(filePath);
// "" --> carica ultima scattata (altrimenti nome)
ThermoCamCont.fileLoad("");
// aggiorno visualizzazione
processImage();
refreshDisplay();
}
catch
{ }
}
// aggiorno visualizzazione
processImage();
refreshDisplay();
}
private void btnReset_Click(object sender, EventArgs e)
{
pointSetup = true;
currConf.origPoints = new SetPoints();
ThermoCamCont.currConf.OrigPoints = new SetPoints();
}
private void btnSave_Click(object sender, EventArgs e)
{
takePicture(true);
ThermoCamCont.takePicture(true);
processImage();
refreshDisplay();
}
private void Camera_ConnectionStatusChanged(object sender, Flir.Atlas.Live.ConnectionStatusChangedEventArgs e)
{
BeginInvoke((Action)(() => toolStripConnectionStatus.Text = e.Status.ToString()));
BeginInvoke((Action)(() => cameraToolStripMenuItem.Enabled = e.Status == ConnectionStatus.Connected));
// se si disconnette --> NUOVA richiesta connessione alla CHILD...
// TODO FARE!!!
}
private void checkLive_CheckedChanged(object sender, EventArgs e)
{
// non serve fare nulla
// cambio periodo timer!
_timerRefreshUi.Interval = checkLive.Checked ? 100 : 500;
}
private void chkPointSetup_CheckedChanged(object sender, EventArgs e)
@@ -370,53 +257,17 @@ namespace ThermalImageStreamerDemo
if (!readTemp)
{
lblReadTemp.Text = "? °C";
lblTempRGB.Text = "? °C";
}
}
private void ConnectCamera(CameraDeviceInfo cameraDeviceInfo)
private void chkShowOrig_CheckedChanged(object sender, EventArgs e)
{
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 (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;
_timerRefreshUi.Start();
}
private void DisconnectCamera()
{
if (IRCam.ThermoCamera == null) return;
IRCam.ThermoCamera.Disconnect();
refreshDisplay();
}
private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
{
DisconnectCamera();
ThermoCamCont.DisconnectCamera();
}
private void discoveryToolStripMenuItem_Click(object sender, EventArgs e)
@@ -424,111 +275,47 @@ namespace ThermalImageStreamerDemo
var discoveryDlg = new DiscoveryForm();
if (discoveryDlg.ShowDialog() == DialogResult.OK)
{
ConnectCamera(discoveryDlg.SelectedCameraDevice);
ThermoCamCont.ConnectCamera(discoveryDlg.SelectedCameraDevice);
// salvo nome camera in conf attuale!
currConf.CameraName = discoveryDlg.SelectedCameraDevice.Name;
saveConf();
ThermoCamCont.currConf.CameraName = discoveryDlg.SelectedCameraDevice.Name;
ThermoCamCont.currConf.CameraAddress = discoveryDlg.SelectedCameraDevice.IpSettings.IpAddress;
ThermoCamCont.saveConf();
}
}
private void displayImages()
{
if (ImgData.Thermal != null)
if (ThermoCamCont.Thermal != null)
{
lblImgA.Text = showOrigBig ? "ORIGINAL image" : "FINAL image";
lblImgB.Text = showOrigBig ? "FINAL image" : "ORIGINAL image";
pBoxA.Image = showOrigBig ? ImgData.ColorTransf : ImgData.Decorated;
pBoxB.Image = showOrigBig ? ImgData.Decorated : ImgData.ColorTransf;
pBoxC.Image = ImgData.GrayTransf;
pBoxA.Image = showOrigBig ? ThermoCamCont.ColorTransf : ThermoCamCont.Decorated;
pBoxB.Image = showOrigBig ? ThermoCamCont.Decorated : ThermoCamCont.ColorTransf;
pBoxC.Image = ThermoCamCont.GrayTransf;
}
}
private void DisposeCamera()
private void ImgData_eh_CameraConnected(object sender, EventArgs e)
{
_timerRefreshUi.Stop();
if (IRCam.ThermoCamera == null) return;
if (_recorder != null)
_timerRefreshUi.Interval = 100;
}
private void ImgData_eh_CameraConnStatusChanged(object sender, Flir.Atlas.Live.ConnectionStatusChangedEventArgs e)
{
try
{
_recorder.UnInitialize();
_recorder.Dispose();
BeginInvoke((Action)(() => toolStripConnectionStatus.Text = e.Status.ToString()));
BeginInvoke((Action)(() => toolStripConnectionStatus.ForeColor = e.Status == ConnectionStatus.Connected ? Color.Green : Color.Gray));
BeginInvoke((Action)(() => cameraToolStripMenuItem.Enabled = e.Status == ConnectionStatus.Connected));
}
IRCam.ThermoCamera.ConnectionStatusChanged -= Camera_ConnectionStatusChanged;
IRCam.ThermoCamera.GetImage().Changed -= Image_Changed;
IRCam.ThermoCamera.Dispose();
catch
{ }
}
private void drawCrossAtPoints()
private void ImgData_eh_CameraDisposed(object sender, EventArgs e)
{
if (ImgData.Thermal != null)
{
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 (refTempPoint != null)
{
drawPoint(Color.Blue, refTempPoint);
}
sw.Stop();
msLastPts = sw.ElapsedMilliseconds;
}
}
private void drawPoint(Color currColor, Point currPoint)
{
// disegno!
using (Graphics gr = Graphics.FromImage(ImgData.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]);
}
}
}
#if false
private void getTemperatures()
{
if (ImgData.Thermal != null)
{
lastReadTemp = 0;
if (readTemp)
{
// recupero temp da FLIR
lastReadTemp = ImgData.Thermal.GetValueAt(ImgData.lastPoint).Value;
// calcolo temp da RGB considerato limiti minMAX...
//int rgbVal = ImgData.lastImageOrig.Image.GetPixel(ImgData.lastPoint.X, ImgData.lastPoint.Y).R;
int rgbVal = getRSmooth(ImgData.lastPoint);
lastCalcTemp = lastTempRange.Minimum + ((lastTempRange.Maximum - lastTempRange.Minimum) * rgbVal / 255);
}
}
}
#endif
private void Image_Changed(object sender, Flir.Atlas.Image.ImageChangedEventArgs e)
{
IsDirty = true;
_timerRefreshUi.Interval = 500;
}
private void lblOrigA_Click(object sender, EventArgs e)
@@ -553,12 +340,8 @@ namespace ThermalImageStreamerDemo
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (_recorder != null && _recorder.IsDisposed == false)
{
_recorder.Dispose();
}
DisposeCamera();
_timerRefreshUi.Stop();
ThermoCamCont.DisposeCamera();
}
private void MainForm_Load(object sender, EventArgs e)
@@ -567,11 +350,6 @@ namespace ThermalImageStreamerDemo
private void MainForm_Shown(object sender, EventArgs e)
{
// avvio l'autoconnessione
if (!string.IsNullOrEmpty(currConf.CameraName))
{
discoveryCamera();
}
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
@@ -592,29 +370,29 @@ namespace ThermalImageStreamerDemo
double ratio = 1;
try
{
if (ImgData.Origin != null && ImgData.Origin.Width > 0)
if (ThermoCamCont.Origin != null && ThermoCamCont.Origin.Width > 0)
{
ratio = (double)pBoxA.Width / ImgData.Origin.Width;
ratio = (double)pBoxA.Width / ThermoCamCont.Origin.Width;
}
}
catch
{ }
// trasformo punto in equivalente originale
var mea = (MouseEventArgs)e;
ImgData.lastPoint = new Point() { X = (int)(mea.X / ratio), Y = (int)(mea.Y / ratio) };
lblPoint.Text = $"({mea.X},{mea.Y}) --> ({ImgData.lastPoint.X},{ImgData.lastPoint.Y})";
ThermoCamCont.lastPoint = new Point() { X = (int)(mea.X / ratio), Y = (int)(mea.Y / ratio) };
lblPoint.Text = $"({mea.X},{mea.Y}) --> ({ThermoCamCont.lastPoint.X},{ThermoCamCont.lastPoint.Y})";
if (pointSetup)
{
// max 4 punti... se sono già FULL --> imposto singolo valore nuovo
if (currConf.origPoints.curr >= 4)
if (ThermoCamCont.currConf.OrigPoints.curr >= 4)
{
if (currPoint >= 0)
{
currConf.origPoints.Coords[currPoint] = ImgData.lastPoint;
ThermoCamCont.currConf.OrigPoints.Coords[currPoint] = ThermoCamCont.lastPoint;
}
else
{
currConf.origPoints = new SetPoints();
ThermoCamCont.currConf.OrigPoints = new SetPoints();
}
}
else
@@ -622,14 +400,14 @@ namespace ThermalImageStreamerDemo
// salvo coordinate in base al num corrente...
try
{
currConf.origPoints.Coords.Add(ImgData.lastPoint);
currConf.origPoints.curr++;
ThermoCamCont.currConf.OrigPoints.Coords.Add(ThermoCamCont.lastPoint);
ThermoCamCont.currConf.OrigPoints.curr++;
}
catch
{ }
}
// salvo conf
saveConf();
ThermoCamCont.saveConf();
// aggiorno visualizzazione
processImage();
@@ -637,7 +415,8 @@ namespace ThermalImageStreamerDemo
}
else if (readTemp)
{
refTempPoint = ImgData.lastPoint;
// x ora fisso 1 solo valore...
ThermoCamCont.saveMeasurePoint(false);
// aggiorno visualizzazione
processImage();
refreshDisplay();
@@ -647,25 +426,13 @@ namespace ThermalImageStreamerDemo
private void processImage()
{
// disegno immagine
ImgData.getTemperatures(readTemp);
ImgData.calculateTarget(chkParallel.Checked, chkRevProc.Checked);
}
private void recorderToolStripMenuItem_Click(object sender, EventArgs e)
{
if (_recorder == null || _recorder.IsDisposed)
{
_recorder = new RecorderForm();
_recorder.Initialize(IRCam.ThermoCamera);
_recorder.SelectedFileMouseDoubleClick += _recorder_SelectedFileMouseDoubleClick;
}
_recorder.Show();
_recorder.Focus();
ThermoCamCont.getTemperatures(readTemp);
ThermoCamCont.calculateTarget();
}
private void refreshDisplay()
{
drawCrossAtPoints();
ThermoCamCont.drawCrossAtPoints();
displayImages();
updateDisplay();
updateTempDisplay();
@@ -673,94 +440,12 @@ namespace ThermalImageStreamerDemo
}
/// <summary>
/// Salva su file il file di conf corrente
/// Sistema le temp range min/Max
/// </summary>
/// <returns></returns>
private bool saveConf()
private void setRangeTemp()
{
bool answ = false;
try
{
string rawData = JsonConvert.SerializeObject(currConf, Formatting.Indented);
File.WriteAllText(confPath, rawData);
answ = true;
}
catch
{ }
return answ;
}
private void saveImgFile()
{
try
{
// fix percorsi
string dirPath = $"{BASE_PATH}\\{thermPath}";
string filePath = $"{dirPath}\\{currImgFile}";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
// salvo!
ImgData.Thermal.Scale.IsAutoAdjustEnabled = true;
ImgData.Thermal.SaveSnapshot(filePath);
}
catch
{ }
}
/// <summary>
/// recupera immagine effettuando eventuale salvataggio
/// </summary>
/// <param name="doSave"></param>
private void takePicture(bool doSave)
{
sw.Restart();
if (!IsDirty) return;
IsDirty = false;
if (IRCam.ThermoCamera == null) return;
IRCam.ThermoCamera.GetImage().EnterLock();
try
{
// non funziona
#if false
// se richiesto imposto temperature min/max...
if (!chkAutoTemp.Checked)
{
Range<double> limits = new Range<double>(273.1 + minTemp, 273.1 + maxTemp);
IRCam.ThermoCamera.RemoteControl.CameraSettings.SetScaleLimits(limits);
}
#endif
ImgData.Thermal = (ThermalImage)IRCam.ThermoCamera.GetImage();
ImgData.Thermal.TemperatureUnit = TemperatureUnit.Celsius;
ImgData.Thermal.Scale.IsAutoAdjustEnabled = true;
// salvo img locale
ImgData.Origin = ImgData.Thermal.Image;
ImgData.Decorated = ImgData.Thermal.Image;
if (doSave)
{
saveImgFile();
}
}
catch (Exception exception)
{
Trace.TraceError(exception.Message);
}
finally
{
IRCam.ThermoCamera.GetImage().ExitLock();
}
sw.Stop();
msLastCam = sw.ElapsedMilliseconds;
#if false
ThermalImage myImg = (ThermalImage)_stream.GetImage();
myImg.TemperatureUnit = TemperatureUnit.Celsius;
string currPath = $"{labelOutputPath.Text}\\{DateTime.Now:yyyyMMyy_HHmmss}.jpg";
myImg.SaveSnapshot(currPath);
#endif
ThermoCamCont.currConf.TargetRange.Min = minRangeTemp;
ThermoCamCont.currConf.TargetRange.Max = maxRangeTemp;
}
/// <summary>
@@ -790,24 +475,6 @@ namespace ThermalImageStreamerDemo
return answ;
}
private void tryReloadConf()
{
if (File.Exists(confPath))
{
// se non è vuoto....
string rawData = File.ReadAllText(confPath);
if (!string.IsNullOrEmpty(rawData))
{
try
{
currConf = JsonConvert.DeserializeObject<ThermoCamConf>(rawData);
}
catch (Exception exc)
{ }
}
}
}
private void txtAB_TextChanged(object sender, EventArgs e)
{
// ricalcolo in proporzione altro valore...
@@ -824,16 +491,26 @@ namespace ThermalImageStreamerDemo
updateDestPt();
}
private void txtMaxScale_TextChanged(object sender, EventArgs e)
{
setRangeTemp();
}
private void txtMinScale_TextChanged(object sender, EventArgs e)
{
setRangeTemp();
}
private void updateDestPt()
{
currConf.destPoints.Coords = new List<Point>();
ThermoCamCont.currConf.DestPoints.Coords = new List<Point>();
// ciclo i punti A-B-C-D...
currConf.destPoints.Coords.Add(new Point() { X = 0, Y = 0 });
currConf.destPoints.Coords.Add(new Point() { X = dimX, Y = 0 });
currConf.destPoints.Coords.Add(new Point() { X = dimX, Y = dimY });
currConf.destPoints.Coords.Add(new Point() { X = 0, Y = dimY });
ThermoCamCont.currConf.DestPoints.Coords.Add(new Point() { X = 0, Y = 0 });
ThermoCamCont.currConf.DestPoints.Coords.Add(new Point() { X = dimX, Y = 0 });
ThermoCamCont.currConf.DestPoints.Coords.Add(new Point() { X = dimX, Y = dimY });
ThermoCamCont.currConf.DestPoints.Coords.Add(new Point() { X = 0, Y = dimY });
// salvo conf
saveConf();
ThermoCamCont.saveConf();
}
private void updateDisplay()
@@ -843,112 +520,77 @@ namespace ThermalImageStreamerDemo
lblOrigC.Text = "C";
lblOrigD.Text = "D";
// popolo
if (currConf.origPoints.Coords.Count > 0)
if (ThermoCamCont.currConf.OrigPoints.Coords.Count > 0)
{
lblOrigA.Text = $"A: ({currConf.origPoints.Coords[0].X},{currConf.origPoints.Coords[0].Y})";
lblOrigA.Text = $"A: ({ThermoCamCont.currConf.OrigPoints.Coords[0].X},{ThermoCamCont.currConf.OrigPoints.Coords[0].Y})";
}
if (currConf.origPoints.Coords.Count > 1)
if (ThermoCamCont.currConf.OrigPoints.Coords.Count > 1)
{
lblOrigB.Text = $"B: ({currConf.origPoints.Coords[1].X},{currConf.origPoints.Coords[1].Y})";
lblOrigB.Text = $"B: ({ThermoCamCont.currConf.OrigPoints.Coords[1].X},{ThermoCamCont.currConf.OrigPoints.Coords[1].Y})";
}
if (currConf.origPoints.Coords.Count > 2)
if (ThermoCamCont.currConf.OrigPoints.Coords.Count > 2)
{
lblOrigC.Text = $"C: ({currConf.origPoints.Coords[2].X},{currConf.origPoints.Coords[2].Y})";
lblOrigC.Text = $"C: ({ThermoCamCont.currConf.OrigPoints.Coords[2].X},{ThermoCamCont.currConf.OrigPoints.Coords[2].Y})";
}
if (currConf.origPoints.Coords.Count > 3)
if (ThermoCamCont.currConf.OrigPoints.Coords.Count > 3)
{
lblOrigD.Text = $"D: ({currConf.origPoints.Coords[3].X},{currConf.origPoints.Coords[3].Y})";
ImgData.calculateTarget(chkParallel.Checked, chkRevProc.Checked);
lblOrigD.Text = $"D: ({ThermoCamCont.currConf.OrigPoints.Coords[3].X},{ThermoCamCont.currConf.OrigPoints.Coords[3].Y})";
ThermoCamCont.calculateTarget();
}
}
private void updateStatDisplay()
{
lblStats.Text = $"Camera: {msLastCam}ms | Persp {msLastTra}ms | Color {msLastCol}ms | Points {msLastPts}ms | Measures {msLastMsr}ms";
if (ThermoCamCont.ExTime.Stats.Count > 0)
{
try
{
lblStats.Text = $"Camera: {ThermoCamCont.lastStatTime("ImageAcquisition")}ms | Persp {ThermoCamCont.lastStatTime("ImageTransf")}ms | Color {ThermoCamCont.lastStatTime("ImageColor")}ms | Points {ThermoCamCont.lastStatTime("AddPoints")}ms | Measures {ThermoCamCont.lastStatTime("GetAllTemperatures")}ms";
}
catch
{ }
}
}
private void updateTempDisplay()
{
if (ImgData.Thermal != null)
if (ThermoCamCont.Thermal != null)
{
if (readTemp)
{
// mostro temp da FLIR
lblReadTemp.Text = $"{ImgData.lastReadTemp:N2} °C";
//calcolo da immagine B/N
lblTempRGB.Text = $"{ImgData.lastCalcTemp:N2} °C";
// cambio colore se > 1 grado...
double delta = Math.Abs(ImgData.lastReadTemp - ImgData.lastCalcTemp);
if (delta < 1)
try
{
lblTempRGB.ForeColor = Color.Black;
}
else if (delta < 2)
{
lblTempRGB.ForeColor = Color.Blue;
}
else if (delta < 3)
{
lblTempRGB.ForeColor = Color.Orange;
}
else
{
lblTempRGB.ForeColor = Color.Red;
// mostro temp da FLIR
lblReadTemp.Text = $"{ThermoCamCont.lastReadTemp:N2} °C";
// mostro minimo / massimo
lblMinTemp.Text = $"{ThermoCamCont.lastTempRange.Minimum:N2}";
lblMaxTemp.Text = $"{ThermoCamCont.lastTempRange.Maximum:N2}";
}
catch
{ }
}
}
}
#endregion Private Methods
#if false
/// <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 (ImgData.Origin != null)
{
// solo se il punto è entro limiti immagine --> 1 pixel entro bordo
if (reqPoint.X > 0 && reqPoint.X < ImgData.Origin.Width)
{
if (reqPoint.Y > 0 && reqPoint.Y < ImgData.Origin.Height)
{
int rgbValMain = ImgData.Origin.GetPixel(ImgData.lastPoint.X, ImgData.lastPoint.Y).R;
int rgbValN = ImgData.Origin.GetPixel(ImgData.lastPoint.X, ImgData.lastPoint.Y - 1).R;
int rgbValNO = ImgData.Origin.GetPixel(ImgData.lastPoint.X - 1, ImgData.lastPoint.Y - 1).R;
int rgbValO = ImgData.Origin.GetPixel(ImgData.lastPoint.X - 1, ImgData.lastPoint.Y).R;
int rgbValSO = ImgData.Origin.GetPixel(ImgData.lastPoint.X - 1, ImgData.lastPoint.Y + 1).R;
int rgbValS = ImgData.Origin.GetPixel(ImgData.lastPoint.X, ImgData.lastPoint.Y + 1).R;
int rgbValSE = ImgData.Origin.GetPixel(ImgData.lastPoint.X + 1, ImgData.lastPoint.Y + 1).R;
int rgbValE = ImgData.Origin.GetPixel(ImgData.lastPoint.X + 1, ImgData.lastPoint.Y).R;
int rgbValNE = ImgData.Origin.GetPixel(ImgData.lastPoint.X + 1, ImgData.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;
}
#endif
#region Public Methods
public void discoveryCamera()
{
var discoveryDialog = new DiscoveryForm();
discoveryDialog.CameraName = currConf.CameraName;
if (!string.IsNullOrEmpty(currConf.CameraName))
// se no connesso così prosegue...
if (!IRCam.ThermoCamera.IsConnected)
{
//discoveryDialog.WindowState = FormWindowState.Minimized;
if (discoveryDialog.ShowDialog() == DialogResult.OK)
discoveryDialog.CameraAddress = ThermoCamCont.currConf.CameraAddress;
discoveryDialog.CameraName = ThermoCamCont.currConf.CameraName;
if (discoveryDialog.doAutoConnect)
{
ConnectCamera(discoveryDialog.SelectedCameraDevice);
//discoveryDialog.WindowState = FormWindowState.Minimized;
if (discoveryDialog.ShowDialog() == DialogResult.OK)
{
ThermoCamCont.ConnectCamera(discoveryDialog.SelectedCameraDevice);
}
}
}
}
@@ -140,6 +140,9 @@
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<None Include="ThermoConf.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="ThermoConf-AX5.json" />
</ItemGroup>
<ItemGroup>
+27 -51
View File
@@ -1,55 +1,31 @@
{
"ConfCameraDevice": {
"IpConfiguration": {
"Error": 1,
"IsDhcpValid": false,
"IsDhcpEnabled": false,
"DefaultGateway": "",
"SubnetMask": ""
"MeasPoints": [],
"CameraName": "FLIR AX5",
"CameraAddress": "",
"DestPoints": {
"Coords": [
"0, 0",
"1500, 0",
"1500, 1200",
"0, 1200"
],
"curr": 0
},
"IsFlirCamera": true,
"CameraDeviceType": 32,
"Name": "FLIR AX5",
"IpSettings": {
"IpAddress": "10.74.82.110",
"Hostname": "",
"Mac": "00:11:1c:04:3d:32",
"SubnetMask": "255.255.255.0",
"DefaultGateway": "",
"IsWireless": false,
"Adapter": "{0EFF8137-F8BD-4A44-A77B-BAACF4C4A8D7}",
"AdapterMac": "00:15:5d:e9:dd:16",
"IsValid": true
"OrigPoints": {
"Coords": [
"55, 214",
"49, 68",
"218, 80",
"197, 226"
],
"curr": 4
},
"StreamingFormats": [
0
],
"SelectedStreamingFormat": 0,
"DeviceIdentifier": "00:11:1c:04:3d:32",
"SerialNumber": "83202739",
"OsImagekitName": "N/A",
"SwCombinationVersion": "Version 1.0 (02.05.15)",
"ConfigurationKitName": "N/A",
"Article": "FLIR AX5",
"VideoQuality": 0,
"IsRecorderEnabled": true
},
"origPoints": {
"curr": 4,
"Coords": [
"66, 223",
"20, 84",
"188, 51",
"205, 197"
]
},
"destPoints": {
"curr": 0,
"Coords": [
"0, 0",
"640, 0",
"640, 512",
"0, 512"
]
}
"TargetRange": {
"Max": 60.0,
"Min": 0.0
},
"TargetSize": {
"X": 1500,
"Y": 1200
}
}
+31
View File
@@ -0,0 +1,31 @@
{
"MeasPoints": [],
"CameraName": "FLIR AX5",
"CameraAddress": "",
"DestPoints": {
"Coords": [
"0, 0",
"1500, 0",
"1500, 1200",
"0, 1200"
],
"curr": 0
},
"OrigPoints": {
"Coords": [
"55, 214",
"49, 68",
"218, 80",
"197, 226"
],
"curr": 4
},
"TargetRange": {
"Max": 60.0,
"Min": 0.0
},
"TargetSize": {
"X": 1500,
"Y": 1200
}
}
@@ -6,206 +6,224 @@ using Thermo.Active.Model.DatabaseModels;
namespace Thermo.Active.Database.Controllers
{
public class ProdInfoController : IDisposable
{
private DatabaseContext dbCtx;
public class ProdInfoController : IDisposable
{
#region Private Fields
public ProdInfoController()
{
// Initialize database context
dbCtx = new DatabaseContext();
}
private DatabaseContext dbCtx;
public void Dispose()
{
// Clear database context
dbCtx.Dispose();
}
/// <summary>
/// Get record by NumDone
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public ProdInfoModel FindByNumDone(int num)
{
return dbCtx
.ProdInfo
.Where(x => x.NumDone == num)
.SingleOrDefault();
}
/// <summary>
/// Get historical paginated data from DB (DESC ordered)
/// </summary>
/// <param name="numStart"></param>
/// <param name="numRecord"></param>
/// <returns></returns>
public List<ProdInfoModel> GetPaginatedDesc(int numStart, int numRecord)
{
int numEnd = numStart - numRecord;
// check numEnd
if (numEnd < 0)
numEnd = 0;
// retrieve
return dbCtx
.ProdInfo
.Where(x => x.NumDone <= numStart)
//.Where(x => x.NumDone <= numStart && x.NumDone > numEnd)
.OrderByDescending(x => x.DtEvent)
.Take(numRecord)
.ToList();
}
/// <summary>
/// Get historical paginated data from DB (ASC ordered)
/// </summary>
/// <param name="numStart"></param>
/// <param name="numRecord"></param>
/// <returns></returns>
public List<ProdInfoModel> GetPaginatedAsc(int numStart, int numRecord)
{
int numEnd = numStart + numRecord;
// retrieve
return dbCtx
.ProdInfo
.Where(x => x.NumDone >= numStart)
.OrderBy(x => x.DtEvent)
.Take(numRecord)
.ToList();
}
/// <summary>
/// Create new prodInfo record on DB
/// </summary>
/// <param name="NumTarget"></param>
/// <param name="NumDone"></param>
/// <param name="TimeWarm"></param>
/// <param name="TimeVent"></param>
/// <param name="TimeVacuum"></param>
/// <param name="TimeCycleGross"></param>
/// <param name="TimeCycleNet"></param>
/// <param name="MaterialTempEndWarm"></param>
/// <param name="MaterialTempEndVent"></param>
/// <param name="MoldTemp"></param>
/// <param name="VacuumReadVal"></param>
/// <param name="MouldEnergyOUT"></param>
/// <param name="MouldEnergyIN"></param>
/// <param name="IsScrap"></param>
/// <returns></returns>
public ProdInfoModel Create(short NumTarget, short NumDone, int TimeWarm, int TimeVent, int TimeVacuum, int TimeCycleGross, int TimeCycleNet, double MaterialTempEndWarm, double MaterialTempEndVent, double MoldTemp, double VacuumReadVal, double MouldEnergyOUT, double MouldEnergyIN, bool IsScrap)
{
// Create database machine model
ProdInfoModel prodData = new ProdInfoModel()
{
DtEvent = DateTime.Now,
NumTarget = NumTarget,
NumDone = NumDone,
TimeWarm = TimeWarm,
TimeVent = TimeVent,
TimeVacuum = TimeVacuum,
TimeCycleGross = TimeCycleGross,
TimeCycleNet = TimeCycleNet,
MaterialTempEndWarm = MaterialTempEndWarm,
MaterialTempEndVent = MaterialTempEndVent,
MoldTemp = MoldTemp,
VacuumReadVal = VacuumReadVal,
MouldEnergyOUT = MouldEnergyOUT,
MouldEnergyIN = MouldEnergyIN,
IsScrap = IsScrap
};
try
{
// Add to database
dbCtx.ProdInfo.AddOrUpdate(prodData);
//dbCtx.ProdInfo.Add(prodData);
// Commit changes
dbCtx.SaveChanges();
}
catch
{ }
#endregion Private Fields
return prodData;
}
/// <summary>
/// Process table and set as scrap by num value
/// </summary>
/// <param name="maxKeep"></param>
/// <returns></returns>
public bool SetScrap(int num, bool isScrap)
{
bool answ = false;
#region Public Constructors
var currRecord = dbCtx
.ProdInfo
.Where(x => x.NumDone == num)
.SingleOrDefault();
try
{
if (currRecord != null)
public ProdInfoController()
{
currRecord.IsScrap = isScrap;
// Initialize database context
dbCtx = new DatabaseContext();
}
// save!
dbCtx.SaveChanges();
answ = true;
}
catch
{ }
return answ;
}
/// <summary>
/// Process table and keep only maxKeep most recent ones
/// </summary>
/// <param name="maxKeep"></param>
/// <returns></returns>
public bool PurgeOldest(int maxKeep)
{
bool answ = false;
#endregion Public Constructors
// check if purge needed
int numRec = dbCtx.ProdInfo.Count();
if (numRec > maxKeep)
{
ProdInfoModel firstToDelete = (ProdInfoModel)(from p in dbCtx.ProdInfo
orderby p.DtEvent descending
select p).Skip(maxKeep).Take(1);
#region Public Methods
// call deletion
dbCtx
.ProdInfo
.RemoveRange(
dbCtx
/// <summary>
/// Create new prodInfo record on DB
/// </summary>
/// <param name="NumTarget"></param>
/// <param name="NumDone"></param>
/// <param name="TimeWarm"></param>
/// <param name="TimeVent"></param>
/// <param name="TimeVacuum"></param>
/// <param name="TimeCycleGross"></param>
/// <param name="TimeCycleNet"></param>
/// <param name="MaterialTempEndWarm"></param>
/// <param name="MaterialTempEndVent"></param>
/// <param name="MoldTemp"></param>
/// <param name="VacuumReadVal"></param>
/// <param name="MouldEnergyOUT"></param>
/// <param name="MouldEnergyIN"></param>
/// <param name="IsScrap"></param>
/// <returns></returns>
public ProdInfoModel Create(short NumTarget, short NumDone, int TimeWarm, int TimeVent, int TimeVacuum, int TimeCycleGross, int TimeCycleNet, float MaterialTempEndWarm, float MaterialTempEndVent, float MoldTemp, float VacuumReadVal, float MouldEnergyOUT, float MouldEnergyIN, bool IsScrap, string ThermoImage)
{
// Create database machine model
ProdInfoModel prodData = new ProdInfoModel()
{
DtEvent = DateTime.Now,
NumTarget = NumTarget,
NumDone = NumDone,
TimeWarm = TimeWarm,
TimeVent = TimeVent,
TimeVacuum = TimeVacuum,
TimeCycleGross = TimeCycleGross,
TimeCycleNet = TimeCycleNet,
MaterialTempEndWarm = MaterialTempEndWarm,
MaterialTempEndVent = MaterialTempEndVent,
MoldTemp = MoldTemp,
VacuumReadVal = VacuumReadVal,
MouldEnergyOUT = MouldEnergyOUT,
MouldEnergyIN = MouldEnergyIN,
IsScrap = IsScrap,
ThermoImage = ThermoImage
};
try
{
// Add to database
dbCtx.ProdInfo.AddOrUpdate(prodData);
//dbCtx.ProdInfo.Add(prodData);
// Commit changes
dbCtx.SaveChanges();
}
catch
{ }
return prodData;
}
public void Dispose()
{
// Clear database context
dbCtx.Dispose();
}
/// <summary>
/// Get record by NumDone
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public ProdInfoModel FindByNumDone(int num)
{
return dbCtx
.ProdInfo
.Where(x => x.DtEvent <= firstToDelete.DtEvent)
);
try
{
// save!
dbCtx.SaveChanges();
answ = true;
.Where(x => x.NumDone == num)
.SingleOrDefault();
}
catch
{ }
}
return answ;
}
/// <summary>
/// Process table and delete all record (truncate)
/// </summary>
/// <returns></returns>
public bool PurgeAll()
{
bool answ = false;
/// <summary>
/// Get historical paginated data from DB (ASC ordered)
/// </summary>
/// <param name="numStart"></param>
/// <param name="numRecord"></param>
/// <returns></returns>
public List<ProdInfoModel> GetPaginatedAsc(int numStart, int numRecord)
{
int numEnd = numStart + numRecord;
// retrieve
return dbCtx
.ProdInfo
.Where(x => x.NumDone >= numStart)
.OrderBy(x => x.DtEvent)
.Take(numRecord)
.ToList();
}
try
{
dbCtx
.Database
.ExecuteSqlCommand("TRUNCATE TABLE prodInfo");
}
catch
{ }
return answ;
/// <summary>
/// Get historical paginated data from DB (DESC ordered)
/// </summary>
/// <param name="numStart"></param>
/// <param name="numRecord"></param>
/// <returns></returns>
public List<ProdInfoModel> GetPaginatedDesc(int numStart, int numRecord)
{
int numEnd = numStart - numRecord;
// check numEnd
if (numEnd < 0)
numEnd = 0;
// retrieve
return dbCtx
.ProdInfo
.Where(x => x.NumDone <= numStart)
//.Where(x => x.NumDone <= numStart && x.NumDone > numEnd)
.OrderByDescending(x => x.DtEvent)
.Take(numRecord)
.ToList();
}
/// <summary>
/// Process table and delete all record (truncate)
/// </summary>
/// <returns></returns>
public bool PurgeAll()
{
bool answ = false;
try
{
dbCtx
.Database
.ExecuteSqlCommand("TRUNCATE TABLE prodInfo");
}
catch
{ }
return answ;
}
/// <summary>
/// Process table and keep only maxKeep most recent ones
/// </summary>
/// <param name="maxKeep"></param>
/// <returns></returns>
public bool PurgeOldest(int maxKeep)
{
bool answ = false;
// check if purge needed
int numRec = dbCtx.ProdInfo.Count();
if (numRec > maxKeep)
{
ProdInfoModel firstToDelete = (ProdInfoModel)(from p in dbCtx.ProdInfo
orderby p.DtEvent descending
select p).Skip(maxKeep).Take(1);
// call deletion
dbCtx
.ProdInfo
.RemoveRange(
dbCtx
.ProdInfo
.Where(x => x.DtEvent <= firstToDelete.DtEvent)
);
try
{
// save!
dbCtx.SaveChanges();
answ = true;
}
catch
{ }
}
return answ;
}
/// <summary>
/// Process table and set as scrap by num value
/// </summary>
/// <param name="maxKeep"></param>
/// <returns></returns>
public bool SetScrap(int num, bool isScrap)
{
bool answ = false;
var currRecord = dbCtx
.ProdInfo
.Where(x => x.NumDone == num)
.SingleOrDefault();
try
{
if (currRecord != null)
{
currRecord.IsScrap = isScrap;
}
// save!
dbCtx.SaveChanges();
answ = true;
}
catch
{ }
return answ;
}
#endregion Public Methods
}
}
}
@@ -0,0 +1,29 @@
// <auto-generated />
namespace Thermo.Active.Database.Migrations
{
using System.CodeDom.Compiler;
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
[GeneratedCode("EntityFramework.Migrations", "6.2.0-61023")]
public sealed partial class Added_ThermoImage_prodInfo : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(Added_ThermoImage_prodInfo));
string IMigrationMetadata.Id
{
get { return "202102171753226_Added_ThermoImage_prodInfo"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,30 @@
namespace Thermo.Active.Database.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class Added_ThermoImage_prodInfo : DbMigration
{
public override void Up()
{
AddColumn("dbo.ProdInfo", "ThermoImage", c => c.String(unicode: false));
AlterColumn("dbo.ProdInfo", "MaterialTempEndWarm", c => c.Single(nullable: false));
AlterColumn("dbo.ProdInfo", "MaterialTempEndVent", c => c.Single(nullable: false));
AlterColumn("dbo.ProdInfo", "MoldTemp", c => c.Single(nullable: false));
AlterColumn("dbo.ProdInfo", "VacuumReadVal", c => c.Single(nullable: false));
AlterColumn("dbo.ProdInfo", "MouldEnergyOUT", c => c.Single(nullable: false));
AlterColumn("dbo.ProdInfo", "MouldEnergyIN", c => c.Single(nullable: false));
}
public override void Down()
{
AlterColumn("dbo.ProdInfo", "MouldEnergyIN", c => c.Double(nullable: false));
AlterColumn("dbo.ProdInfo", "MouldEnergyOUT", c => c.Double(nullable: false));
AlterColumn("dbo.ProdInfo", "VacuumReadVal", c => c.Double(nullable: false));
AlterColumn("dbo.ProdInfo", "MoldTemp", c => c.Double(nullable: false));
AlterColumn("dbo.ProdInfo", "MaterialTempEndVent", c => c.Double(nullable: false));
AlterColumn("dbo.ProdInfo", "MaterialTempEndWarm", c => c.Double(nullable: false));
DropColumn("dbo.ProdInfo", "ThermoImage");
}
}
}
File diff suppressed because one or more lines are too long
@@ -154,6 +154,10 @@
<Compile Include="Migrations\202011051531133_AddedKeyboaSoftkey.Designer.cs">
<DependentUpon>202011051531133_AddedKeyboaSoftkey.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\202102171753226_Added_ThermoImage_prodInfo.cs" />
<Compile Include="Migrations\202102171753226_Added_ThermoImage_prodInfo.Designer.cs">
<DependentUpon>202102171753226_Added_ThermoImage_prodInfo.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Redis\redUtil.cs" />
@@ -205,6 +209,9 @@
<EmbeddedResource Include="Migrations\202011051531133_AddedKeyboaSoftkey.resx">
<DependentUpon>202011051531133_AddedKeyboaSoftkey.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Migrations\202102171753226_Added_ThermoImage_prodInfo.resx">
<DependentUpon>202102171753226_Added_ThermoImage_prodInfo.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -44,26 +44,26 @@ namespace Thermo.Active.Model.ConfigModels
#region Public Fields
public int Canale;
public int Riga;
public int Tipo;
public int IdGruppo;
public int Riga;
public int Tipo;
#endregion Public Fields
}
public class RiskResistModel
{
#region Public Fields
#region Public Properties
public int Column { get; set; } = 0;
public int Dimension { get; set; } = 0;
public int Id { get; set; } = 0;
public int IdChannel { get; set; } = 0;
public int IdReflector { get; set; } = 0;
public int IdGroup { get; set; } = 0;
public int IdReflector { get; set; } = 0;
public int Row { get; set; } = 0;
#endregion Public Fields
#endregion Public Properties
}
public class RiskRiferimenti
@@ -7,95 +7,112 @@ using System.Threading.Tasks;
namespace Thermo.Active.Model.DTOModels.ThProd
{
public class DTOProdInfo
{
public DateTime DtEvent { get; set; }
public short NumTarget { get; set; } = 0;
public short NumDone { get; set; } = 0;
public double TimeWarm { get; set; } = 0;
public double TimeVent { get; set; } = 0;
public double TimeVacuum { get; set; } = 0;
public double TimeCycleGross { get; set; } = 0;
public double TimeCycleNet { get; set; } = 0;
public int NumDec { get; set; } = 1;
public int ScaleFactor { get; set; } = 1000;
public double MaterialTempEndWarm { get; set; } = 0;
public double MaterialTempEndVent { get; set; } = 0;
public double MoldTemp { get; set; } = 0;
public double VacuumReadVal { get; set; } = 0;
public double MouldEnergyOUT { get; set; } = 0;
public double MouldEnergyIN { get; set; } = 0;
public bool IsScrap { get; set; } = false;
public short NumPreHot { get; set; } = 0;
public override bool Equals(object obj)
public class DTOProdInfo
{
// Object is not a GaugeModel instance
if (!(obj is DTOProdInfo item))
return false;
#region Public Constructors
if (DtEvent != item.DtEvent)
return false;
if (NumTarget != item.NumTarget)
return false;
if (NumDone != item.NumDone)
return false;
if (Math.Round(Math.Abs(TimeWarm - item.TimeWarm), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeVent - item.TimeVent), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeVacuum - item.TimeVacuum), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeCycleGross - item.TimeCycleGross), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeCycleNet - item.TimeCycleNet), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MaterialTempEndWarm - item.MaterialTempEndWarm), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MaterialTempEndVent - item.MaterialTempEndVent), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MoldTemp - item.MoldTemp), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(VacuumReadVal - item.VacuumReadVal), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MouldEnergyOUT - item.MouldEnergyOUT), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MouldEnergyIN - item.MouldEnergyIN), 1) >= Constants.EPSILON)
return false;
if (IsScrap != item.IsScrap)
return false;
if (NumPreHot != item.NumPreHot)
return false;
public DTOProdInfo()
{
}
return true;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
public DTOProdInfo(ThermoModels.ProdInfoModel pimRawData)
{
this.DtEvent = pimRawData.DtEvent;
this.NumDone = pimRawData.NumDone;
this.NumTarget = pimRawData.NumTarget;
this.ThermoImage = pimRawData.ThermoImage;
this.TimeCycleGross = Math.Round((double)pimRawData.TimeCycleGross / this.ScaleFactor, 2);
this.TimeCycleNet = Math.Round((double)pimRawData.TimeCycleNet / this.ScaleFactor, 2);
this.TimeVacuum = Math.Round((double)pimRawData.TimeVacuum / this.ScaleFactor, 2);
this.TimeVent = Math.Round((double)pimRawData.TimeVent / this.ScaleFactor, 2);
this.TimeWarm = Math.Round((double)pimRawData.TimeWarm / this.ScaleFactor, 2);
this.MaterialTempEndWarm = pimRawData.MaterialTempEndWarm;
this.MaterialTempEndVent = pimRawData.MaterialTempEndVent;
this.MoldTemp = pimRawData.MoldTemp;
this.VacuumReadVal = pimRawData.VacuumReadVal;
this.MouldEnergyIN = pimRawData.MouldEnergyIN;
this.MouldEnergyOUT = pimRawData.MouldEnergyOUT;
this.IsScrap = pimRawData.IsScrap;
this.NumPreHot = pimRawData.NumPreHot;
}
public DTOProdInfo()
{
}
#endregion Public Constructors
public DTOProdInfo(ThermoModels.ProdInfoModel pimRawData)
{
this.DtEvent = pimRawData.DtEvent;
this.NumDone = pimRawData.NumDone;
this.NumTarget = pimRawData.NumTarget;
this.TimeCycleGross = Math.Round((double)pimRawData.TimeCycleGross / this.ScaleFactor, 2);
this.TimeCycleNet = Math.Round((double)pimRawData.TimeCycleNet / this.ScaleFactor, 2);
this.TimeVacuum = Math.Round((double)pimRawData.TimeVacuum / this.ScaleFactor, 2);
this.TimeVent = Math.Round((double)pimRawData.TimeVent / this.ScaleFactor, 2);
this.TimeWarm = Math.Round((double)pimRawData.TimeWarm / this.ScaleFactor, 2);
this.MaterialTempEndWarm = pimRawData.MaterialTempEndWarm;
this.MaterialTempEndVent = pimRawData.MaterialTempEndVent;
this.MoldTemp = pimRawData.MoldTemp;
this.VacuumReadVal = pimRawData.VacuumReadVal;
this.MouldEnergyIN = pimRawData.MouldEnergyIN;
this.MouldEnergyOUT = pimRawData.MouldEnergyOUT;
this.IsScrap = pimRawData.IsScrap;
this.NumPreHot = pimRawData.NumPreHot;
#region Public Properties
public DateTime DtEvent { get; set; }
public bool IsScrap { get; set; } = false;
public double MaterialTempEndVent { get; set; } = 0;
public double MaterialTempEndWarm { get; set; } = 0;
public double MoldTemp { get; set; } = 0;
public double MouldEnergyIN { get; set; } = 0;
public double MouldEnergyOUT { get; set; } = 0;
public int NumDec { get; set; } = 1;
public short NumDone { get; set; } = 0;
public short NumPreHot { get; set; } = 0;
public short NumTarget { get; set; } = 0;
public int ScaleFactor { get; set; } = 1000;
public string ThermoImage { get; set; } = "";
public double TimeCycleGross { get; set; } = 0;
public double TimeCycleNet { get; set; } = 0;
public double TimeVacuum { get; set; } = 0;
public double TimeVent { get; set; } = 0;
public double TimeWarm { get; set; } = 0;
public double VacuumReadVal { get; set; } = 0;
#endregion Public Properties
#region Public Methods
public override bool Equals(object obj)
{
// Object is not a GaugeModel instance
if (!(obj is DTOProdInfo item))
return false;
if (DtEvent != item.DtEvent)
return false;
if (NumTarget != item.NumTarget)
return false;
if (NumDone != item.NumDone)
return false;
if (ThermoImage != item.ThermoImage)
return false;
if (Math.Round(Math.Abs(TimeWarm - item.TimeWarm), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeVent - item.TimeVent), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeVacuum - item.TimeVacuum), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeCycleGross - item.TimeCycleGross), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(TimeCycleNet - item.TimeCycleNet), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MaterialTempEndWarm - item.MaterialTempEndWarm), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MaterialTempEndVent - item.MaterialTempEndVent), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MoldTemp - item.MoldTemp), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(VacuumReadVal - item.VacuumReadVal), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MouldEnergyOUT - item.MouldEnergyOUT), 1) >= Constants.EPSILON)
return false;
if (Math.Round(Math.Abs(MouldEnergyIN - item.MouldEnergyIN), 1) >= Constants.EPSILON)
return false;
if (IsScrap != item.IsScrap)
return false;
if (NumPreHot != item.NumPreHot)
return false;
return true;
}
public override int GetHashCode()
{
return base.GetHashCode();
}
#endregion Public Methods
}
}
}
}
@@ -8,19 +8,27 @@ namespace Thermo.Active.Model.DTOModels.ThWarmers
{
public class DTOThermoCam
{
/// <summary>
/// Opzione ThermoCamera (set by PLC)
/// </summary>
public bool ThermoOptionActive { get; set; } = false;
#region Public Properties
/// <summary>
/// Modalità ThermoCamera (set by HMI)
/// </summary>
public bool ThermoCamMode { get; set; } = false;
/// <summary>
/// Funzionamento ThermoCamera (set by HMI)
/// </summary>
public bool ThermoCamOnOff { get; set; } = false;
/// <summary>
/// Opzione ThermoCamera (set by PLC)
/// </summary>
public bool ThermoOptionActive { get; set; } = false;
#endregion Public Properties
#region Public Methods
/// <summary>
/// Equality test for class object
/// </summary>
@@ -49,5 +57,7 @@ namespace Thermo.Active.Model.DTOModels.ThWarmers
{
return base.GetHashCode();
}
#endregion Public Methods
}
}
}
@@ -6,16 +6,42 @@ using System.Threading.Tasks;
namespace Thermo.Active.Model.DTOModels.ThWarmers
{
public class PointReq
{
#region Public Properties
public List<ThermoPointFlir> List { get; set; } = new List<ThermoPointFlir>();
#endregion Public Properties
}
public class ThermoPoint
{
#region Public Properties
public int X { get; set; } = 0;
public int Y { get; set; } = 0;
#endregion Public Properties
#region Public Methods
public static int distance(ThermoPoint a, ThermoPoint b)
{
int answ = 0;
answ = (int)Math.Sqrt(Math.Pow((a.X - b.X), 2) + Math.Pow((a.Y - b.Y), 2));
return answ;
}
#endregion Public Methods
}
}
public class ThermoPointFlir : ThermoPoint
{
#region Public Properties
public float Temperature { get; set; } = 0;
#endregion Public Properties
}
}
@@ -7,43 +7,58 @@ namespace Thermo.Active.Model.DatabaseModels
[Table("ProdInfo")]
public class ProdInfoModel
{
#region Public Properties
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Column("DtEvent", Order = 0)]
public DateTime DtEvent { get; set; }
[Column("NumTarget")]
public short NumTarget { get; set; }
[Column("NumDone")]
public short NumDone { get; set; }
[Column("TimeWarm")]
public int TimeWarm { get; set; }
[Column("TimeVent")]
public int TimeVent { get; set; }
[Column("TimeVacuum")]
public int TimeVacuum { get; set; }
[Column("TimeCycleGross")]
public int TimeCycleGross { get; set; }
[Column("TimeCycleNet")]
public int TimeCycleNet { get; set; }
[Column("MaterialTempEndWarm")]
public double MaterialTempEndWarm { get; set; }
[Column("MaterialTempEndVent")]
public double MaterialTempEndVent { get; set; }
[Column("MoldTemp")]
public double MoldTemp { get; set; }
[Column("VacuumReadVal")]
public double VacuumReadVal { get; set; }
[Column("MouldEnergyOUT")]
public double MouldEnergyOUT { get; set; }
[Column("MouldEnergyIN")]
public double MouldEnergyIN { get; set; }
[Column("IsScrap")]
public bool IsScrap { get; set; }
[Column("MaterialTempEndVent")]
public float MaterialTempEndVent { get; set; }
[Column("MaterialTempEndWarm")]
public float MaterialTempEndWarm { get; set; }
[Column("MoldTemp")]
public float MoldTemp { get; set; }
[Column("MouldEnergyIN")]
public float MouldEnergyIN { get; set; }
[Column("MouldEnergyOUT")]
public float MouldEnergyOUT { get; set; }
[Column("NumDone")]
public short NumDone { get; set; }
[Column("NumTarget")]
public short NumTarget { get; set; }
[Column("ThermoImage")]
public string ThermoImage { get; set; }
[Column("TimeCycleGross")]
public int TimeCycleGross { get; set; }
[Column("TimeCycleNet")]
public int TimeCycleNet { get; set; }
[Column("TimeVacuum")]
public int TimeVacuum { get; set; }
[Column("TimeVent")]
public int TimeVent { get; set; }
[Column("TimeWarm")]
public int TimeWarm { get; set; }
[Column("VacuumReadVal")]
public float VacuumReadVal { get; set; }
#endregion Public Properties
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,20 +1,13 @@
using System;
using CMS_CORE_Library.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using Thermo.Active.Database.Controllers;
using Thermo.Active.Listeners;
using Thermo.Active.Model.DatabaseModels;
using Thermo.Active.Model.DTOModels.AlarmModels;
using System.Web.Http.Description;
using Thermo.Active.Model.DTOModels.ThWarmers;
using Thermo.Active.NC;
using Thermo.Active.Provider;
using Thermo.Active.Thermocamera;
using Thermo.Active.Utils;
using static Thermo.Active.Config.ServerConfig;
using static Thermo.Active.Model.Constants;
@@ -23,6 +16,57 @@ namespace Thermo.Active.Controllers.WebApi
[RoutePrefix("api/thermocamera")]
public class ThermocameraController : ApiController
{
#region Protected Fields
/// <summary>
/// Oggetto adapter condiviso da WebAPI
/// </summary>
protected static NcAdapter ncAdapter = new NcAdapter();
#endregion Protected Fields
#region Public Methods
[ResponseType(typeof(PointReq))]
[Route("getTemperatures"), HttpGet]
public IHttpActionResult GetTempAtPoints(PointReq pointRequest)
{
// Try connection
CmsError libraryError = ncAdapter.Connect();
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"NC Not connected! | GetTempAtPoints | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
PointReq results = new PointReq();
// fake: genero casualmenteEsegui
Random rnd = new Random();
int numval = pointRequest != null && pointRequest.List != null && pointRequest.List.Count > 0 ? pointRequest.List.Count : 10;
for (int i = 0; i < numval; i++)
{
ThermoPointFlir newVal = new ThermoPointFlir()
{
X = rnd.Next(0, 1500),
Y = rnd.Next(0, 1200),
Temperature = ((float)rnd.Next(100, 2000)) / 10
};
results.List.Add(newVal);
}
#if false
// leggo dati gauges
libraryError = ncAdapter.ReadValIO(out DTOChannelsIOVal ChannelsIOVal);
if (libraryError.IsError())
{
ThermoActiveLogger.LogError($"GetChannelsIoVal error | {libraryError.exception}");
return BadRequest(libraryError.localizationKey);
}
#endif
// ritorno!
return Ok(results);
}
[Route("show"), HttpPost]
public IHttpActionResult showCamera()
{
@@ -30,16 +74,16 @@ namespace Thermo.Active.Controllers.WebApi
String ThermoCameraYpos = AdditionalParametersConfig["ThermoCameraYpos"];
String ThermoCameraXdim = AdditionalParametersConfig["ThermoCameraXdim"];
String ThermoCameraYdim = AdditionalParametersConfig["ThermoCameraYdim"];
if(ThermoCameraXpos != null && ThermoCameraYpos != null && ThermoCameraXdim != null && ThermoCameraYdim != null)
if (ThermoCameraXpos != null && ThermoCameraYpos != null && ThermoCameraXdim != null && ThermoCameraYdim != null)
{
if (ThermocameraComunicator.getInstance().showWindow(Int32.Parse(ThermoCameraXpos), Int32.Parse(ThermoCameraYpos), Int32.Parse(ThermoCameraXdim), Int32.Parse(ThermoCameraYdim), 3000))
return Ok();
else
return BadRequest();
}
return BadRequest();
}
#endregion Public Methods
}
}
+1 -1
View File
@@ -30,4 +30,4 @@ using System.Runtime.InteropServices;
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.1.158")]
[assembly: AssemblyVersion("1.1.160")]
@@ -25,20 +25,16 @@ export default class outputRow extends Vue {
}
async force(value: number) {
console.log("force",value);
await underTheHoodService.forceChannel(this.group, this.item, value);
/*
if(this.item.isForced)
await underTheHoodService.forceChannel(this.group, this.item, value);
else
{
if(!this.item.isForced && (this.item.forcedValue === undefined || value != this.item.forcedValue))
{
ModalHelper.AskConfirm( this.$options.filters.localize("modal_confirm_title", "Richiesta di conferma"),
this.$options.filters.localize("softkey_confirm", "Confirm?"),
async() => {
await underTheHoodService.forceChannel(this.group, this.item, value);
this.$options.filters.localize("softkey_confirm", "Confirm?"),
async() => {
await underTheHoodService.forceChannel(this.group, this.item, value);
}, null, "modal");
}*/
}
else
await underTheHoodService.forceChannel(this.group, this.item, value);
}
async reset() {
@@ -18,11 +18,11 @@ export default class RiscaldiTable extends Vue {
}
getBoard(id) {
return Math.floor((id-1)/16);
return Math.floor((id-1)/16) +1;
}
getOutput(id) {
return Math.floor((id-1)%16);
return Math.floor((id-1)%16) +1;
}
mounted() {
+18
View File
@@ -0,0 +1,18 @@
using Flir.Atlas.Live.Discovery;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ThermoCamUtils
{
public class DiscoveryHelper
{
#region Private Fields
private Discovery _discovery;
#endregion Private Fields
}
}
+1 -6
View File
@@ -6,10 +6,6 @@ using System.Threading.Tasks;
namespace ThermoCamUtils
{
public class Enums
{
}
public enum pointList
{
A = 0,
@@ -17,5 +13,4 @@ namespace ThermoCamUtils
C,
D
}
}
}
-217
View File
@@ -1,217 +0,0 @@
using Flir.Atlas.Image;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
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
/// <summary>
/// Ultimo range di temperature osservato
/// </summary>
protected Range<double> lastTempRange = new Range<double>(0, 5000);
/// <summary>
/// Stopwatch x benchmarking
/// </summary>
protected Stopwatch sw = new Stopwatch();
#endregion Protected Fields
#region Public Fields
/// <summary>
/// Statistiche esecuzione task
/// </summary>
public ExecTime ExTime = new ExecTime();
/// <summary>
/// Ultima temp calcolata da immagine B/N
/// </summary>
public double lastCalcTemp = 0;
/// <summary>
/// Ultimo punto acquisito
/// </summary>
public Point lastPoint = new Point();
/// <summary>
/// Ultima temp letta da FLIR
/// </summary>
public double lastReadTemp = 0;
#endregion Public Fields
#region Public Properties
/// <summary>
/// Ultima immagine ricolorata e trasformata (perspective)
/// </summary>
public Bitmap ColorTransf { get; set; }
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 Protected Methods
/// <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>
/// <param name="fastBitmap">Indica se processare bitmap in memoria (true) o con metodi standard (false)</param>
/// <param name="colorizeFirst">Indica se prima fare falsi colori poi trasformazione proiettiva</param>
public void calculateTarget(bool fastBitmap, bool colorizeFirst)
{
if (Thermal != null)
{
try
{
//lastTempRange = new Range<double>(lastThermalImage.GetValueFromSignal(lastThermalImage.MinSignalValue), lastThermalImage.GetValueFromSignal(lastThermalImage.MaxSignalValue));
lastTempRange = new Range<double>(Thermal.Scale.Range.Minimum, Thermal.Scale.Range.Maximum);
sw.Restart();
var pTransf = new PerspectiveTransform(currConf.origPoints.Coords, currConf.destPoints.Coords);
var rTrasf = new ReColorize(lastTempRange.Minimum, lastTempRange.Maximum, currConf.TargetRange.Min, currConf.TargetRange.Max);
var transfImg = pTransf.convertImage(Origin, currConf.TargetSize.X, currConf.TargetSize.Y);
GrayTransf = transfImg;
sw.Stop();
ExTime.recordData("ImageTransf", sw.ElapsedMilliseconds);
sw.Restart();
if (colorizeFirst)
{
// ora calcolo ricolorazione da immagine originale
var colImg = rTrasf.process(Origin, fastBitmap);
// e faccio la stessa trasformazione di riscalatura
var transfColImg = pTransf.convertImage(colImg, currConf.TargetSize.X, currConf.TargetSize.Y);
ColorTransf = transfColImg;
}
else
{
// old way da immagine BN full size
ColorTransf = rTrasf.process(GrayTransf, fastBitmap);
}
sw.Stop();
ExTime.recordData("ImageColor", sw.ElapsedMilliseconds);
}
catch (Exception exc)
{
}
}
}
/// <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)
{
// recupero temp da FLIR
lastReadTemp = Thermal.GetValueAt(lastPoint).Value;
// calcolo temp da RGB considerato limiti minMAX...
//int rgbVal = lastImageOrig.Image.GetPixel(lastPoint.X, lastPoint.Y).R;
int rgbVal = getRSmooth(lastPoint);
lastCalcTemp = lastTempRange.Minimum + ((lastTempRange.Maximum - lastTempRange.Minimum) * rgbVal / 255);
}
}
}
/// <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();
}
}
#endregion Public Methods
}
}
+48
View File
@@ -7,6 +7,28 @@ using System.Threading.Tasks;
namespace ThermoCamUtils
{
public class MeasurePoint
{
#region Public Properties
/// <summary>
/// Punto di riferimento
/// </summary>
public Point Coords { get; set; } = new Point();
/// <summary>
/// Id del punto
/// </summary>
public int Id { get; set; } = 0;
/// <summary>
/// Temperatura rilevata al punto
/// </summary>
public double Temperature { get; set; } = 0;
#endregion Public Properties
}
public class SetPoints
{
#region Public Properties
@@ -16,4 +38,30 @@ namespace ThermoCamUtils
#endregion Public Properties
}
[Serializable]
/// <summary>
/// Classe
/// </summary>
public class TemperatureData
{
#region Public Properties
/// <summary>
/// Size Reticolo (=immagine)
/// </summary>
public Size ArraySize { get; set; }
/// <summary>
/// Ordine scansione coordinate immagine, YX = prima Y (per righe), XY = prima X (per colonne)
/// </summary>
public string ScanOrder { get; set; } = "YX";
/// <summary>
/// valori associati al reticolo
/// </summary>
public double[] Values { get; set; }
#endregion Public Properties
}
}
+32 -57
View File
@@ -13,23 +13,18 @@ namespace ThermoCamUtils
{
#region Protected Fields
protected double delta = 0;
protected double maxSca = 5000;
protected double maxVal = 5000;
protected double minSca = -999;
protected double minVal = -999;
#endregion Protected Fields
#region Public Constructors
public ReColorize(double minValue, double maxValue, double minScale, double maxScale)
//public ReColorize(double minValue, double maxValue, double minScale, double maxScale)
public ReColorize(double minScale, double maxScale)
{
minVal = minValue;
maxVal = maxValue;
minSca = minScale;
maxSca = maxScale;
delta = minVal - minSca;
}
#endregion Public Constructors
@@ -37,20 +32,17 @@ namespace ThermoCamUtils
#region Protected Methods
/// <summary>
/// Calcola colore su scala dato rapporto valore B/N su min/max
/// Calcola colore su scala dato rapporto valore temperatura su min/max
/// </summary>
/// <param name="ValOrig"></param>
/// <param name="currTemp"></param>
/// <returns></returns>
protected Color Rescale(ref int ValRGB)
protected Color Rescale(ref double currTemp)
{
int R = 0;
int G = 0;
int B = 0;
int ValScal = 0;
// calcolo retta interpolazione per il valore in gradi...Y = M * X + DELTA
double M = (maxVal - minVal) / 255;
double currTemp = M * ValRGB + delta;
// ora calcolo valore scalare
ValScal = (int)(255 * (currTemp - minSca) / (maxSca - minSca));
@@ -104,7 +96,13 @@ namespace ThermoCamUtils
#region Public Methods
public Bitmap process(Bitmap original, bool doFast)
/// <summary>
/// Processing ricolorazione
/// </summary>
/// <param name="original"></param>
/// <param name="tempVal"></param>
/// <returns></returns>
public Bitmap process(Bitmap original, double[] tempVal)
{
/*---------------------------------------------
// indicazioni x ottimizzare da qui:
@@ -112,55 +110,32 @@ namespace ThermoCamUtils
-----------------------------------------------*/
Bitmap imgColor = original.Clone(new Rectangle(0, 0, original.Width, original.Height), original.PixelFormat);
int currVal = 0;
BitmapData bitmapData = imgColor.LockBits(new Rectangle(0, 0, imgColor.Width, imgColor.Height), ImageLockMode.ReadWrite, imgColor.PixelFormat);
if (doFast)
int bytesPerPixel = Bitmap.GetPixelFormatSize(imgColor.PixelFormat) / 8;
int byteCount = bitmapData.Stride * imgColor.Height;
byte[] pixels = new byte[byteCount];
IntPtr ptrFirstPixel = bitmapData.Scan0;
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
for (int y = 0; y < heightInPixels; y++)
{
BitmapData bitmapData = imgColor.LockBits(new Rectangle(0, 0, imgColor.Width, imgColor.Height), ImageLockMode.ReadWrite, imgColor.PixelFormat);
int bytesPerPixel = Bitmap.GetPixelFormatSize(imgColor.PixelFormat) / 8;
int byteCount = bitmapData.Stride * imgColor.Height;
byte[] pixels = new byte[byteCount];
IntPtr ptrFirstPixel = bitmapData.Scan0;
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
int heightInPixels = bitmapData.Height;
int widthInBytes = bitmapData.Width * bytesPerPixel;
for (int y = 0; y < heightInPixels; y++)
int currentLine = y * bitmapData.Stride;
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
int currentLine = y * bitmapData.Stride;
for (int x = 0; x < widthInBytes; x = x + bytesPerPixel)
{
// prendo il rosso
int oldRed = pixels[currentLine + x + 0];
currVal = pixels[currentLine + x + 2];
var newCol = Rescale(ref currVal);
pixels[currentLine + x] = (byte)newCol.B;
pixels[currentLine + x + 1] = (byte)newCol.G;
pixels[currentLine + x + 2] = (byte)newCol.R;
//currVal = original.GetPixel(x, y).R;
//imgColor.SetPixel(x, y, Rescale(ref currVal));
}
}
// copy modified bytes back
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
imgColor.UnlockBits(bitmapData);
}
else
{
// recupero matrice di punti con valore RGB
for (int x = 0; x < original.Width; x++)
{
for (int y = 0; y < original.Height; y++)
{
// esecuo ricalcolo
currVal = original.GetPixel(x, y).R;
imgColor.SetPixel(x, y, Rescale(ref currVal));
}
var newCol = Rescale(ref tempVal[x / bytesPerPixel + original.Width * y]);
pixels[currentLine + x] = (byte)newCol.B;
pixels[currentLine + x + 1] = (byte)newCol.G;
pixels[currentLine + x + 2] = (byte)newCol.R;
}
}
// copy modified bytes back
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
imgColor.UnlockBits(bitmapData);
return imgColor;
}
+728
View File
@@ -0,0 +1,728 @@
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 TCContr
{
#region Protected Fields
protected const string colorPath = "images\\colored";
protected const string confFileName = "ThermoConf.json";
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 TCContr()
{
// 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; }
protected string confPath
{
get
{
// se esiste il file... path assoluto
string answ = confFileName;
if (!Path.IsPathRooted(answ))
{
answ = BASE_PATH + "\\" + confFileName;
}
return answ;
}
}
#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 (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>
/// Salva su file il file di conf corrente
/// </summary>
/// <returns></returns>
public bool saveConf()
{
bool answ = false;
try
{
string rawData = JsonConvert.SerializeObject(currConf, Formatting.Indented);
File.WriteAllText(confPath, rawData);
answ = true;
}
catch
{ }
return answ;
}
/// <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;
}
public void tryReloadConf()
{
if (File.Exists(confPath))
{
// se non è vuoto....
string rawData = File.ReadAllText(confPath);
if (!string.IsNullOrEmpty(rawData))
{
try
{
currConf = JsonConvert.DeserializeObject<ThermoCamConf>(rawData);
}
catch (Exception exc)
{ }
}
}
}
#endregion Public Methods
}
}
+24 -2
View File
@@ -2,6 +2,7 @@
using Flir.Atlas.Live.Discovery;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@@ -44,8 +45,22 @@ namespace ThermoCamUtils
public class ThermoCamConf
{
#region Public Fields
/// <summary>
/// Elenco di punti x misurazione temperatura
/// </summary>
public List<MeasurePoint> MeasPoints = new List<MeasurePoint>();
#endregion Public Fields
#region Public Properties
/// <summary>
/// Indirizzo Camera selezionata x autoconnect ("" = nessun autoconnect)
/// </summary>
public string CameraAddress { get; set; } = "";
/// <summary>
/// Camera selezionata x autoconnect ("" = nessun autoconnect)
/// </summary>
@@ -54,12 +69,19 @@ namespace ThermoCamUtils
/// <summary>
/// Punti su IMG destinazione
/// </summary>
public SetPoints destPoints { get; set; } = new SetPoints();
public SetPoints DestPoints { get; set; } = new SetPoints();
/// <summary>
/// Punti su IMG origine
/// </summary>
public SetPoints origPoints { get; set; } = new SetPoints();
public SetPoints OrigPoints { get; set; } = new SetPoints();
#if false
/// <summary>
/// Camera selezionata
/// </summary>
public CameraDeviceInfo SelectedCameraDevice { get; set; }
#endif
/// <summary>
/// Range scala colori desiderata
+5 -1
View File
@@ -46,6 +46,9 @@
<Reference Include="Flir.Atlas.Live">
<HintPath>..\..\..\..\..\..\Program Files (x86)\FLIR Systems\FLIR Atlas SDK 4\bin\x64\Flir.Atlas.Live.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OpenCvSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6adad1e807fea099, processorArchitecture=MSIL">
<HintPath>..\packages\OpenCvSharp4.4.5.1.20210208\lib\net461\OpenCvSharp.dll</HintPath>
</Reference>
@@ -85,9 +88,10 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DiscoveryHelper.cs" />
<Compile Include="ExecTime.cs" />
<Compile Include="IRCam.cs" />
<Compile Include="ImageData.cs" />
<Compile Include="TCContr.cs" />
<Compile Include="ThermoCamConf.cs" />
<Compile Include="Enums.cs" />
<Compile Include="Objects.cs" />
+1
View File
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="12.0.3" targetFramework="net462" />
<package id="OpenCvSharp4" version="4.5.1.20210208" targetFramework="net462" />
<package id="OpenCvSharp4.runtime.win" version="4.5.1.20210208" targetFramework="net462" />
<package id="OpenCvSharp4.Windows" version="4.5.1.20210208" targetFramework="net462" />