问题

功能需求

实现超声中的M图(不用深究,理解后面我的数据流向就可以)的展示,和历史图像的播放。
在这里插入图片描述
上图中红色方框内为M图的截图,具体动画效果以数据流动想象(这个CSDN没搞懂这么传视频)。
M图有两种播放方式,分别为流动模式和覆盖模式。假设红色框的的显示宽度大小为5。
在这里插入图片描述
上图中的数字越大,代表越新的数据,以此类推,便可以达到通话效果。
还有一个是历史图像播放,等同于上图的一、二、三、四、五、六、七次的动画效果能够自由切换,此时我们需要记录更久之前的数据,所以我们需要一个更大存储空间(我这里用的list)存放更多的数据。此时我们就有了一个大list和一个小list,大list的大小表示最大存放历史数据大小,这个大小可调;小list等于这个播放窗口大小,例如上面的显示宽度5,那么我们小list的大小就为5,这个大小也可调。

实现一个什么呢

实现一个类来管理这两个list的读和写,而且读取出来的数据达到流动效果和覆盖效果(实现一种也可以)。
下面是我们实现的类,类中有一个不知道是不是bug的bug,有一个变量会一直加一,超出这个变量的最大值需要1年多的时间。

//H_ListFrameM.h
#ifndef H_LISTFRAMEM_H
#define H_LISTFRAMEM_H

#include "../frame/H_FrameM.h"
#include "../../../types/HSArray.h"

class H_ListFrameM
{
public:
    H_ListFrameM();
    ~H_ListFrameM();

public:
    // 设置最大帧
    HSBool setMax(HSInt max);

    // 设置滚动方式
    HSBool setScroll(HSBool scroll);

    // 获取滚动方式
    HSBool scroll() const;

    // 获取当前帧数
    HSInt size(HSBool afterCut) const;

    // 获取起始位置
    HSInt start() const;

    // 设置当前位置为起始位置
    HSBool setStart();

    // 设置起始位置
    HSBool setStart(HSInt start);

    // 获取结束位置
    HSInt end() const;

    // 设置当前位置为结束位置
    HSBool setEnd();

    // 设置结束位置
    HSBool setEnd(HSInt end);

    // 设置当前帧位置
    HSBool setPos(HSInt pos);

    // 设置当前帧位置
    HSBool setPos(HSBool add, HSBool loop);

    // 获取当前帧位置
    HSInt posRead() const;

    // 添加一帧
    HSVoid push(H_HardData* hd);

    // 获取第pos帧的图像
    HSBool pop(HSInt pos, HSImage& image, HSUIntArray& stamp, HSInt blockW);

    // 获取平均帧频
    HSDouble avgFps();

    // 释放内存(keepLastFrame=是否保留最后一帧)
    HSVoid clear(HSBool keepLastFrame);
    
private:
    HSBool    alloc(const H_FrameM& frame);
    HSVoid    zero();
    HSInt     maxWidth();
    HSInt     posWrite();
    HSBool    posRead(HSInt pos, HSInt blockW, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2, HSInt& src3, HSInt& dst3, HSInt& len3, HSInt& src4, HSInt& dst4, HSInt& len4);
    HSVoid    posReadScroll(HSInt blockW, HSInt start, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2);
    HSVoid    posRead1(HSInt blockW, HSInt start, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2, HSInt frees);
    HSVoid    posRead2(HSInt blockW, HSInt start, HSInt& src3, HSInt& dst3, HSInt& len3, HSInt& src4, HSInt& dst4, HSInt& len4, HSInt frees);
    HSUShort* scanLine(HSInt x, HSInt y);

private:
    HSBool                m_scroll;

private:
    HSInt                 m_max;
    std::vector<HSUShort> m_list;
    std::vector<HSUInt>   m_stamp;    // M图历史时间戳
    HSInt64               m_write;
    HSInt                 m_read;
    HSInt                 m_start;
    HSInt                 m_end;

private:
    HSInt                 m_speed;
    HSInt                 m_height;

private:
    HSInt64               m_last;     // M图历史计数器(用于计算平均帧频)
    HSUInt                m_time;     // M图计时(用于计算平均帧频)
    HSDouble              m_avgfps;   // M图平均帧频
};
#endif // H_LISTFRAMEM_H
//H_ListFrameM.cpp
#include "H_ListFrameM.h"
#include "../../../types/HSImage.h"
#include "../../../types/HS_Math.h"
#include "../../thread/H_Clock.h"

