[英]How to draw a simulated ECG?
What I would like to create (it doesn't have to be very precise, it's just for entertainment purposes):我想创造什么(它不必非常精确,它只是为了娱乐目的):
What I have:我有的:
I have a REST API to a service that let's me query the current BPM of the person wearing the pulse measuring device.我有一个 REST API 到一个服务,让我查询佩戴脉搏测量设备的人的当前 BPM。 So I don't have an Event that indicates when a hearth beat is happening.
因此,我没有指示何时发生炉膛跳动的事件。 I would have to calculate this with the given BPM.
我必须用给定的 BPM 来计算这个。 But that's not the issue.
但这不是问题。
The Question:问题:
How would you draw the lines and make them disappear behind and from left to right with a reset when it reaches the right corner.当它到达右上角时,您将如何绘制线条并使它们从左到右消失并重置。 I have some experience in C# WPF, that's why I created the REST Querying stuff there.
我在 C# WPF 方面有一些经验,这就是我创建 REST 查询内容的原因。 Are there some Libraries for the drawing part?
绘图部分是否有一些库? Is there an easy way to do this by hand?
有没有一种简单的方法可以手动完成?
I'm really greatful for any advice, since I can't find that much on a rather specific issue like this on the internet.我非常感谢任何建议,因为我在互联网上这样一个相当具体的问题上找不到那么多。 So thank you!
所以谢谢!
UPDATE: I got something working using WritableBitmap, but it looks pretty bad.更新:我得到了一些使用 WritableBitmap 的东西,但它看起来很糟糕。 Any idea on how to get a better resolution?
关于如何获得更好的分辨率的任何想法? I already increased the resolution of the bitmap, but it still looks quite horrible.
我已经提高了 bitmap 的分辨率,但它看起来仍然很糟糕。 Is there some sort of Anti-aliasing on this?
是否有某种抗锯齿功能?
This will get you started:这将使您开始:
Install WriteableBitmapEx package:安装 WriteableBitmapEx package:
Install-Package WriteableBitmapEx
安装包 WriteableBitmapEx
Code:代码:
<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>
Code:代码:
#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;
}
}
}
Here I simply I erase a 1 pixel wide rectangle ahead the value I'm drawing, in your case, erase a larger rectangle to get the effect you want.在这里,我只是在我正在绘制的值前面擦除一个 1 像素宽的矩形,在你的情况下,擦除一个更大的矩形以获得你想要的效果。
See that you'll need to keep history of previous value and draw a line from it instead to have a solid drawing.请注意,您需要保留先前值的历史记录并从中画一条线,而不是绘制实体图。
Also, you may want to look at these libraries as well:此外,您可能还想查看这些库:
https://sourceforge.net/projects/ecgtoolkit-cs/ https://sourceforge.net/projects/ecgtoolkit-cs/
https://github.com/rdtek/ECGViewer https://github.com/rdtek/ECGViewer
https://github.com/Refactoring/ECGToolkit https://github.com/Refactoring/ECGToolkit
You can use a LinearGradientBrush as an OpacityMask to black out parts of the image and then animate the offsets horizontally:您可以使用 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>
It's not 100% perfect, because your ECG image has blank space to the left and right of it, but if you clip it it'll look better.它不是 100% 完美的,因为您的心电图图像的左右两侧都有空白区域,但如果您将其剪辑,它会看起来更好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.