VC语言

本类阅读TOP10

·VC++下使用ADO编写数据库程序
·VC++ 学习笔记(二)
·Windows消息大全
·每个开发人员现在应该下载的十种必备工具
·在2000和xp下,隐藏进程,VC6.0测试通过!!!
·用Visual C++打造IE浏览器(1)
·Netmsg 局域网聊天程序
·教你用VC6做QQ对对碰外挂程序
·VC++学习笔记(四)
·VC++中经常使用的函数!~~

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
轻松实现视频渐入渐出

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

陆其明 2004-08-18

 http://hqtech.nease.net/Article/DS_VideoTransition.htm

 

在一段主题视频内容的开始部分或者结束部分加入渐变特效,是当今很多影视片制作的惯用手法。这种特效处理,带给观众的将是更自然、更舒适的视觉享受。作为程序员,你想过如何来实现这种特效吗?本文介绍的就是一种实现视频渐入渐出的简单易行的编程方法。

 

一.        渐入渐出算法与实现

 

本文将介绍一种类似于时针扫描的渐入渐出效果。首先,我们来描述一下时针扫描的运动过程。

 

1 时针扫描过程

 

如图1,直线L1保持不动,直线L2以恒定的速率逆时针转动。L1L2将视频图像帧分成两个区域:扇形区域1和扇形区域2。随着L2的旋转,扇形区域1的面积越来越大,扇形区域2的面积越来越小;直到L2旋转360度,最终与L1重合。如果是视频渐入,扇形区域1显示的就是主题视频内容,扇形区域2显示的就是背景色;总体的效果是:从一开始整幅的背景色,逐渐过渡到主题视频内容。如果是视频渐出,扇形区域1显示的就是背景色,扇形区域2显示的就是主题视频内容;总体的效果是:正在播放的主题视频内容上被一点一点覆盖上背景色,直至背景色占据整个图像帧范围(表示主题视频内容播放完毕)。

下面,笔者将给出上述这个渐入渐出过程的C++实现。为了方便起见,我们将一幅图像分成如图24个区域。

 

2 时针扫描图像帧的区域划分

 

当视频渐入时,随着直线L2的旋转,它会依次落在第1区域、第2区域、第3区域和第4区域。当L2位于第1区域,第23 4区域应该完全填上背景色,还有第1区域内L2上面的部分(通过计算L2的斜率来判断)也要填上背景色(第1区域内剩余的部分自然是显示主题视频内容);当L2位于第2区域,第3 4区域应该完全填上背景色,另加第2区域内L2下面的部分;当L2位于第3区域,第 4区域应该完全填上背景色,另加第3区域内L2下面的部分;当L2位于第4区域,仅第4区域内L2上面的部分填上背景色。整个视频渐入过程如图3。(注:黑色为背景色,白色区域显示主题视频内容。)

 

3 L2分别落在4个区域的情况(视频渐入)

 

视频渐入的C++实现

// 图像帧数据(注意:图像数据是以从下往上、从左往右的顺序存储的!)

unsigned char * pData;

unsigned char * m_pPixel;      // 像素指针

unsigned char * m_pSubLine; // 行指针

// m_nWidthm_nHeight为图像的宽度和高度(以像素为单位)

// m_nOriginalX m_nOriginalY为所分区域的宽度和高度

int m_nOriginalX  = m_nWidth / 2;

int m_nOriginalY  = m_nHeight / 2;

//……

 

// 假设整个运动过程在36个视频帧的时间内完成,

// L2每次步进的角度m_dStepAngle10

double m_dStepAngle = 360. / 36.;

// m_lProgress表示运动的进度,每次递增1,取值范围0~36

// Alpha表示L1L2当前形成的角度,如图1所示

double  Alpha = m_lProgress * m_dStepAngle;

// m_dSlope表示L2的斜率

const double m_pi = 3.1415926535

double m_dSlope = fabs(tan(Alpha * m_pi / 180.));

// m_pxlConverter为一个自定义的像素转化器,

// GetPixelSize()函数返回每个像素使用的字节数

// 计算图像帧的宽度(以字节为单位)

int m_nLineBytes = m_nWidth * m_pxlConverter->GetPixelSize();

 

if (Alpha < 90)        // L2位于第1区域

