Skip to content

Commit be624b1

Browse files
authored
Merge pull request Smorodov#67 from Nuzhny007/master
SSD Detector works on all frame area
2 parents 63b010e + 6c6f19e commit be624b1

5 files changed

Lines changed: 154 additions & 31 deletions

File tree

Detector/DNNDetector.cpp

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "DNNDetector.h"
2+
#include "nms.h"
23

34
///
45
/// \brief DNNDetector::DNNDetector
@@ -10,8 +11,18 @@ DNNDetector::DNNDetector(
1011
cv::UMat& colorFrame
1112
)
1213
:
13-
BaseDetector(collectPoints, colorFrame)
14+
BaseDetector(collectPoints, colorFrame),
15+
m_WHRatio(InWidth / (float)InHeight),
16+
m_inScaleFactor(0.007843f),
17+
m_meanVal(127.5),
18+
m_confidenceThreshold(0.2f)
1419
{
20+
m_classNames = { "background",
21+
"aeroplane", "bicycle", "bird", "boat",
22+
"bottle", "bus", "car", "cat", "chair",
23+
"cow", "diningtable", "dog", "horse",
24+
"motorbike", "person", "pottedplant",
25+
"sheep", "sofa", "train", "tvmonitor" };
1526
}
1627

1728
///
@@ -38,38 +49,63 @@ bool DNNDetector::Init(std::string modelConfiguration, std::string modelBinary)
3849
///
3950
void DNNDetector::Detect(cv::UMat& colorFrame)
4051
{
41-
const int inWidth = 300;
42-
const int inHeight = 300;
43-
const float WHRatio = inWidth / (float)inHeight;
44-
const float inScaleFactor = 0.007843f;
45-
const float meanVal = 127.5;
46-
const float confidenceThreshold = 0.2f;
47-
std::string classNames[] = {"background",
48-
"aeroplane", "bicycle", "bird", "boat",
49-
"bottle", "bus", "car", "cat", "chair",
50-
"cow", "diningtable", "dog", "horse",
51-
"motorbike", "person", "pottedplant",
52-
"sheep", "sofa", "train", "tvmonitor"};
53-
54-
cv::Size cropSize;
55-
if (colorFrame.cols / (float)colorFrame.rows > WHRatio)
52+
m_regions.clear();
53+
54+
regions_t tmpRegions;
55+
56+
cv::Mat colorMat = colorFrame.getMat(cv::ACCESS_READ);
57+
58+
if (colorFrame.cols / (float)colorFrame.rows > m_WHRatio)
5659
{
57-
cropSize = cv::Size(cvRound(colorFrame.rows * WHRatio), colorFrame.rows);
60+
cv::Rect crop(0, 0, cvRound(colorFrame.rows * m_WHRatio), colorFrame.rows);
61+
62+
for (; crop.x < colorMat.cols; crop.x += crop.width)
63+
{
64+
if (crop.x + crop.width >= colorMat.cols)
65+
{
66+
crop.x = colorMat.cols - crop.width;
67+
}
68+
69+
DetectInCrop(colorMat, crop, tmpRegions);
70+
}
5871
}
5972
else
6073
{
61-
cropSize = cv::Size(colorFrame.cols, cvRound(colorFrame.cols / WHRatio));
74+
cv::Rect crop(0, 0, colorFrame.cols, cvRound(colorFrame.cols / m_WHRatio));
75+
76+
for (; crop.y < colorMat.rows; crop.y += crop.height)
77+
{
78+
if (crop.y + crop.height >= colorMat.rows)
79+
{
80+
crop.y = colorMat.rows - crop.height;
81+
}
82+
83+
DetectInCrop(colorMat, crop, tmpRegions);
84+
}
6285
}
6386

64-
cv::Rect crop(cv::Point((colorFrame.cols - cropSize.width) / 2, (colorFrame.rows - cropSize.height) / 2), cropSize);
87+
nms3<CRegion>(tmpRegions, m_regions, 0.5f,
88+
[](const CRegion& reg) -> cv::Rect { return reg.m_rect; },
89+
[](const CRegion& reg) -> float { return reg.m_confidence; },
90+
0, 0.f);
91+
}
6592

