Skip to content

Commit 5e592c2

Browse files
author
Alexander Panov
authored
Merge pull request #3699 from AleksandrPanov:mcc_add_perf_tests_improve_performance
Mcc add perf tests improve performance #3699 Added perf tests to mcc module. Also these optimizations have been added: - added `parallel_for_` to `performThreshold()` - removed `toL`/`fromL` and added `dst` to avoid copy data - added `parallel_for_` to `elementWise()` ("batch" optimization improves performance of Windows version, Linux without changes). Configuration: Ryzen 5950X, 2x16 GB 3000 MHz DDR4 OS: Windows 10, Ubuntu 20.04.5 LTS Performance results in milliseconds: | OS and alg version | process, ms | infer, ms | | -------------------- | ----- | ------ | | win_default | 63.09 | 457.57 | | win_optimized_without_batch | 48.69 | 111.78 | | win_optimized_batch | 48.42 | 47.28 | | linux_default | 50.88 | 300.7 | | linux_optimized_batch| 36.06 | 41.62 | ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
1 parent 5300337 commit 5e592c2

File tree

9 files changed

+131
-54
lines changed

9 files changed

+131
-54
lines changed

modules/mcc/perf/perf_main.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#include "perf_precomp.hpp"
2+
3+
CV_PERF_TEST_MAIN(mcc)

modules/mcc/perf/perf_mcc.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// This file is part of OpenCV project.
2+
// It is subject to the license terms in the LICENSE file found in the top-level directory
3+
// of this distribution and at http://opencv.org/license.html.
4+
5+
#include "perf_precomp.hpp"
6+
7+
namespace opencv_test
8+
{
9+
namespace
10+
{
11+
12+
using namespace std;
13+
14+
PERF_TEST(CV_mcc_perf, detect) {
15+
string path = cvtest::findDataFile("cv/mcc/mcc_ccm_test.jpg");
16+
Mat img = imread(path, IMREAD_COLOR);
17+
Ptr<CCheckerDetector> detector = CCheckerDetector::create();
18+
19+
// detect MCC24 board
20+
TEST_CYCLE() {
21+
ASSERT_TRUE(detector->process(img, MCC24, 1, false));
22+
}
23+
SANITY_CHECK_NOTHING();
24+
}
25+
26+
PERF_TEST(CV_mcc_perf, infer) {
27+
// read gold chartsRGB
28+
string path = cvtest::findDataFile("cv/mcc/mcc_ccm_test.yml");
29+
FileStorage fs(path, FileStorage::READ);
30+
Mat chartsRGB;
31+
FileNode node = fs["chartsRGB"];
32+
node >> chartsRGB;
33+
fs.release();
34+
35+
// compute CCM
36+
ColorCorrectionModel model(chartsRGB.col(1).clone().reshape(3, chartsRGB.rows/3) / 255., COLORCHECKER_Macbeth);
37+
model.run();
38+
39+
Mat img(1000, 4000, CV_8UC3);
40+
randu(img, 0, 255);
41+
img.convertTo(img, CV_64F, 1. / 255.);
42+
43+
TEST_CYCLE() {
44+
model.infer(img);
45+
}
46+
47+
SANITY_CHECK_NOTHING();
48+
}
49+
50+
} // namespace
51+
} // namespace opencv_test

modules/mcc/perf/perf_precomp.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef __OPENCV_PERF_PRECOMP_HPP__
2+
#define __OPENCV_PERF_PRECOMP_HPP__
3+
4+
#include "opencv2/ts.hpp"
5+
#include "opencv2/mcc.hpp"
6+
7+
namespace opencv_test
8+
{
9+
using namespace cv::mcc;
10+
using namespace cv::ccm;
11+
using namespace perf;
12+
}
13+
14+
#endif

modules/mcc/src/ccm.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,13 @@ Mat ColorCorrectionModel::infer(const Mat& img, bool islinear)
289289
CV_Error(Error::StsBadArg, "No CCM values!" );
290290
}
291291
Mat img_lin = (p->linear)->linearize(img);
292-
Mat img_ccm(img_lin.size(), img_lin.type());
293-
Mat ccm_ = p->ccm.reshape(0, p->shape / 3);
294-
img_ccm = multiple(p->prepare(img_lin), ccm_);
292+
Mat ccm = p->ccm.reshape(0, p->shape / 3);
293+
Mat img_ccm = multiple(p->prepare(img_lin), ccm);
295294
if (islinear == true)
296295
{
297296
return img_ccm;
298297
}
299-
return p->cs.fromL(img_ccm);
298+
return p->cs.fromLFunc(img_ccm, img_lin);
300299
}
301300

