Android——ECG心电图的绘制实现

Posted 化作孤岛的瓜

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android——ECG心电图的绘制实现相关的知识,希望对你有一定的参考价值。

在上篇Android——ECG心电图的绘制实现博客中,实现了心电图的数据展示绘制。

在之后又新增了 心电图的自动滑动展示 实时绘制 功能。效果如下:

自动滑动展示

实时绘制(这里用到了一个timer不断添加数据)

一、自动滑动展示 实现

实现思路:

通过开启定时器实现下标scrollIndex不断增加,以此来计算展示数据的开始下标scrollStartIndex与结束下标scrollEndIndex,来获得一段数据data[]中的展示数据,该段数据刚好填满view的宽度(按比例填满),然后不断的更细视图,实现视觉上的滑动效果(View实际上没有滑动)。如图所示:

代码实现:

首先在initData()初始化数据的时候,调用startScrollTimer()方法,开启一个timer,去不断的更新下标:

    private fun startScrollTimer() 
        timer = Timer()
        timerTask = object : TimerTask() 
            override fun run() 
                if (scrollIndex < data!!.size) 
                    scrollIndex++
                 else 
                    scrollIndex = 0
                
            
        
        timer!!.schedule(timerTask, 0, 50)
    

然后在ondraw中,进行具体的绘制:

// 绘制心电滚动视图
    private fun drawHeartScroll(canvas: Canvas) 
        if (data == null || data!!.size == 0) 
            return
        
        paint!!.reset()
        path!!.reset()
        paint!!.style = Paint.Style.STROKE
        paint!!.color = Color.parseColor("#31CE32")
        paint!!.strokeWidth = mGridLinestrokeWidth
        paint!!.isAntiAlias = true
        path!!.moveTo(0f, mHeight / 2)

        var scrollStartIndex = 0
        var scrollEndIndex = 0

        scrollEndIndex = scrollIndex

        scrollStartIndex = scrollEndIndex - intervalNumHeart
        if (scrollStartIndex < 0) 
            scrollStartIndex = 0
        

        var nowX: Float
        var nowY: Float
        for (i in scrollStartIndex until scrollEndIndex) 
            nowX = (i - scrollStartIndex) * intervalRowHeart

            var dataValue = data!![i]
            if (dataValue > 0) 
                if (dataValue > MAX_VALUE * 0.8f) 
                    dataValue = MAX_VALUE * 0.8f
                
             else 
                if (dataValue < -MAX_VALUE * 0.8f) 
                    dataValue = -(MAX_VALUE * 0.8f)
                
            
            nowY = mHeight / 2 - dataValue * intervalColumnHeart
            path!!.lineTo(nowX, nowY)
            LogUtils.d("drawHeartScroll $nowX $nowY")
        

        canvas.drawPath(path!!, paint!!)
        postInvalidate()
    

其中,前半部分是对数据下标的整理,后半部分是对整理的data数据进行实时展示。

二、实时绘制刷新refresh 实现

实现思路

这个就比上一个复杂多了。通过showLine(float float) 方法,让外界能输入数据并动态展示在心电图上,也就是说需要实现一个动态递增的Arraylist,然后在具体的绘制中,实现如下所示的数据结构:

第1次添加   1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,                      
第2次添加   1 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,                      
第3次添加   1 , 2 , 3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,                      
第4次添加   1 , 2 , 3 , 4 , 0 , 0 , 0 , 0 , 0 , 0 ,                      
第5次添加   1 , 2 , 3 , 4 , 5 , 0 , 0 , 0 , 0 , 0 ,                      
第6次添加   1 , 2 , 3 , 4 , 5 , 6 , 0 , 0 , 0 , 0 ,                      
第7次添加   1 , 2 , 3 , 4 , 5 , 6 , 7 , 0 , 0 , 0 ,                      
第8次添加   1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 0 , 0 ,                      
第9次添加   1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 0 ,                      
第10次添加   1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,                      
第11次添加   11 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,                      
第12次添加   11 , 12 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,                      
第13次添加   11 , 12 , 13 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ,                      
第14次添加   11 , 12 , 13 , 14 , 5 , 6 , 7 , 8 , 9 , 10 ,                      
第15次添加   11 , 12 , 13 , 14 , 15 , 6 , 7 , 8 , 9 , 10 ,                      
第16次添加   11 , 12 , 13 , 14 , 15 , 16 , 7 , 8 , 9 , 10 ,                      
第17次添加   11 , 12 , 13 , 14 , 15 , 16 , 17 , 8 , 9 , 10 ,                      
第18次添加   11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 9 , 10 ,                      
第19次添加   11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 10 ,                      
第20次添加   11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,                      
第21次添加   21 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,                      
第22次添加   21 , 22 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,                      
第23次添加   21 , 22 , 23 , 14 , 15 , 16 , 17 , 18 , 19 , 20 ,                      
第24次添加   21 , 22 , 23 , 24 , 15 , 16 , 17 , 18 , 19 , 20 ,                      
第25次添加   21 , 22 , 23 , 24 , 25 , 16 , 17 , 18 , 19 , 20 ,                      
第26次添加   21 , 22 , 23 , 24 , 25 , 26 , 17 , 18 , 19 , 20 ,                      
第27次添加   21 , 22 , 23 , 24 , 25 , 26 , 27 , 18 , 19 , 20 ,    ....(后面省略)