#define MAX_SIZE    4096
#define MAX_HEIGHT   512

H_ListFrameM::H_ListFrameM()
{
    m_scroll = HSFalse;

    m_max    = 0;
    m_write  = -1;
    m_read   = -1;
    m_start  = -1;
    m_end    = -1;

    m_speed  = 0;
    m_height = 0;

    m_last   = 0;
    m_time   = H_Clock::clock_ms();
    m_avgfps = 0.0;
}

H_ListFrameM::~H_ListFrameM()
{
    this->clear(HSFalse);
    m_list.clear();
}

HSBool H_ListFrameM::setMax(HSInt max)
{
    HSBool ok = HSFalse;
    if ((max > 0) && (m_max != max))
    {
        m_max   = max;
        m_start = -1;
        m_end   = -1;
        ok = HSTrue;
    }
    return ok;
}

HSBool H_ListFrameM::setScroll(HSBool scroll)
{
    HSBool ok = HSFalse;
    if (m_scroll != scroll)
    {
        m_scroll = scroll;
        ok = HSTrue;
    }
    return ok;
}

HSBool H_ListFrameM::scroll() const
{
    return m_scroll;
}

HSInt H_ListFrameM::size(HSBool afterCut) const
{
    HSInt ok = 0;
    if (!afterCut || (m_start < 0))
    {
        ok = HSMin(m_max, m_write + 1);
    }
    else
    {
        ok = (m_end - m_start + 1);
    }
    return ok;
}

HSInt H_ListFrameM::start() const
{
    return HSMax(m_start, 0);
}

HSBool H_ListFrameM::setStart()
{
    return this->setStart(m_read);
}

HSBool H_ListFrameM::setStart(HSInt start)
{
    HSBool ok = HSFalse;
    if (m_start != start)
    {
        if (start < this->size(HSFalse))
        {
            if (m_end < 0)
            {
                m_start = start;
                m_end = this->size(HSFalse) - 1;
                m_read = m_start;
            }
            else if (start <= m_end)
            {
                m_start = start;
            }
            else
            {
                m_start = m_end;
                m_end = start;
            }
            ok = HSTrue;
        }
    }
    return ok;
}

HSInt H_ListFrameM::end() const
{
    return ((m_end < 0) ? this->size(HSFalse) - 1 : 0);
}

HSBool H_ListFrameM::setEnd()
{
    return this->setEnd(m_read);
}

HSBool H_ListFrameM::setEnd(HSInt end)
{
    HSBool ok = HSFalse;
    if (m_end != end)
    {
        if (end < this->size(HSFalse))
        {
            if (m_start < 0)
            {
                m_end = end;
                m_start = 0;
                m_read = m_start;
            }
            else if (end >= m_start)
            {
                m_end = end;
            }
            else
            {
                m_end = m_start;
                m_start = end;
            }
            ok = HSTrue;
        }
    }
    return ok;
}

HSBool H_ListFrameM::setPos(HSInt pos)
{
    HSBool ok = HSFalse;
    if (m_read != pos)
    {
        m_read = pos;
        ok = HSTrue;
    }
    return ok;
}

HSBool H_ListFrameM::setPos(HSBool add, HSBool loop)
{
    HSBool ok = HSFalse;
    if (m_write >= 0)
    {
        HSInt start = (m_start < 0) ?                       0 : m_start;
        HSInt end   = (m_end   < 0) ? this->size(HSFalse) - 1 : m_end;

        HSUInt pos = HS_Math::getBound<HSInt>(m_read, start, end, 1, add, loop);
        if (m_read != pos)
        {
            m_read = pos;
            ok = HSTrue;
        }
    }
    return ok;
}

