如何动态、连续地显示波形啊? ( 积分: 100 )

赛平

Unregistered / Unconfirmed
GUEST, unregistred user!
各位高手:小生在设计的过程中需要动态、连续地显示波形图(心电波形图),当读入新的数据的时候就图像左移相应的点数,但是如果采用重画的方法,就会损失前面所画的图像,现在我所采用的方法只能画出读入的前1000个数据,后面的n多数据就无法再显示了,轻问如何解决啊?
现有的程序程序如下:
unit show;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ToolWin, ComCtrls, ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Bevel2: TBevel;
Image1: TImage;
Mainmenu: TToolBar;
read: TSpeedButton;
drawing: TSpeedButton;
ResetButton: TSpeedButton;
analysisbox: TGroupBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure readClick(Sender: TObject);
procedure drawingClick(Sender: TObject);
procedure ResetButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
function SelectionSort(var a:array of smallint):smallint;//中值滤波函数原型声明
function derivative(var a:array of smallint):boolean;//五点差分函数原型声明
implementation
function SelectionSort(var a: array of smallint):smallint;//中值滤波函数的实现部分
var
i, j, t: integer;
begin
for i := low(a) to high(a) - 1 do
for j := i+1 to high(a) do
if a > a[j] then
begin
//交换值(a, a[j], i, j);
t := a;
a := a[j];
a[j] := t;
end;
end;

function derivative(var a:array of smallint):boolean;//五点差分函数的定义部分
var //局部范围的定义区
y,i:integer;
begin
//y(n)=1/8[-x(n-2)-2x(n-1)+2x(n+1)+x(n+2)]
y:=(-2*a[i-2]-a[i-1]+2*a[i+1]+a[i+2]);
y:=y div 8; //五点差分方程
if y=0 then
result:=true
else
result:=False;
end;

{$R *.dfm}
Var FilePos:Longint;
procedure TForm1.readClick(Sender: TObject);
var
i,j:integer;
ECGdata:array [1..9000] of byte;
TransData1,TransData2:array[1..3000] of smallint;
ECGFile:File of byte;
ObjFile,ObjFile1:File of smallint;
readnum,num:longint;
tmpdata:Smallint;
StopNum:integer;
begin
if opendialog1.Execute then
begin
StopNum:=0;
assignfile(ECGfile,Opendialog1.FileName);
reset(ECGfile);
assignfile(ObjFile,'d:/1.ecg');
rewrite(ObjFile);
assignfile(ObjFile1,'d:/2.ecg');
rewrite(ObjFile1);
seek(ECGfile,300);
num:=9000;
repeat
blockread(ECGfile,ECGdata,num,readnum);
j:=1;
i:=1;
repeat
tmpdata:=ECGdata[i+1];
TransData1[j]:=((tmpdata and $F)shl 8) or ECGdata;
TransData2[j]:=((tmpdata and $F0)shl 4) or ECGdata[i+2];
i:=i+3;
j:=j+1;
until i>=readnum;
Blockwrite(ObjFile,TransData1,j-2);
BlockWrite(objfile1,TransData2,j-2);
StopNum:=StopNum+1;
until stopNum=11;
closefile(ECGfile);
CloseFile(ObjFile);
Closefile(ObjFile1);
FilePos:=1;
MessageDlg('数据已读入!', mtInformation,[mbOk], 0);
end;
end;

procedure TForm1.drawingClick(Sender: TObject);//绘制心电图

