PDA

View Full Version : Simple Deinterlacing



Stefan Geissler
October 6, 2003, 11:41:06
Hello,

Here comes a sample code for a simple image deinterlacing. The trick is to copy the even lines of a frame to a buffer first at the even and the next odd line Then the buffer is displayed in the video window. In the next step the odd lines are copied to the odd and next even line of the buffer and the buffer is displayed again. This results in two times display of the same frame, that is delivered from the frame grabber. Because of the double use of SetDIBitsToDevice(), the video seems to flicker at fast movements. In this case, only the even or the odd field should be copied and displayed.

The algorithm is implemented in a class named CListener. This class is inherited from CGrabberListener.

The header of Clistener looks as follows:


class CListener : public GrabberListener
{
public:
void SetViewCWnd( CWnd *pView);
CListener();
virtual ~CListener();
virtual void deviceLost( Grabber& param);
void SetParent(CWnd* pParent);
virtual void frameReady( Grabber& param, smart_ptr<MemBuffer> pBuffer, DWORD FrameNumber);

protected:
CWnd* m_pParent;
CWnd* m_pDrawCWnd;
void DrawBuffer( smart_ptr<MemBuffer> pBuffer);
void DoDeInterlace( smart_ptr<MemBuffer> pBuffer);
HBITMAP m_hbmBuffer; // Bitmap of the resulting image
CDC m_cBufferDC; // DC for the buffer bitmap
BYTE* m_pData; // pointer to the image data of the buffer image.

};


The deinterlacing is done as follows:


//////////////////////////////////////////////////////////////////////////
/*! Here do the DeInterlace
*/
void CListener::DoDeInterlace( smart_ptr<MemBuffer> pBuffer)
{
smart_ptr<BITMAPINFOHEADER> pInf = pBuffer->getBitmapInfoHeader();
int iBpP = pInf->biBitCount / 8; // Bytes per Pixel
BYTE *pBuf = pBuffer->getPtr(); // Pointer to the image data of the source image
int ibWidth = pInf->biWidth*iBpP; // Width in bytes of a scanline.
int iLine, iPos;

if( m_hbmBuffer == NULL)
{
// Create the buffer bitmap, if not already done.
BITMAPINFO bi;
ZeroMemory(&bi,sizeof( BITMAPINFO));
memcpy( &bi.bmiHeader, pInf.get(), sizeof(BITMAPINFOHEADER ));
bi.bmiHeader.biHeight = pInf->biWidth;
bi.bmiHeader.biWidth = pInf->biHeight;


m_hbmBuffer = CreateDIBSection(m_cBufferDC, &bi, DIB_RGB_COLORS,(void**)&m_pData,NULL,0);
}

// This is a simple and fast way. It copies the even source scan lines to the even
// and odd line of the destination bitmap.
for( iLine = 0; iLine < pInf->biHeight; iLine += 2)
{
iPos = iLine*ibWidth;
// copy even line to the even line in the buffer bitmap
memcpy( &(m_pData[iPos]), &(pBuf[iPos]), ibWidth);

// copy odd line to the even line in the buffer bitmap
memcpy( &(m_pData[(iLine+1)*ibWidth]), &(pBuf[iPos]), ibWidth);
}

DrawBuffer( pBuffer);
Sleep(5); // Sleep some milliseconds to slow down the frame rate between odd and even
// image.

// Now draw the second field
for( iLine = 1; iLine < pInf->biHeight-1; iLine += 2)
{
iPos = iLine*ibWidth;
// copy even line to the even line in the buffer bitmap
memcpy( &(m_pData[iPos]), &(pBuf[iPos]), ibWidth);

// copy odd line to the even line in the buffer bitmap
memcpy( &(m_pData[(iLine+1)*ibWidth]), &(pBuf[iPos]), ibWidth);
}
DrawBuffer( pBuffer);

}

