[PPTX解析] 图片效果算法篇:柔化边缘

您所在的位置:网站首页 ppt的柔化边缘在哪 [PPTX解析] 图片效果算法篇:柔化边缘

[PPTX解析] 图片效果算法篇:柔化边缘

2024-07-11 06:51:40| 来源: 网络整理| 查看: 265

PPTX解析:柔化边缘

PPT中可以对形状和图片进行柔化边缘操作(如图所示),其本质上可以看为对一个可视化对象的呈现进行视觉处理操作。通过本篇内容,我们将介绍柔化边缘的存储相关,并将说明我们如何实现近似相同的效果(因为使用的算法会导致最终生成的效果会有细微的差别)。在本案例中,将通过对一张图片进行处理,来理解柔化边缘的实现。

image

存储解析

PPT对图片进行柔化边缘这个行为,并不会对原图进行修改,而是通过将修改信息直接存入xml中,并在加载图片时通过计算将效果渲染出来。由于PPT不会存储一张经过该效果处理后的图片,所以第三方应用需要主动获取相关的存储信息,解析后将原图进行修改或通过着色器处理渲染效果。

首先,让我们通过存储节点来看一下PPTX中柔化边缘效果存放在哪一个节点中:

...... ...... ...... 节点名称含义值含义p:pic图片此元素指定文档中的图片对象的存在p:spPr形状属性此元素指定图片对象具有形状属性(没错,PPT中图片和形状共用一部分属性)a:effectLst效果列表存放特殊效果(阴影、发光、柔化边缘等)的列表a:softEdge柔化边缘效果柔化边缘效果,具有属性

该效果节点****的属性如下:

属性名称属性含义值含义补充说明rad效果半径柔化边缘的效果半径英制公制单位(English Metric Unit)。用于对接厘米(“Cm”)和英寸(“Inch”)的虚拟单位。其特殊的数值设计,便于让你在转换百位以内的英寸和毫米、像素长度时,不会产生小数。

注:我们可以根据需要参考下面的代码将英制公制单位的值转为像素值。

/// /// 将英制公制单位 转换为像素值 /// 英制公制单位的值 /// 设备DPI /// public static double ToPixel(double emu, double dpi) { return emu / 914400 * dpi; } 效果实现

下面我们通过两种方式实现柔化边缘的效果。

效果实现(OpenCv)

本方案仅提供OpenCv实现的思想,而不提供代码实现。因为在C#的项目中使用OpenCv的库代价太大了(体积50M+),让人直呼受不了!所以我们将在下面使用C#编写简单的算法代替将要使用到的OpenCv算法。

首先,柔化边缘所要用到的算法基于以下两个点:

图像腐蚀图像模糊

图像的柔化边缘的本质是将图片的Alpha通道进行腐蚀,然后将Alpha通道进行模糊处理。需要注意的一点是需要将超出图像的位置Alpha通道视为透明,并且参与腐蚀运算(可以视为图像的最外圈像素的Alpha值为0)。

因此,我们只需要基于OpenCv的erode()函数将图片的Alpha通道进行3次腐蚀操作,再通过blur()函数将图片的Alpha通道进行3次模糊操作,就能获得和PPT柔化边缘的近似效果。但根据选择的模糊算法,生成的最终效果也会有区别。下面的实现中,我们将通过C#来实现erode()和blur()的效果。

