Click here to Skip to main content
15,893,588 members
Articles / Programming Languages / C++

ECG recording, storing, filtering and recognition

Rate me:
Please Sign up or sign in to vote.
4.72/5 (110 votes)
14 Apr 200411 min read 733.5K   38.4K   156  
Full open code project for making driver and application software for ECG medical measurements.
// ECG_DRAW.cpp: implementation of the ECG_DRAW class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ECG_DRAW.h"
#include "Person.h"
#include "stdio.h"
#include "math.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ECG_DRAW::ECG_DRAW()
{

}

ECG_DRAW::~ECG_DRAW()
{

}

void ECG_DRAW::SetEcgDrawRect(CDC* pDC,CRect rDrawRect,int from,int to)
{
	//Before using this code you must specify
	//in your app the CRect&CClientDC
	//then pass them as parameters
	//in function SetEcgDrawrect
	///////////
/*	CRect rcClient;
	GetClientRect(rcClient);
	CClientDC dc(this);
*/	///////////
	//Set the rect for drawing
	m_rDrawRect = rDrawRect;
	//Get CDC pointer
	DC = pDC;
	i_from = from;
	i_to = to;
	Draw();
}

void ECG_DRAW::Draw()
{
	//test draw line
//	DC->MoveTo(0,0);
//	DC->LineTo(100,200);
	int DY = 100;
	//in to this class
	CBitmap Bitmap;
	CBitmap* pbmOld = NULL;//Pointer to the CBitmap object
	CDC dcMem;
	CRect BmpRect;
	BmpRect.SetRect(0,0,500,255);
	dcMem.CreateCompatibleDC(DC);//Greate painting object
	Bitmap.CreateCompatibleBitmap(DC,BmpRect.Width(),BmpRect.Height());
	//In to DCMem is getting the object bitmap
	pbmOld = dcMem.SelectObject(&Bitmap);
	//Creates the bitmap rectangle

	dcMem.PatBlt(0,0,500,255,WHITENESS);
	DrawGrid(&dcMem,BmpRect,1,RGB(190,220,190));
	DrawEcg(&dcMem,BmpRect,1);
	DrawQRS(&dcMem,1);
	DrawFromTo(&dcMem,1);
	DrawText(&dcMem,1);

	//Shows the bitmap on the dlg screen dY=100
	DC->BitBlt(m_rDrawRect.left,m_rDrawRect.top,m_rDrawRect.right,
		m_rDrawRect.bottom,&dcMem,0,0,SRCCOPY);

	dcMem.SelectObject(pbmOld);
	dcMem.DeleteDC();

}

void ECG_DRAW::SetArr(double *srcECG,double *srcQRS, int lenght)
{
	if(lenght>5000)
		lenght = 5000;
	//Copy the info from pointer*source to ECG array
	for(int i=0;i<lenght/2;i++)
	{
		ECG[i] = float(*(srcECG+i))/4;
		QRS[i] = float(*(srcQRS+i))/4;
	}

}

void ECG_DRAW::DrawGrid(CDC *pDC,CRect rRect,int d,COLORREF color)
{
	int dx=0;
	if(d==2)
		dx = 65;

	CPen lpenR(PS_SOLID,1,color);//Select color green
	CPen* pOldpen = pDC->SelectObject(&lpenR);
	pDC->SelectObject(&lpenR);

	pDC->Rectangle(rRect);
	//draw horizontal lines
	for(int i=0;i<255;i=i+63)
	{
		pDC->MoveTo(rRect.left*d+dx,i*d);
		pDC->LineTo(rRect.right*d+dx,i*d);
	}
	//draw vertical lines each one is equal to 1 sec
	for(i=0;i<550;i=i+50)
	{
		pDC->MoveTo(i*d+dx,rRect.top*d);
		pDC->LineTo(i*d+dx,rRect.bottom*d);
	}
	pDC->SelectObject(pOldpen);
}