The display of the image buffer is done as follows:
//////////////////////////////////////////////////////////////////////////
/*! Draw the image buffer into the DrawCWnd.
*/
void CListener::DrawBuffer( smart_ptr<MemBuffer> pBuffer)
{
if( m_pDrawCWnd != NULL)
{
if( pBuffer != 0 )
{
CDC *pDC = m_pDrawCWnd->GetDC();

smart_ptr<BITMAPINFOHEADER> pInf = pBuffer->getBitmapInfoHeader();

void* pBuf = pBuffer->getPtr();

int nLines = SetDIBitsToDevice(
pDC->GetSafeHdc(),// Handle to the device
0,
0,
pInf->biWidth, // Source rectangle width
pInf->biHeight, // Source rectangle height
0, // X-coordinate of lower-left corner of the source rect
0, // Y-coordinate of lower-left corner of the source rect
0, // First scan line in array
pInf->biHeight, // Number of scan lines
m_pData, // Modified address of array with DIB bits
reinterpret_cast<LPBITMAPINFO>( &*pInf ), // Address of structure with bitmap info
DIB_RGB_COLORS // RGB or palette indices
);
m_pDrawCWnd->ReleaseDC(pDC);
}
}
}


A complete VC++ 6.0 sample is attached to this entry

Stefan Geissler
October 6, 2003, 12:45:52
The following method interpolates the lines between two lines of a field:


void CListener::DoDeInterlaceInterpolate( smart_ptr<MemBuffer> pBuffer)
{
smart_ptr<BITMAPINFOHEADER> pInf = pBuffer->getBitmapInfoHeader();
int iBpP = pInf->biBitCount / 8; // Bytes per Pixel
BYTE *pBuf = pBuffer->getPtr(); // Pointer to the image data of the source image
int ibWidth = pInf->biWidth*iBpP; // Width in bytes of a scanline.
int iLine, iCol, iPos;
int iDestIndex, iNextLineIndex;

if( m_hbmBuffer == NULL)
{
// Create the buffer bitmap, if not already done.
BITMAPINFO bi;
ZeroMemory(&bi,sizeof( BITMAPINFO));
memcpy( &bi.bmiHeader, pInf.get(), sizeof(BITMAPINFOHEADER ));
bi.bmiHeader.biHeight = pInf->biWidth;
bi.bmiHeader.biWidth = pInf->biHeight;


m_hbmBuffer = CreateDIBSection(m_cBufferDC, &bi, DIB_RGB_COLORS,(void**)&m_pData,NULL,0);
}

for( iLine = 0; iLine < pInf->biHeight; iLine += 2)
{
iPos = iLine*ibWidth;
// copy even line to the even line in the buffer bitmap
memcpy( &(m_pData[iPos]), &(pBuf[iPos]), ibWidth);
iDestIndex = (iLine+1)*ibWidth;
iNextLineIndex = (iLine+2)*ibWidth;

for( iCol = 0; iCol < ibWidth; iCol++)
{
m_pData[iDestIndex] = (pBuf[iPos + iCol] + pBuf[iNextLineIndex]) >> 1;
iDestIndex++;
iNextLineIndex++;
}
}

DrawBuffer( pBuffer);

Sleep(2); // Sleep some milliseconds to slow down the frame rate between odd and even
// image.

// Now draw the second field
for( iLine = 1; iLine < pInf->biHeight-1; iLine += 2)
{
iPos = iLine*ibWidth;
// copy even line to the even line in the buffer bitmap
memcpy( &(m_pData[iPos]), &(pBuf[iPos]), ibWidth);

iDestIndex = (iLine+1)*ibWidth;
iNextLineIndex = (iLine+2)*ibWidth;

for( iCol = 0; iCol < ibWidth; iCol++)
{
m_pData[iDestIndex] = (pBuf[iPos + iCol] + pBuf[iNextLineIndex]) >> 1;
iDestIndex++;
iNextLineIndex++;
}
}
DrawBuffer( pBuffer);

}