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

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

我们首先来看一下同一帧视频图像在进行马赛克处理前后的对比效果,如图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;
}
}

二. 组件开发与演示

有了马赛克处理的算法实现,接下去的问题就是,如何来获取连续的视频图像帧数据?在这里我们可以借助于DirectX SDK自带的一个工具软件GraphEdit(即SDK目录下的Bin/DXUtils/graphedt.exe)。运行GraphEdit,如图5:


图5 GraphEdit工具软件

执行菜单命令File | Render Media File…,在随后弹出的对话框中选择一个多媒体文件(比如选定一个含有人像、位置比较固定的MPEG2文件mp2_Sales.mpg),自动构建如图6的链路:


图6 使用GraphEdit构建的播放链路

然后执行菜单命令Graph | Play就可以对mp2_Sales.mpg文件实现播放了。同样执行Graph | Pause或Graph | Stop就可以暂停或停止当前的播放。
值的注意的是,GraphEdit播放mp2_Sales.mpg文件采用的就是DirectShow技术!大家知道,DirectX是微软公司提供的一套在Windows平台上开发高性能图形、声音、输入、输出和网络游戏的编程接口;而DirectShow就是DirectX的一个成员,专门用于音视频数据采集、多媒体文件播放等方面的应用。DirectShow中最基本的功能模块叫做Filter(图6中每个矩形块都代表一个Filter);每个Filter都至少有一个Pin,用于接收数据或者输出数据;Filter总是完成一定的功能(图6中左边第一个Filter是文件源,MPEG-2 Splitter负责将MPEG2数据流中的音频和视频分离,CyberLink Audio Decoder负责将MPEG格式的音频数据解码,HQ MPEG-2 Video Decoder负责将MPEG格式的视频数据解码,Default DirectSound Device负责音频播放,Video Renderer负责视频显示);各种Filter按照一定的顺序串联起来,相互协作;数据在Filter之间沿着箭头的方向流动,直到Default DirectSound Device和Video Renderer。
DirectShow是一个模块化的、开放性的应用框架。我们可以开发自己的Filter组件,然后插入到Filter链路中的某个位置,以获得处理数据流的机会。拿本文需要实现的视频马赛克处理来说,我们完全可以将马赛克处理算法实现在一个Filter中,然后将其连接到视频解码Filter后面,以获取连续的、非压缩的图像帧数据。我们把这个Filter取名为“HQ Video Mosaic”;因为这个Filter可以在输入的图像帧上“就地”修改数据,因此Filter可以采用Trans-In-Place模型;Filter接受16位、24位、32位RGB格式的数据输入。HQ Video Mosaic开发完成后生成Hqmosaic.ax文件(假设放在C:/下),然后使用系统的Regsvr32.exe注册(方法是:执行命令行Regsvr32 C:/Hqmosaic.ax)。(注意:关于DirectShow Filter开发方法更详细的介绍,限于篇幅,笔者在这里就不作展开了;有兴趣的读者可以参考笔者的两本拙作《DirectShow开发指南》和《DirectShow实务精选》。HQ Video Mosaic Filter的源代码请读者到http://hqtech.nease.net下载。)
Filter组件开发完成并且成功注册之后就可以在GraphEdit中使用了。首先还是构建如图6的Filter链路。然后执行菜单命令Graph | Insert Filters…,在随后弹出的对话框中点开“DirectShow Filters”目录,然后找到“HQ Video Mosaic”一项双击将其加入。接着将HQ MPEG-2 Video Decoder与Video Renderer的连接断开(用鼠标选中这两个Filter之间的箭头后按下键盘的Delete键)。然后将HQ MPEG-2 Video Decoder连向HQ Video Mosaic,再将HQ Video Mosaic连向Video Renderer。(两个Filter之间的连接方法:首先在欲连接的上一级Filter的输出Pin上按住鼠标左键不放,拖动鼠标到下一级Filter的输入Pin上,最后放开鼠标左键。)最终的Filter链路如图7:


图7 在GraphEdit中使用渐入渐出Filter

现在,执行菜单命令Graph | Play,我们就可以看到类似图1的视频局部区域马赛克处理的演示了。另外,通过如图8的HQ Video Mosaic Filter的属性页(打开属性页的方法:鼠标选中HQ Video Mosaic,执行右键菜单项“Filter Properties…”),我们还可以动态更新需要进行马赛克处理的区域,以及像素水平/垂直放大的比率。


图8 HQ Video Mosaic Filter的属性页

三. 小结

本文介绍了视频马赛克处理的原理,以及一种使用C++的算法实现。随后借助于DirectShow,本文还完成了视频局部区域马赛克处理的效果演示。

视频局部区域的马赛克处理相关推荐

  1. 苹果自带相册打马赛克_剪映app怎么给视频局部打马赛克

    剪映app怎么给视频局部打马赛克呢?很多用户对此还不是很清楚,小编这里就给大家带来有关剪映app怎么给视频局部打马赛克的回答,希望能够对大家有所帮助. 1.首先打开剪映app,进入首页后点击开始创作选 ...

  2. 如何用Final Cut Pro X给图片局部处理加马赛克?

    想要用Final Cut Pro X给视频中的人和物加马赛克该怎么操作呢?Final Cut Pro X如何局部处理加马赛克,模糊遮挡效果教程分享给大家.其实很简单,这里用到的是Final Cut P ...

  3. EDIUS中的局部区域该怎么进行模糊

    我们常常会在新闻视频中看到视频局部被做成模糊的效果,比如模糊人眼,使其不被认出.那么在EDIUS中,有什么办法可以实现局部区域模糊呢?在这篇文章里,小编要向大家展示EDIUS手绘遮罩特效的强大之处,相 ...

  4. html局部可复制,截取网页局部区域css样式的方法和系统的制作方法

    截取网页局部区域css样式的方法和系统的制作方法 [技术领域] [0001]本发明涉及计算机网络技术领域,特别是涉及一种截取网页局部区域CSS样式的方法和系统. [背景技术] [0002]CSS(Ca ...

  5. 【Opencv系列】之显示图像以及使用鼠标截取图像局部区域进行放大

    序  本文主要介绍通过Opencv显示一副图像,同时又可以使用鼠标左键框选局部区域且放大一倍: 1. 使用IplImage的示例代码 #include <stdio.h> #include ...

  6. php 给视频打水印,如何给视频加表情 给视频局部画面加动态图片或水印

    如何给视频加表情 给视频局部画面加动态图片或水印 /// 如何给视频加贴图(图片或水印) 视频添加贴图软件中的给视频叠加贴图功能,也是我们通常所说的给视频加图片或给视频加水印.同时,它也包括我们在&l ...

  7. 在ANSYS workbench中如何对物体局部区域进行网格细密化

    版权声明:本文为博主原创文章,转载请附源链接. 一.我们需要知道的 在本文内容之前,需要说明的是,我们利用ANSYS workben进行仿真分析时,无论是什么分析,流体分析,模态分析,静力分析等.注意 ...

  8. mars3d-canvans风向图支持自定义绘制局部区域

    场景 在河道范围内根据 udata 和 vdata ,生成流向粒子图.不是矩形范围的局部区域. 问题 1.mars3d-canvans风向图-局部区域 支持自定义绘制局部区域吗? 2.或者有其他方式可 ...

  9. 电脑上怎么消除视频logo,如何马赛克视频内容

    随着科技的快速发展以及快节奏的生活方式,很多人都是通过网络来接收外界的信息,而信息的来源由文字变成了图片或者视频,很少会有人愿意静下心来去阅读文字,图文并茂或者视频是当今的主流,那我们自己在社交平台发 ...

最新文章

  1. 深度学习 常用python操作(1)
  2. android 的webview解析
  3. java 长轮询_java – Spring中的长轮询
  4. 到天宫做客(2017寒假培训测试压轴题)
  5. 重温.NET下Assembly的加载过程
  6. (四)Linux内核模块化编程
  7. Windows 编程[10] - WM_LBUTTONDOWN、WM_LBUTTONUP 和 WM_MOUSEMOVE 消息
  8. 等时替代模型( Isotemporal Substitution Model)
  9. 云计算时代,数据中心运维应该注意哪些问题?
  10. centos7搭建GRE隧道进行通信
  11. 码云上最棒的Java管理后台系统
  12. 如何避免自己发出的邮件被误判为垃圾邮件
  13. 英语四级核心词,记住这些就够了
  14. 图像质量评价数据库与图像质量算法性能评价指标
  15. Three.js的DEM建模【数字高程模型】
  16. 阿里云智能客服机器人,自定义函数调用配置
  17. 一个好用的在线录屏软件
  18. 工控软件装机常规设置
  19. html5小游戏主要用的js,用js+HTML5实现的小游戏-- 捕鱼达人游戏
  20. svg格式文件转换为png图片文件

热门文章

  1. GLSL到HLSL参考
  2. Spring Framework 开发参考手册 之十四 JMS支持
  3. 使用Flexible.js实现手机端网页内容适配(rem适配法)
  4. 【MySQL】navicat for mysql 安装及使用
  5. 把ipad作为window系统电脑的扩展屏
  6. 股票买卖原理_如何在智能手机上买卖股票
  7. MOOS-ivp 实验十四(2)behavior简要概述
  8. 计算机限制打开外接硬盘,在win7中,为什么打开磁盘出现限制提示?
  9. 国标GB/T28181视频流媒体服务器4G摄像头视频无插件直播方案对接过程中前端设备正常上线但视频无法播放问题解决
  10. Kaldi-Timit 训练