var
i,j,k:integer;
ECGData1,ECGData2:array[1..5000] of smallint;
OldECGData1,OldECGData2: array[1..5000] of smallint;
px,py:Longint;
Bx,By:Longint;
Wx,Wy:Single;
ECGFile1,ECGFile2:File of Smallint;
EcgData:array[1..1000]of smallint;
thresholdECG,judgeECG:array[1..5]of smallint;
QRSSite:Array[1..1000] of longint;
sumThre:smallint;
dectQRS:boolean;
m,n:Longint;
Num,NumRead:Longint;
begin
image1.Canvas.MoveTo(0,0);
assignfile(ECGFile1,'d:/1.ecg');
Reset(ECGFile1);
Seek(ECGFile1,FilePos);
assignfile(ECGFile2,'d:/2.ecg');
Reset(ECGFile2); //以只读方式打开ECGFile2
Seek(ECGFile2,FilePos);
Wx:=Image1.Width/1000;
Wy:=Image1.Height/2000;
image1.Canvas.Brush.Color:=clblack; //指定背景色
image1.Canvas.Pen.Color:=clGreen; //画笔颜色
image1.Canvas.FillRect(Rect(0,0,image1.Width,image1.Height)); //指定背景的填色区域
for i:=1 to 1000 do
QRSSite:=0;
for i:=1 to 5 do
begin
thresholdEcg:=10;
end;
sumThre:=10;
k:=0;
m:=0;
//repeat
//i:=3;
BlockRead(ECGFile1,ECGData1,1000,Num); // 读 1000个记录到变量ECGData1中
BlockRead(ECGFile2,ECGData2,1000,Num); //读入1000个记录到变量ECGData中}
for i:=1 to 1000 do
begin
OldECGData1:=ECGData1;
end;
i:=0;
repeat
i:=i+1;
//画图
Px:=round(i*Wx);
Py:=round(ECGData1*Wy)+image1.Height div 4-100;
image1.Canvas.LineTo(Px,Py);
for j:=-2 to 2 do
begin
judgeECG[j+3]:=OldECGData1[i-j];
end;
SelectionSort(judgeECG);//调用中值滤波

if derivative(judgeECG)=true then //调用derivative函数,用于判断五点差分求导后的过零点
if JudgeECG>sumThre then
dectQRS:=true
else
dectQRS:=False;
if dectQRS=True then
begin
QRSSite[k]:=m*1000+i;
k:=k+1;

sumThre:=0;
for j:=1 to 4 do //阈值模版更新
begin
thresholdEcg[j]:=thresholdECG[j+1];
thresholdEcg[5]:=ECGData;
sumThre:=thresholdECG[j]+sumThre;
end;
sumThre:=sumThre div 5;
i:=round(i+0.2*250);//200毫秒不应期
//作标记
BX:=image1.Canvas.PenPos.X;
BY:=image1.Canvas.PenPos.Y;
image1.Canvas.Pen.Color :=clred;
image1.Canvas.MoveTo(QRSsite,0);
image1.Canvas.LineTo(QRSsite,image1.Height);
image1.Canvas.MoveTo(Bx,By);
image1.Canvas.Pen.Color:=clGreen;
end;
until i>=Num-2;
//m:=m+1;
//until m=10;
//FilePos:=FilePos+1000;
// Label1.Caption:='数据位置:'+IntToStr(FilePos-1000)+' - '+intToStr(FilePos);
closeFile(ECGFile1);
closefile(ECGFile2);
end;

procedure TForm1.ResetButtonClick(Sender: TObject);
begin
FilePos:=1;
end;

end.
 

赛平

Unregistered / Unconfirmed
GUEST, unregistred user!
各位高手:小生在设计的过程中需要动态、连续地显示波形图(心电波形图),当读入新的数据的时候就图像左移相应的点数,但是如果采用重画的方法,就会损失前面所画的图像,现在我所采用的方法只能画出读入的前1000个数据,后面的n多数据就无法再显示了,轻问如何解决啊?
现有的程序程序如下:
unit show;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, Buttons, ToolWin, ComCtrls, ExtCtrls, StdCtrls;

type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
Bevel2: TBevel;
Image1: TImage;
Mainmenu: TToolBar;
read: TSpeedButton;
drawing: TSpeedButton;
ResetButton: TSpeedButton;
analysisbox: TGroupBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure readClick(Sender: TObject);
procedure drawingClick(Sender: TObject);
procedure ResetButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
function SelectionSort(var a:array of smallint):smallint;//中值滤波函数原型声明
function derivative(var a:array of smallint):boolean;//五点差分函数原型声明
implementation
function SelectionSort(var a: array of smallint):smallint;//中值滤波函数的实现部分
var
i, j, t: integer;
begin
for i := low(a) to high(a) - 1 do
for j := i+1 to high(a) do
if a > a[j] then
begin
//交换值(a, a[j], i, j);
t := a;
a := a[j];
a[j] := t;
end;
end;