void ECG_DRAW::DrawEcg(CDC *pDC, CRect rRect,int d)
{
	int dx=0;
	if(d==2)
		dx = 65;

	int i=0;
	int di=0;
	for(i=0;i<500;i++)
	{
		di = i*5;
		if(di<i_from)
		{
			pDC->MoveTo(i*d+dx,30*d - int(ECG[di])*d/2);
			pDC->LineTo(i*d+1+dx,30*d - int(ECG[di+5])*d/2);
		}
		if(di>i_from)
		{
			CPen lpenR(PS_SOLID,1,RGB(255,0,0));//Select color green
			CPen* pOldpen = pDC->SelectObject(&lpenR);
			pDC->SelectObject(&lpenR);
			pDC->MoveTo(i*d+dx,30*d - int(ECG[di])*d/2);
			pDC->LineTo(i*d+1+dx,30*d - int(ECG[di+5])*d/2);
			pDC->SelectObject(pOldpen);
		}
		if(di>i_to)
		{
	//		CPen lpenR(PS_SOLID,1,RGB(0,255,0));//Select color green
	//		CPen* pOldpen = pDC->SelectObject(&lpenR);
	//		pDC->SelectObject(&lpenR);
			pDC->MoveTo(i*d+dx,30*d - int(ECG[di])*d/2);
			pDC->LineTo(i*d+1+dx,30*d - int(ECG[di+5])*d/2);

	//		pDC->SelectObject(pOldpen);
		}		
	}		
}

void ECG_DRAW::DrawText(CDC *pDC,int d)
{
	CFont Font;
	Font.CreateFont(3,3,0,0,FW_DONTCARE,FALSE,FALSE,0,
		DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,
		CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,
		DEFAULT_PITCH|FF_DONTCARE,
		"MS Sans Serif");
	CFont* pOldFont = pDC->SelectObject(&Font);

	
	CString str;
	if(d==2)
		str = "      ";
	pDC->TextOut(2*d,200*d,str+"10s ECG record "+s_BmpInfo);

	for(int i=0;i<5;i++)
	{
		str.Format("%dmV",i);
		pDC->TextOut(460*d,255 - i*55,str);
	}
	//return the old font
	pDC->SelectObject(pOldFont);
}

void ECG_DRAW::DrawQRS(CDC *pDC,int d)
{
/*	int i=0;
	CPen lpenR(PS_SOLID,1,RGB(255,0,0));//Select color green
	CPen* pOldpen = pDC->SelectObject(&lpenR);
	pDC->SelectObject(&lpenR);

	pDC->MoveTo(0,127 - int(QRS[0]));
	double y_temp=0;
	for(i=0;i<500;i++)
	{
		for(int j=0;j<4;j++)
		{
			y_temp = y_temp + QRS[i*5+j];
		}
		y_temp = y_temp/4;
		pDC->LineTo(i+1,127 + int(y_temp));
	}
	pDC->SelectObject(pOldpen);
	*/
}

void ECG_DRAW::DrawFromTo(CDC *pDC,int d)
{
	int dx=0;
	if(d==2)
		dx = 65;

	if(i_to>2500)
		i_to=2500;
	int i=0;	
	for(i=i_from;i<i_to;i++)
	{
		pDC->MoveTo(i*d-i_from*d+dx,127*d - int(ECG[i])*d);
		pDC->LineTo(i*d+1-i_from*d+dx,127*d - int(ECG[i+1])*d);
	}
	//
	CPen lpenR(PS_SOLID,1,RGB(255,0,0));//Select color green
	CPen* pOldpen = pDC->SelectObject(&lpenR);
	pDC->SelectObject(&lpenR);
	for(i=i_from;i<i_to;i++)
	{
		pDC->MoveTo(i*d-i_from*d+dx,127*d - int(QRS[i])*d);
		pDC->LineTo(i*d+1-i_from*d+dx,127*d - int(QRS[i+1])*d);
	}
	pDC->SelectObject(pOldpen);
		CFont Font;
	Font.CreateFont(3,3,0,0,FW_DONTCARE,FALSE,FALSE,0,
		DEFAULT_CHARSET,OUT_CHARACTER_PRECIS,
		CLIP_CHARACTER_PRECIS,DEFAULT_QUALITY,
		DEFAULT_PITCH|FF_DONTCARE,
		"MS Sans Serif");
	CFont* pOldFont = pDC->SelectObject(&Font);

	CString str;
	str.Format("segment of ECG record %ds, to %ds    (x=2000ms, y=4mV)",i_from/250,i_to/250);
	if(d==2)
		str = "      " + str;
	pDC->TextOut(1*d,232*d,str);
	pDC->SelectObject(pOldFont);
}

