43 std::vector<vsi_nn_tensor_attr_t>
const & attrs,
44 std::vector<cv::Rect> & crops)
46 bool const detail = details::get();
48 cv::Scalar m = mean::get();
49 cv::Scalar sd = stdev::get();
50 if (sd[0] == 0.0 || sd[1] == 0.0 || sd[2] == 0.0)
LFATAL(
"stdev cannot be zero");
51 float sc = scale::get();
52 if (sc == 0.0F)
LFATAL(
"Scale cannot be zero");
54 std::vector<cv::Mat> blobs;
size_t bnum = 0;
55 for (vsi_nn_tensor_attr_t
const & attr : attrs)
62 std::string prefix;
if (detail) prefix =
"Blob " + std::to_string(bnum) +
": ";
65 unsigned int bw = bsiz.width, bh = bsiz.height;
66 if (bw == 1 || bw == 3 || bh == 1 || bh == 3)
68 "; did you swap NHWC vs NCHW in your intensors specification?");
77 roi.x = (img.cols - bw) / 2;
78 roi.y = (img.rows - bh) / 2;
83 crop.x = (img.cols - bw) / 2;
84 crop.y = (img.rows - bh) / 2;
87 DETAILS(
"Letterbox %dx%d @ %d,%d", bw, bh, crop.x, crop.y);
95 crop.width = img.cols;
96 crop.height = img.rows;
101 cv::InterpolationFlags interpflags;
102 switch (interp::get())
104 case jevois::dnn::preprocessor::InterpMode::Linear: interpflags = cv::INTER_LINEAR;
break;
105 case jevois::dnn::preprocessor::InterpMode::Cubic: interpflags = cv::INTER_CUBIC;
break;
106 case jevois::dnn::preprocessor::InterpMode::Area: interpflags = cv::INTER_AREA;
break;
107 case jevois::dnn::preprocessor::InterpMode::Lanczos4: interpflags = cv::INTER_LANCZOS4;
break;
108 default: interpflags = cv::INTER_NEAREST;
111 cv::resize(blob, blob, bsiz, 0.0, 0.0, interpflags);
112 DETAILS(
"Resize to %dx%d%s", blob.cols, blob.rows, letterbox::get() ?
"" :
" (stretch)");
117 bool swapped =
false;
118 if (swaprb && attr.dtype.fmt == VSI_NN_DIM_FMT_NHWC)
120 switch (blob.channels())
122 case 3: cv::cvtColor(blob, blob, cv::COLOR_RGB2BGR); swapped =
true;
break;
123 case 4: cv::cvtColor(blob, blob, cv::COLOR_RGBA2BGRA); swapped =
true;
break;
130 if (swaprb && swapped ==
false) { std::swap(m[0], m[2]); std::swap(sd[0], sd[2]); }
135 unsigned int const bt = blob.depth();
136 bool const uniformsd = (sd[0] == sd[1] && sd[1] == sd[2]);
137 bool const uniformmean = (m[0] == m[1] && m[1] == m[2]);
138 bool const unitsd = (uniformsd && sd[0] > 0.99 && sd[0] < 1.01);
141 if (bt == CV_8U && tt == CV_8U && attr.dtype.qnt_type == VSI_NN_QNT_TYPE_NONE)
143 DETAILS(
"8U to 8U direct no quantization");
144 DETAILS(
"(ignoring mean, scale, stdev)");
148 else if (unitsd && attr.dtype.qnt_type == VSI_NN_QNT_TYPE_DFP)
150 if (bt == CV_8U && tt == CV_8S)
154 cv::Mat newblob(bsiz, CV_MAKETYPE(tt, blob.channels()));
156 uint8_t
const * bdata = (uint8_t
const *)blob.data;
157 uint32_t
const sz = blob.total() * blob.channels();
158 int8_t * data = (int8_t *)newblob.data;
159 if (attr.dtype.fl > 7)
LFATAL(
"Invalid DFP fl value " << attr.dtype.fl <<
": must be in [0..7]");
160 int const shift = 8 - attr.dtype.fl;
161 for (uint32_t i = 0; i < sz; ++i) *data++ = *bdata++ >> shift;
163 DETAILS(
"8U to 8S DFP:%d: bit-shift >> %d", attr.dtype.fl, shift);
166 if (m[0] > 1.0 || m[1] > 1.0 || m[2] > 1.0)
169 DETAILS(
"Subtract mean [%.2f %.2f %.2f]", m[0], m[1], m[2]);
173 else if (bt == CV_8U && tt == CV_16S)
177 int const fl = attr.dtype.fl;
178 uint8_t
const * bdata = (uint8_t
const *)blob.data;
179 uint32_t
const sz = blob.total() * blob.channels();
180 if (fl > 15)
LFATAL(
"Invalid DFP fl value " << fl <<
": must be in [0..15]");
183 cv::Mat newblob(bsiz, CV_MAKETYPE(tt, blob.channels()));
184 int16_t * data = (int16_t *)newblob.data;
185 int const shift = fl - 8;
186 for (uint32_t i = 0; i < sz; ++i) *data++ = int16_t(*bdata++) << shift;
188 DETAILS(
"8U to 16S DFP:%d: bit-shift << %d", fl, shift);
192 cv::Mat newblob(bsiz, CV_MAKETYPE(tt, blob.channels()));
193 int16_t * data = (int16_t *)newblob.data;
194 int const shift = 8 - fl;
195 for (uint32_t i = 0; i < sz; ++i) *data++ = int16_t(*bdata++) >> shift;
197 DETAILS(
"8U to 16S DFP:%d: bit-shift >> %d", fl, shift);
201 blob.convertTo(blob, tt);
202 DETAILS(
"8U to 16S DFP:%d: direct conversion", fl);
205 if (m[0] > 1.0 || m[1] > 1.0 || m[2] > 1.0)
208 DETAILS(
"Subtract mean [%.2f %.2f %.2f]", m[0], m[1], m[2]);
215 if (notdone && uniformsd && uniformmean)
218 switch (attr.dtype.qnt_type)
220 case VSI_NN_QNT_TYPE_AFFINE_ASYMMETRIC: qs = attr.dtype.scale; zp = attr.dtype.zero_point; notdone =
false;
break;
221 case VSI_NN_QNT_TYPE_DFP: qs = 1.0 / (1 << attr.dtype.fl); zp = 0.0; notdone =
false;
break;
225 if (notdone ==
false)
227 if (qs == 0.0)
LFATAL(
"Quantizer scale must not be zero");
228 double alpha = sc / (sd[0] * qs);
229 double beta = zp - m[0] * alpha;
230 if (alpha > 0.99 && alpha < 1.01) alpha = 1.0;
231 if (beta > -0.51 && beta < 0.51) beta = 0.0;
233 if (alpha == 1.0 && beta == 0.0 && bt == tt)
234 DETAILS(
"No conversion needed");
238 blob.convertTo(newblob, tt, alpha, beta);
243 if (m[0])
DETAILS2(
"Subtract mean [%.2f %.2f %.2f]", m[0], m[1], m[2]);
244 if (sd[0] != 1.0)
DETAILS2(
"Divide by stdev [%f %f %f]", sd[0], sd[1], sd[2]);
245 if (sc != 1.0F)
DETAILS2(
"Multiply by scale %f (=1/%.2f)", sc, 1.0/sc);
246 if (qs != 1.0F)
DETAILS2(
"Divide by quantizer scale %f (=1/%.2f)", qs, 1.0/qs);
247 if (zp)
DETAILS2(
"Add quantizer zero-point %.2f", zp);
248 if (alpha == 1.0 && beta == 0.0)
DETAILS2(
"Summary: out = in");
249 else if (alpha == 1.0)
DETAILS2(
"Summary: out = in%+f", beta);
250 else if (beta == 0.0)
DETAILS2(
"Summary: out = in*%f", alpha);
251 else DETAILS2(
"Summary: out = in*%f%+f", alpha, beta);
260 blob.convertTo(blob, CV_32F);
264 if (m != cv::Scalar())
267 DETAILS(
"Subtract mean [%.2f %.2f %.2f]", m[0], m[1], m[2]);
270 if (sd != cv::Scalar(1.0F, 1.0F, 1.0F))
272 if (sd[0] == 0.0F || sd[1] == 0.0F || sd[2] == 0.0F)
LFATAL(
"Parameter stdev cannot contain any zero");
273 if (sc != 1.0F && sc != 0.0F)
276 DETAILS(
"Divide stdev by scale %f (=1/%.2f)", sc, 1.0/sc);
279 DETAILS(
"Divide by stdev [%f %f %f]", sd[0], sd[1], sd[2]);
284 DETAILS(
"Multiply by scale %f (=1/%.2f)", sc, 1.0/sc);
287 if (tt == CV_16F || tt == CV_64F)
289 blob.convertTo(blob, tt);
292 else if (tt != CV_32F)
302 int const nch = blob.channels();
312 vsi_nn_dim_fmt_e fmt = attr.dtype.fmt;
313 if (fmt == VSI_NN_DIM_FMT_AUTO)
315 if (attr.size[0] > attr.size[2]) fmt = VSI_NN_DIM_FMT_NCHW;
316 else fmt = VSI_NN_DIM_FMT_NHWC;
321 case VSI_NN_DIM_FMT_NCHW:
324 int dims[] = { 1, nch, blob.rows, blob.cols };
325 cv::Mat newblob(4, dims, tt);
329 for (
int i = 0; i < nch; ++i) nbc[i] = cv::Mat(blob.rows, blob.cols, tt, newblob.ptr(0, i));
332 std::swap(nbc[0], nbc[2]);
337 cv::split(blob, nbc);
338 DETAILS(
"Split channels (NHWC->NCHW)");
345 case VSI_NN_DIM_FMT_NHWC:
348 blob = blob.reshape(1, { 1, bsiz.height, bsiz.width, 3 });
352 default:
LFATAL(
"Can only handle NCHW or NHWC intensors shapes");
357 default:
LFATAL(
"Can only handle input images with 1, 3, or 4 channels");
363 blobs.emplace_back(blob);
364 crops.emplace_back(crop);
373 if (bnum >= numin::get())
break;