function derivative(var a:array of smallint):boolean;//五点差分函数的定义部分
var //局部范围的定义区
y,i:integer;
begin
//y(n)=1/8[-x(n-2)-2x(n-1)+2x(n+1)+x(n+2)]
y:=(-2*a[i-2]-a[i-1]+2*a[i+1]+a[i+2]);
y:=y div 8; //五点差分方程
if y=0 then
result:=true
else
result:=False;
end;

{$R *.dfm}
Var FilePos:Longint;
procedure TForm1.readClick(Sender: TObject);
var
i,j:integer;
ECGdata:array [1..9000] of byte;
TransData1,TransData2:array[1..3000] of smallint;
ECGFile:File of byte;
ObjFile,ObjFile1:File of smallint;
readnum,num:longint;
tmpdata:Smallint;
StopNum:integer;
begin
if opendialog1.Execute then
begin
StopNum:=0;
assignfile(ECGfile,Opendialog1.FileName);
reset(ECGfile);
assignfile(ObjFile,'d:/1.ecg');
rewrite(ObjFile);
assignfile(ObjFile1,'d:/2.ecg');
rewrite(ObjFile1);
seek(ECGfile,300);
num:=9000;
repeat
blockread(ECGfile,ECGdata,num,readnum);
j:=1;
i:=1;
repeat
tmpdata:=ECGdata[i+1];
TransData1[j]:=((tmpdata and $F)shl 8) or ECGdata;
TransData2[j]:=((tmpdata and $F0)shl 4) or ECGdata[i+2];
i:=i+3;
j:=j+1;
until i>=readnum;
Blockwrite(ObjFile,TransData1,j-2);
BlockWrite(objfile1,TransData2,j-2);
StopNum:=StopNum+1;
until stopNum=11;
closefile(ECGfile);
CloseFile(ObjFile);
Closefile(ObjFile1);
FilePos:=1;
MessageDlg('数据已读入!', mtInformation,[mbOk], 0);
end;
end;

procedure TForm1.drawingClick(Sender: TObject);//绘制心电图

var
i,j,k:integer;
ECGData1,ECGData2:array[1..5000] of smallint;
OldECGData1,OldECGData2: array[1..5000] of smallint;
px,py:Longint;
Bx,By:Longint;
Wx,Wy:Single;
ECGFile1,ECGFile2:File of Smallint;
EcgData:array[1..1000]of smallint;
thresholdECG,judgeECG:array[1..5]of smallint;
QRSSite:Array[1..1000] of longint;
sumThre:smallint;
dectQRS:boolean;
m,n:Longint;
Num,NumRead:Longint;
begin
image1.Canvas.MoveTo(0,0);
assignfile(ECGFile1,'d:/1.ecg');
Reset(ECGFile1);
Seek(ECGFile1,FilePos);
assignfile(ECGFile2,'d:/2.ecg');
Reset(ECGFile2); //以只读方式打开ECGFile2
Seek(ECGFile2,FilePos);
Wx:=Image1.Width/1000;
Wy:=Image1.Height/2000;
image1.Canvas.Brush.Color:=clblack; //指定背景色
image1.Canvas.Pen.Color:=clGreen; //画笔颜色
image1.Canvas.FillRect(Rect(0,0,image1.Width,image1.Height)); //指定背景的填色区域
for i:=1 to 1000 do
QRSSite:=0;
for i:=1 to 5 do
begin
thresholdEcg:=10;
end;
sumThre:=10;
k:=0;
m:=0;
//repeat
//i:=3;
BlockRead(ECGFile1,ECGData1,1000,Num); // 读 1000个记录到变量ECGData1中
BlockRead(ECGFile2,ECGData2,1000,Num); //读入1000个记录到变量ECGData中}
for i:=1 to 1000 do
begin
OldECGData1:=ECGData1;
end;
i:=0;
repeat
i:=i+1;
//画图
Px:=round(i*Wx);
Py:=round(ECGData1*Wy)+image1.Height div 4-100;
image1.Canvas.LineTo(Px,Py);
for j:=-2 to 2 do
begin
judgeECG[j+3]:=OldECGData1[i-j];
end;
SelectionSort(judgeECG);//调用中值滤波

