mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 00:03:03 +04:00
Merge pull request #12243 from dkurt:dnn_tf_mask_rcnn
* Support Mask-RCNN from TensorFlow * Fix a sample
This commit is contained in:
committed by
Alexander Alekhin
parent
4f360f8b1a
commit
472b71ecef
@@ -99,6 +99,13 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (boxes.rows < out.size[0])
|
||||
{
|
||||
// left = top = right = bottom = 0
|
||||
std::vector<cv::Range> dstRanges(4, Range::all());
|
||||
dstRanges[0] = Range(boxes.rows, out.size[0]);
|
||||
out(dstRanges).setTo(inp.ptr<float>(0, 0, 0)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -115,6 +115,7 @@ public:
|
||||
// It's true whenever predicted bounding boxes and proposals are normalized to [0, 1].
|
||||
bool _bboxesNormalized;
|
||||
bool _clip;
|
||||
bool _groupByClasses;
|
||||
|
||||
enum { _numAxes = 4 };
|
||||
static const std::string _layerName;
|
||||
@@ -183,6 +184,7 @@ public:
|
||||
_locPredTransposed = getParameter<bool>(params, "loc_pred_transposed", 0, false, false);
|
||||
_bboxesNormalized = getParameter<bool>(params, "normalized_bbox", 0, false, true);
|
||||
_clip = getParameter<bool>(params, "clip", 0, false, false);
|
||||
_groupByClasses = getParameter<bool>(params, "group_by_classes", 0, false, true);
|
||||
|
||||
getCodeType(params);
|
||||
|
||||
@@ -381,7 +383,7 @@ public:
|
||||
{
|
||||
count += outputDetections_(i, &outputsData[count * 7],
|
||||
allDecodedBBoxes[i], allConfidenceScores[i],
|
||||
allIndices[i]);
|
||||
allIndices[i], _groupByClasses);
|
||||
}
|
||||
CV_Assert(count == numKept);
|
||||
}
|
||||
@@ -497,7 +499,7 @@ public:
|
||||
{
|
||||
count += outputDetections_(i, &outputsData[count * 7],
|
||||
allDecodedBBoxes[i], allConfidenceScores[i],
|
||||
allIndices[i]);
|
||||
allIndices[i], _groupByClasses);
|
||||
}
|
||||
CV_Assert(count == numKept);
|
||||
}
|
||||
@@ -505,9 +507,36 @@ public:
|
||||
size_t outputDetections_(
|
||||
const int i, float* outputsData,
|
||||
const LabelBBox& decodeBBoxes, Mat& confidenceScores,
|
||||
const std::map<int, std::vector<int> >& indicesMap
|
||||
const std::map<int, std::vector<int> >& indicesMap,
|
||||
bool groupByClasses
|
||||
)
|
||||
{
|
||||
std::vector<int> dstIndices;
|
||||
std::vector<std::pair<float, int> > allScores;
|
||||
for (std::map<int, std::vector<int> >::const_iterator it = indicesMap.begin(); it != indicesMap.end(); ++it)
|
||||
{
|
||||
int label = it->first;
|
||||
if (confidenceScores.rows <= label)
|
||||
CV_Error_(cv::Error::StsError, ("Could not find confidence predictions for label %d", label));
|
||||
const std::vector<float>& scores = confidenceScores.row(label);
|
||||
const std::vector<int>& indices = it->second;
|
||||
|
||||
const int numAllScores = allScores.size();
|
||||
allScores.reserve(numAllScores + indices.size());
|
||||
for (size_t j = 0; j < indices.size(); ++j)
|
||||
{
|
||||
allScores.push_back(std::make_pair(scores[indices[j]], numAllScores + j));
|
||||
}
|
||||
}
|
||||
if (!groupByClasses)
|
||||
std::sort(allScores.begin(), allScores.end(), util::SortScorePairDescend<int>);
|
||||
|
||||
dstIndices.resize(allScores.size());
|
||||
for (size_t j = 0; j < dstIndices.size(); ++j)
|
||||
{
|
||||
dstIndices[allScores[j].second] = j;
|
||||
}
|
||||
|
||||
size_t count = 0;
|
||||
for (std::map<int, std::vector<int> >::const_iterator it = indicesMap.begin(); it != indicesMap.end(); ++it)
|
||||
{
|
||||
@@ -524,14 +553,15 @@ public:
|
||||
for (size_t j = 0; j < indices.size(); ++j, ++count)
|
||||
{
|
||||
int idx = indices[j];
|
||||
int dstIdx = dstIndices[count];
|
||||
const util::NormalizedBBox& decode_bbox = label_bboxes->second[idx];
|
||||
outputsData[count * 7] = i;
|
||||
outputsData[count * 7 + 1] = label;
|
||||
outputsData[count * 7 + 2] = scores[idx];
|
||||
outputsData[count * 7 + 3] = decode_bbox.xmin;
|
||||
outputsData[count * 7 + 4] = decode_bbox.ymin;
|
||||
outputsData[count * 7 + 5] = decode_bbox.xmax;
|
||||
outputsData[count * 7 + 6] = decode_bbox.ymax;
|
||||
outputsData[dstIdx * 7] = i;
|
||||
outputsData[dstIdx * 7 + 1] = label;
|
||||
outputsData[dstIdx * 7 + 2] = scores[idx];
|
||||
outputsData[dstIdx * 7 + 3] = decode_bbox.xmin;
|
||||
outputsData[dstIdx * 7 + 4] = decode_bbox.ymin;
|
||||
outputsData[dstIdx * 7 + 5] = decode_bbox.xmax;
|
||||
outputsData[dstIdx * 7 + 6] = decode_bbox.ymax;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
||||
@@ -33,9 +33,7 @@ public:
|
||||
interpolation = params.get<String>("interpolation");
|
||||
CV_Assert(interpolation == "nearest" || interpolation == "bilinear");
|
||||
|
||||
bool alignCorners = params.get<bool>("align_corners", false);
|
||||
if (alignCorners)
|
||||
CV_Error(Error::StsNotImplemented, "Resize with align_corners=true is not implemented");
|
||||
alignCorners = params.get<bool>("align_corners", false);
|
||||
}
|
||||
|
||||
bool getMemoryShapes(const std::vector<MatShape> &inputs,
|
||||
@@ -66,8 +64,15 @@ public:
|
||||
outHeight = outputs[0].size[2];
|
||||
outWidth = outputs[0].size[3];
|
||||
}
|
||||
scaleHeight = static_cast<float>(inputs[0]->size[2]) / outHeight;
|
||||
scaleWidth = static_cast<float>(inputs[0]->size[3]) / outWidth;
|
||||
if (alignCorners && outHeight > 1)
|
||||
scaleHeight = static_cast<float>(inputs[0]->size[2] - 1) / (outHeight - 1);
|
||||
else
|
||||
scaleHeight = static_cast<float>(inputs[0]->size[2]) / outHeight;
|
||||
|
||||
if (alignCorners && outWidth > 1)
|
||||
scaleWidth = static_cast<float>(inputs[0]->size[3] - 1) / (outWidth - 1);
|
||||
else
|
||||
scaleWidth = static_cast<float>(inputs[0]->size[3]) / outWidth;
|
||||
}
|
||||
|
||||
void forward(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr) CV_OVERRIDE
|
||||
@@ -166,6 +171,7 @@ protected:
|
||||
int outWidth, outHeight, zoomFactorWidth, zoomFactorHeight;
|
||||
String interpolation;
|
||||
float scaleWidth, scaleHeight;
|
||||
bool alignCorners;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -537,4 +537,56 @@ TEST(Test_TensorFlow, two_inputs)
|
||||
normAssert(out, firstInput + secondInput);
|
||||
}
|
||||
|
||||
TEST(Test_TensorFlow, Mask_RCNN)
|
||||
{
|
||||
std::string proto = findDataFile("dnn/mask_rcnn_inception_v2_coco_2018_01_28.pbtxt", false);
|
||||
std::string model = findDataFile("dnn/mask_rcnn_inception_v2_coco_2018_01_28.pb", false);
|
||||
|
||||
Net net = readNetFromTensorflow(model, proto);
|
||||
Mat img = imread(findDataFile("dnn/street.png", false));
|
||||
Mat refDetections = blobFromNPY(path("mask_rcnn_inception_v2_coco_2018_01_28.detection_out.npy"));
|
||||
Mat refMasks = blobFromNPY(path("mask_rcnn_inception_v2_coco_2018_01_28.detection_masks.npy"));
|
||||
Mat blob = blobFromImage(img, 1.0f, Size(800, 800), Scalar(), true, false);
|
||||
|
||||
net.setPreferableBackend(DNN_BACKEND_OPENCV);
|
||||
|
||||
net.setInput(blob);
|
||||
|
||||
// Mask-RCNN predicts bounding boxes and segmentation masks.
|
||||
std::vector<String> outNames(2);
|
||||
outNames[0] = "detection_out_final";
|
||||
outNames[1] = "detection_masks";
|
||||
|
||||
std::vector<Mat> outs;
|
||||
net.forward(outs, outNames);
|
||||
|
||||
Mat outDetections = outs[0];
|
||||
Mat outMasks = outs[1];
|
||||
normAssertDetections(refDetections, outDetections, "", /*threshold for zero confidence*/1e-5);
|
||||
|
||||
// Output size of masks is NxCxHxW where
|
||||
// N - number of detected boxes
|
||||
// C - number of classes (excluding background)
|
||||
// HxW - segmentation shape
|
||||
const int numDetections = outDetections.size[2];
|
||||
|
||||
int masksSize[] = {1, numDetections, outMasks.size[2], outMasks.size[3]};
|
||||
Mat masks(4, &masksSize[0], CV_32F);
|
||||
|
||||
std::vector<cv::Range> srcRanges(4, cv::Range::all());
|
||||
std::vector<cv::Range> dstRanges(4, cv::Range::all());
|
||||
|
||||
outDetections = outDetections.reshape(1, outDetections.total() / 7);
|
||||
for (int i = 0; i < numDetections; ++i)
|
||||
{
|
||||
// Get a class id for this bounding box and copy mask only for that class.
|
||||
int classId = static_cast<int>(outDetections.at<float>(i, 1));
|
||||
srcRanges[0] = dstRanges[1] = cv::Range(i, i + 1);
|
||||
srcRanges[1] = cv::Range(classId, classId + 1);
|
||||
outMasks(srcRanges).copyTo(masks(dstRanges));
|
||||
}
|
||||
cv::Range topRefMasks[] = {Range::all(), Range(0, numDetections), Range::all(), Range::all()};
|
||||
normAssert(masks, refMasks(&topRefMasks[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user