问题:白色等背景(幕布)下的批量图像,自动分割出前景物体,无须交互
环境: ubuntu 16.04 + opencv3 + openmp + cmake
**注意:具体分割效果可以自己调整腐蚀膨胀和grabcut中的阈值大小来优化。
本文章主要是用处理后的结果来重建物体,所以难以避免的是会保留一部分背景,以保证重建效果**
1.使用阈值分割,提取目标物体大概位置
//阈值分割,提取前景的大致轮廓
threshold(gray,mask,0,255,THRESH_BINARY|CV_THRESH_OTSU);
2.通过膨胀腐蚀操作,构造出容纳物体的mask
//膨胀,去掉噪点
dilate(mask,mask, element1);
if(debug) imshow("膨胀",mask);
//腐蚀,得到整块的小车位置
erode(mask, mask, element0);
if(debug) imshow("腐蚀",mask);
3。构造出frabcut需要的mask图像,标记前后背景像素
//构造grabcut的mask
for(int i=0;i<mask.rows;i++)
{
for(int j=0;j<mask.cols;j++)
{
if(mask.at<uchar>(i,j)>100)
mask.at<uchar>(i,j)=cv::GC_PR_BGD;//标记为可能的背景
else
mask.at<uchar>(i,j)=cv::GC_PR_FGD;//标记为可能的前景
}
}
4 调用opencv中的grabcut函数进行分割操作
Mat bgModel,fgModel;
grabCut(img,mask,Rect(0,0,img.cols,img.rows),bgModel,fgModel,1, cv::GC_INIT_WITH_MASK);
5.使用openmp多线程库,加速计算
#pragma omp parallel for
for(int i=0;i<fileName.size();i++)
{
string filePath=basePath+fileName.at(i);
cout<<filePath<<endl;
Mat img=imread(filePath);
if(img.empty())
{
cerr<<"读不到该图像!"<<endl;
continue;
}
resize(img,img,Size(img.cols/3,img.rows/3));
//imwrite(outputPath+fileName.at(i),img);
//提取白布里面的部分
img=getWhitePart(img);
//imshow("original",img);
Mat result=grabCutImage(img);
//imshow("result", result);
imwrite(outputPath+fileName.at(i),result);
//waitKey(0);
}
6.自动读取给定目录下的图片,输出到指定目录
vector<string> getFiles(string cate_dir)
{
vector<string> files;//存放文件名
#ifdef WIN32
_finddata_t file;
long lf;
//输入文件夹路径
if ((lf=_findfirst(cate_dir.c_str(), &file)) == -1) {
cout<<cate_dir<<" not found!!!"<<endl;
} else {
while(_findnext(lf, &file) == 0) {
//输出文件名
//cout<<file.name<<endl;
if (strcmp(file.name, ".") == 0 || strcmp(file.name, "..") == 0)
continue;
files.push_back(file.name);
}
}
_findclose(lf);
#endif
#ifdef linux
DIR *dir;
struct dirent *ptr;
char base[1000];
if ((dir=opendir(cate_dir.c_str())) == NULL)
{
perror("Open dir error...");
exit(1);
}
while ((ptr=readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0|| ptr->d_name[0]=='.') ///current dir OR parrent dir
continue;
else if(ptr->d_type == 8) ///file
//printf("d_name:%s/%s\n",basePath,ptr->d_name);
files.push_back(ptr->d_name);
else if(ptr->d_type == 10) ///link file
//printf("d_name:%s/%s\n",basePath,ptr->d_name);
continue;
else if(ptr->d_type == 4) ///dir
{
files.push_back(ptr->d_name);
/*
memset(base,'\0',sizeof(base));
strcpy(base,basePath);
strcat(base,"/");
strcat(base,ptr->d_nSame);
readFileList(base);
*/
}
}
closedir(dir);
#endif
//排序,按从小到大排序
sort(files.begin(), files.end());
return files;
}
源图:
结果图: