简体   繁体   English

如何绘制模拟心电图?

[英]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):我想创造什么(它不必非常精确,它只是为了娱乐目的):

ECG DEMO心电图演示

在此处输入图像描述

ECG Picture心电图图片

心电图图片

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM