结合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,实现人像去除相关推荐
- python 黑白tif提取边界像素坐标_OpenCV GrabCut算法:前景分割和提取
点击上方"蓝色小字"关注我呀 文章翻译自光头哥哥的博客,原文链接: https://www.pyimagesearch.com/2020/07/27/opencv-grabcut- ...
- Inpaint9.1最新网页版下载及inpaint怎么去水印教程
市面上去水印的软件很多,但专业去除水印的,除了Photoshop,inpaint占有一席之地.在今天的数字时代,我们经常会遇到需要处理图片的情况.然而,当我们遇到水印在图片上,我们就需要寻找一个有效的 ...
- OpenCVSharp(C# OpenCV)图像去水印实例(二) 去除水印并保留文本原始色彩
导读 具体介绍与实现步骤请参考下面文章: 实战 | 文本图片去水印--同时保持文本原始色彩(附源码)_Color Space的博客-CSDN博客点击下方卡片,关注"OpenCV与AI深度学习 ...
- 使用cmake宝葫芦炼化Opencv第一丹
大家还记得西游记里银角大王的那个宝葫芦吗?大圣也被收服进去炼化过.而cmake牌宝葫芦就是把开源的代码适配成您VS法宝调用的dll链接库文件.Cmake处理后可以导入VS平台批量编译,再也不用担心代码 ...
- OpenCVSharp(C# OpenCV)图像去水印实例
导读 具体介绍与实现步骤请参考下面文章: OpenCV对比度亮度变换竟能用来去水印(附Python/C++源码)_Color Space的博客-CSDN博客点击下方卡片,关注"OpenCV与 ...
- 图片还原去遮挡_如何把人像照片上的遮盖物去除看到原来人像?
如何把人像照片上的遮盖物去除看到原来人像? 虽然目前的图像后期软件很强大,但恢复本来不存在的内容还是很困难的,那就不是恢复,而是画了.所以题主提到的的覆盖物遮挡的内容也是有一定前提条件的,当然遮挡物越 ...
- ps人像精修教程——去除皱纹
Ps人像精修教程之去除皱纹 导入素材,并复制图层作为副本(注意了,现在有两个图层,一个叫"背景",一个叫"背景副本"): [在百度上找的素材,如果侵权,请联系 ...
- inpaint 9.1新版3秒去除一切图片中的无关元素
Inpaint9.1是最新可用的一款PC端图片去水印工具,有了它,你只需轻轻动几下鼠标,就可以轻松去除图片上的马赛克和水印等内容了,恢复图片原来的样子. 简单删除任何不需要的元素 图片上除了我们想看到 ...
- python --去除人像背景(抠图)
方法一 注册 https://www.remove.bg/zh/api#api-reference 实操 import time import requests import win32ui impo ...
最新文章
- 浏览器访问网页过程中发生了什么?(转)
- 解决 后台播放音乐时,设置手机铃声,后台音乐不会暂停
- 记事本写python怎么运行-从头学Python之编写可执行的.py文件
- React 中使用sass
- python 面向对象实现CNN(四)
- 博客系统评论模块列表转树形结构
- android安装管理,android-使用下载管理器下载后安装apk,并退出...
- matlab畸变程度计算,matlab 畸变校正代码
- 使用Arduino,蓝牙和Android app的开源爬墙机器人
- 淘宝关键词搜索采集商品数据接口
- Unity URP/SRP可编程渲染管线
- Django实战教程: 开发企业级应用智能文档管理系统smartdoc(1)
- 俄罗斯 搜索引擎 邮箱创建
- Linux中的文本流
- IDEA菜单栏Build选项
- iOS上二维码和一维码识别系列二
- dnf剑魂buff等级上限_DNF:鬼剑士buff换装、白金徽章以及时装详解,萌新也能变老手...
- CaEGCN: Cross-Attention Fusion based Enhanced Graph Convolutional Network for Clustering 2021
- 基于FMCW技术的汽车自适应巡航控制
- mete20可以升级鸿蒙,从微信小程序到鸿蒙js开发【12】——storage缓存自动登录