c#实现SharedMatting抠图算法
内容简介
将Alpha Matting抠图算法由c++ 版本移植至c#环境。 主要采用OpenCV的C#版本Emgu取代c++支撑的OpenCV。
参考资料
http://www.inf.ufrgs.br/~eslgastal/SharedMatting/
这个网页是算法的论文介绍页,可以从该网页下载到论文原文以及测试用图以及linux下的Demo。
https://github.com/np-csu/AlphaMatting
我从该网页下载了Alpha Matting算法的c++源码。
https://www.cnblogs.com/Imageshop/p/3550185.html
这是我在查询Alpha Matting算法资料时看见的比较友善的算法介绍。作者优化了C++版的算法。
我的实现效果
实验环境
系统: Windows 8.1 专业版
工具:Visual Studio 2017
Emgu:emgucv-windesktop 3.2.0.2682
C#测试工程: WPF工程项目
避免采坑
- 最好不要用最新版Vs2019
我刚开始采用VS2019,安装OpenCv后测试运行C++,各种不通。后续发现vs2019新建的项目自动配置为VC16 环境。 而下载的OpenCv明确指定了需要VC14或VC15. 如我下载的OpenCV: opencv-3.4.5-vc14_vc15.exe. 从名称即可看出。废了我许多不必要的尝试时间。
2、版本差异
刚开始下载OpenCV 最新的4.1.1 版本,报了很多类型错误。 建议使用3.* 的版本。 4.1.1版本我注释掉了部分OpenCv的代码,算法可以继续无差运行,但总感觉不完美,所以我替换成了3.* 的版本。
关键信息
C++类型 |
我处理成的对应c#类型 |
cv::Point |
System.Drawing.Point |
vector<cv::Point>& |
List<System.Drawing.Point> |
vector<vector<cv::Point>>& |
List<List<System.Drawing.Point>> |
char* |
string |
struct labelPoint |
public class labelPoint |
Tuple |
public class TupleInfo |
Ftuple |
public class FtupleInfo |
int** |
Int[,] |
uchar* |
Byte[] |
iterator |
更改为For循环 |
Scalar |
Emgu: MCvScalar |
public class labelPoint
{
public int x;
public int y;
public int label;
}; public class TupleInfo
{
public double FR;
public double FG;
public double FB; public double BR;
public double BG;
public double BB; public double sigmaf;
public double sigmab;
public int flag;
}; public class FtupleInfo
{
public double FR;
public double FG;
public double FB; public double BR;
public double BG;
public double BB; public double alphar;
public double confidence;
}; public void loadImage(string sFile)
{
pImg = CvInvoke.Imread(sFile);
if (pImg.GetData() == null || pImg.GetData().Length == )
{
Console.WriteLine("load pImg failed!");
return;
} height = pImg.Rows;
width = pImg.Cols;
step = pImg.Step / (pImg.ElementSize / pImg.NumberOfChannels);
channels = pImg.NumberOfChannels;
data = pImg.GetData();
unknownIndex = new int[height, width];
tri = new int[height, width];
alpha = new int[height, width];
}
有了这些对应信息,你就可以尝试自己移植了。
深化尝试
从我的调试结果来看,可以实现抠图,如果你也同时在C++环境下运行了算法,你会发现C#环境下的算法运行时间远超C++。然后我就考虑将抠图算法在C++环境下打包成dll供C#调用。
由于不熟悉c#与C++的交互,我踩了很多坑,实现的也并不算完美,不过总之调通了。
我将提前准备好的原图以及Trimap图的路径传给C++的dll,期望返回处理过后的Alpha数组。
c#端:
首先添加我生成的C++ Dll并声明引用。
[DllImport("ImgIntelligHelper.dll", CharSet = CharSet.Unicode)]
public extern static IntPtr GetMatteMap([MarshalAs(UnmanagedType.LPStr)] string sInput,
[MarshalAs(UnmanagedType.LPStr)] string sOutput);
然后对dll中的函数进行调用,返回透明度矩阵的内存地址,然后赋值到我创建的数组中。
// sInput - 原图路径; sTrimap: Trimap图路径
System.Drawing.Bitmap oBitmap = new Bitmap(sInput);
int nlength = oBitmap.Width * oBitmap.Height;
IntPtr intptr = GetMatteMap(sInput, sTrimap);
int[] arrAlpha = new int[nlength];
Marshal.Copy(intptr, arrAlpha, , nlength);
C++端:
新增了一个方法,将矩阵转换为int数组。
void AlphaMatting::GetAlphaMap()
{
int h = matte.rows;
int w = matte.cols;
Map = new int[h*w];
for (int i = ; i < h; ++i)
{
for (int j = ; j < w; ++j)
{
Map[i * w + j] = alpha[i][j];
}
};
} // 接收图片并处理
int* GetMatteMap(char* sInput, char* sTrimap)
{
AlphaMatting alphaMatHelper;
alphaMatHelper.loadImage(sInput);
alphaMatHelper.loadTrimap(sTrimap);
alphaMatHelper.solveAlpha();
alphaMatHelper.GetAlphaMap();
return alphaMatHelper.Map;
}
最后用原图以及dll返回的Alpha数组实现抠图。 这是可行的方式,整个流程进行下来效率相对于纯C#版会有较大的改进。但是相对于纯C++版本来说,消耗还是过高。
然后我又尝试将C++版算法改成控制台应用程序。在C#中采用启动进程的方式,传入原图、Trimap图、输出图路径值,然后以不显示应用程序窗口的方式在后台静默执行。 进程结束后见到了C++应用程序处理过后的结果。
C#中调用C++生成的控制台应用exe。
private void DoConvert(string sIndex)
{
string sBasePath = AppDomain.CurrentDomain.BaseDirectory;
string sExeFile = sBasePath + @"\AlphaMattingPlugin.exe";
string sInput = sBasePath + @"\Datas\input" + sIndex+ ".jpg";
string sTrimap = sBasePath + @"\Datas\trimap" + sIndex + ".jpg";
string sOutput = sBasePath + @"\Datas\AlphaMattingPluginSample" + sIndex + ".png"; Process process = new Process();
process.StartInfo.FileName = sExeFile;
// 调用C++版本的控制台Exe,传入原图、Trimap图、抠图结果输出文件路径
process.StartInfo.Arguments = " " + sInput + " " + sTrimap + " " + sOutput;
process.StartInfo.CreateNoWindow = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
process.WaitForExit(); if (File.Exists(sOutput))
this.ShowImage(this.ImgResult, sOutput);
} private void ShowImage(Image img, string sFile)
{
byte[] bytes = System.IO.File.ReadAllBytes(sFile);
BitmapImage bitImg = new BitmapImage();
bitImg.BeginInit();
bitImg.StreamSource = new System.IO.MemoryStream(bytes);
bitImg.EndInit();
bitImg.Freeze();
img.Source = bitImg;
}
这样处理后比纯C++环境多耗时0.5s左右,这个结论对于我是能接受的。
采用这种方式,抠图算法执行时间消耗我进行了测试,如下图
原来需要10-20s的现在仅用1-3s就能实现。如下图在C#环境下WPF工程调用C++版exe的调试截图:
结论
Alpha Matting抠图算法可以移植至C#平台,但是最佳实践还是用C++去处理,采用C#调用C++的方式会大大节省耗时。
图片越大耗时会越高,目前我尚未尝试4K图。
原本还想将Global Matting 及其他几种抠图算法也想法移植到C#平台,但是经过上文中一些列测试,发现还是保留原版本更为合理,用C#直接去调用Dll 或 包装的exe应用即可,而且效率更高。
源码下载:微信扫描下方二维码文章末尾获取链接。
c#实现SharedMatting抠图算法的更多相关文章
- 图像抠图算法学习 - Shared Sampling for Real-Time Alpha Matting
一.序言 陆陆续续的如果累计起来,我估计至少有二十来位左右的朋友加我QQ,向我咨询有关抠图方面的算法,可惜的是,我对这方面之前一直是没有研究过的.除了利用和Photoshop中的魔棒一样的技术或者 ...
- Alpha matting算法发展
一.抠图算法简介 Alpha matting算法研究的是如何将一幅图像中的前景信息和背景信息分离的问题,即抠图.这类问题是数字图像处理与数字图像编辑领域中的一类经典问题,广泛应用于视频编缉与视频分割领 ...
- MIT提出精细到头发丝的语义分割技术,打造效果惊艳的特效电影
来自 MIT CSAIL 的研究人员开发了一种精细程度远超传统语义分割方法的「语义软分割」技术,连头发都能清晰地在分割掩码中呈现.在对比实验中,他们的结果远远优于 PSPNet.Mask R-CNN. ...
- PIE SDK打开自定义栅格数据
1. 数据介绍 信息提取和解译的过程中,经常会生成一部分中间临时栅格数据,这些数据在执行完对应操作后就失去了存在的价值,针对这种情况,PIE增加了内存栅格数据集,来协助用户完成对自定义栅格数据的读取和 ...
- 超像素经典算法SLIC的代码的深度优化和分析。
现在这个社会发展的太快,到处都充斥着各种各样的资源,各种开源的平台,如github,codeproject,pudn等等,加上一些大型的官方的开源软件,基本上能找到各个类型的代码.很多初创业的老板可能 ...
- 基于暗通道优先算法的去雾应用(Matlab/C++)
基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理: 参见论文:Single Image Haze Removal Using Dark Channel Pri ...
- paper 116:自然图像抠图/视频抠像技术梳理(image matting, video matting)
1. Bayesian Matting, Chuang, CVPR 2001.http://grail.cs.washington.edu/projects/digital-matting/paper ...
- 在线抠图网站速抠图sukoutu.com全面技术解析之canvas应用
技术关键词 Canvas应用,泛洪算法(Flood Fill),图片缩放,相对位置等比缩放,判断一个点是否在一个平面闭合多边形,nginx代理 业务关键词 在线抠图,智能抠图,一键抠图,钢笔抠图,矩阵 ...
- Python 3 行代码 5 秒抠图的 AI 神器,根本无需 PS
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 苏克1900 PS:如有需要Python学习资料的小伙伴可以加点击下 ...
随机推荐
- 【跟唐老师学习云网络】-第8篇 iptables - filter过滤功能
[摘要] 前面的各种协议已经可以把基本可用的物理网络世界给形成了,在正常情况下,它可以玩的很溜.比如组个局域网办公,或者打个联机魔兽争霸,都没有什么问题. 一.背景介绍 前面的各种协议已经可以把基本可 ...
- RocketMq在SparkStreaming中的总结
其实Rocketmq的给第三方的插件已经全了,如果大家有兴趣的话请移步https://github.com/apache/rocketmq-externals.本文主要是结合笔者已有的rmq在spar ...
- Snack3 一个新的微型JSON框架
Snack3 一个新的微型JSON框架 一个作品,一般表达作者的一个想法.因为大家想法不同,所有作品会有区别.就做技术而言,因为有很多有区别的框架,所以大家可以选择的框架很丰富. snack3.基于j ...
- 史上最全的linuxvi命令的总结
第8章 linux编辑文件内容命令 8.1 vi命令 8.1.1 快速移动光标技巧 ID 快捷键 快捷键说明 1 G 将光标快速移动到最后一行 2 gg 将光标快速移动到行首 3 nG 将光标快速移动 ...
- Python3 类的继承小练习
1.打印并解释结果 class Parent(object): x = 1 class Child1(Parent): pass class Child2(Parent): pass print(Pa ...
- UWP 应用启动速度优化——关闭加载动画
准备 在开始之前,我们应该先处理好预启动来加速启动应用.请参见文末链接. 步骤 关闭加载动画主要在包清单文件中进行. 首先,以代码方式打开 Package.appxmanifest,在顶部的 Pack ...
- kubernetes-部署harbor
Habor是由VMWare中国团队开源的容器镜像仓库.事实上,Habor是在Docker Registry上进行了相应的企业级扩展,从而获得了更加广泛的应用,这些新的企业级特性包括:管理用户界面,基于 ...
- centos7 php(mariadb)安装pdo
环境:centos7+php5.4.16+mariadb5.5.52 在centos7环境下安装PDO,安装的时候都是自己分开安装的,先装的PHP(httpd)后装的mariadb. 数据库安装完成后 ...
- XML字符串转为Map集合
public class xmlToMapUtils { /** * xml字符串转为map集合 * @param xmlStr * @return */ public static Map<S ...
- CCF-CSP题解 201712-3 Crontab
做完一定要仔仔细细地看一遍题目再交,之后发现坑点只能追悔莫及.比如这次"英文缩写(不区分大小写)"\(OwQ\). 给定多个周期性执行的任务,每个任务调度执行有时间的要求.求给定时 ...