结合grabcut和inpaint,实现人像去除



#include "stdafx.h"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/photo.hpp" #include <iostream> using namespace std;
using namespace cv; /************************************************************************/
/* 9. Write an image-processing function to interactively remove people from an
image. Use cv::grabCut() to segment the person, and then use cv::inpaint()
to fill in the resulting hole (recall that we learned about cv::inpaint() in the
previous chapter). */
/************************************************************************/ static void help()
{
cout << "\nThis program demonstrates GrabCut segmentation -- select an object in a region\n"
"and then grabcut will attempt to segment it out.\n"
"Call:\n"
"./grabcut <image_name>\n"
"\nSelect a rectangular area around the object you want to segment\n" <<
"\nHot keys: \n"
"\tESC - quit the program\n"
"\tr - restore the original image\n"
"\tn - next iteration\n"
"\n"
"\tleft mouse button - set rectangle\n"
"\n"
"\tCTRL+left mouse button - set GC_BGD pixels\n"
"\tSHIFT+left mouse button - set GC_FGD pixels\n"
"\n"
"\tCTRL+right mouse button - set GC_PR_BGD pixels\n"
"\tSHIFT+right mouse button - set GC_PR_FGD pixels\n" << endl;
} const Scalar RED = Scalar(0,0,255);
const Scalar PINK = Scalar(230,130,255);
const Scalar BLUE = Scalar(255,0,0);
const Scalar LIGHTBLUE = Scalar(255,255,160);
const Scalar GREEN = Scalar(0,255,0); const int BGD_KEY = EVENT_FLAG_CTRLKEY;
const int FGD_KEY = EVENT_FLAG_SHIFTKEY; static void getBinMask( const Mat& comMask, Mat& binMask )
{
if( comMask.empty() || comMask.type()!=CV_8UC1 )
CV_Error( Error::StsBadArg, "comMask is empty or has incorrect type (not CV_8UC1)" );
if( binMask.empty() || binMask.rows!=comMask.rows || binMask.cols!=comMask.cols )
binMask.create( comMask.size(), CV_8UC1 );
binMask = comMask & 1;
} class GCApplication
{
public:
enum{ NOT_SET = 0, IN_PROCESS = 1, SET = 2 };
static const int radius = 2;
static const int thickness = -1; void reset();
void setImageAndWinName( const Mat& _image, const string& _winName );
void showImage() const;
void mouseClick( int event, int x, int y, int flags, void* param );
int nextIter();
int getIterCount() const { return iterCount; }
private:
void setRectInMask();
void setLblsInMask( int flags, Point p, bool isPr ); const string* winName;
const Mat* image;
Mat mask;
Mat bgdModel, fgdModel; uchar rectState, lblsState, prLblsState;
bool isInitialized; Rect rect;
vector<Point> fgdPxls, bgdPxls, prFgdPxls, prBgdPxls;
int iterCount;
}; void GCApplication::reset()
{
if( !mask.empty() )
mask.setTo(Scalar::all(GC_BGD));
bgdPxls.clear(); fgdPxls.clear();
prBgdPxls.clear(); prFgdPxls.clear(); isInitialized = false;
rectState = NOT_SET;
lblsState = NOT_SET;
prLblsState = NOT_SET;
iterCount = 0;
} void GCApplication::setImageAndWinName( const Mat& _image, const string& _winName )
{
if( _image.empty() || _winName.empty() )
return;
image = &_image;
winName = &_winName;
mask.create( image->size(), CV_8UC1);
reset();
} void GCApplication::showImage() const
{
if( image->empty() || winName->empty() )
return; Mat res;
Mat binMask;
if( !isInitialized )
image->copyTo( res );
else
{
getBinMask( mask, binMask );
image->copyTo( res, binMask );
// mask and source code
Mat src = *image;
Mat mask = binMask;
//inpaint
Mat inpainted;
inpaint(src, mask, inpainted, 3, CV_INPAINT_TELEA);
imshow("inpainted result",inpainted);
} vector<Point>::const_iterator it;
for( it = bgdPxls.begin(); it != bgdPxls.end(); ++it )
circle( res, *it, radius, BLUE, thickness );
for( it = fgdPxls.begin(); it != fgdPxls.end(); ++it )
circle( res, *it, radius, RED, thickness );
for( it = prBgdPxls.begin(); it != prBgdPxls.end(); ++it )
circle( res, *it, radius, LIGHTBLUE, thickness );
for( it = prFgdPxls.begin(); it != prFgdPxls.end(); ++it )
circle( res, *it, radius, PINK, thickness ); if( rectState == IN_PROCESS || rectState == SET )
rectangle( res, Point( rect.x, rect.y ), Point(rect.x + rect.width, rect.y + rect.height ), GREEN, 2); imshow( *winName, res );
} void GCApplication::setRectInMask()
{
CV_Assert( !mask.empty() );
mask.setTo( GC_BGD );
rect.x = max(0, rect.x);
rect.y = max(0, rect.y);
rect.width = min(rect.width, image->cols-rect.x);
rect.height = min(rect.height, image->rows-rect.y);
(mask(rect)).setTo( Scalar(GC_PR_FGD) );
} void GCApplication::setLblsInMask( int flags, Point p, bool isPr )
{
vector<Point> *bpxls, *fpxls;
uchar bvalue, fvalue;
if( !isPr )
{
bpxls = &bgdPxls;
fpxls = &fgdPxls;
bvalue = GC_BGD;
fvalue = GC_FGD;
}
else
{
bpxls = &prBgdPxls;
fpxls = &prFgdPxls;
bvalue = GC_PR_BGD;
fvalue = GC_PR_FGD;
}
if( flags & BGD_KEY )
{
bpxls->push_back(p);
circle( mask, p, radius, bvalue, thickness );
}
if( flags & FGD_KEY )
{
fpxls->push_back(p);
circle( mask, p, radius, fvalue, thickness );
}
} void GCApplication::mouseClick( int event, int x, int y, int flags, void* )
{
// TODO add bad args check
switch( event )
{
case EVENT_LBUTTONDOWN: // set rect or GC_BGD(GC_FGD) labels
{
bool isb = (flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;
if( rectState == NOT_SET && !isb && !isf )
{
rectState = IN_PROCESS;
rect = Rect( x, y, 1, 1 );
}
if ( (isb || isf) && rectState == SET )
lblsState = IN_PROCESS;
}
break;
case EVENT_RBUTTONDOWN: // set GC_PR_BGD(GC_PR_FGD) labels
{
bool isb = (flags & BGD_KEY) != 0,
isf = (flags & FGD_KEY) != 0;
if ( (isb || isf) && rectState == SET )
prLblsState = IN_PROCESS;
}
break;
case EVENT_LBUTTONUP:
if( rectState == IN_PROCESS )
{
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
rectState = SET;
setRectInMask();
CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
showImage();
}
if( lblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), false);
lblsState = SET;
showImage();
}
break;
case EVENT_RBUTTONUP:
if( prLblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), true);
prLblsState = SET;
showImage();
}
break;
case EVENT_MOUSEMOVE:
if( rectState == IN_PROCESS )
{
rect = Rect( Point(rect.x, rect.y), Point(x,y) );
CV_Assert( bgdPxls.empty() && fgdPxls.empty() && prBgdPxls.empty() && prFgdPxls.empty() );
showImage();
}
else if( lblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), false);
showImage();
}
else if( prLblsState == IN_PROCESS )
{
setLblsInMask(flags, Point(x,y), true);
showImage();
}
break;
}
} int GCApplication::nextIter()
{
if( isInitialized )
grabCut( *image, mask, rect, bgdModel, fgdModel, 1 );
else
{
if( rectState != SET )
return iterCount; if( lblsState == SET || prLblsState == SET )
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_MASK );
else
grabCut( *image, mask, rect, bgdModel, fgdModel, 1, GC_INIT_WITH_RECT ); isInitialized = true;
}
iterCount++; bgdPxls.clear(); fgdPxls.clear();
prBgdPxls.clear(); prFgdPxls.clear(); return iterCount;
} GCApplication gcapp; static void on_mouse( int event, int x, int y, int flags, void* param )
{
gcapp.mouseClick( event, x, y, flags, param );
} int main( int argc, char** argv )
{
cv::CommandLineParser parser(argc, argv, "{help h||}{@input||}");
if (parser.has("help"))
{
help();
return 0;
}
string filename = parser.get<string>("@input");
if( filename.empty() )
{
cout << "\nDurn, empty filename" << endl;
return 1;
}
Mat image = imread( filename, 1 );
if( image.empty() )
{
cout << "\n Durn, couldn't read image filename " << filename << endl;
return 1;
} help(); const string winName = "image";
namedWindow( winName, WINDOW_AUTOSIZE );
setMouseCallback( winName, on_mouse, 0 ); gcapp.setImageAndWinName( image, winName );
gcapp.showImage(); for(;;)
{
char c = (char)waitKey(0);
switch( c )
{
case '\x1b':
cout << "Exiting ..." << endl;
goto exit_main;
case 'r':
cout << endl;
gcapp.reset();
gcapp.showImage();
break;
case 'n':
int iterCount = gcapp.getIterCount();
cout << "<" << iterCount << "... ";
int newIterCount = gcapp.nextIter();
if( newIterCount > iterCount )
{
gcapp.showImage();
cout << iterCount << ">" << endl;
}
else
cout << "rect must be determined>" << endl;
break;
}
} exit_main:
destroyWindow( winName );
return 0;
}
核心的部分在这里
getBinMask( mask, binMask );
image->copyTo( res, binMask );
// mask and source code
Mat src = *image;
Mat mask = binMask;
//inpaint
Mat inpainted;
inpaint(src, mask, inpainted, 3, CV_INPAINT_TELEA);
imshow("inpainted result",inpainted);
结合grabcut和inpaint,实现人像去除的更多相关文章
- 使用inpaint例子,去除水印
		