HSInt H_ListFrameM::posRead() const
{
    return m_read;
}

HSVoid H_ListFrameM::push(H_HardData* hd)
{
    if (m_max && hd && hd->containsM())
    {
        H_FrameM frame(hd);
        if (!frame.isEmpty())
        {
            if (this->alloc(frame))
            {
                HSInt posWrite = this->posWrite();
                for (HSInt y=0; y<frame.m_height; y++)
                {
                    HSUShort* src = frame.scanLine(y);
                    HSUShort* dst = this->scanLine(posWrite, y);
                    memmove(dst, src, m_speed * sizeof(HSUShort));
                }

                for (HSInt x=0; x<frame.m_speed; x++)
                {
                    m_stamp[posWrite + x] = frame.m_stamp;
                }

                m_write = (m_write + 1);
                m_read  = this->size(HSFalse) - 1;
            }
        }
    }
}

HSBool H_ListFrameM::pop(HSInt pos, HSImage& image, HSUIntArray& stamp, HSInt blockW)
{
    HSBool ok = HSFalse;
    if (m_write >= 0)
    {
        if (image.isEmpty() || (image.width() != blockW) || (image.height() != m_height))
        {
            image.create(blockW, m_height, HSImage::IT_16U_C1);
        }

        HSInt src1, dst1, len1, src2, dst2, len2, src3, dst3, len3, src4, dst4, len4;
        if (this->posRead(pos, blockW, src1, dst1, len1, src2, dst2, len2, src3, dst3, len3, src4, dst4, len4))
        {
            if (len1)
            {
                for (HSInt y=0; y<m_height; y++)
                {
                    HSUShort* src = (HSUShort*)this->scanLine(src1, y);
                    HSUShort* dst = (HSUShort*)image.scanLine(dst1, y);
                    memcpy(dst, src, len1 * sizeof(HSUShort));
                }
            }
            if (len2)
            {
                for (HSInt y=0; y<m_height; y++)
                {
                    HSUShort* src = (HSUShort*)this->scanLine(src2, y);
                    HSUShort* dst = (HSUShort*)image.scanLine(dst2, y);
                    memcpy(dst, src, len2 * sizeof(HSUShort));
                }
            }
            if (len3)
            {
                for (HSInt y=0; y<m_height; y++)
                {
                    HSUShort* src = (HSUShort*)this->scanLine(src3, y);
                    HSUShort* dst = (HSUShort*)image.scanLine(dst3, y);
                    memcpy(dst, src, len3 * sizeof(HSUShort));
                }
            }
            if (len4)
            {
                for (HSInt y=0; y<m_height; y++)
                {
                    HSUShort* src = (HSUShort*)this->scanLine(src4, y);
                    HSUShort* dst = (HSUShort*)image.scanLine(dst4, y);
                    memcpy(dst, src, len4 * sizeof(HSUShort));
                }
            }

            stamp.resize(blockW);
            if (len1) stamp.set(dst1, &m_stamp[src1], len1);
            if (len2) stamp.set(dst2, &m_stamp[src2], len2);
            if (len3) stamp.set(dst3, &m_stamp[src3], len3);
            if (len4) stamp.set(dst4, &m_stamp[src4], len4);
        }

        ok = HSTrue;
    }
    return ok;
}

HSDouble H_ListFrameM::avgFps()
{
    if (m_write >= 0)
    {
        HSUInt current = H_Clock::clock_ms();

        // 时间有效
        if (current - m_time >= (m_last ? 1000 : 0))
        {
            if (m_write - m_last >= (m_last ? 1 : 16))
            {
                HSInt count = (m_write - m_last) * m_speed;

                HSDouble tc = 0.0;
                for (HSUInt n=0; n<count-1; n++)
                {
                    HSInt pos1 = (m_last * m_speed + n + 0) % this->maxWidth();
                    HSInt pos2 = (m_last * m_speed + n + 1) % this->maxWidth();
                    tc += m_stamp[pos2] - m_stamp[pos1];
                }

                // 保存平均帧频
                if (tc > 0.0) m_avgfps = 1000.0 / (tc / count);

                m_last = m_write;
                m_time = current;
            }
        }
    }
    return m_avgfps;
}

