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

避免采坑

  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

 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 == 0)
        {
              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, 0, nlength);

C++端:

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

void AlphaMatting::GetAlphaMap()
{
    int h = matte.rows;
    int w = matte.cols;
    Map = new int[h*w];
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; 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应用即可,而且效率更高。

  源码下载:微信扫描下方二维码文章末尾获取链接。

?

原文地址:https://www.cnblogs.com/duel/p/removebg.html

时间: 2024-08-30 17:41:18

c#实现SharedMatting抠图算法的相关文章

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

http://www.tuicool.com/articles/63aANv 一.序言 陆陆续续的如果累计起来,我估计至少有二十来位左右的朋友加我QQ,向我咨询有关抠图方面的算法,可惜的是,我对这方面之前一直是没有研究过的.除了利用和Photoshop中的魔棒一样的技术或者Photoshop中的选区菜单中的色彩范围类似的算法(这两个我有何PS至少90%一致的代码)是实现简单的抠图外,现在一些state of art 方面的算法我都不了解.因此,也浪费了不少的将知识转换为资产的机会.年30那天,偶

使用FFmpeg实现抠图合并功能(chroma key)

自己以前实现抠图算法好久了,没想到ffmpeg里面早有这个功能了 在很多视频中可以看到图像是合成的,例如有些神剧里面某大侠跳下万丈深渊的场景,某人在三昧真火中被烧的场景,还有些游戏主播,体育主播在主场景前面有个人解说的场景,都是chroma key的技术实现的,具体的链接可以参考: http://www.cs.utah.edu/~michael/chroma/ 效果图如下: 在最新版本的ffmpeg中,已经增加了chroma key功能的filter,只需要一条命令即可搞定 点击(此处)折叠或打

Alpha matting算法发展

一.抠图算法简介 Alpha matting算法研究的是如何将一幅图像中的前景信息和背景信息分离的问题,即抠图.这类问题是数字图像处理与数字图像编辑领域中的一类经典问题,广泛应用于视频编缉与视频分割领域中.Alpha matting的数学模型是     由Porter 和 Duff于1984 年提出[1].他们首先引入了α 通道的概念,即它是一种前景和背景颜色的线性混合表示方法.一张图片包含前景信息.背景信息,将该图片看成是前景图和背景图的合成图,于是便有了以上的混合模型.前景α为1, 背景α为

显著性检测初步总结

目前相对传统的显著性检测方法主要分为两类: 一类是纯数据驱动独立于任务的自底而上的显著性检测方法(主要基于生物学原理),另一类是受意识支配依赖于任务的自顶而下的显著性检测方法(主要基于机器学习). 自顶而下的图像显著性检测方法 自顶而下的显著性模型一般包括特征学习和显著性计算两个部分. 由于人类自顶而下的选择注意由高层的脑部信息所控制,对于同一场景不同的人注意的结果不同,其动机.情感等因素比较难以控制和分析,因此构建自顶而下的显著性模型比较复杂,所以对于这类显著性模型的研究不是很多.   自底而

图像处理URL

随笔分类 - 图像处理/图像增强等 图像增强: 图像复原: 图像重建: 图像分割: 图像特效: 图像匹配: 图像形态学处理: 图像几何处理: 图像正交变换: 人工智能: 跟踪: 图像处理之增强---图像模糊检测 摘要: 这种检测可以做宽动态的检测,也可应用稳像算法我们实现了拉普拉斯方差算法,该算法提供给我们一个浮点数来代表具体图像的"模糊度".该算法快速,简单且易于使用--用拉普拉斯算子与输入图像做卷积然后计算方差即可.如果方差低于预定义阈值,图像就被标记为"模糊"

图像背景虚化

背景 在一幅摄影作品中,背景虚化可以很好地烘托主体,但是对于一些摄影爱好者来说,大光圈太贵:长焦镜头使用时限制太多:手中相机功能太低--虽条件不足,但又很想拍出主体突出.背景虚化的照片,这时候该怎么办呢?接下来本文简要介绍背景虚化的步骤. 步骤 抠图得到图像的前景区域 对背景使用高斯模糊,得到图层 将原图前景区域叠加到第二步得到的图层对应区域 注:第一步中,可以使用的抠图算法很多,你可以在这里寻找. 第二步中,最好使用一些保边模糊的滤波器,这里我使用Domain Transform filter

计算机视觉算法与代码集锦

计算机视觉算法与代码集锦 计算机视觉是结合了传统摄影测量,现代计算机信息技术.人工智能等多学科的一个大学科,是一片开垦不足的大陆,路很远,但很多人都在跋涉! 本文转自CSDN(地址http://blog.csdn.net/whucv/article/details/7907391),是一篇很好的算法与代码总结文档,转载在此供大家学习参考. 原文如下: UIUC的Jia-Bin Huang同学收集了很多计算机视觉方面的代码,链接如下: https://netfiles.uiuc.edu/jbhua

Poisson image editing算法实现的Matlab代码解析

之前我发了数篇系列博文来仔细研究Poisson Image Editing算法,每次重新审视和深入,仿佛都能有更为深刻的认识和很大的收获.这应该算是我这个系列的完结篇,会用用Matlab代码一点一点的演示,原文作者到底是如何设计和实现他那个强大且影响深远的算法的.希望你在看本文之前务必参考一下文章来了解算法原理,本文将主要讲解编程实现的问题,对于前面讲过的内容,我不会深究.但我个人总体的感觉是,现在图像处理算法对数学的要求是越来越高了,像泊松融合.泊松抠图这样的算法如果没有偏微分方程(本算法中涉

OpenCV——证件照自动抠图

今天去交社保,要白底的电子版照片,我目前手头就是一个蓝底的,又不想手动抠图,于是想做一个自动换背景的程序. 先上效果: 具体分三步,第一步是大体的背景转换,把蓝色变为白色: void colortransfer(cv::Mat image) //蓝背景转白背景,有边缘残留 { int Diff; int num_row = image.rows; int num_col = image.cols; for (int r = 0; r < num_row; r++) { cv::Vec3b *da