if derivative(judgeECG)=true then //调用derivative函数,用于判断五点差分求导后的过零点
if JudgeECG>sumThre then
dectQRS:=true
else
dectQRS:=False;
if dectQRS=True then
begin
QRSSite[k]:=m*1000+i;
k:=k+1;

sumThre:=0;
for j:=1 to 4 do //阈值模版更新
begin
thresholdEcg[j]:=thresholdECG[j+1];
thresholdEcg[5]:=ECGData;
sumThre:=thresholdECG[j]+sumThre;
end;
sumThre:=sumThre div 5;
i:=round(i+0.2*250);//200毫秒不应期
//作标记
BX:=image1.Canvas.PenPos.X;
BY:=image1.Canvas.PenPos.Y;
image1.Canvas.Pen.Color :=clred;
image1.Canvas.MoveTo(QRSsite,0);
image1.Canvas.LineTo(QRSsite,image1.Height);
image1.Canvas.MoveTo(Bx,By);
image1.Canvas.Pen.Color:=clGreen;
end;
until i>=Num-2;
//m:=m+1;
//until m=10;
//FilePos:=FilePos+1000;
// Label1.Caption:='数据位置:'+IntToStr(FilePos-1000)+' - '+intToStr(FilePos);
closeFile(ECGFile1);
closefile(ECGFile2);
end;

procedure TForm1.ResetButtonClick(Sender: TObject);
begin
FilePos:=1;
end;

end.
 
G

gzgzlxg

Unregistered / Unconfirmed
GUEST, unregistred user!
使用BitBlt
 

来如风

Unregistered / Unconfirmed
GUEST, unregistred user!
那干吗不用tchart呢?
 
S

SeekMyself

Unregistered / Unconfirmed
GUEST, unregistred user!
用 PaintBox 画也不错的
 

赛平

Unregistered / Unconfirmed
GUEST, unregistred user!
啊。我觉得使用BitBlt,tchart,PaintBox还是image关系都不大,关键是采用的输入及绘图算法的改进,也就是希望能够实现象cpu的状态显示那样的效果~~~
 
D

dawnsong

Unregistered / Unconfirmed
GUEST, unregistred user!
TChart好像就是数据和画图分离,维护一个数据,并计算出需要画的部分,然后就实现了高速的绘画而没有闪烁

---------------------------------
cpu的状态显示那样的效果

这个,看看C++Builder6中关于这个控件(类似CPU使用情况网格图)的源代码后才知道,这个是不维护数据的,于是就不会存在历史数据
能够一格一格的往左移动,是在定义后最右边一个Rect(此部分Rect为接受新数据部分)后,然后不断的CopyRect到左边,左边和“最右边一个Rect”所对应的Rect于是就丢失了,于是实现的动画
简单Rect分布图如下
-----------------------
|
| <-此处接收新数据,也就是画图只需要画出这一Rect
| 其他部分通过CopyRect来实现快速,但仍不能避免闪烁
-----------------------
 

金卡绣球jk8.com

Unregistered / Unconfirmed
GUEST, unregistred user!
K

kinneng

Unregistered / Unconfirmed
GUEST, unregistred user!
心电图是不移动的,不断向右画,到达右面之后,又从左面开始覆盖着向右画,图象不移动,使波形总能在一个位置保持一定时间,看得比移动的清楚,其实很多仪器都是这种现实方式,如果楼主做心电图,一定要看看实物
 
G

gzgzlxg

Unregistered / Unconfirmed
GUEST, unregistred user!
我仔细研究过TaskMgr任务管理器绘CPU图形的方法,它就是使用BitBlt,我也用Delphi写了一个任务管理器(没有最后完工,但性能部分完成了),和原版的任务管理器完全一样,就是仿照TaskMgr,用的BitBlt完成的。
 

提香

Unregistered / Unconfirmed
GUEST, unregistred user!
非常感谢dawnsong和 kinneng的指点,是否能够再详细一点说明?
 

赛平

Unregistered / Unconfirmed
GUEST, unregistred user!
感谢各位的点拨,很有启发
 
顶部