HSVoid H_ListFrameM::clear(HSBool keepLastFrame)
{
    if (keepLastFrame)
    {
        if (m_write >= 0)
        {
            // 回退到最后一帧前的位置
            HSInt start = (m_write * m_speed) % this->maxWidth();

            // 无需分段计算
            for (HSInt y=0; y<m_height; y++)
            {
                memset(this->scanLine(0,               y), 0, sizeof(HSUShort) * start);
                memset(this->scanLine(start + m_speed, y), 0, sizeof(HSUShort) * (this->maxWidth() - (start + m_speed)));
            }

            memset(&m_stamp[0],               0, start                                  * sizeof(HSUInt));
            memset(&m_stamp[start + m_speed], 0, (this->maxWidth() - (start + m_speed)) * sizeof(HSUInt));
        }
    }
    else
    {
        if (m_list.size())
        {
            this->zero();

            m_write  = -1;
            m_read   = -1;
            m_start  = -1;
            m_end    = -1;

            m_last   = 0;
            m_time   = H_Clock::clock_ms();
            m_avgfps = 0.0;
        }
    }
}

HSBool H_ListFrameM::alloc(const H_FrameM& frame)
{
    HSBool ok = HSFalse;
    if (!frame.isEmpty())
    {
        if ((m_speed != frame.m_speed) || (m_height != frame.m_height))
        {
            m_speed  = frame.m_speed;
            m_height = frame.m_height;

            m_list.resize(this->maxWidth() * m_height);
            m_stamp.resize(this->maxWidth());

            this->zero();
        }
        ok = HSTrue;
    }
    return ok;
}

HSVoid H_ListFrameM::zero()
{
    memset(&m_list[0],  0, m_list.size()  * sizeof(HSUShort));
    memset(&m_stamp[0], 0, m_stamp.size() * sizeof(HSUShort));
}

HSInt H_ListFrameM::maxWidth()
{
    return (m_speed * MAX_SIZE);
}

HSInt H_ListFrameM::posWrite()
{
    HSInt ok = 0;
    {
        // 待写入位置乘以M超速度
        ok = (m_write + 1) * m_speed;

        // 格式化为圆形位置
        ok %= this->maxWidth();
    }
    return ok;
}

HSBool H_ListFrameM::posRead(HSInt pos, HSInt blockW, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2, HSInt& src3, HSInt& dst3, HSInt& len3, HSInt& src4, HSInt& dst4, HSInt& len4)
{
    HSBool ok = HSFalse;
    {
        if (pos == -1) pos = m_read;

        if (m_write + 1 >= m_max)
        {
            pos += (m_write + 1) - m_max;
        }

        if (m_scroll)
        {
            // 回退到目标图像宽度前的位置
            HSInt start = (pos + 1) * m_speed - blockW;

            // 分段计算
            this->posReadScroll(blockW, start, src1, dst1, len1, src2, dst2, len2);

            src3 = 0;
            len3 = 0;
            src4 = 0;
            len4 = 0;

            ok = HSTrue;
        }
        else
        {
            // 共循环了多少次(一次=目标图像宽度)
            HSInt lines = (pos + 1) * m_speed / blockW;

            // 又流动了多少线(小于目标图像宽度的部分)
            HSInt frees = (pos + 1) * m_speed % blockW;

            // 最后一次采集在目标图像宽度前的位置
            HSInt current = (m_write + 1) * m_speed;

            // 求最一次完整帧的起始位置
            {
                // 回退小于目标图像宽度的部分
                HSInt start = current - frees;

                // 若超出一次目标图像宽度,则继续回退一次,此时start为最后一次完整帧+覆盖部分前的位置
                if (lines) start -= blockW;

                // 格式化为有效部分(因为前面frees会再次覆盖,故后续无需复制,提前去掉)
                start += frees;

                // 分段计算
                this->posRead1(blockW, start, src1, dst1, len1, src2, dst2, len2, frees);
            }

            // 求覆盖完整帧的起始位置
            {
                // 回退小于目标图像宽度的部分
                HSInt start = current - frees;

                // 分段计算
                this->posRead2(blockW, start, src3, dst3, len3, src4, dst4, len4, frees);
            }

            ok = HSTrue;
        }
    }
    return ok;
}

