内容简介

将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工程项目

避免采坑

  1. 最好不要用最新版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

  1. public class labelPoint
  2. {
  3. public int x;
  4. public int y;
  5. public int label;
  6. };
  7.  
  8. public class TupleInfo
  9. {
  10. public double FR;
  11. public double FG;
  12. public double FB;
  13.  
  14. public double BR;
  15. public double BG;
  16. public double BB;
  17.  
  18. public double sigmaf;
  19. public double sigmab;
  20. public int flag;
  21. };
  22.  
  23. public class FtupleInfo
  24. {
  25. public double FR;
  26. public double FG;
  27. public double FB;
  28.  
  29. public double BR;
  30. public double BG;
  31. public double BB;
  32.  
  33. public double alphar;
  34. public double confidence;
  35. };
  36.  
  37. public void loadImage(string sFile)
  38. {
  39. pImg = CvInvoke.Imread(sFile);
  40. if (pImg.GetData() == null || pImg.GetData().Length == )
  41. {
  42. Console.WriteLine("load pImg failed!");
  43. return;
  44. }
  45.  
  46. height = pImg.Rows;
  47. width = pImg.Cols;
  48. step = pImg.Step / (pImg.ElementSize / pImg.NumberOfChannels);
  49. channels = pImg.NumberOfChannels;
  50. data = pImg.GetData();
  51. unknownIndex = new int[height, width];
  52. tri = new int[height, width];
  53. alpha = new int[height, width];
  54. }

有了这些对应信息,你就可以尝试自己移植了。

深化尝试

从我的调试结果来看,可以实现抠图,如果你也同时在C++环境下运行了算法,你会发现C#环境下的算法运行时间远超C++。然后我就考虑将抠图算法在C++环境下打包成dll供C#调用。

由于不熟悉c#与C++的交互,我踩了很多坑,实现的也并不算完美,不过总之调通了。

我将提前准备好的原图以及Trimap图的路径传给C++的dll,期望返回处理过后的Alpha数组。

c#端:

首先添加我生成的C++ Dll并声明引用。

  1. [DllImport("ImgIntelligHelper.dll", CharSet = CharSet.Unicode)]
  2. public extern static IntPtr GetMatteMap([MarshalAs(UnmanagedType.LPStr)] string sInput,
  3. [MarshalAs(UnmanagedType.LPStr)] string sOutput);

然后对dll中的函数进行调用,返回透明度矩阵的内存地址,然后赋值到我创建的数组中。

  1. // sInput - 原图路径; sTrimap: Trimap图路径
  2. System.Drawing.Bitmap oBitmap = new Bitmap(sInput);
  3. int nlength = oBitmap.Width * oBitmap.Height;
  4. IntPtr intptr = GetMatteMap(sInput, sTrimap);
  5. int[] arrAlpha = new int[nlength];
  6. Marshal.Copy(intptr, arrAlpha, , nlength);

C++端:

新增了一个方法,将矩阵转换为int数组。

  1. void AlphaMatting::GetAlphaMap()
  2. {
  3. int h = matte.rows;
  4. int w = matte.cols;
  5. Map = new int[h*w];
  6. for (int i = ; i < h; ++i)
  7. {
  8. for (int j = ; j < w; ++j)
  9. {
  10. Map[i * w + j] = alpha[i][j];
  11. }
  12. };
  13. }
  14.  
  15. // 接收图片并处理
  16. int* GetMatteMap(char* sInput, char* sTrimap)
  17. {
  18. AlphaMatting alphaMatHelper;
  19. alphaMatHelper.loadImage(sInput);
  20. alphaMatHelper.loadTrimap(sTrimap);
  21. alphaMatHelper.solveAlpha();
  22. alphaMatHelper.GetAlphaMap();
  23. return alphaMatHelper.Map;
  24. }

最后用原图以及dll返回的Alpha数组实现抠图。 这是可行的方式,整个流程进行下来效率相对于纯C#版会有较大的改进。但是相对于纯C++版本来说,消耗还是过高。

然后我又尝试将C++版算法改成控制台应用程序。在C#中采用启动进程的方式,传入原图、Trimap图、输出图路径值,然后以不显示应用程序窗口的方式在后台静默执行。 进程结束后见到了C++应用程序处理过后的结果。

C#中调用C++生成的控制台应用exe。

  1. private void DoConvert(string sIndex)
  2. {
  3. string sBasePath = AppDomain.CurrentDomain.BaseDirectory;
  4. string sExeFile = sBasePath + @"\AlphaMattingPlugin.exe";
  5. string sInput = sBasePath + @"\Datas\input" + sIndex+ ".jpg";
  6. string sTrimap = sBasePath + @"\Datas\trimap" + sIndex + ".jpg";
  7. string sOutput = sBasePath + @"\Datas\AlphaMattingPluginSample" + sIndex + ".png";
  8.  
  9. Process process = new Process();
  10. process.StartInfo.FileName = sExeFile;
  11. // 调用C++版本的控制台Exe,传入原图、Trimap图、抠图结果输出文件路径
  12. process.StartInfo.Arguments = " " + sInput + " " + sTrimap + " " + sOutput;
  13. process.StartInfo.CreateNoWindow = false;
  14. process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
  15. process.Start();
  16. process.WaitForExit();
  17.  
  18. if (File.Exists(sOutput))
  19. this.ShowImage(this.ImgResult, sOutput);
  20. }
  21.  
  22. private void ShowImage(Image img, string sFile)
  23. {
  24. byte[] bytes = System.IO.File.ReadAllBytes(sFile);
  25. BitmapImage bitImg = new BitmapImage();
  26. bitImg.BeginInit();
  27. bitImg.StreamSource = new System.IO.MemoryStream(bytes);
  28. bitImg.EndInit();
  29. bitImg.Freeze();
  30. img.Source = bitImg;
  31. }

