工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > 开发专栏 > VC > 正文
用DirectShow实现视频马赛克处理
[文章信息]
作者:陆其明
时间:2004-10-28
出处:hqtech.nease.net
责任编辑:方舟
[文章导读]
本文介绍的就是一种实现视频局部区域马赛克处理的简单易行的编程方法
advertisement
热点推荐
· 真没想到VB也可以这样用之指针技术
· 禁止QQ登录的方法
· 给你的XML文件做个数字签名
· ImageReady制作“焰火”小动画
· Java加密和数字签名编程快速入门
[正文]

1 2  下一页

  在电视采访中,有时候一些采访对象不愿意抛头露面。这种情况下,被采访者可能会背对摄像镜头;但更通常的做法是,被采访者仍然面对镜头,而在电视节目播出时对采访对象的面部进行马赛克处理。这种马赛克处理,使观众无法看清被采访者的真实面目,从而满足被采访者不愿抛头露面的初衷。作为程序员,你想过如何来实现这种效果处理吗?本文介绍的就是一种实现视频局部区域马赛克处理的简单易行的编程方法。

  一. 马赛克处理原理及其实现

  我们首先来看一下同一帧视频图像在进行马赛克处理前后的对比效果,如图1。



图1 对人像面部进行马赛克处理前后的效果对比

  经过马赛克处理后,你无法识别她的真实面目了吧?那么,怎么会出现马赛克效果的呢?大家知道,图像是由像素组成的;像素颗粒的大小决定了图像表现的精度(这就是为什么小尺寸的电视机比大尺寸的电视机看起来更清楚的原因)。如果我们把指定区域的像素进行放大,不就出现马赛克效果了吗?别急,这里有个关键问题:对于给定的一种显示设备,其像素颗粒大小是物理不可变的,怎么进行放大呢?!

  有办法:使用相邻的几个像素同时表现为同一个像素值,不就等于将像素放大了吗?只是如果我们把指定区域中的每一个像素都进行这样的放大处理后,马赛克区域将超出用户最初指定的区域(如果用户指定区域的宽度为w,像素水平放大的比率为ratiox,则这种马赛克处理后的区域宽度将覆盖w x ratiox)。如何将马赛克处理后的区域仍然限定在用户指定的区域内呢?笔者的做法是,对指定区域内的像素进行一次亚采样。如图2,假设我们将对图像中的R1区域进行马赛克处理。


图2 需要进行马赛克处理的区域

  假设R1区域的像素排列如图3:


图3 R1区域的像素示意图

  再假设像素的水平放大比率(ratiox)为3,垂直放大比率(ratioy)也为3,则经过马赛克处理后各对应位置像素值分布如图4:


图4 R1区域经过马赛克处理后的像素示意图

  我们看到在R1区域内,水平方向上每3个像素采样1次(P00、P03、P06、P09、P30、P33、P36、P39、P60、P63、P66、P69等都是采样点),垂直方向上每个采样像素行都重复3次(第2、3行复制第1行的内容,第5、6行复制第4行的内容,以此类推);每个采样点像素都被放大到一个3 x 3的宏块,也就是说,采样点像素被放大了9倍。

  图像指定区域马赛克处理的C++实现

// 图像帧数据指针
PBYTE pImage;
// 获取图像数据
// …
// 指向图像第1行开头的指针
PBYTE pImageTopLine = NULL;
// 图像的跨度(以字节为单位)
long imageStride = 0;
// 如果图像数据是以从下往上的扫描顺序存储的,
// 则图像的第1行应该在pImage数据的倒数第1行;
// 如果图像数据是以从上往下的扫描顺序存储的,
// 则图像的第1行就是pImage指的位置
if (m_bIsBottomUp)
{
 imageStride = -m_nImageStride;
 pImageTopLine = pImage + m_nImageStride * (m_nImageHeight - 1);
}
else
{
 imageStride = m_nImageStride;
 pImageTopLine = pImage;
}

