目录
3.1 Mask R-CNN运行
3.2 SegmentDynObject::SegmentDynObject()
3.3 SegmentDynObject::GetSegmentation()
3.1 Mask R-CNN运行
在Examples/RGB-D/rgbd_tum.cc文件开始运行Mask R-CNN网络,首先进入MaskNet->GetSegmentation函数。
// Segment out the images
// 开始进行图像分割
cv::Mat mask = cv::Mat::ones(480,640,CV_8U);
if (argc == 6 || argc == 7)
{
cv::Mat maskRCNN;
// 利用GetSegmentation()函数进行图像分割
maskRCNN = MaskNet->GetSegmentation(imRGB,string(argv[5]),vstrImageFilenamesRGB[ni].replace(0,4,""));
// 将分割的结果 maskRCNN 复制到 maskRCNNdil
cv::Mat maskRCNNdil = maskRCNN.clone();
// 对 maskRCNN 应用膨胀操作,使用 kernel 作为内核
cv::dilate(maskRCNN,maskRCNNdil, kernel);
// 将 maskRCNNdil 从 mask 中减去,得到最终的mask结果
mask = mask - maskRCNNdil;
}
3.2 SegmentDynObject::SegmentDynObject()
(1) SegmentDynObject()函数的主要功能是加载网络的配置文件和初始化网络。
SegmentDynObject::SegmentDynObject(){
std::cout << "Importing Mask R-CNN Settings..." << std::endl;
//调用ImportSettings()函数加载Mask R-CNN网络设置
ImportSettings();
std::string x;
//设置环境变量PYTHONPATH,通过/src/python文件夹设置为this->py_path
setenv("PYTHONPATH", this->py_path.c_str(), 1);
//获取环境变量PYTHONPATH的值,并将其赋值给变量x。
x = getenv("PYTHONPATH");
//初始化Python解释器
Py_Initialize();
//创建一个新的NDArray转换器
this->cvt = new NDArrayConverter();
//通过Pylmport_ImportModule方法读入src/python目录下的MaskRCNN.py文件
this->py_module = PyImport_ImportModule(this->module_name.c_str());
//查py_module是否为空,如果为空则终止程序
assert(this->py_module != NULL);
//通过PyObject_GetAttrString方法导入模块(MaskRCNN.py)中的方法或类
this->py_class = PyObject_GetAttrString(this->py_module, this->class_name.c_str());
//检查py_class是否为空,如果为空则终止程序
assert(this->py_class != NULL);
//使用py_class创建一个新的Python实例,并将其赋值给net变量
this->net = PyInstance_New(this->py_class, NULL, NULL);
//检查net是否为空,如果为空则终止程序
assert(this->net != NULL);
std::cout << "Creating net instance..." << std::endl;
cv::Mat image = cv::Mat::zeros(480,640,CV_8UC3); //Be careful with size!!
std::cout << "Loading net parameters..." << std::endl;
GetSegmentation(image);
}
首先做的就是通过ImportSettings加载Mask R-CNN网络配置:
void SegmentDynObject::ImportSettings(){
std::string strSettingsFile = "./Examples/RGB-D/MaskSettings.yaml";
cv::FileStorage fs(strSettingsFile.c_str(), cv::FileStorage::READ);
fs["py_path"] >> this->py_path; // src/python目录
fs["module_name"] >> this->module_name; // MaskRCNN文件
fs["class_name"] >> this->class_name; //Mask类
fs["get_dyn_seg"] >> this->get_dyn_seg; //MaskRCNN中的方法获取mask信息
// std::cout << " py_path: "<< this->py_path << std::endl;
// std::cout << " module_name: "<< this->module_name << std::endl;
// std::cout << " class_name: "<< this->class_name << std::endl;
// std::cout << " get_dyn_seg: "<< this->get_dyn_seg << std::endl;
}
主要是加载了几个参数:
- py_path:src/python目录
- module name:MaskRCNN文件
- class_name:Mask类
- get_dyn_seg:GetDynSeg MaskRCNN中的方法获取mask信息
# 获取mask信息
def GetDynSeg(image,image2=None):
h = image.shape[0]
w = image.shape[1]
if len(image.shape) == 2:
im = np.zeros((h,w,3))
im[:,:,0]=image
im[:,:,1]=image
im[:,:,2]=image
image = im
#if image2 is not None:
# args+=[image2]
# Run detection
results = model.detect([image], verbose=0)
# Visualize results
r = results[0]
i = 0
mask = np.zeros((h,w))
for roi in r['rois']:
if class_names[r['class_ids'][i]] == 'person':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'bicycle':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'car':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'motorcycle':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'airplane':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'bus':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'train':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'truck':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'boat':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'bird':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'cat':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'dog':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'horse':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'sheep':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'cow':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'elephant':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'bear':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'zebra':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
if class_names[r['class_ids'][i]] == 'giraffe':
image_m = r['masks'][:,:,i]
mask[image_m == 1] = 1.
i+=1
#print('GetSeg mask shape:',mask.shape)
return maskk
(2) 然后设置环境变量,设置环境变量PYTHONPATH,通过/src/python文件夹设置为this->py_path ,然后将环境变量的值赋值给x。
//设置环境变量PYTHONPATH,通过/src/python文件夹设置为this->py_path
setenv("PYTHONPATH", this->py_path.c_str(), 1);
setenvi起到改变或增加环境变量的作用,用法如下:
int setenv(const char *name,const char value,int overwrite);
- name:为环境变量名称字符串。
- value:为变量内容。
- overwrite:用来决定是否要改变已存在的环境变量。如果overwrite不为0,则改变环境变量原有内容,原有内容会被改为参数value所指的变量内容。如果overwrite:为O,且该环境变量已有内容,则参数value会被忽略。
- reuturn:执行成功则返回0,有错误发生时返回-1。
(3) 然后初始化Python解释器,创建一个NDArray转换器。
//初始化Python解释器
Py_Initialize();
//创建一个新的NDArray转换器
this->cvt = new NDArrayConverter();
(4) 然后进行一些列的模型的导入和检查,最后调用GetSegmentation函数对该张图片进行处理。
//通过Pylmport_ImportModule方法读入src/python目录下的MaskRCNN.py文件
this->py_module = PyImport_ImportModule(this->module_name.c_str());
//查py_module是否为空,如果为空则终止程序
assert(this->py_module != NULL);
//通过PyObject_GetAttrString方法导入模块(MaskRCNN.py)中的方法或类
this->py_class = PyObject_GetAttrString(this->py_module, this->class_name.c_str());
//检查py_class是否为空,如果为空则终止程序
assert(this->py_class != NULL);
//使用py_class创建一个新的Python实例,并将其赋值给net变量
this->net = PyInstance_New(this->py_class, NULL, NULL);
//检查net是否为空,如果为空则终止程序
assert(this->net != NULL);
std::cout << "Creating net instance..." << std::endl;
cv::Mat image = cv::Mat::zeros(480,640,CV_8UC3); //Be careful with size!!
std::cout << "Loading net parameters..." << std::endl;
GetSegmentation(image);
3.3 SegmentDynObject::GetSegmentation()
函数的主要功能是获取图像的分割结果 。
- 首先读取目录路径和文件名指定的图像文件,将图像转换为Python的NDArray类型,因为Mask R-CNN是python语言编写,图像格式要满足网络要求。
- 然后将图像传递给Mask R-CNN网络进行处理,将分割结果转换为cv::Mat格式,进一步将分割结果转换为CV_8U,即将数据类型转换为8位无符号整数,其中0表示背景,1表示前景。
- 最后判断路径是否安全,如果安全则首先尝试打开目录,如果目录不存在,则创建目录;将分割结果保存为目录路径和文件名指定的图像文件。
/*
* 获取图像的分割结果
*/
cv::Mat SegmentDynObject::GetSegmentation(cv::Mat &image,std::string dir, std::string name){
// 读取目录路径和文件名指定的图像文件
cv::Mat seg = cv::imread(dir+"/"+name,CV_LOAD_IMAGE_UNCHANGED);
if(seg.empty()){
// 图像转换为Python的NDArray类型
PyObject* py_image = cvt->toNDArray(image.clone());
assert(py_image != NULL);
// 将图像传递给网络进行处理
PyObject* py_mask_image = PyObject_CallMethod(this->net, const_cast<char*>(this->get_dyn_seg.c_str()),"(O)",py_image);
// 将分割结果转换为cv::Mat格式
seg = cvt->toMat(py_mask_image).clone();
// 将分割结果转换为CV_8U,即将数据类型转换为8位无符号整数,其中0表示背景,1表示前景。
seg.cv::Mat::convertTo(seg,CV_8U);//0 background y 1 foreground
// 判断路径是否安全
if(dir.compare("no_save")!=0){
// 则首先尝试打开目录,如果目录不存在,则创建目录
DIR* _dir = opendir(dir.c_str());
if (_dir) {closedir(_dir);}
else if (ENOENT == errno)
{
const int check = mkdir(dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
if (check == -1) {
std::string str = dir;
str.replace(str.end() - 6, str.end(), "");
mkdir(str.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}
}
//最后将分割结果保存为目录路径和文件名指定的图像文件。
cv::imwrite(dir+"/"+name,seg);
}
}
return seg;
}