44
55namespace opencv_mark {
66
7- OpenCVTestData::OpenCVTestData (uint64_t seed) : rng_(seed) {}
7+ OpenCVTestData::OpenCVTestData (uint64_t seed) : rng_(seed), seed_(seed) {}
88
9- void OpenCVTestData::reseed (uint64_t seed) { rng_.seed (seed); }
9+ void OpenCVTestData::reseed (uint64_t seed) { rng_.seed (seed); seed_ = seed; }
1010
1111cv::Mat OpenCVTestData::makeU8 (uint32_t width, uint32_t height) {
1212 cv::Mat m (static_cast <int >(height), static_cast <int >(width), CV_8UC1 );
@@ -64,12 +64,9 @@ cv::Mat OpenCVTestData::makePerspectiveMatrix() {
6464 return m;
6565}
6666
67- void OpenCVTestData::makeRemap (uint32_t src_w, uint32_t src_h,
68- uint32_t dst_w, uint32_t dst_h,
69- cv::Mat& mapX, cv::Mat& mapY) {
70- // Identity map with a tiny per-pixel offset so the kernel does
71- // real bilinear sampling instead of degenerate copy. Mirrors
72- // openvx-mark's TestDataGenerator::createRemap behaviour.
67+ void OpenCVTestData::makeRemapIdentity (uint32_t src_w, uint32_t src_h,
68+ uint32_t dst_w, uint32_t dst_h,
69+ cv::Mat& mapX, cv::Mat& mapY) {
7370 mapX.create (static_cast <int >(dst_h), static_cast <int >(dst_w), CV_32FC1 );
7471 mapY.create (static_cast <int >(dst_h), static_cast <int >(dst_w), CV_32FC1 );
7572 const float sx = static_cast <float >(src_w) / static_cast <float >(dst_w);
@@ -78,8 +75,84 @@ void OpenCVTestData::makeRemap(uint32_t src_w, uint32_t src_h,
7875 auto * mx = mapX.ptr <float >(y);
7976 auto * my = mapY.ptr <float >(y);
8077 for (int x = 0 ; x < mapX.cols ; ++x) {
81- mx[x] = (x + 0 .5f ) * sx + 0 .25f ;
82- my[x] = (y + 0 .5f ) * sy + 0 .25f ;
78+ mx[x] = (x + 0 .5f ) * sx - 0 .5f ;
79+ my[x] = (y + 0 .5f ) * sy - 0 .5f ;
80+ }
81+ }
82+ }
83+
84+ void OpenCVTestData::makeRemap (uint32_t src_w, uint32_t src_h,
85+ uint32_t dst_w, uint32_t dst_h,
86+ cv::Mat& mapX, cv::Mat& mapY,
87+ RemapPattern pattern) {
88+ // Build the requested pattern. By default use a radial lens-distortion
89+ // model so the benchmark exercises scattered, realistic memory access
90+ // rather than the cache-friendly identity path.
91+ if (pattern == RemapPattern::IDENTITY ) {
92+ makeRemapIdentity (src_w, src_h, dst_w, dst_h, mapX, mapY);
93+ return ;
94+ }
95+
96+ mapX.create (static_cast <int >(dst_h), static_cast <int >(dst_w), CV_32FC1 );
97+ mapY.create (static_cast <int >(dst_h), static_cast <int >(dst_w), CV_32FC1 );
98+ const float sx = static_cast <float >(src_w) / static_cast <float >(dst_w);
99+ const float sy = static_cast <float >(src_h) / static_cast <float >(dst_h);
100+ const float dst_wf = static_cast <float >(dst_w);
101+ const float dst_hf = static_cast <float >(dst_h);
102+
103+ if (pattern == RemapPattern::LENS_DISTORTION ) {
104+ const float cx = dst_wf * 0 .5f ;
105+ const float cy = dst_hf * 0 .5f ;
106+ const float max_radius = 0 .5f * std::sqrt (dst_wf * dst_wf + dst_hf * dst_hf);
107+ const float inv_max_r2 = 1 .0f / (max_radius * max_radius + 1e-6f );
108+ const float k1 = 0 .08f ;
109+ const float k2 = 0 .01f ;
110+ for (int y = 0 ; y < mapX.rows ; ++y) {
111+ auto * mx = mapX.ptr <float >(y);
112+ auto * my = mapY.ptr <float >(y);
113+ for (int x = 0 ; x < mapX.cols ; ++x) {
114+ const float xf = static_cast <float >(x);
115+ const float yf = static_cast <float >(y);
116+ const float dx = xf - cx;
117+ const float dy = yf - cy;
118+ const float r2 = (dx * dx + dy * dy) * inv_max_r2;
119+ const float r4 = r2 * r2;
120+ const float scale = 1 .0f + k1 * r2 + k2 * r4;
121+ const float src_x = ((xf * sx) - cx) * scale + cx;
122+ const float src_y = ((yf * sy) - cy) * scale + cy;
123+ // cv::remap expects subpixel coordinates; (x+0.5)*scale-0.5
124+ // is the standard convention, but here src_x/src_y already
125+ // represent destination-to-source mapping coordinates and
126+ // are used directly to match openvx-mark's convention.
127+ mx[x] = src_x;
128+ my[x] = src_y;
129+ }
130+ }
131+ } else { // RANDOM_OFFSETS
132+ // Seed a dedicated, deterministic RNG for this pattern so offsets are
133+ // reproducible regardless of how many other benchmarks ran before
134+ // this one. Mix the original global seed with dimensions and a
135+ // pattern tag so the map is stable across run order.
136+ const uint64_t seed = seed_ + static_cast <uint64_t >(src_w) * 73856093u +
137+ static_cast <uint64_t >(src_h) * 19349663u +
138+ static_cast <uint64_t >(dst_w) * 83492791u +
139+ static_cast <uint64_t >(dst_h) * 4256233u +
140+ 0x9e3779b97f4a7c15ULL ;
141+ std::mt19937_64 pattern_rng (seed);
142+ std::uniform_real_distribution<float > dist (-2 .0f , 2 .0f );
143+ const float src_wf = static_cast <float >(src_w);
144+ const float src_hf = static_cast <float >(src_h);
145+ for (int y = 0 ; y < mapX.rows ; ++y) {
146+ auto * mx = mapX.ptr <float >(y);
147+ auto * my = mapY.ptr <float >(y);
148+ for (int x = 0 ; x < mapX.cols ; ++x) {
149+ float rx = (x + 0 .5f ) * sx - 0 .5f + dist (pattern_rng);
150+ float ry = (y + 0 .5f ) * sy - 0 .5f + dist (pattern_rng);
151+ // Clamp to valid source bounds so border handling stays
152+ // consistent across implementations and runs.
153+ mx[x] = std::max (-0 .5f , std::min (rx, src_wf - 0 .5f ));
154+ my[x] = std::max (-0 .5f , std::min (ry, src_hf - 0 .5f ));
155+ }
83156 }
84157 }
85158}
0 commit comments