{

                // 2区域应该填上背景色

                DrawSecondRegion(pData);

// 34区域应该填上背景色

                DrawBelowHalf(pData);

                // 1区域的一部分应该填上背景色

                // 扫描图像帧第1区域中的各个像素                           

                for (int y = m_nOriginalY; y < m_nHeight; y++)

                {

                                for (int x = m_nOriginalX; x < m_nWidth; x++)

                                {

                                                // 将图像帧第1区域中L2上面的像素替换为背景色

                                                if ((y - m_nOriginalY) >= m_dSlope * (x - m_nOriginalX))

                                                {

                                                                // 定位到(x,y)表示的像素

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                // 将(x,y)位置的像素替换为背景色

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 90 && Alpha < 180)   // L2位于第2区域

{

                // 34区域应该填上背景色

                DrawBelowHalf(pData);

                // 2区域的一部分应该填上背景色

                for (int y = m_nOriginalY; y < m_nHeight; y++)

                {

                                for (int x = 0; x < m_nOriginalX; x++)

                                {

                                                // 将图像帧第2区域中L2下面的像素替换为背景色

                                                if ((y - m_nOriginalY) <= m_dSlope * (m_nOriginalX - x))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 180 && Alpha < 270)   // L2位于第3区域

{

                // 4区域应该填上背景色

                DrawFourthRegion(pData);

                // 3区域的一部分应该填上背景色

                for (int y = 0; y < m_nOriginalY; y++)

                {

                                for (int x = 0; x < m_nOriginalX; x++)

                                {

                                                // 将图像帧第3区域中L2下面的像素替换为背景色

                                                if ((m_nOriginalY - y) >= m_dSlope * (m_nOriginalX - x))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 270 && Alpha < 360)   // L2位于第4区域

{

                // 4区域的一部分应该填上背景色

                for (int y = 0; y < m_nOriginalY; y++)

                {

                                for (int x = m_nOriginalX; x < m_nWidth; x++)

                                {

                                                // 将图像帧第4区域中L2上面的像素替换为背景色

                                                if ((m_nOriginalY - y) <= m_dSlope * (x - m_nOriginalX))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

m_lProgress++;

 

当视频渐出时,随着直线L2的旋转,它同样会依次落在第1234区域。当L2位于第1区域,仅第1区域内L2下面的部分填上背景色;当L2位于第2区域,第1区域应该完全填上背景色,另加第2区域内L2上面的部分;当L2位于第3区域,第12区域应该完全填上背景色,另加第3区域内L2上面的部分;当L2位于第4区域,第123区域应该完全填上背景色,另加第4区域内L2下面的部分。整个视频渐出过程如图4。(注:黑色为背景色,白色区域显示主题视频内容。)

 

4 L2分别落在4个区域的情况(视频渐出)

 

视频渐出的C++实现

if (Alpha < 90)        // L2位于第1区域

{

                // 1区域的一部分应该填上背景色           

                for (int y = m_nOriginalY; y < m_nHeight; y++)

                {

                                for (int x = m_nOriginalX; x < m_nWidth; x++)

                                {

                                                // 将图像帧第1区域中L2下面的像素替换为背景色

                                                if ((y - m_nOriginalY) <= m_dSlope * (x - m_nOriginalX))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 90 && Alpha < 180)   // L2位于第2区域

{

                // 1区域应该填上背景色

                DrawFirstRegion(pData);

                // 2区域的一部分应该填上背景色

                for (int y = m_nOriginalY; y < m_nHeight; y++)

                {

                                for (int x = 0; x < m_nOriginalX; x++)

                                {

                                                // 将图像帧第2区域中L2上面的像素替换为背景色

                                                if ((y - m_nOriginalY) >= m_dSlope * (m_nOriginalX - x))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 180 && Alpha < 270)  // L2位于第3区域

{

                // 12区域应该填上背景色

                DrawAboveHalf(pData);

                // 3区域的一部分应该填上背景色

                for (int y = 0; y < m_nOriginalY; y++)

                {

                                for (int x = 0; x < m_nOriginalX; x++)

                                {

                                                // 将图像帧第3区域中L2上面的像素替换为背景色

                                                if ((m_nOriginalY - y) <= m_dSlope * (m_nOriginalX - x))

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 270 && Alpha < 360)  // L2位于第4区域

{

                // 12区域应该填上背景色

                DrawAboveHalf(pData);

// 3区域应该填上背景色

                DrawThirdRegion(pData);

                // 4区域的一部分应该填上背景色

                for (int y = 0; y < m_nOriginalY; y++)

                {

                                for (int x = m_nOriginalX; x < m_nWidth; x++)

                                {

                                                // 将图像帧第4区域中L2下面的像素替换为背景色

                                                if ((m_nOriginalY - y) >= m_dSlope * (x - m_nOriginalX)) // Below the line...

                                                {

                                                                m_pPixel  = pData + y * m_nLineBytes;

                                                                m_pPixel += x * m_pxlConverter->GetPixelSize();

                                                                m_pxlConverter->Convert(m_pPixel);

                                                }

                                }

                }

}

else if (Alpha >= 360) // L2L1重合之后

{

                // 将整个图像帧都填上背景色

                m_pSubLine = pData;

                for (int y = 0; y < m_nHeight; y++)

                {

                                m_pPixel = m_pSubLine;

                                for (int x = 0; x < m_nWidth; x++)

                                {

                                                // 将当前像素替换为背景色

                                                m_pxlConverter->Convert(m_pPixel);

                             &n