效果实现(C#)

下面我们将通过自己的算法实现腐蚀和模糊操作,进而实现柔化边缘的效果。

需要注意的内容:

如果希望将PPT的效果和以下代码实现的近乎一致,记得将柔化半径进行转换(PPT中使用的是英制公制单位,而下面的案例使用的是像素单位)。在进行效果处理时,建议将图片缩放至真实显示的尺寸再进行处理(例如原图是4K大小,实际显示的是720P的大小,那么我们应该对720P的尺寸进行计算提高运算效率)。 /// /// PPTX柔化边缘效果 /// public class ImageEffect { /// /// 根据原始图片创建带有柔化边缘的图片 /// /// 源图片 /// 柔化半径(单位:像素) /// public Bitmap CreateSoftEdgeBitmap(Bitmap bitmap, float radius) { var cols = bitmap.Width; var rows = bitmap.Height; //克隆一个32位ARgb图片,用于读取Alpha通道 var image = bitmap.Clone(new Rectangle(0, 0, cols, rows), PixelFormat.Format32bppArgb); SetSoftEdgeEffect(image, radius); return image; } /// /// 为原始图片设置柔化边缘的效果 /// /// 源图片(必须是32位带Alpha通道的图片) /// 柔化半径(单位:像素) /// public void SetSoftEdgeEffect(Bitmap source, float radius) { var pixelFormat = source.PixelFormat; if (pixelFormat != PixelFormat.Format32bppArgb) { throw new NotSupportedException($"Unsupported image pixel format {nameof(pixelFormat)} is used."); } //锁定图片并拷贝图片像素 var cols = source.Width; var rows = source.Height; var rect = new Rectangle(0, 0, cols, rows); var channels = System.Drawing.Image.GetPixelFormatSize(PixelFormat.Format32bppArgb) / 8; var total = cols * rows * channels; var data = new byte[total]; var bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat); var iPtr = bitmapData.Scan0; Marshal.Copy(iPtr, data, 0, total); //通过算法设置柔化边缘效果 SetSoftEdgeEffect(data, cols, rows, channels, radius); Marshal.Copy(data, 0, iPtr, total); source.UnlockBits(bitmapData); } /// /// 设置柔化边缘效果 /// /// /// /// /// /// private void SetSoftEdgeEffect(byte[] data, int cols, int rows, int channels, float radius) { //创建并提供Alpha蒙层来进行腐蚀和模糊 var mask = CreateSoftEdgeAlphaMask(data, cols, rows, channels); var offsetX = (int)Math.Round(radius / 4.0); var offsetY = (int)Math.Round(radius / 4.0); var size = new Size(offsetX, offsetY); //腐蚀操作 mask = AlphaErode(mask, size, 3); //模糊操作 mask = AlphaBlur(mask, size, 3); //应用Alpha蒙层数据 ApplySoftEdgeAlphaMask(data, mask, cols, rows, channels); } /// /// 创建Alpha通道蒙层数据 /// /// 图像原始数据 /// 图像宽度 /// 图像高度 /// 图像通道数 /// private byte[,] CreateSoftEdgeAlphaMask(byte[] data, int cols, int rows, int channels) { //根据宽高设置一个蒙层数组 var masks = new byte[cols, rows]; //需要考虑大小端 var isLittleEndian = BitConverter.IsLittleEndian; for (var row = 0; row < rows; row++) { for (var col = 0; col < cols; col++) { var indexOffset = (row * cols + col) * channels; var alpha = isLittleEndian ? data[indexOffset + 3] : data[indexOffset + 0]; masks[col, row] = alpha == 0 ? (byte)0 : byte.MaxValue; } } return masks; } /// /// 应用Alpha通道蒙层数据 /// /// 图像原始数据 /// 图像Alpha蒙层 /// 图像宽度 /// 图像高度 /// 图像通道数 /// private void ApplySoftEdgeAlphaMask(byte[] data, byte[,] mask, int cols, int rows, int channels) { //需要考虑大小端 var isLittleEndian = BitConverter.IsLittleEndian; for (var row = 0; row < rows; row++) { for (var col = 0; col < cols; col++) { var indexOffset = (row * cols + col) * channels; var index = isLittleEndian ? indexOffset + 3 : indexOffset; //根据蒙层设置Alpha var alpha = (byte)(mask[col, row] / 255.0d * data[index]); data[index] = alpha; } } } /// /// 对Alpha蒙层进行腐蚀操作 /// /// 输入蒙层数据 /// 腐蚀操作卷积核大小 /// 连续腐蚀次数 /// 输出蒙层数据 private byte[,] AlphaErode(byte[,] sourceMask, Size size, uint iteration) { var offsetX = size.Width; var offsetY = size.Height; var cols = sourceMask.GetLength(0); var rows = sourceMask.GetLength(1); var erodeMask = new byte[cols, rows]; for (var i = 0; i < iteration; i++) { var target = new byte[cols, rows]; var mask = sourceMask; //下面的卷积操作会尽可能减少不必要的运算过程 Parallel.For(offsetY, rows - offsetY, row => { var isNeedInitialize = true; var blackPointCols = new List(); for (var col = offsetX; col < cols - offsetX; col++) { var minCol = col - offsetX; var maxCol = col + offsetX; var minRow = row - offsetY; var maxRow = row + offsetY; if (isNeedInitialize) { for (var x = minCol; x 0 && y < rows) { value += mask[x, y]; } } } valueCache.Add(x, value); } isNeedInitialize = false; } else { var value = 0; valueCache.Remove(minCol - 1); if (maxCol > 0 && maxCol < cols) { for (var y = minRow; y < maxRow; y++) { if (y > 0 && y < rows) { value += mask[maxCol, y]; } } } valueCache.Add(maxCol, value); } var targetValue = valueCache.Values.Sum() / (double)count; target[col, row] = (byte)Math.Round(targetValue); } }); sourceMask = target; blurMask = target; } return blurMask; } } 实现的效果

file

GitHub项目仓库

如果希望参考完整案例,请参考下面的项目: 柔化边缘案例

附加

如果您有更好的方案欢迎留言分享!

我的博客会首发于 个人博客-仙尘阁,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 晓嗔戈 (包含链接: https://imxcg.blog.csdn.net/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 。



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