302301
void ColorCorrectionModel::Impl::getColor(CONST_COLOR constcolor)

modules/mcc/src/checker_detector.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -539,17 +539,18 @@ void CCheckerDetectorImpl::
539539
// number of window sizes (scales) to apply adaptive thresholding
540540
int nScales = (params->adaptiveThreshWinSizeMax - params->adaptiveThreshWinSizeMin) / params->adaptiveThreshWinSizeStep + 1;
541541
thresholdImgs.create(nScales, 1, CV_8U);
542-
std::vector<cv::Mat> _thresholdImgs;
543-
for (int i = 0; i < nScales; i++)
544-
{
545-
int currScale = params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep;
546-
547-
cv::Mat tempThresholdImg;
548-
cv::adaptiveThreshold(grayscaleImg, tempThresholdImg, 255, cv::ADAPTIVE_THRESH_MEAN_C,
549-
cv::THRESH_BINARY_INV, currScale, params->adaptiveThreshConstant);
550-
551-
_thresholdImgs.push_back(tempThresholdImg);
552-
}
542+
std::vector<cv::Mat> _thresholdImgs(nScales);
543+
parallel_for_(Range(0, nScales),[&](const Range& range) {
544+
const int start = range.start;
545+
const int end = range.end;
546+
for (int i = start; i < end; i++) {
547+
int currScale = params->adaptiveThreshWinSizeMin + i * params->adaptiveThreshWinSizeStep;
548+
cv::Mat tempThresholdImg;
549+
cv::adaptiveThreshold(grayscaleImg, tempThresholdImg, 255, ADAPTIVE_THRESH_MEAN_C,
550+
THRESH_BINARY_INV, currScale, params->adaptiveThreshConstant);
551+
_thresholdImgs[i] = tempThresholdImg;
552+
}
553+
});
553554

554555
thresholdImgs.assign(_thresholdImgs);
555556
}

modules/mcc/src/colorspace.cpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ Operations RGBBase_::relation(const ColorSpace& other) const
8383
}
8484
if (linear)
8585
{
86-
return Operations({ Operation(fromL) });
86+
return Operations({ Operation([this](Mat rgbl) -> Mat { return fromLFunc(rgbl); }) });
8787
}
88-
return Operations({ Operation(toL) });
88+
return Operations({ Operation([this](Mat rgb) -> Mat { return toLFunc(rgb); })});
8989
}
9090

9191
/* @brief Initial operations.
@@ -134,36 +134,32 @@ void RGBBase_::calM()
134134
*/
135135
void RGBBase_::calOperations()
136136
{
137-
// rgb -> rgbl
138-
toL = [this](Mat rgb) -> Mat { return toLFunc(rgb); };
139-
140-
// rgbl -> rgb
141-
fromL = [this](Mat rgbl) -> Mat { return fromLFunc(rgbl); };
142-
143137
if (linear)
144138
{
145139
to = Operations({ Operation(M_to.t()) });
146140
from = Operations({ Operation(M_from.t()) });
147141
}
148142
else
149143
{
150-
to = Operations({ Operation(toL), Operation(M_to.t()) });
151-
from = Operations({ Operation(M_from.t()), Operation(fromL) });
144+
// rgb -> rgbl
145+
to = Operations({ Operation([this](Mat rgb) -> Mat { return toLFunc(rgb); }), Operation(M_to.t()) });
146+
// rgbl -> rgb
147+
from = Operations({ Operation(M_from.t()), Operation([this](Mat rgbl) -> Mat { return fromLFunc(rgbl); }) });
152148
}
153149
}
154150

155-
Mat RGBBase_::toLFunc(Mat& /*rgb*/) { return Mat(); }
151+
Mat RGBBase_::toLFunc(Mat& /*rgb*/) const { return Mat(); }
156152