http://www.opencv.org.cn/forum.php?mod=viewthread&tid=33151 #include "stdafx.h" #inclu ...
 - opencv —— inpaint 图像修补、去除指定区域物体
		
实现图像修补.物体去除:inpaint 函数 void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double ...
 - Atitit.去除水印的方案
		
Atitit.去除水印的方案 1.1. 查找水印的位置 Kegwa imgd posit zo ok le .. Auto find d zo troub ...manu easy 1.2. 还原去除 ...
 - 基于python的图片修复程序-可用于水印去除
		
图片修复程序-可用于水印去除 在现实的生活中,我们可能会遇到一些美好的或是珍贵的图片被噪声干扰,比如旧照片的折痕,比如镜头上的灰尘或污渍,更或者是某些我们想为我所用但有讨厌水印,那么有没有一种办法可以 ...
 - OpenCV 学习笔记 04 深度估计与分割——GrabCut算法与分水岭算法
		
1 使用普通摄像头进行深度估计 1.1 深度估计原理 这里会用到几何学中的极几何(Epipolar Geometry),它属于立体视觉(stereo vision)几何学,立体视觉是计算机视觉的一个分 ...
 - python利用opencv去除水印方法
		
OpenCV(Open Source Computer Vision Library)是一个跨平台计算机视觉库,实现了图像处理和计算机视觉方面的很多通用算法 在python中可以利用opencv来去除 ...
 - 人像美妆---妆容迁移算法研究(Makeup transfer)
		