这样处理后比纯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抠图算法的更多相关文章

  1. 图像抠图算法学习 - Shared Sampling for Real-Time Alpha Matting

    一.序言   陆陆续续的如果累计起来,我估计至少有二十来位左右的朋友加我QQ,向我咨询有关抠图方面的算法,可惜的是,我对这方面之前一直是没有研究过的.除了利用和Photoshop中的魔棒一样的技术或者 ...

  2. Alpha matting算法发展

    一.抠图算法简介 Alpha matting算法研究的是如何将一幅图像中的前景信息和背景信息分离的问题,即抠图.这类问题是数字图像处理与数字图像编辑领域中的一类经典问题,广泛应用于视频编缉与视频分割领 ...

  3. MIT提出精细到头发丝的语义分割技术,打造效果惊艳的特效电影

    来自 MIT CSAIL 的研究人员开发了一种精细程度远超传统语义分割方法的「语义软分割」技术,连头发都能清晰地在分割掩码中呈现.在对比实验中,他们的结果远远优于 PSPNet.Mask R-CNN. ...

  4. PIE SDK打开自定义栅格数据

    1. 数据介绍 信息提取和解译的过程中,经常会生成一部分中间临时栅格数据,这些数据在执行完对应操作后就失去了存在的价值,针对这种情况,PIE增加了内存栅格数据集,来协助用户完成对自定义栅格数据的读取和 ...

  5. 超像素经典算法SLIC的代码的深度优化和分析。

    现在这个社会发展的太快,到处都充斥着各种各样的资源,各种开源的平台,如github,codeproject,pudn等等,加上一些大型的官方的开源软件,基本上能找到各个类型的代码.很多初创业的老板可能 ...

  6. 基于暗通道优先算法的去雾应用(Matlab/C++)

    基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理:             参见论文:Single Image Haze Removal Using Dark Channel Pri ...

  7. paper 116:自然图像抠图/视频抠像技术梳理(image matting, video matting)

    1. Bayesian Matting, Chuang, CVPR 2001.http://grail.cs.washington.edu/projects/digital-matting/paper ...

  8. 在线抠图网站速抠图sukoutu.com全面技术解析之canvas应用

    技术关键词 Canvas应用,泛洪算法(Flood Fill),图片缩放,相对位置等比缩放,判断一个点是否在一个平面闭合多边形,nginx代理 业务关键词 在线抠图,智能抠图,一键抠图,钢笔抠图,矩阵 ...

  9. Python 3 行代码 5 秒抠图的 AI 神器,根本无需 PS

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 苏克1900 PS:如有需要Python学习资料的小伙伴可以加点击下 ...

随机推荐

  1. 检测是否引入jQuery

    if (typeof jQuery != 'undefined') { document.write("jquery已经被加载"); } else { document.write ...

  2. k 近邻算法解决字体反爬手段|效果非常好

    字体反爬,是一种利用 CSS 特性和浏览器渲染规则实现的反爬虫手段.其高明之处在于,就算借助(Selenium 套件.Puppeteer 和 Splash)等渲染工具也无法拿到真实的文字内容. 这种反 ...

  3. IDEA插件开发(一)一个简单的表单demo

  4. 2017 CCPC秦皇岛 H题 Prime set

    Given an array of  integers , we say a set  is a prime set of the given array, if  and  is prime. Ba ...

  5. 重排数列-Java实现(2018网易校招研发岗)

    题目: 链接:https://www.nowcoder.com/questionTerminal/6c184566ecff4d3baff3536449d4a3e2 来源:牛客网 小易有一个长度为N的正 ...

  6. 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解

    写在前面的话 相关背景及资源: 曹工说Spring Boot源码系列开讲了(1)-- Bean Definition到底是什么,附spring思维导图分享 工程代码地址 思维导图地址 工程结构图: 正 ...

  7. 一线互联网公司Redis使用精髓,你必须要掌握这4点!

    先来看一下这些Redis面试题你会几道? 1.什么是 Redis?简述它的优缺点? 2.Redis 与 memcached 相比有哪些优势? 3.Redis 支持哪几种数据类型? 4.Redis 主要 ...

  8. Linux常见指令大全

    转载自https://www.cnblogs.com/caozy/p/9261224.html 前言 本文特点 授之以渔:了解命令学习方法.用途:不再死记硬背,拒绝漫无目的: 准确无误:所有命令执行通 ...

  9. iview表单验证trigger:'change,blur'

    今天发现,如果设置select的trigger:'blur'就算选择之后还是边框是红色的,之后查了一下iview的文档,也没有找到准确的蚊子描述,只看到form那个组件其中有一个例子,大概是selec ...

  10. scrapy框架(二)

    scrapy框架(二) 一.scrapy 选择器 概述: Scrapy提供基于lxml库的解析机制,它们被称为选择器. 因为,它们“选择”由XPath或CSS表达式指定的HTML文档的某部分. Sca ...