void ECG_DRAW::SaveBMP()
{
		
}

void ECG_DRAW::PrintBMP(CPerson* lpperson)
{
	//Problem with device pDC
	//Do not know how to enlarge the picture
	CPrintDialog dlgPrint(FALSE,PD_ALLPAGES,NULL);
	if(dlgPrint.DoModal()==IDOK)
	{
		CDC dcPrint;
		dcPrint.Attach(dlgPrint.GetPrinterDC());
		DOCINFO PrintJob;
		PrintJob.cbSize = sizeof(PrintJob);
		PrintJob.lpszDocName = "BMP printing";
		PrintJob.lpszOutput = NULL;
		PrintJob.lpszDatatype = NULL;
		PrintJob.fwType = NULL;

		if(dcPrint.StartDoc(&PrintJob)>=0)
		{
			int k=2;
			CRect BmpRect;
			//enlarge width from 500->1000
			BmpRect.SetRect(0,0,500,255);
			dcPrint.StartPage();
			//Draw ECG information
			DrawGrid(&dcPrint,BmpRect,k,RGB(140,140,140));
			DrawEcg(&dcPrint,BmpRect,k);
			DrawQRS(&dcPrint,k);
			DrawFromTo(&dcPrint,k);
			DrawText(&dcPrint,k);
			//print the person information
			DrawPersonalInfo(&dcPrint,65,510,lpperson);
			//print this ecg info
	
			dcPrint.EndPage();
			dcPrint.EndDoc();
		}
		
		dcPrint.DeleteDC();
	}

}

void ECG_DRAW::SetEcgInfo(CString info)
{
	s_BmpInfo = "";
	s_BmpInfo = s_BmpInfo + info;
}

int ECG_DRAW::DrawPersonalInfo(CDC *pDC, int x, int y,CPerson* lpperson)
{
	//Print current time
	COleDateTime curtime;
	curtime = COleDateTime::GetCurrentTime();
	y = y+30;
	pDC->TextOut(x,y,"   Printed date: "+
				curtime.Format("%dd.%mm.%Yy - %Xh"));
	//print the person information
	//Print EGN 
	y = y+60;
	pDC->TextOut(x,y,"                 Personal Info");
	y = y+35;
	pDC->TextOut(x,y,"            EGN: "+lpperson->sEGN);
	//Print birthdate
	y = y+30;
	//Format age etring
	CString sage;
	sage.Format(" - %dy.",curtime.GetYear()-lpperson->Birth_Date.GetYear());
	pDC->TextOut(x,y,"      birthdate: "+lpperson->Birth_Date.Format("%dd.%mm.%Yy")+
		sage);
	//Print name
	y =y+30;
	pDC->TextOut(x,y,"           name: "+lpperson->sName_1+" "+
		lpperson->sName_2+" "+lpperson->sName_3);
	//Print sex
	y = y+30;
	pDC->TextOut(x,y,"            sex: "+lpperson->Sex);
	//Print address
	y = y+30;
	pDC->TextOut(x,y,"        address: "+lpperson->sAddress);
	//Print phone
	y = y+30;
	pDC->TextOut(x,y,"          phone: "+lpperson->sPhone);
	return y;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Systems Engineer
Bulgaria Bulgaria
PhD, Cum Laude in digital automation systems
M.S. in Telemommunication management
B.S. in Telecommunication systems engineering
Programming: CUDA, C/C++, VHDL
Software and Hardware development and consulting:
data acquisition, image processing, medical instrumentation

Comments and Discussions