可以看到要位置一个总长度固定的数据,但是随着数据的增加新的数据是从左往右进行刷新的(对应刷新心电图数据的刷新方式),实现了该结构之后,再去做数据展示就可以实现心电图的刷新绘制了。

为此我专门写了一个测试类去测试:

public class TestClass 
    private static List<Float> refreshList = new ArrayList<>();
    private static float[] data; //一排显示的数据  一排10个
    private static int intervalNumHeart = 10;

    private static int showIndex;

    public static void main(String[] args) 
        data = new float[intervalNumHeart];

        for (int i = 1; i < 100; i++) 
            refreshList.add((float) i);
            drawHeartRefresh();
        

    

    private static void drawHeartRefresh() 
        int nowIndex = refreshList.size(); //当前长度
        if (nowIndex < intervalNumHeart) 
            showIndex = nowIndex - 1;
         else 
            showIndex = (nowIndex - 1) % intervalNumHeart;
        
        for (int i = 0; i < intervalNumHeart; i++) 
            if (i > refreshList.size() - 1) 
                break;
            
            if (nowIndex <= intervalNumHeart) 
                data[i] = refreshList.get(i);
             else 
                int times = (nowIndex - 1) / intervalNumHeart;
                int temp = times * intervalNumHeart + i;
                if (temp < nowIndex) 
                    data[i] =
                            refreshList.get(temp);
                
            
        
        logdata();
    

    private static void logdata() 
        String str = "";
        for (float temp : data) 
            int tempInt = (int) temp;
            str += tempInt + " , ";

        
        Log( "第" +(refreshList.size()) + "次添加   " + str + "                     " );
    

    private static void Log(String txt) 
        System.out.println(txt);
    


代码实现

一样分为两个部分,前半部分实现该结构,后半部分进行具体的绘制:

private fun drawHeartRefresh(canvas: Canvas) 
        paint!!.reset()
        path!!.reset()
        paint!!.style = Paint.Style.STROKE
        paint!!.color = Color.parseColor("#31CE32")
        paint!!.strokeWidth = mGridLinestrokeWidth
        paint!!.isAntiAlias = true
        path!!.moveTo(0f, mHeight / 2)

        val nowIndex = if (refreshList == null) 0 else refreshList!!.size //当前长度

        if (nowIndex == 0) 
            return
        

        if (nowIndex < intervalNumHeart) 
            showIndex = nowIndex - 1
         else 
            showIndex = (nowIndex - 1) % intervalNumHeart
        


        for (i in 0 until intervalNumHeart) 
            if (i > refreshList!!.size - 1) 
                break
            
            if (nowIndex <= intervalNumHeart) 

                data!![i] = refreshList!![i]
             else 
                val times = (nowIndex - 1) / intervalNumHeart

                val temp = times * intervalNumHeart + i

                if (temp < nowIndex) 
                    data?.set(i, refreshList!![temp])
                
            
        

        logdata()

        //绘制出data
        var nowX: Float
        var nowY: Float
        for (i in data!!.indices) 
            nowX = i * intervalRowHeart
            var dataValue = data!![i]
            if (dataValue > 0) 
                if (dataValue > MAX_VALUE * 0.8f) 
                    dataValue = MAX_VALUE * 0.8f
                
             else 
                if (dataValue < -MAX_VALUE * 0.8f) 
                    dataValue = -(MAX_VALUE * 0.8f)
                
            
            nowY = mHeight / 2 - dataValue * intervalColumnHeart

            if (i - 1 == showIndex) 
                path!!.moveTo(nowX, nowY)

             else 
                path!!.lineTo(nowX, nowY)
            

        

        canvas.drawPath(path!!, paint!!)
    

 

 

近期在把所有写过的自定义view(实用性较强的)整理成一个开源框架,Github地址:

https://github.com/jiangzhengnan/UI#ngui

gradle依赖:

compile 'ng.ngui.ngbase:nguilib:0.0.1'

以上是关于Android——ECG心电图的绘制实现的主要内容,如果未能解决你的问题,请参考以下文章

Android 根据心电图(ECG)数据分析绘制心电图

ECG/EKG 软件语言建议

深度学习Heartpy心电图分析

使用Python+TensorFlow2构建基于卷积神经网络(CNN)的ECG心电信号识别分类

ECG - ADS1298 使用笔记- 芯片简介(转)

WPF 实现心电图曲线绘制