如何绘制模拟心电图?
Posted
技术标签:
【中文标题】如何绘制模拟心电图?【英文标题】:How to draw a simulated ECG? 【发布时间】:2022-01-13 22:05:43 【问题描述】:我想创作的东西(不需要很精确,只是为了娱乐目的):
ECG DEMO
ECG Picture
我有什么:
我有一个服务的 REST API,让我可以查询佩戴脉搏测量设备的人的当前 BPM。因此,我没有指示何时发生炉膛跳动的事件。我必须用给定的 BPM 来计算这个。但这不是问题。
问题:
您将如何绘制线条并使其在到达右上角时从左到右消失并重置。我在 C# WPF 方面有一些经验,这就是我在那里创建 REST Querying 的原因。绘图部分是否有一些库?有没有简单的手动操作方法?
我真的很感激任何建议,因为我在互联网上找不到像这样的相当具体的问题。所以谢谢你!
更新: 我使用 WritableBitmap 得到了一些工作,但它看起来很糟糕。关于如何获得更好的分辨率的任何想法?我已经提高了位图的分辨率,但它看起来仍然很糟糕。是否有某种抗锯齿功能?
【问题讨论】:
下次自己贴图,我已经给你做了。 【参考方案1】:这会让你开始:
安装 WriteableBitmapEx 包:
Install-Package WriteableBitmapEx
代码:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Width="256" Height="256">
<Grid>
<Image x:Name="Image1" Stretch="Fill" />
</Grid>
</Window>
代码:
#nullable enable
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace WpfApp1
public partial class MainWindow
private readonly WriteableBitmap _bitmap;
private readonly DispatcherTimer _timer;
private int _bitmapCursor;
public MainWindow()
InitializeComponent();
Loaded += MainWindow_Loaded;
_bitmap = BitmapFactory.New(256, 256);
Image1.Source = _bitmap;
_timer = new DispatcherTimer(
TimeSpan.FromMilliseconds(20),
DispatcherPriority.Render,
Tick,
Dispatcher.CurrentDispatcher
);
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
_timer.Start();
private void Tick(object? sender, EventArgs e)
var cy = _bitmap.Height * 0.5;
var y = (int)(cy + Math.Sin(DateTime.Now.TimeOfDay.TotalSeconds) * cy);
_bitmap.DrawLine(_bitmapCursor, 0, _bitmapCursor, _bitmap.PixelHeight - 1, Colors.Transparent);
_bitmap.SetPixel(_bitmapCursor, y, Colors.Red);
_bitmapCursor++;
_bitmapCursor %= _bitmap.PixelWidth;
在这里,我只是在我正在绘制的值前面擦除一个 1 像素宽的矩形,在你的情况下,擦除一个更大的矩形以获得你想要的效果。
请注意,您需要保留先前值的历史记录,并从中画一条线,而不是绘制实体图。
此外,您可能还想查看这些库:
https://sourceforge.net/projects/ecgtoolkit-cs/
https://github.com/rdtek/ECGViewer
https://github.com/Refactoring/ECGToolkit
【讨论】:
你先生,太棒了。我会检查它并在我实施后立即报告!谢谢 不是位图,而是更新 Canvas 的两个 Polylines 子元素的 Points 集合。 @Clemens 这也有道理!【参考方案2】:您可以使用 LinearGradientBrush 作为 OpacityMask 将图像的某些部分涂黑,然后水平动画偏移:
<Grid Background="Black" HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Source="4ku8e.png">
<Image.Triggers>
<EventTrigger RoutedEvent="Image.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="Gradient1" Storyboard.TargetProperty="Offset" From="-1.0" To="0" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient2" Storyboard.TargetProperty="Offset" From="-0.9" To="0.1" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient3" Storyboard.TargetProperty="Offset" From="-0.5" To="0.5" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient4" Storyboard.TargetProperty="Offset" From="0" To="1" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient5" Storyboard.TargetProperty="Offset" From="0" To="1" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient6" Storyboard.TargetProperty="Offset" From="0.1" To="1.1" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient7" Storyboard.TargetProperty="Offset" From="0.5" To="1.5" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient8" Storyboard.TargetProperty="Offset" From="1" To="2.0" Duration="0:0:6" RepeatBehavior="Forever" />
<DoubleAnimation Storyboard.TargetName="Gradient9" Storyboard.TargetProperty="Offset" From="1" To="2.0" Duration="0:0:6" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
<Image.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<LinearGradientBrush.GradientStops>
<GradientStop x:Name="Gradient1" Color="#00000000" />
<GradientStop x:Name="Gradient2" Color="#00000000" />
<GradientStop x:Name="Gradient3" Color="#FF000000" />
<GradientStop x:Name="Gradient4" Color="#FF000000" />
<GradientStop x:Name="Gradient5" Color="#00000000" />
<GradientStop x:Name="Gradient6" Color="#00000000" />
<GradientStop x:Name="Gradient7" Color="#FF000000" />
<GradientStop x:Name="Gradient8" Color="#FF000000" />
<GradientStop x:Name="Gradient9" Color="#00000000" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Image.OpacityMask>
</Image>
</Grid>
这不是 100% 完美的,因为您的心电图图像的左右两侧都有空白区域,但如果您将其剪辑,它会更好看。您现在要做的就是将所有这些 Duration
属性绑定到您的视图模型中的一个值,该值是您根据该人的 BPM 设置的。
【讨论】:
以上是关于如何绘制模拟心电图?的主要内容,如果未能解决你的问题,请参考以下文章