原文:人像美妆---妆容迁移算法研究(Makeup transfer) 对于人像美妆算法,现在的美妆相机.玩美彩妆之类的app已经做的比较成熟了,但是具体算法,基本网络上是杳无可查,今天本人介绍一种自 ...
 - 图片去水印工具:Inpaint 7.2中文专业破解版下载及使用方法
		
下载地址: 点我 Inpaint 是一款可以从图片上去除不必要的物体,让您轻松摆脱照片上的水印.划痕.污渍.标志等瑕疵的实用型软件:简单说来,Inpaint 就是一款强大实用的图片去水印软件,您的图片 ...
 - Python黑科技神奇去除马赛克
		
图片修复程序-可用于水印去除 在现实的生活中,我们可能会遇到一些美好的或是珍贵的图片被噪声干扰,比如旧照片的折痕,比如镜头上的灰尘或污渍,更或者是某些我们想为我所用但有讨厌水印,那么有没有一种办法可以 ...
 
随机推荐
- 安装安全狗后,MP4无法播放
 - EUI组件之BitmapLabel  位图字体
			
一.制作文图字体文件 使用TextureMerger制作位图字体,具体查看 官方教程. 我们这里制作了一组位图字体. 二.导入位图字体 位图字体素材放入资源配置文件default.res.json 三 ...
 - shell批量重命令文件脚本
			
批量重命名脚步记录,以备用 假如有一批11.txt 12.txt 13,txt 14.txt 15.txt脚步要要重命名为1.txt 2.txt 3.txt .... 脚本如下: #!/bin/bas ...
 - windows dos 常用命令行
			
有关某个命令的详细信息,请键入 HELP 命令名 dir (directory) :列出当前目录下的文件以及文件夹 md (make directory): 创建目录 rd (remove direc ...
 - Java学习记录-Lambda表达式示例
			
List<Integer> userIds=userInfoList.stream().map(m->m.getUserId()).collect(Collectors.toList ...
 - 设计模式之——Memento模式
			
Memento模式即快照模式,就是在某一时刻,设定一个状态,在后面随时可以返回到当前状态的模式. 我们拿一个闯关游戏作为举例,一共有十关,每闯一关,玩家所持金额增加一百,而闯关失败就扣一百.初始时,给 ...
 - Crossed ladders---poj2507(二分+简单几何)
			
题目链接:http://poj.org/problem?id=2507 题意就是给你x y c求出?的距离: h1 = sqrt(x*x-d*d); h2 = sqrt(y*y-d*d); (h1 ...
 - 【我的Android进阶之旅】Android 源代码中的Java代码中//$NON-NLS-1$ 注释是什么意思?
			
1.背景 最近在负责公司基础业务和移动基础设施的开发工作,正在负责Lint代码静态检查工作.因此编写了自定义的Lint规则,在编写自定义的Lint规则前,当然是需要去把Google的关于Lint检测的 ...
 - RSA与AES的区别
			
RSA 非对称加密,公钥加密,私钥解密,反之亦然.由于需要大数的乘幂求模等算法,运行速度慢,不易于硬件实现. 通常私钥长度有512bit,1024bit,2048bit,4096bit,长度越长,越安 ...
 - Mirror--生成用于镜像用户同步的脚本
			
USE master GO IF OBJECT_ID ('sp_hexadecimal') IS NOT NULL DROP PROCEDURE sp_hexadecimal GO CREATE PR ...