// ratioX是水平方向上像素的放大倍数
// ratioY是垂直方向上像素的放大倍数
// maskStride为进行马赛克处理的区域的宽度(以字节为单位)
/* macroWidth和macorHeight有如下计算关系:
RECT m_MaskRect; // 需要进行马赛克处理的矩形区域(由用户指定)
int maskWidth = m_MaskRect.right - m_MaskRect.left + 1;
int maskHeight = m_MaskRect.bottom - m_MaskRect.top + 1;
macroWidth = maskWidth / m_nRatioX;
macroHeight = maskHeight / m_nRatioY;
*/
int macroWidth, macroHeight, maskStride, ratioX, ratioY;
// 马赛克处理过程中:
// pMaskPixel 指向当前像素,
// pMaskLine指向当前行,
// pMaskNextLine下一行
PBYTE pMaskTopLine, pMaskLine, pMaskNextLine, pMaskPixel;
// pMaskTopLine指向需要进行马赛克处理的区域的第1行
// 注:m_nPixelBytes为单个像素占用的字节数
pMaskTopLine = pImageTopLine + m_MaskRect.top * imageStride + m_MaskRect.left * m_nPixelBytes;
macroWidth = m_nMacroWidth;
macroHeight = m_nMacroHeight;
maskStride = m_nMaskStride;
ratioX = m_nRatioX;
ratioY = m_nRatioY;

// 扫描指定区域的像素,进行马赛克处理…
int cycle = 0;
for (int i = 0; i < macroHeight; i++)
{
 // 定位需要进行马赛克处理的当前行
 pMaskLine = pMaskTopLine + i * ratioY * imageStride;
 // 定位需要进行马赛克处理的当前像素
 pMaskPixel = pMaskLine;
 for (int j = 0; j < macroWidth; j++)
 {
  // 水平方向上进行像素放大
  for (cycle = 0; cycle < ratioX - 1; cycle++)
  {
   // 将当前像素值复制给右边的下一个像素
   memcpy(pMaskPixel+m_nPixelBytes, pMaskPixel, m_nPixelBytes);
   // 指向下一个像素
   pMaskPixel += m_nPixelBytes;
  }
  // 指向下一个采样像素
  pMaskPixel += m_nPixelBytes;
 }

 // 垂直方向上进行像素放大
 for (cycle = 0; cycle < ratioY - 1; cycle++)
 {
  // 获得马赛克处理区域的下一行指针
  pMaskNextLine = pMaskLine + imageStride;
  // 将马赛克处理区域的当前行(已经完成马赛克处理)复制给下一行
  memcpy(pMaskNextLine, pMaskLine, maskStride);
  // 修改当前行指针,指向下一行
  pMaskLine = pMaskNextLine;
 }
}


1 2  下一页

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • VC+Delphi编程实现英文文章语音输出
  • 在VC++中使用OpenGL绘制典型曲面
  • VC下动态数据交换技术之执行远程命令
  • VC下动态数据交换技术之永久数据链路
  • 向ATL的DLL中传递C++对象参数
  • 民营家电商排队造手机 设备商全面杀入
  • 英特尔澄清杨旭任职传闻 官方没宣布此消息
  • 国资委河北密制联通拆分方案
  • 垃圾邮件害人害企害国 清除垃圾邮件不手软
  • 中兴携手阿尔卡特 全球逐鹿CDMA
  • 用友总裁王文京:誓将ERP变成“大众消费”
  • 香港消费者委员会:数码相机最贵未必最好
  • 外电称中兴正评估西门子手机业务 或能并购
  • Advertisement

    天极无线


    奇妙科幻|美好风光|清风车影|漫画卡通|星座生肖|明星写真|动物世界
    老鼠爱大米
    挥着翅膀的女孩
    女人味
    栀子花开
    白月光
    刚刚好
    江南
    快乐崇拜
    亲爱的你怎么不在我身边
    小薇
    2002年的第一场雪
    有多少爱可以重来
    我的地盘
    七里香
    情人
     
    老鼠爱大米 老板电话
    冲动的惩罚 七里香
    我不是黄蓉 女生撒娇
    盛夏的果实 坚持到底
    孤单北半球 眉飞色舞
    挪威的森林 可爱女人
    最浪漫的事 老板电话

    CSEEK搜索