157-
Mat RGBBase_::fromLFunc(Mat& /*rgbl*/) { return Mat(); }
153+
Mat RGBBase_::fromLFunc(Mat& /*rgbl*/, Mat dst) const { return dst; }
158154

159155
/* @brief Base of Adobe RGB color space;
160156
*/
161157

162-
Mat AdobeRGBBase_::toLFunc(Mat& rgb) { return gammaCorrection(rgb, gamma); }
158+
Mat AdobeRGBBase_::toLFunc(Mat& rgb) const { return gammaCorrection(rgb, gamma); }
163159

164-
Mat AdobeRGBBase_::fromLFunc(Mat& rgbl)
160+
Mat AdobeRGBBase_::fromLFunc(Mat& rgbl, Mat dst) const
165161
{
166-
return gammaCorrection(rgbl, 1. / gamma);
162+
return gammaCorrection(rgbl, 1. / gamma, dst);
167163
}
168164

169165
/* @brief Base of sRGB color space;
@@ -179,7 +175,7 @@ void sRGBBase_::calLinear()
179175

180176
/* @brief Used by toLFunc.
181177
*/
182-
double sRGBBase_::toLFuncEW(double& x)
178+
double sRGBBase_::toLFuncEW(double& x) const
183179
{
184180
if (x > K0)
185181
{
@@ -199,15 +195,15 @@ double sRGBBase_::toLFuncEW(double& x)
199195
* @param rgb the input array, type of cv::Mat.
200196
* @return the output array, type of cv::Mat.
201197
*/
202-
Mat sRGBBase_::toLFunc(Mat& rgb)
198+
Mat sRGBBase_::toLFunc(Mat& rgb) const
203199
{
204200
return elementWise(rgb,
205201
[this](double a_) -> double { return toLFuncEW(a_); });
206202
}
207203

208204
/* @brief Used by fromLFunc.
209205
*/
210-
double sRGBBase_::fromLFuncEW(double& x)
206+
double sRGBBase_::fromLFuncEW(const double& x) const
211207
{
212208
if (x > beta)
213209
{
@@ -227,10 +223,9 @@ double sRGBBase_::fromLFuncEW(double& x)
227223
* @param rgbl the input array, type of cv::Mat.
228224
* @return the output array, type of cv::Mat.
229225
*/
230-
Mat sRGBBase_::fromLFunc(Mat& rgbl)
226+
Mat sRGBBase_::fromLFunc(Mat& rgbl, Mat dst) const
231227
{
232-
return elementWise(rgbl,
233-
[this](double a_) -> double { return fromLFuncEW(a_); });
228+
return elementWise(rgbl, [this](double a_) -> double { return fromLFuncEW(a_); }, dst);
234229
}
235230

236231
/* @brief sRGB color space.

modules/mcc/src/colorspace.hpp

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,6 @@ class RGBBase_ : public ColorSpace
8383
double yg;
8484
double xb;
8585
double yb;
86-
MatFunc toL;
87-
MatFunc fromL;
8886
Mat M_to;
8987
Mat M_from;
9088

@@ -108,6 +106,9 @@ class RGBBase_ : public ColorSpace
108106
*/
109107
void bind(RGBBase_& rgbl);
110108

109+
virtual Mat toLFunc(Mat& /*rgb*/) const;
110+
111+
virtual Mat fromLFunc(Mat& /*rgbl*/, Mat dst=Mat()) const;
111112
private:
112113
virtual void setParameter() {};
113114

@@ -120,10 +121,6 @@ class RGBBase_ : public ColorSpace
120121
virtual void calOperations();
121122

122123
virtual void calLinear() {};
123-
124-
virtual Mat toLFunc(Mat& /*rgb*/);
125-
126-
virtual Mat fromLFunc(Mat& /*rgbl*/);
127124
};
128125

129126
/** @brief Base of Adobe RGB color space;
@@ -136,8 +133,8 @@ class AdobeRGBBase_ : public RGBBase_
136133
double gamma;
137134

138135
private:
139-
Mat toLFunc(Mat& rgb) CV_OVERRIDE;
140-
Mat fromLFunc(Mat& rgbl) CV_OVERRIDE;
136+
Mat toLFunc(Mat& rgb) const CV_OVERRIDE;
137+
Mat fromLFunc(Mat& rgbl, Mat dst=Mat()) const CV_OVERRIDE;
141138
};
142139

143140
/** @brief Base of sRGB color space;
@@ -160,23 +157,23 @@ class sRGBBase_ : public RGBBase_
160157
virtual void calLinear() CV_OVERRIDE;
161158
/** @brief Used by toLFunc.
162159
*/
163-
double toLFuncEW(double& x);
160+
double toLFuncEW(double& x) const;
164161

165162
/** @brief Linearization.
166163
@param rgb the input array, type of cv::Mat.
167164
@return the output array, type of cv::Mat.
168165
*/
169-
Mat toLFunc(Mat& rgb) CV_OVERRIDE;
166+
Mat toLFunc(Mat& rgb) const CV_OVERRIDE;
170167

171168
/** @brief Used by fromLFunc.
172169
*/
173-
double fromLFuncEW(double& x);
170+
double fromLFuncEW(const double& x) const;
174171

175172
/** @brief Delinearization.
176173
@param rgbl the input array, type of cv::Mat.
177174
@return the output array, type of cv::Mat.
178175
*/
179-
Mat fromLFunc(Mat& rgbl) CV_OVERRIDE;
176+
Mat fromLFunc(Mat& rgbl, Mat dst=Mat()) const CV_OVERRIDE;
180177
};
181178

182179
/** @brief sRGB color space.

modules/mcc/src/utils.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@
3030
namespace cv {
3131
namespace ccm {
3232

33-
double gammaCorrection_(const double& element, const double& gamma)
33+
inline double gammaCorrection_(const double& element, const double& gamma)
3434
{
3535
return (element >= 0 ? pow(element, gamma) : -pow((-element), gamma));
3636
}
3737

38-
Mat gammaCorrection(const Mat& src, const double& gamma)
38+
Mat gammaCorrection(const Mat& src, const double& gamma, Mat dst)
3939
{
40-
return elementWise(src, [gamma](double element) -> double { return gammaCorrection_(element, gamma); });
40+
return elementWise(src, [gamma](double element) -> double { return gammaCorrection_(element, gamma); }, dst);
4141
}
4242

4343
Mat maskCopyTo(const Mat& src, const Mat& mask)

modules/mcc/src/utils.hpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,9 @@ double gammaCorrection_(const double& element, const double& gamma);
4242
\f]
4343
@param src the input array,type of Mat.
4444
@param gamma a constant for gamma correction.
45+
@param dst the output array, type of Mat.
4546
*/
46-
Mat gammaCorrection(const Mat& src, const double& gamma);
47+
Mat gammaCorrection(const Mat& src, const double& gamma, Mat dst=Mat());
4748

4849
/** @brief maskCopyTo a function to delete unsatisfied elementwise.
4950
@param src the input array, type of Mat.
@@ -77,10 +78,26 @@ Mat rgb2gray(const Mat& rgb);
7778
@param lambda a for operation
7879
*/
7980
template <typename F>
80-
Mat elementWise(const Mat& src, F&& lambda)
81+
Mat elementWise(const Mat& src, F&& lambda, Mat dst=Mat())
8182
{
82-
Mat dst = src.clone();
83+
if (dst.empty() || !dst.isContinuous() || dst.total() != src.total() || dst.type() != src.type())
84+
dst = Mat(src.rows, src.cols, src.type());
8385
const int channel = src.channels();
86+
if (src.isContinuous()) {
87+
const int num_elements = (int)src.total()*channel;
88+
const double *psrc = (double*)src.data;
89+
double *pdst = (double*)dst.data;
90+
const int batch = getNumThreads() > 1 ? 128 : num_elements;
91+
const int N = (num_elements / batch) + ((num_elements % batch) > 0);
92+
parallel_for_(Range(0, N),[&](const Range& range) {
93+
const int start = range.start * batch;
94+
const int end = std::min(range.end*batch, num_elements);
95+
for (int i = start; i < end; i++) {
96+
pdst[i] = lambda(psrc[i]);
97+
}
98+
});
99+
return dst;
100+
}
84101
switch (channel)
85102
{
86103
case 1:

0 commit comments

Comments
 (0)