66-
cv::Mat inputBlob = cv::dnn::blobFromImage(colorFrame.getMat(cv::ACCESS_READ), inScaleFactor, cv::Size(inWidth, inHeight), meanVal, false); //Convert Mat to batch of images
93+
///
94+
/// \brief DNNDetector::DetectInCrop
95+
/// \param colorFrame
96+
/// \param crop
97+
/// \param tmpRegions
98+
///
99+
void DNNDetector::DetectInCrop(cv::Mat colorFrame, const cv::Rect& crop, regions_t& tmpRegions)
100+
{
101+
//Convert Mat to batch of images
102+
cv::Mat inputBlob = cv::dnn::blobFromImage(cv::Mat(colorFrame, crop), m_inScaleFactor, cv::Size(InWidth, InHeight), m_meanVal, false, true);
67103

68104
m_net.setInput(inputBlob, "data"); //set the network input
69105

70106
cv::Mat detection = m_net.forward("detection_out"); //compute output
71107

72-
std::vector<double> layersTimings;
108+
//std::vector<double> layersTimings;
73109
//double freq = cv::getTickFrequency() / 1000;
74110
//double time = m_net.getPerfProfile(layersTimings) / freq;
75111

@@ -81,13 +117,13 @@ void DNNDetector::Detect(cv::UMat& colorFrame)
81117
//putText(frame, ss.str(), Point(20,20), 0, 0.5, Scalar(0,0,255));
82118
//std::cout << "Inference time, ms: " << time << endl;
83119

84-
m_regions.clear();
120+
//cv::Point correctPoint((colorFrame.cols - crop.width) / 2, (colorFrame.rows - crop.height) / 2);
85121

86122
for (int i = 0; i < detectionMat.rows; ++i)
87123
{
88124
float confidence = detectionMat.at<float>(i, 2);
89125

90-
if (confidence > confidenceThreshold)
126+
if (confidence > m_confidenceThreshold)
91127
{
92128
size_t objectClass = (size_t)(detectionMat.at<float>(i, 1));
93129

@@ -98,7 +134,7 @@ void DNNDetector::Detect(cv::UMat& colorFrame)
98134

99135
cv::Rect object(xLeftBottom, yLeftBottom, xRightTop - xLeftBottom, yRightTop - yLeftBottom);
100136

101-
m_regions.push_back(CRegion(object, classNames[objectClass], confidence));
137+
tmpRegions.push_back(CRegion(object, m_classNames[objectClass], confidence));
102138

103139
//cv::rectangle(frame, object, Scalar(0, 255, 0));
104140
//std::string label = classNames[objectClass] + ": " + std::to_string(confidence);

Detector/DNNDetector.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,14 @@ class DNNDetector : public BaseDetector
2020

2121
private:
2222
cv::dnn::Net m_net;
23+
24+
void DetectInCrop(cv::Mat colorFrame, const cv::Rect& crop, regions_t& tmpRegions);
25+
26+
static const int InWidth = 300;
27+
static const int InHeight = 300;
28+
float m_WHRatio;
29+
float m_inScaleFactor;
30+
float m_meanVal;
31+
float m_confidenceThreshold;
32+
std::vector<std::string> m_classNames;
2333
};

TODO

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
1. Collect points for all types of detectors
2-
2. MobileNet for all frame not for crop
3-
3. External API for the detectors options: for Background subtractors, confidenceThreshold for DNNDetector etc.
4-
4. New Multitarget tracking algorithm based on Discrete-Continuous Energy Minimization: https://bitbucket.org/amilan/dctracking
2+
2. External API for the detectors options: for Background subtractors, confidenceThreshold for DNNDetector etc.
3+
3. New Multitarget tracking algorithm based on Discrete-Continuous Energy Minimization: https://bitbucket.org/amilan/dctracking
4+
4. Deep SORT: https://github.com/nwojke/deep_sort

VideoExample.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -578,15 +578,15 @@ class DNNDetectorExample : public VideoExample
578578
m_detector->SetMinObjectSize(cv::Size(frame.cols / 20, frame.rows / 20));
579579

580580
m_tracker = std::make_unique<CTracker>(m_useLocalTracking,
581-
tracking::DistCenters,
581+
tracking::DistRects,
582582
tracking::KalmanLinear,
583583
tracking::FilterRect,
584584
tracking::TrackKCF, // Use KCF tracker for collisions resolving
585585
tracking::MatchHungrian,
586586
0.3f, // Delta time for Kalman filter
587587
0.1f, // Accel noise magnitude for Kalman filter
588-
frame.rows / 5, // Distance threshold between region and object on two frames
589-
1 * m_fps, // Maximum allowed skipped frames
588+
frame.rows / 10, // Distance threshold between region and object on two frames
589+
2 * m_fps, // Maximum allowed skipped frames
590590
5 * m_fps // Maximum trace length
591591
);
592592

@@ -606,7 +606,7 @@ class DNNDetectorExample : public VideoExample
606606

607607
for (const auto& track : m_tracker->tracks)
608608
{
609-
if (track->IsRobust(2, // Minimal trajectory size
609+
if (track->IsRobust(5, // Minimal trajectory size
610610
0.5f, // Minimal ratio raw_trajectory_points / trajectory_lenght
611611
cv::Size2f(0.1f, 8.0f)) // Min and max ratio: width / height
612612
)

nms.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,80 @@ inline void nms2(
145145
}
146146
}
147147
}
148+
149+
150+
/**
151+
* @brief nms2
152+
* Non maximum suppression with detection scores
153+
* @param srcRects
154+
* @param resRects
155+
* @param thresh
156+
* @param neighbors
157+
*/
158+
template<typename OBJ, typename GET_RECT_FUNC, typename GET_SCORE_FUNC>
159+
inline void nms3(
160+
const std::vector<OBJ>& srcRects,
161+
std::vector<OBJ>& resRects,
162+
float thresh,
163+
GET_RECT_FUNC GetRect,
164+
GET_SCORE_FUNC GetScore,
165+
int neighbors = 0,
166+
float minScoresSum = 0.f
167+
)
168+
{
169+
resRects.clear();
170+
171+
const size_t size = srcRects.size();
172+
if (!size)
173+
{
174+
return;
175+
}
176+
177+
// Sort the bounding boxes by the detection score
178+
std::multimap<float, size_t> idxs;
179+
for (size_t i = 0; i < size; ++i)
180+
{
181+
idxs.insert(std::pair<float, size_t>(GetScore(srcRects[i]), i));
182+
}
183+
184+
// keep looping while some indexes still remain in the indexes list
185+
while (idxs.size() > 0)
186+
{
187+
// grab the last rectangle
188+
auto lastElem = --std::end(idxs);
189+
size_t lastPos = lastElem->second;
190+
const cv::Rect& rect1 = GetRect(srcRects[lastPos]);
191+
192+
int neigborsCount = 0;
193+
float scoresSum = lastElem->first;
194+
195+
idxs.erase(lastElem);
196+
197+
for (auto pos = std::begin(idxs); pos != std::end(idxs); )
198+
{
199+
// grab the current rectangle
200+
const cv::Rect& rect2 = GetRect(srcRects[pos->second]);
201+
202+
float intArea = (rect1 & rect2).area();
203+
float unionArea = rect1.area() + rect2.area() - intArea;
204+
float overlap = intArea / unionArea;
205+
206+
// if there is sufficient overlap, suppress the current bounding box
207+
if (overlap > thresh)
208+
{
209+
scoresSum += pos->first;
210+
pos = idxs.erase(pos);
211+
++neigborsCount;
212+
}
213+
else
214+
{
215+
++pos;
216+
}
217+
}
218+
if (neigborsCount >= neighbors &&
219+
scoresSum >= minScoresSum)
220+
{
221+
resRects.push_back(srcRects[lastPos]);
222+
}
223+
}
224+
}

0 commit comments

Comments
 (0)