ecgdraw.cs
来自「ecg tool kit for medical image retrieval」· CS 代码 · 共 1,206 行 · 第 1/4 页
CS
1,206 行
/***************************************************************************
Copyright 2008, Thoraxcentrum, Erasmus MC, Rotterdam, The Netherlands
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Written by Maarten JB van Ettinger.
****************************************************************************/
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace ECGConversion
{
using ECGDemographics;
using ECGSignals;
public class ECGDraw
{
// variables used for Bitmap output.
public const float mm_Per_Inch = 25.4f;
public const float Inch_Per_mm = 1f / mm_Per_Inch;
public static float uV_Per_Channel
{
get
{
return _uV_Per_Channel;
}
set
{
if ((value % 1000) == 0)
_uV_Per_Channel = value;
}
}
public static float DpiX = 96.0f;
public static float DpiY = 96.0f;
private static float _uV_Per_Channel = 3000.0f;
private static float _mm_Per_GridLine = 5.0f;
private static float _TextSize = 9.0f;
public const int DirtSolutionFactor = 20; // max 20!!
// Colors for drawing.
public static Color SignalColor = Color.Black;
public static Color TextColor = Color.Black;
public static Color BackColor = Color.Transparent;
public static Color GraphColor = Color.FromArgb(255, 187, 187);
public static Color GraphSecondColor = Color.FromArgb(255, 229, 229);
public enum GridType
{
None = 0,
OneMillimeters = 1,
FiveMillimeters = 2
}
// Configuration of the displayed info.
public static bool DisplayInfo = true;
public static GridType DisplayGrid = GridType.OneMillimeters;
/// <summary>
/// Function to write an ECG in to an bitmap. Will only draw stored leads and will not display average beat.
/// </summary>
/// <param name="src">an ECG file to convert</param>
/// <param name="output">returns bitmap with signals.</param>
/// <returns>0 on success</returns>
public static int ToBitmap(IECGFormat src, float mm_Per_s, float mm_Per_mV, out Bitmap output)
{
return ToBitmap(src, 4f * mm_Per_Inch, 4f * mm_Per_Inch, mm_Per_s, mm_Per_mV, out output);
}
/// <summary>
/// Function to write an ECG in to an bitmap. Will only draw stored leads and will not display average beat.
/// </summary>
/// <param name="src">an ECG file to convert</param>
/// <param name="output">returns bitmap with signals.</param>
/// <returns>0 on success</returns>
public static int ToBitmap(IECGFormat src, float dpiX, float dpiY, float mm_Per_s, float mm_Per_mV, out Bitmap output)
{
DpiX = dpiX; DpiY = dpiY;
output = null;
DateTime dtRecordTime = DateTime.MinValue;
IDemographic dem = src.Demographics;
if (dem != null)
dtRecordTime = dem.TimeAcquisition;
ECGSignals.Signals signals;
if ((src.Signals == null)
|| (src.Signals.getSignals(out signals) != 0))
{
return 1;
}
int nExtraSpace = (int) (_TextSize * DpiY * Inch_Per_mm * .4f);
// begin: find start and end.
int nStart = int.MaxValue,
nEnd = int.MinValue;
for (int lead=0;lead < signals.NrLeads;lead++)
{
if (signals[lead] != null)
{
nStart = Math.Min(nStart, signals[lead].RhythmStart);
nEnd = Math.Max(nEnd, signals[lead].RhythmEnd);
}
}
// end: find start and end.
float
fPixel_Per_s = mm_Per_s * DpiX * Inch_Per_mm,
fPixel_Per_uV = mm_Per_mV * DpiY * Inch_Per_mm * 0.001f,
fLeadYSpace = _uV_Per_Channel * fPixel_Per_uV;
output = new Bitmap(
(int) Math.Ceiling((((float) (nEnd - nStart)) / signals.RhythmSamplesPerSecond) * fPixel_Per_s + (0.2f * fPixel_Per_s)) + 1,
(int) Math.Ceiling(fLeadYSpace * signals.NrLeads) + nExtraSpace + 1);
DrawECG(Graphics.FromImage(output), signals, dtRecordTime, 0, mm_Per_s, mm_Per_mV, false);
return 0;
}
/// <summary>
/// Function to draw an ECG on a bitmap.
/// </summary>
/// <param name="myBM">Bitmap do draw ECG in.</param>
/// <param name="signals">Signal data to draw (can change due to resampling).</param>
/// <param name="dtRecordTime">Start time of recording</param>
/// <param name="nTime">Start drawing at this sample number.</param>
/// <param name="fmm_Per_s">mm per second</param>
/// <param name="fmm_Per_mV">mm per mV</param>
/// /// <returns>Sample number to start next draw ECG on.</returns>
public static int DrawECG(Bitmap myBM, ECGSignals.Signals signals, DateTime dtRecordTime, int nTime, float fmm_Per_s, float fmm_Per_mV)
{
return DrawECG(Graphics.FromImage(myBM), signals, dtRecordTime, nTime, fmm_Per_s, fmm_Per_mV, false);
}
/// <summary>
/// Function to draw an ECG on a bitmap.
/// </summary>
/// <param name="myBM">Bitmap do draw ECG in.</param>
/// <param name="signals">Signal data to draw (can change due to resampling).</param>
/// <param name="dtRecordTime">Start time of recording</param>
/// <param name="nTime">Start drawing at this sample number.</param>
/// <param name="fmm_Per_s">mm per second</param>
/// <param name="fmm_Per_mV">mm per mV</param>
/// <param name="bAllowResample">True if resample of signal is allowed.</param>
/// <returns>Sample number to start next draw ECG on.</returns>
public static int DrawECG(Bitmap myBM, ECGSignals.Signals signals, DateTime dtRecordTime, int nTime, float fmm_Per_s, float fmm_Per_mV, bool bAllowResample)
{
return DrawECG(Graphics.FromImage(myBM), signals, dtRecordTime, nTime, fmm_Per_s, fmm_Per_mV, bAllowResample);
}
/// <summary>
/// Function to draw an ECG on a bitmap.
/// </summary>
/// <param name="myGraphics">The drawing surface.</param>
/// <param name="signals">Signal data to draw (can change due to resampling).</param>
/// <param name="dtRecordTime">Start time of recording</param>
/// <param name="nTime">Start drawing at this sample number.</param>
/// <param name="fmm_Per_s">mm per second</param>
/// <param name="fmm_Per_mV">mm per mV</param>
/// <param name="bAllowResample">True if resample of signal is allowed.</param>
/// <returns>Sample number to start next draw ECG on.</returns>
public static int DrawECG(Graphics myGraphics, ECGSignals.Signals signals, DateTime dtRecordTime, int nTime, float fmm_Per_s, float fmm_Per_mV, bool bAllowResample)
{
// begin: drawing of ECG.
float
fPixel_Per_ms = fmm_Per_s * DpiX * Inch_Per_mm * 0.001f,
fPixel_Per_uV = fmm_Per_mV * DpiY * Inch_Per_mm * 0.001f,
fLeadYSpace = _uV_Per_Channel * fPixel_Per_uV,
fGridY = (DpiY * Inch_Per_mm) * _mm_Per_GridLine;
int nMinX = 0,
nMinY = (int) (_TextSize * DpiY * Inch_Per_mm * .4f),
nMaxX,
nMaxY;
if ((myGraphics == null)
|| (signals == null))
return 0;
if (Math.Ceiling((fLeadYSpace * signals.NrLeads) + fGridY) >= (myGraphics.VisibleClipBounds.Height - nMinY))
{
fLeadYSpace = (float) Math.Floor(((myGraphics.VisibleClipBounds.Height - nMinY - (fGridY * 2)) / signals.NrLeads) / fGridY) * fGridY;
}
DrawGrid(myGraphics, fLeadYSpace, signals.NrLeads, nMinX, nMinY, out nMaxX, out nMaxY);
return DrawSignal(myGraphics, signals, dtRecordTime, true, nTime, fmm_Per_s, fmm_Per_mV, nMinX, nMinY, nMaxX, nMaxY, fPixel_Per_ms * 1000f, fPixel_Per_uV, fLeadYSpace, bAllowResample);
// end: drawing of ECG.
}
/// <summary>
/// Enumaration for specific ECG draw types.
/// </summary>
public enum ECGDrawType
{
None = 0x00,
Regular = 0x01,
ThreeXFour = 0x02,
ThreeXFourPlusOne = 0x04,
ThreeXFourPlusThree = 0x08,
SixXTwo = 0x10,
Median = 0x20
}
/// <summary>
/// Function to determine the possible draw types.
/// </summary>
/// <param name="signals">signal to detemine draw types for</param>
/// <returns>possible draw types</returns>
public static ECGDrawType PossibleDrawTypes(ECGSignals.Signals signals)
{
ECGDrawType ret = ECGDrawType.None;
if (signals != null)
{
ret = ECGDrawType.Regular;
if (signals.IsTwelveLeads)
{
int start, end;
signals.CalculateStartAndEnd(out start, out end);
int length = (int) Math.Round((end - start) / (float)signals.RhythmSamplesPerSecond);
if (length <= 10)
{
ret = ECGDrawType.Regular
| ECGDrawType.ThreeXFour
| ECGDrawType.ThreeXFourPlusOne
| ECGDrawType.ThreeXFourPlusThree
| ECGDrawType.SixXTwo;
}
if ((signals.MedianAVM != 0)
&& (signals.MedianSamplesPerSecond != 0)
&& (signals.MedianLength != 0))
ret |= ECGDrawType.Median;
}
}
return ret;
}
/// <summary>
/// An ECGDrawSection object will describe a bit of signal on the image.
/// </summary>
public class ECGDrawSection
{
/// <summary>
/// Constructor to draw an Calibration pulse.
/// </summary>
/// <param name="fmm_Per_mV">millimeters per milliVolt</param>
/// <param name="x">position X on image in millimeters</param>
/// <param name="y">position Y on image in millimeters</param>
/// <param name="sps">samples per second</param>
/// <param name="length">length in nr of 5 mm blocks</param>
public ECGDrawSection(float fmm_Per_mV, float x, float y, int sps, int length)
: this(false, fmm_Per_mV, x, y, sps, length) {}
/// <summary>
/// Constructor to draw provided sample data.
/// (one sample is one pixel on the X-axis)
/// </summary>
/// <param name="fmm_Per_mV">millimeters per milliVolt</param>
/// <param name="x">position X on image in millimeters</param>
/// <param name="y">position Y on image in millimeters</param>
/// <param name="leadType">type of the lead</param>
/// <param name="avm">AVM of signal data</param>
/// <param name="sps">samples per seconds of signal data</param>
/// <param name="start">start point in signal data</param>
/// <param name="end">end point in signal data</param>
/// <param name="data">signal data</param>
public ECGDrawSection(float fmm_Per_mV, float x, float y, LeadType leadType, double avm, int sps, int start, int end, short[] data)
: this(false, fmm_Per_mV, x, y, leadType, avm, sps, start, end, data) {}
/// <summary>
/// Constructor to draw an Calibration pulse.
/// </summary>
/// <param name="bInPixels">x and y are in pixels if this value is true</param>
/// <param name="fmm_Per_mV">millimeters per milliVolt</param>
/// <param name="x">position X in pixels or millimeters</param>
/// <param name="y">position Y in pixels or millimeters</param>
/// <param name="sps">samples per second</param>
/// <param name="length">length in nr of 5 mm blocks</param>
public ECGDrawSection(bool bInPixels, float fmm_Per_mV, float x, float y, int sps, int length)
{
if (bInPixels)
{
_X = x;
_Y = y;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?