HSVoid H_ListFrameM::posReadScroll(HSInt blockW, HSInt start, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2)
{
    src1 = dst1 = len1 = src2 = dst2 = len2 = 0;

    // 尚未采集满目标图像宽度
    if (start < 0) start += this->maxWidth();

    // 格式化为圆形位置
    start %= this->maxWidth();

    // 无跨越,一次性拷贝数据
    if (start + blockW < this->maxWidth())
    {
        src1 = start;
        dst1 = 0;
        len1 = blockW;
    }
    // 跨越起始位置,需分段拷贝
    else
    {
        src1 = start;
        dst1 = 0;
        len1 = this->maxWidth() - start;
        src2 = 0;
        dst2 = len1;
        len2 = blockW - len1;
    }
}

HSVoid H_ListFrameM::posRead1(HSInt blockW, HSInt start, HSInt& src1, HSInt& dst1, HSInt& len1, HSInt& src2, HSInt& dst2, HSInt& len2, HSInt frees)
{
    src1 = dst1 = len1 = src2 = dst2 = len2 = 0;

    // 尚未采集满目标图像宽度
    if (start < 0) start += this->maxWidth();

    // 格式化为圆形位置
    start %= this->maxWidth();

    // 无跨越,一次性拷贝数据
    if (start + (blockW - frees) <= this->maxWidth())
    {
        src1 = start;
        dst1 = frees;
        len1 = blockW - frees;
    }
    // 跨越起始位置,需分段拷贝
    else
    {
        src1 = start;
        dst1 = frees;
        len1 = this->maxWidth() - start;
        src2 = 0;
        dst2 = frees + len1;
        len2 = (blockW - frees) - len1;
    }
}

HSVoid H_ListFrameM::posRead2(HSInt blockW, HSInt start, HSInt& src3, HSInt& dst3, HSInt& len3, HSInt& src4, HSInt& dst4, HSInt& len4, HSInt frees)
{
    src3 = dst3 = len3 = src4 = dst4 = len4 = 0;

    // 尚未采集满目标图像宽度
    if (start < 0) start += this->maxWidth();

    // 格式化为圆形位置
    start %= this->maxWidth();

    // 无跨越,一次性拷贝数据
    if (start + frees <= this->maxWidth())
    {
        src3 = start;
        dst3 = 0;
        len3 = frees;
    }
    // 跨越起始位置,需分段拷贝
    else
    {
        src3 = start;
        dst3 = 0;
        len3 = this->maxWidth() - start;
        src4 = 0;
        dst4 = len3;
        len4 = frees - len3;
    }
}

HSUShort* H_ListFrameM::scanLine(HSInt x, HSInt y)
{
    return &m_list[this->maxWidth() * y + x];
}
我为什么写这篇文章

集思广益,上面是我们的实现的源码,思路就不说了。自由思考,不一样的思路可能对于我们来说会更好。

实现思路

1.首先,管理一个大链表,链表采用圆形链表的思想,该链表两个功能,一是存放历史数据,而是给显示区域提供数据。
2.显示区域等同一个稍小的链表,链表中的数据来源是大链表,去大链表中取得对应的数据,在小链表中进行填充,填充的过程得符合流动和覆盖的方式。
3.最开始我的想法是在数据开始填充的开始,就是大链表中的数据还不能完全填充完小链表,这是一种情况,其次就是大链表未装满,但是能满足小链表的数据要求,在这两种情况下去寻找规律,这个画出示意图即可看出。

4.实现到上面部分,问题就来了。当大链表填充完了之后,大链表的赋值相当于重新开始,我的小链表的取值也跟着从头开始,这里就出现了问题,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值