26 #include <linux/videodev2.h>
28 #include <opencv2/imgproc/imgproc.hpp>
37 case 3:
return cv::Mat(src.
height, src.
width, CV_8UC3, src.
buf->data());
38 case 2:
return cv::Mat(src.
height, src.
width, CV_8UC2, src.
buf->data());
39 case 1:
return cv::Mat(src.
height, src.
width, CV_8UC1, src.
buf->data());
40 default:
LFATAL(
"Unsupported RawImage format");
47 inline void rgb565pixrgb(
unsigned short rgb565,
unsigned char & r,
unsigned char & g,
unsigned char & b)
49 r = ((((rgb565 >> 11) & 0x1F) * 527) + 23) >> 6;
50 g = ((((rgb565 >> 5) & 0x3F) * 259) + 33) >> 6;
51 b = (((rgb565 & 0x1F) * 527) + 23) >> 6;
54 class rgb565ToGray :
public cv::ParallelLoopBody
57 rgb565ToGray(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
58 inImg(inputImage), outImg(outImage)
60 inlinesize = inputImage.cols * 2;
61 outlinesize = outw * 1;
64 virtual void operator()(
const cv::Range & range)
const
66 for (
int j = range.start; j < range.end; ++j)
68 int const inoff = j * inlinesize;
69 int const outoff = j * outlinesize;
71 for (
int i = 0; i < inImg.cols; ++i)
73 int const in = inoff + i * 2;
74 int const out = outoff + i;
75 unsigned short const rgb565 = ((
unsigned short)(inImg.data[in + 0]) << 8) | inImg.data[in + 1];
76 unsigned char r, g, b;
77 rgb565pixrgb(rgb565, r, g, b);
78 int lum = int(r + g + b) / 3;
85 cv::Mat
const & inImg;
86 unsigned char * outImg;
87 int inlinesize, outlinesize;
90 class rgb565ToBGR :
public cv::ParallelLoopBody
93 rgb565ToBGR(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
94 inImg(inputImage), outImg(outImage)
96 inlinesize = inputImage.cols * 2;
97 outlinesize = outw * 3;
100 virtual void operator()(
const cv::Range & range)
const
102 for (
int j = range.start; j < range.end; ++j)
104 int const inoff = j * inlinesize;
105 int const outoff = j * outlinesize;
107 for (
int i = 0; i < inImg.cols; ++i)
109 int const in = inoff + i * 2;
110 int const out = outoff + i * 3;
111 unsigned short const rgb565 = ((
unsigned short)(inImg.data[in + 0]) << 8) | inImg.data[in + 1];
113 unsigned char r, g, b; rgb565pixrgb(rgb565, r, g, b);
122 cv::Mat
const & inImg;
123 unsigned char * outImg;
124 int inlinesize, outlinesize;
127 class rgb565ToRGB :
public cv::ParallelLoopBody
130 rgb565ToRGB(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
131 inImg(inputImage), outImg(outImage)
133 inlinesize = inputImage.cols * 2;
134 outlinesize = outw * 3;
137 virtual void operator()(
const cv::Range & range)
const
139 for (
int j = range.start; j < range.end; ++j)
141 int const inoff = j * inlinesize;
142 int const outoff = j * outlinesize;
144 for (
int i = 0; i < inImg.cols; ++i)
146 int const in = inoff + i * 2;
147 int const out = outoff + i * 3;
148 unsigned short const rgb565 = ((
unsigned short)(inImg.data[in + 0]) << 8) | inImg.data[in + 1];
150 unsigned char r, g, b; rgb565pixrgb(rgb565, r, g, b);
159 cv::Mat
const & inImg;
160 unsigned char * outImg;
161 int inlinesize, outlinesize;
164 class rgb565ToRGBA :
public cv::ParallelLoopBody
167 rgb565ToRGBA(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
168 inImg(inputImage), outImg(outImage)
170 inlinesize = inputImage.cols * 2;
171 outlinesize = outw * 4;
174 virtual void operator()(
const cv::Range & range)
const
176 for (
int j = range.start; j < range.end; ++j)
178 int const inoff = j * inlinesize;
179 int const outoff = j * outlinesize;
181 for (
int i = 0; i < inImg.cols; ++i)
183 int const in = inoff + i * 2;
184 int const out = outoff + i * 4;
185 unsigned short const rgb565 = ((
unsigned short)(inImg.data[in + 0]) << 8) | inImg.data[in + 1];
187 unsigned char r, g, b; rgb565pixrgb(rgb565, r, g, b);
191 outImg[out + 3] = (
unsigned char)(255);
197 cv::Mat
const & inImg;
198 unsigned char * outImg;
199 int inlinesize, outlinesize;
203 #ifdef JEVOIS_PLATFORM
207 class yuyvToGrayNEON :
public cv::ParallelLoopBody
210 yuyvToGrayNEON(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
211 inImg(inputImage), outImg(outImage)
213 inlinesize = inputImage.cols * 2;
214 outlinesize = outw * 1;
215 initer = (inputImage.cols >> 4);
218 virtual void operator()(
const cv::Range & range)
const
220 unsigned char const * inptr = inImg.data + range.start * inlinesize;
221 unsigned char * outptr = outImg + range.start * outlinesize;
223 for (
int j = range.start; j < range.end; ++j)
225 unsigned char const * ip = inptr;
unsigned char * op = outptr;
227 for (
int i = 0; i < initer; ++i)
229 uint8x16x2_t
const pixels = vld2q_u8(ip);
230 vst1q_u8(op, pixels.val[0]);
233 inptr += inlinesize; outptr += outlinesize;
238 cv::Mat
const & inImg;
239 unsigned char * outImg;
240 int inlinesize, outlinesize, initer;
253 case V4L2_PIX_FMT_GREY:
return rawimgcv;
255 case V4L2_PIX_FMT_YUYV:
258 result = cv::Mat(cv::Size(src.
width, src.
height), CV_8UC1);
259 cv::parallel_for_(cv::Range(0, src.
height), yuyvToGrayNEON(rawimgcv, result.data, result.cols));
261 cv::cvtColor(rawimgcv, result, cv::COLOR_YUV2GRAY_YUYV);
265 case V4L2_PIX_FMT_SRGGB8: cv::cvtColor(rawimgcv, result, cv::COLOR_BayerBG2GRAY);
return result;
267 case V4L2_PIX_FMT_RGB565:
268 result = cv::Mat(cv::Size(src.
width, src.
height), CV_8UC1);
269 cv::parallel_for_(cv::Range(0, src.
height), rgb565ToGray(rawimgcv, result.data, result.cols));
272 case V4L2_PIX_FMT_MJPEG:
LFATAL(
"MJPEG not supported");
274 case V4L2_PIX_FMT_BGR24: cv::cvtColor(rawimgcv, result, cv::COLOR_BGR2GRAY);
return result;
276 case V4L2_PIX_FMT_RGB24: cv::cvtColor(rawimgcv, result, cv::COLOR_RGB2GRAY);
return result;
278 LFATAL(
"Unknown RawImage pixel format");
289 case V4L2_PIX_FMT_BGR24:
return rawimgcv;
291 case V4L2_PIX_FMT_YUYV: cv::cvtColor(rawimgcv, result, cv::COLOR_YUV2BGR_YUYV);
return result;
292 case V4L2_PIX_FMT_GREY: cv::cvtColor(rawimgcv, result, cv::COLOR_GRAY2BGR);
return result;
293 case V4L2_PIX_FMT_SRGGB8: cv::cvtColor(rawimgcv, result, cv::COLOR_BayerBG2BGR);
return result;
295 case V4L2_PIX_FMT_RGB565:
296 result = cv::Mat(cv::Size(src.
width, src.
height), CV_8UC3);
297 cv::parallel_for_(cv::Range(0, src.
height), rgb565ToBGR(rawimgcv, result.data, result.cols));
300 case V4L2_PIX_FMT_MJPEG:
LFATAL(
"MJPEG not supported");
301 case V4L2_PIX_FMT_RGB24: cv::cvtColor(rawimgcv, result, cv::COLOR_RGB2BGR);
return result;
303 LFATAL(
"Unknown RawImage pixel format");
314 case V4L2_PIX_FMT_RGB24:
return rawimgcv;
316 case V4L2_PIX_FMT_YUYV: cv::cvtColor(rawimgcv, result, cv::COLOR_YUV2RGB_YUYV);
return result;
317 case V4L2_PIX_FMT_GREY: cv::cvtColor(rawimgcv, result, cv::COLOR_GRAY2RGB);
return result;
318 case V4L2_PIX_FMT_SRGGB8: cv::cvtColor(rawimgcv, result, cv::COLOR_BayerBG2RGB);
return result;
320 case V4L2_PIX_FMT_RGB565:
321 result = cv::Mat(cv::Size(src.
width, src.
height), CV_8UC3);
322 cv::parallel_for_(cv::Range(0, src.
height), rgb565ToRGB(rawimgcv, result.data, result.cols));
325 case V4L2_PIX_FMT_MJPEG:
LFATAL(
"MJPEG not supported");
326 case V4L2_PIX_FMT_BGR24: cv::cvtColor(rawimgcv, result, cv::COLOR_BGR2RGB);
return result;
328 LFATAL(
"Unknown RawImage pixel format");
339 case V4L2_PIX_FMT_YUYV: cv::cvtColor(rawimgcv, result, cv::COLOR_YUV2RGBA_YUYV);
return result;
341 case V4L2_PIX_FMT_GREY: cv::cvtColor(rawimgcv, result, cv::COLOR_GRAY2RGBA);
return result;
343 case V4L2_PIX_FMT_SRGGB8:
348 cv::cvtColor(rawimgcv, fixme, cv::COLOR_BayerBG2RGB);
349 cv::cvtColor(fixme, result, cv::COLOR_RGB2RGBA);
353 case V4L2_PIX_FMT_RGB565:
354 result = cv::Mat(cv::Size(src.
width, src.
height), CV_8UC4);
355 cv::parallel_for_(cv::Range(0, src.
height), rgb565ToRGBA(rawimgcv, result.data, result.cols));
358 case V4L2_PIX_FMT_MJPEG:
LFATAL(
"MJPEG not supported");
360 case V4L2_PIX_FMT_BGR24: cv::cvtColor(rawimgcv, result, cv::COLOR_BGR2RGBA);
return result;
362 case V4L2_PIX_FMT_RGB24: cv::cvtColor(rawimgcv, result, cv::COLOR_RGB2RGBA);
return result;
364 LFATAL(
"Unknown RawImage pixel format");
370 if (img.
bytesperpix() != 2)
LFATAL(
"Can only byteswap images with 2 bytes/pixel");
372 #ifdef JEVOIS_PLATFORM
374 unsigned int ncores = 4;
375 size_t const nbc = img.
bytesize() / ncores;
376 unsigned char * ptr = img.
pixelsw<
unsigned char>();
381 std::vector<std::future<void> > fut;
382 for (
unsigned int core = 0; core < ncores-1; ++core)
384 unsigned char * cptr = ptr + core * nbc;
385 for (size_t i = 0; i < nbc; i += 16) vst1q_u8(cptr + i, vrev16q_u8(vld1q_u8(cptr + i)));
390 for (
size_t i = (ncores-1) * nbc; i < sz; i += 16) vst1q_u8(ptr + i, vrev16q_u8(vld1q_u8(ptr + i)));
393 for (
auto & f : fut) f.get();
397 unsigned short * ptr = img.
pixelsw<
unsigned short>();
398 for (
size_t i = 0; i < sz; ++i) ptr[i] = __builtin_bswap16(ptr[i]);
405 if (src.
fmt != dest.
fmt)
LFATAL(
"src and dest must have the same pixel format");
406 if (x < 0 || y < 0 || x + src.width > dest.
width || y + src.
height > dest.
height)
407 LFATAL(
"src does not fit within dest");
411 unsigned char const * sptr = src.
pixels<
unsigned char>();
412 unsigned char * dptr = dest.
pixelsw<
unsigned char>() + (x + y * dest.
width) * bpp;
413 size_t const srclinelen = src.
width * bpp;
414 size_t const dstlinelen = dest.
width * bpp;
416 for (
unsigned int j = 0; j < src.
height; ++j)
418 memcpy(dptr, sptr, srclinelen);
428 if (src.
fmt != dest.
fmt)
LFATAL(
"src and dest must have the same pixel format");
429 if (x < 0 || y < 0 || x + w > src.
width || y +
h > src.
height)
LFATAL(
"roi not within source image");
430 if (dx < 0 || dy < 0 || dx + w > dest.
width || dy +
h > dest.
height)
LFATAL(
"roi not within dest image");
434 unsigned char const * sptr = src.
pixels<
unsigned char>() + (x + y * src.
width) * bpp;
435 unsigned char * dptr = dest.
pixelsw<
unsigned char>() + (dx + dy * dest.
width) * bpp;
436 size_t const srclinelen = src.
width * bpp;
437 size_t const dstlinelen = dest.
width * bpp;
439 for (
unsigned int j = 0; j <
h; ++j)
441 memcpy(dptr, sptr, w * bpp);
450 if (x + src.cols >
int(dest.
width) || y + src.rows >
int(dest.
height))
LFATAL(
"src does not fit within dest");
453 unsigned char const * sptr = src.data;
454 unsigned char * dptr = dest.
pixelsw<
unsigned char>() + (x + y * dest.
width) * bpp;
455 size_t const dststride = (dest.
width - src.cols) * bpp;
457 for (
int j = 0; j < src.rows; ++j)
459 for (
int i = 0; i < src.cols; ++i) { *dptr++ = *sptr++; *dptr++ = 0x80; }
468 unsigned short *
const dptr = img.
pixelsw<
unsigned short>();
469 int const w = int(img.
width);
471 if (rad == 0) {
if (img.
coordsOk(cx, cy)) dptr[cx + w * cy] = col;
return; }
473 int const intrad = rad;
474 for (
int y = -intrad; y <= intrad; ++y)
476 int bound = int(std::sqrt(
float(intrad * intrad - y * y)));
477 for (
int x = -bound; x <= bound; ++x)
478 if (img.
coordsOk(x + cx, y + cy)) dptr[x + cx + w * (y + cy)] = col;
484 unsigned int thick,
unsigned int col)
491 int bound1 = rad, bound2;
493 for (
unsigned int dy = 1; dy <= rad; ++dy)
496 bound1 = int(0.4999
F + sqrtf(rad*rad - dy*dy));
497 for (
int dx = bound1; dx <= bound2; ++dx)
511 inline bool isZero(
double a)
512 {
return (a < 0.0001 && a > -0.0001 ); }
514 bool clipT(
double num,
double denom,
double & tE,
double & tL)
516 if (isZero(denom))
return (num <= 0.0);
518 double t = num / denom;
521 if (t > tL)
return false;
524 if (t < tE)
return false;
537 if (x1 < wxmin && x2 < wxmin)
return false;
538 if (x1 >= wxmax && x2 >= wxmax)
return false;
539 if (y1 < wymin && y2 < wymin)
return false;
540 if (y1 >= wymax && y2 >= wymax)
return false;
542 int const toofar = 5000;
543 if (x1 < -toofar || x1 > toofar || y1 < -toofar || y1 > toofar)
return false;
544 if (x2 < -toofar || x2 > toofar || y2 < -toofar || y2 > toofar)
return false;
548 double dx = x2 - x1, dy = y2 - y1;
549 if (isZero(dx) && isZero(dy))
return true;
551 double tE = 0.0, tL = 1.0;
553 if (clipT(wxmin - x1, dx, tE, tL) && clipT(x1 - wxmax, -dx, tE, tL) &&
554 clipT(wymin - y1, dy, tE, tL) && clipT(y1 - wymax, -dy, tE, tL))
556 if (tL < 1) { x2 = x1 + tL * dx; y2 = y1 + tL * dy; }
557 if (tE > 0) { x1 += tE * dx; y1 += tE * dy; }
568 if (thick > 500)
LFATAL(
"Thickness " << thick <<
" too large. Did you mistakenly swap thick and col?");
576 int const dx = x2 - x1;
int const ax = std::abs(dx) << 1;
int const sx = dx < 0 ? -1 : 1;
577 int const dy = y2 - y1;
int const ay = std::abs(dy) << 1;
int const sy = dy < 0 ? -1 : 1;
583 int d = ay - (ax >> 1);
589 if (d >= 0) { y += sy; d -= ax; }
595 int d = ax - (ay >> 1);
600 if (d >= 0) { x += sx; d -= ay; }
608 unsigned int thick,
unsigned int col)
634 unsigned int const imgw = img.
width;
635 unsigned short * b = img.
pixelsw<
unsigned short>() + x + y * imgw;
638 unsigned int const offy = (
h-1) * imgw;
639 for (
unsigned int xx = 0; xx < w; ++xx) { b[xx] = col; b[xx + offy] = col; }
642 unsigned int const offx = w-1;
643 for (
unsigned int yy = 0; yy <
h * imgw; yy += imgw) { b[yy] = col; b[yy + offx] = col; }
656 unsigned int const stride = img.
width - w;
657 unsigned short * b = img.
pixelsw<
unsigned short>() + x + y * img.
width;
659 for (
unsigned int yy = 0; yy <
h; ++yy)
661 for (
unsigned int xx = 0; xx < w; ++xx) *b++ = col;
672 extern const unsigned char font10x20[95][200];
673 extern const unsigned char font11x22[95][242];
674 extern const unsigned char font12x22[95][264];
675 extern const unsigned char font14x26[95][364];
676 extern const unsigned char font15x28[95][420];
677 extern const unsigned char font16x29[95][464];
678 extern const unsigned char font20x38[95][760];
679 extern const unsigned char font5x7[95][35];
680 extern const unsigned char font6x10[95][60];
681 extern const unsigned char font7x13[95][91];
699 int len = int(strlen(txt));
700 unsigned int const imgw = img.
width;
702 int fontw, fonth;
unsigned char const * fontptr;
717 default:
LFATAL(
"Invalid font");
721 if (y < 0 || y + fonth >
int(img.
height))
return;
722 while (x + len * fontw >
int(imgw)) { --len;
if (len <= 0)
return; }
729 unsigned short * b = img.
pixelsw<
unsigned short>() + x + y * imgw;
731 for (
int i = 0; i < len; ++i)
733 int idx = txt[i] - 32;
if (idx >= 95) idx = 0;
734 unsigned char const * ptr = fontptr + fontw * fonth * idx;
735 unsigned short * bb = b;
736 for (
int yy = 0; yy < fonth; ++yy)
739 for (
int xx = 0; xx < fontw; ++xx)
if (*ptr++) ++bb;
else *bb++ = col;
749 unsigned char * b = img.
pixelsw<
unsigned char>() + x + y * imgw;
751 for (
int i = 0; i < len; ++i)
753 int idx = txt[i] - 32;
if (idx >= 95) idx = 0;
754 unsigned char const * ptr = fontptr + fontw * fonth * idx;
755 unsigned char * bb = b;
756 for (
int yy = 0; yy < fonth; ++yy)
759 for (
int xx = 0; xx < fontw; ++xx)
if (*ptr++) ++bb;
else *bb++ = col;
768 LFATAL(
"Sorry, only 1 and 2 bytes/pixel images are supported for now");
775 class bgrToBayer :
public cv::ParallelLoopBody
778 bgrToBayer(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
779 inImg(inputImage), outImg(outImage)
781 inlinesize = inputImage.cols * 3;
782 outlinesize = outw * 1;
785 virtual void operator()(
const cv::Range & range)
const
787 for (
int j = range.start; j < range.end; ++j)
789 int const inoff = j * inlinesize;
790 int const outoff = j * outlinesize;
792 for (
int i = 0; i < inImg.cols; i += 2)
794 int const in = inoff + i * 3;
795 int const out = outoff + i;
797 if ( (j & 1) == 0) { outImg[out + 0] = inImg.data[in + 2]; outImg[out + 1] = inImg.data[in + 4]; }
798 else { outImg[out + 0] = inImg.data[in + 1]; outImg[out + 1] = inImg.data[in + 3]; }
804 cv::Mat
const & inImg;
805 unsigned char * outImg;
806 int inlinesize, outlinesize;
812 if (src.type() != CV_8UC3)
814 if (dst.
fmt != V4L2_PIX_FMT_SRGGB8)
LFATAL(
"dst format must be V4L2_PIX_FMT_SRGGB8");
815 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
817 cv::parallel_for_(cv::Range(0, src.rows), bgrToBayer(src, dst.
pixelsw<
unsigned char>(), dst.
width));
824 class rgbToBayer :
public cv::ParallelLoopBody
827 rgbToBayer(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
828 inImg(inputImage), outImg(outImage)
830 inlinesize = inputImage.cols * 3;
831 outlinesize = outw * 1;
834 virtual void operator()(
const cv::Range & range)
const
836 for (
int j = range.start; j < range.end; ++j)
838 int const inoff = j * inlinesize;
839 int const outoff = j * outlinesize;
841 for (
int i = 0; i < inImg.cols; i += 2)
843 int const in = inoff + i * 3;
844 int const out = outoff + i;
846 if ( (j & 1) == 0) { outImg[out + 0] = inImg.data[in + 0]; outImg[out + 1] = inImg.data[in + 4]; }
847 else { outImg[out + 0] = inImg.data[in + 1]; outImg[out + 1] = inImg.data[in + 5]; }
853 cv::Mat
const & inImg;
854 unsigned char * outImg;
855 int inlinesize, outlinesize;
861 if (src.type() != CV_8UC3)
863 if (dst.
fmt != V4L2_PIX_FMT_SRGGB8)
LFATAL(
"dst format must be V4L2_PIX_FMT_SRGGB8");
864 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
866 cv::parallel_for_(cv::Range(0, src.rows), rgbToBayer(src, dst.
pixelsw<
unsigned char>(), dst.
width));
873 class grayToBayer :
public cv::ParallelLoopBody
876 grayToBayer(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
877 inImg(inputImage), outImg(outImage)
879 inlinesize = inputImage.cols * 1;
880 outlinesize = outw * 1;
883 virtual void operator()(
const cv::Range & range)
const
885 for (
int j = range.start; j < range.end; ++j)
887 int const inoff = j * inlinesize;
888 int const outoff = j * outlinesize;
890 memcpy(&outImg[outoff], &inImg.data[inoff], inlinesize);
895 cv::Mat
const & inImg;
896 unsigned char * outImg;
897 int inlinesize, outlinesize;
903 if (src.type() != CV_8UC1)
905 if (dst.
fmt != V4L2_PIX_FMT_SRGGB8)
LFATAL(
"dst format must be V4L2_PIX_FMT_SRGGB8");
906 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
908 cv::parallel_for_(cv::Range(0, src.rows), grayToBayer(src, dst.
pixelsw<
unsigned char>(), dst.
width));
915 class rgbaToBayer :
public cv::ParallelLoopBody
918 rgbaToBayer(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
919 inImg(inputImage), outImg(outImage)
921 inlinesize = inputImage.cols * 4;
922 outlinesize = outw * 1;
925 virtual void operator()(
const cv::Range & range)
const
927 for (
int j = range.start; j < range.end; ++j)
929 int const inoff = j * inlinesize;
930 int const outoff = j * outlinesize;
932 for (
int i = 0; i < inImg.cols; i += 2)
934 int const in = inoff + i * 4;
935 int const out = outoff + i;
937 if ( (j & 1) == 0) { outImg[out + 0] = inImg.data[in + 0]; outImg[out + 1] = inImg.data[in + 5]; }
938 else { outImg[out + 0] = inImg.data[in + 1]; outImg[out + 1] = inImg.data[in + 6]; }
944 cv::Mat
const & inImg;
945 unsigned char * outImg;
946 int inlinesize, outlinesize;
952 if (src.type() != CV_8UC4)
954 if (dst.
fmt != V4L2_PIX_FMT_SRGGB8)
LFATAL(
"dst format must be V4L2_PIX_FMT_SRGGB8");
955 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
957 cv::parallel_for_(cv::Range(0, src.rows), rgbaToBayer(src, dst.
pixelsw<
unsigned char>(), dst.
width));
964 class bgrToYUYV :
public cv::ParallelLoopBody
967 bgrToYUYV(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
968 inImg(inputImage), outImg(outImage)
970 inlinesize = inputImage.cols * 3;
971 outlinesize = outw * 2;
974 virtual void operator()(
const cv::Range & range)
const
976 for (
int j = range.start; j < range.end; ++j)
978 int const inoff = j * inlinesize;
979 int const outoff = j * outlinesize;
981 for (
int i = 0; i < inImg.cols; i += 2)
983 int mc = inoff + i * 3;
984 unsigned char const B1 = inImg.data[mc + 0];
985 unsigned char const G1 = inImg.data[mc + 1];
986 unsigned char const R1 = inImg.data[mc + 2];
987 unsigned char const B2 = inImg.data[mc + 3];
988 unsigned char const G2 = inImg.data[mc + 4];
989 unsigned char const R2 = inImg.data[mc + 5];
991 float const Y1 = (0.257F * R1) + (0.504
F * G1) + (0.098F * B1) + 16.0
F;
993 float const U1 = -(0.148F * R1) - (0.291
F * G1) + (0.439F * B1) + 128.0
F;
994 float const Y2 = (0.257F * R2) + (0.504
F * G2) + (0.098F * B2) + 16.0
F;
995 float const V2 = (0.439F * R2) - (0.368
F * G2) - (0.071F * B2) + 128.0
F;
1000 outImg[mc + 1] = U1;
1001 outImg[mc + 2] = Y2;
1002 outImg[mc + 3] = V2;
1008 cv::Mat
const & inImg;
1009 unsigned char * outImg;
1010 int inlinesize, outlinesize;
1016 if (src.type() != CV_8UC3)
1018 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1019 if (
int(dst.
width) != src.cols ||
int(dst.
height) < src.rows)
LFATAL(
"src and dst dims must match");
1021 cv::parallel_for_(cv::Range(0, src.rows), bgrToYUYV(src, dst.
pixelsw<
unsigned char>(), dst.
width));
1028 if (src.type() != CV_8UC3)
1030 dst = cv::Mat(src.rows, src.cols, CV_8UC2);
1032 cv::parallel_for_(cv::Range(0, src.rows), bgrToYUYV(src, dst.data, dst.cols));
1038 if (src.type() != CV_8UC3)
1040 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1041 if (x + src.cols >
int(dst.
width) || y + src.rows >
int(dst.
height))
LFATAL(
"src does not fit within dst");
1043 cv::parallel_for_(cv::Range(0, src.rows), bgrToYUYV(src, dst.
pixelsw<
unsigned char>() +
1050 class rgbToYUYV :
public cv::ParallelLoopBody
1053 rgbToYUYV(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
1054 inImg(inputImage), outImg(outImage)
1056 inlinesize = inputImage.cols * 3;
1057 outlinesize = outw * 2;
1060 virtual void operator()(
const cv::Range & range)
const
1062 for (
int j = range.start; j < range.end; ++j)
1064 int const inoff = j * inlinesize;
1065 int const outoff = j * outlinesize;
1067 for (
int i = 0; i < inImg.cols; i += 2)
1069 int mc = inoff + i * 3;
1070 unsigned char const R1 = inImg.data[mc + 0];
1071 unsigned char const G1 = inImg.data[mc + 1];
1072 unsigned char const B1 = inImg.data[mc + 2];
1073 unsigned char const R2 = inImg.data[mc + 3];
1074 unsigned char const G2 = inImg.data[mc + 4];
1075 unsigned char const B2 = inImg.data[mc + 5];
1077 float const Y1 = (0.257F * R1) + (0.504
F * G1) + (0.098F * B1) + 16.0
F;
1079 float const U1 = -(0.148F * R1) - (0.291
F * G1) + (0.439F * B1) + 128.0
F;
1080 float const Y2 = (0.257F * R2) + (0.504
F * G2) + (0.098F * B2) + 16.0
F;
1081 float const V2 = (0.439F * R2) - (0.368
F * G2) - (0.071F * B2) + 128.0
F;
1084 mc = outoff + i * 2;
1085 outImg[mc + 0] = Y1;
1086 outImg[mc + 1] = U1;
1087 outImg[mc + 2] = Y2;
1088 outImg[mc + 3] = V2;
1094 cv::Mat
const & inImg;
1095 unsigned char * outImg;
1096 int inlinesize, outlinesize;
1102 if (src.type() != CV_8UC3)
1104 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1105 if (
int(dst.
width) != src.cols ||
int(dst.
height) < src.rows)
LFATAL(
"src and dst dims must match");
1107 cv::parallel_for_(cv::Range(0, src.rows), rgbToYUYV(src, dst.
pixelsw<
unsigned char>(), dst.
width));
1114 if (src.type() != CV_8UC3)
1116 dst = cv::Mat(src.rows, src.cols, CV_8UC2);
1118 cv::parallel_for_(cv::Range(0, src.rows), rgbToYUYV(src, dst.data, dst.cols));
1124 if (src.type() != CV_8UC3)
1126 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1127 if (x + src.cols >
int(dst.
width) || y + src.rows >
int(dst.
height))
LFATAL(
"src does not fit within dst");
1129 cv::parallel_for_(cv::Range(0, src.rows), rgbToYUYV(src, dst.
pixelsw<
unsigned char>() +
1136 class grayToYUYV :
public cv::ParallelLoopBody
1139 grayToYUYV(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
1140 inImg(inputImage), outImg(outImage)
1142 inlinesize = inputImage.cols * 1;
1143 outlinesize = outw * 2;
1146 virtual void operator()(
const cv::Range & range)
const
1148 for (
int j = range.start; j < range.end; ++j)
1150 int const inoff = j * inlinesize;
1151 int const outoff = j * outlinesize;
1153 for (
int i = 0; i < inImg.cols; ++i)
1156 unsigned char const G = inImg.data[mc + 0];
1158 mc = outoff + i * 2;
1160 outImg[mc + 1] = 0x80;
1166 cv::Mat
const & inImg;
1167 unsigned char * outImg;
1168 int inlinesize, outlinesize;
1174 if (src.type() != CV_8UC1)
1176 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1177 if (
int(dst.
width) != src.cols ||
int(dst.
height) < src.rows)
LFATAL(
"src and dst dims must match");
1179 cv::parallel_for_(cv::Range(0, src.rows), grayToYUYV(src, dst.
pixelsw<
unsigned char>(), dst.
width));
1186 if (src.type() != CV_8UC1)
1188 dst = cv::Mat(src.rows, src.cols, CV_8UC2);
1190 cv::parallel_for_(cv::Range(0, src.rows), grayToYUYV(src, dst.data, dst.cols));
1196 class rgbaToYUYV :
public cv::ParallelLoopBody
1199 rgbaToYUYV(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
1200 inImg(inputImage), outImg(outImage)
1202 inlinesize = inputImage.cols * 4;
1203 outlinesize = outw * 2;
1206 virtual void operator()(
const cv::Range & range)
const
1208 for (
int j = range.start; j < range.end; ++j)
1210 int const inoff = j * inlinesize;
1211 int const outoff = j * outlinesize;
1213 for (
int i = 0; i < inImg.cols; i += 2)
1215 int mc = inoff + i * 4;
1216 unsigned char const R1 = inImg.data[mc + 0];
1217 unsigned char const G1 = inImg.data[mc + 1];
1218 unsigned char const B1 = inImg.data[mc + 2];
1219 unsigned char const R2 = inImg.data[mc + 4];
1220 unsigned char const G2 = inImg.data[mc + 5];
1221 unsigned char const B2 = inImg.data[mc + 6];
1223 float const Y1 = (0.257F * R1) + (0.504
F * G1) + (0.098F * B1) + 16.0
F;
1224 float const U1 = -(0.148F * R1) - (0.291
F * G1) + (0.439F * B1) + 128.0
F;
1225 float const Y2 = (0.257F * R2) + (0.504
F * G2) + (0.098F * B2) + 16.0
F;
1226 float const V2 = (0.439F * R2) - (0.368
F * G2) - (0.071F * B2) + 128.0
F;
1228 mc = outoff + i * 2;
1229 outImg[mc + 0] = Y1;
1230 outImg[mc + 1] = U1;
1231 outImg[mc + 2] = Y2;
1232 outImg[mc + 3] = V2;
1238 cv::Mat
const & inImg;
1239 unsigned char * outImg;
1240 int inlinesize, outlinesize;
1246 if (src.type() != CV_8UC4)
1248 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1249 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
1251 cv::parallel_for_(cv::Range(0, src.rows), rgbaToYUYV(src, dst.
pixelsw<
unsigned char>(), dst.
width));
1258 if (src.type() != CV_8UC4)
1260 dst = cv::Mat(src.rows, src.cols, CV_8UC2);
1262 cv::parallel_for_(cv::Range(0, src.rows), rgbaToYUYV(src, dst.data, dst.cols));
1268 if (src.type() != CV_8UC3)
1270 if (
int(dst.
width) != src.cols ||
int(dst.
height) < src.rows)
LFATAL(
"src and dst dims must match");
1277 case V4L2_PIX_FMT_SRGGB8: convertCvBGRtoBayer(src, dst);
break;
1278 case V4L2_PIX_FMT_YUYV: convertCvBGRtoYUYV(src, dst);
break;
1279 case V4L2_PIX_FMT_GREY: cv::cvtColor(src, dstcv, cv::COLOR_BGR2GRAY);
break;
1280 case V4L2_PIX_FMT_RGB565: cv::cvtColor(src, dstcv, cv::COLOR_BGR2BGR565);
break;
1283 case V4L2_PIX_FMT_RGB24: cv::cvtColor(src, dstcv, cv::COLOR_BGR2RGB);
break;
1291 if (src.type() != CV_8UC3)
1293 if (
int(dst.
width) != src.cols ||
int(dst.
height) < src.rows)
LFATAL(
"src and dst dims must match");
1300 case V4L2_PIX_FMT_SRGGB8: convertCvRGBtoBayer(src, dst);
break;
1301 case V4L2_PIX_FMT_YUYV: convertCvRGBtoYUYV(src, dst);
break;
1302 case V4L2_PIX_FMT_GREY: cv::cvtColor(src, dstcv, cv::COLOR_RGB2GRAY);
break;
1303 case V4L2_PIX_FMT_RGB565: cv::cvtColor(src, dstcv, cv::COLOR_RGB2BGR565);
break;
1305 case V4L2_PIX_FMT_BGR24: cv::cvtColor(src, dstcv, cv::COLOR_RGB2BGR);
break;
1314 if (src.type() != CV_8UC4)
1316 if (dst.
fmt != V4L2_PIX_FMT_GREY)
LFATAL(
"dst must have pixel type V4L2_PIX_FMT_GREY");
1317 int const w = src.cols,
h = src.rows;
1318 if (
int(dst.
width) < w ||
int(dst.
height) < 4 *
h)
LFATAL(
"dst must be at least as wide and 4x as tall as src");
1320 unsigned char const * sptr = src.data;
unsigned char * dptr = dst.
pixelsw<
unsigned char>();
1321 int const stride = int(dst.
width) - w;
1324 std::vector<std::future<void> > fut;
1325 for (
int i = 0; i < 3; ++i) fut.push_back(
jevois::async([&](
int offset) {
1326 unsigned char const * s = sptr + offset; unsigned char * d = dptr + offset * w * h;
1327 for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { *d++ = *s; s += 4; } d += stride; } }, i));
1329 unsigned char const * s = sptr + 3;
unsigned char * d = dptr + 3 * w *
h;
1330 for (
int y = 0; y <
h; ++y) {
for (
int x = 0; x < w; ++x) { *d++ = *s; s += 4; } d += stride; }
1333 for (
auto & f : fut) f.get();
1339 if (src.type() != CV_8UC4)
1341 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
1347 case V4L2_PIX_FMT_SRGGB8: convertCvRGBAtoBayer(src, dst);
break;
1348 case V4L2_PIX_FMT_YUYV: convertCvRGBAtoYUYV(src, dst);
break;
1349 case V4L2_PIX_FMT_GREY: cv::cvtColor(src, dstcv, cv::COLOR_RGBA2GRAY);
break;
1350 case V4L2_PIX_FMT_RGB565: cv::cvtColor(src, dstcv, cv::COLOR_BGRA2BGR565);
break;
1352 case V4L2_PIX_FMT_BGR24: cv::cvtColor(src, dstcv, cv::COLOR_RGBA2BGR);
break;
1353 case V4L2_PIX_FMT_RGB24: cv::cvtColor(src, dstcv, cv::COLOR_RGBA2RGB);
break;
1361 if (src.type() != CV_8UC1)
1363 if (
int(dst.
width) != src.cols ||
int(dst.
height) != src.rows)
LFATAL(
"src and dst dims must match");
1369 case V4L2_PIX_FMT_SRGGB8: convertCvGRAYtoBayer(src, dst);
break;
1370 case V4L2_PIX_FMT_YUYV: convertCvGRAYtoYUYV(src, dst);
break;
1372 case V4L2_PIX_FMT_RGB565: cv::cvtColor(src, dstcv, cv::COLOR_GRAY2BGR565);
break;
1374 case V4L2_PIX_FMT_BGR24: cv::cvtColor(src, dstcv, cv::COLOR_GRAY2BGR);
break;
1375 case V4L2_PIX_FMT_RGB24: cv::cvtColor(src, dstcv, cv::COLOR_GRAY2RGB);
break;
1383 class hflipYUYV :
public cv::ParallelLoopBody
1386 hflipYUYV(
unsigned char * outImage,
size_t outw) :
1387 outImg(outImage), linesize(outw * 2)
1390 virtual void operator()(
const cv::Range & range)
const
1392 for (
int j = range.start; j < range.end; ++j)
1394 int const off = j * linesize;
1396 for (
int i = 0; i < linesize / 2; i += 4)
1398 unsigned char * ptr1 = outImg + off + i;
1399 unsigned char * ptr2 = outImg + off + linesize - 4 - i;
1400 std::swap(ptr1[0], ptr2[2]);
1401 std::swap(ptr1[1], ptr2[1]);
1402 std::swap(ptr1[2], ptr2[0]);
1403 std::swap(ptr1[3], ptr2[3]);
1409 unsigned char * outImg;
1418 if (img.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"img format must be V4L2_PIX_FMT_YUYV");
1419 cv::parallel_for_(cv::Range(0, img.
height), hflipYUYV(img.
pixelsw<
unsigned char>(), img.
width));
1426 class bayerToYUYV :
public cv::ParallelLoopBody
1429 bayerToYUYV(cv::Mat
const & inputImage,
unsigned char * outImage,
size_t outw) :
1430 inImg(inputImage), outImg(outImage)
1432 inlinesize = inputImage.cols;
1433 outlinesize = outw * 2;
1436 virtual void operator()(
const cv::Range & range)
const
1438 uint16x8_t
const masklo = vdupq_n_u16(255);
1440 const uint8x8_t u8_zero = vdup_n_u8(0);
1441 const uint16x8_t u16_rounding = vdupq_n_u16(128);
1442 const int16x8_t s16_rounding = vdupq_n_s16(128);
1443 const int8x16_t s8_rounding = vdupq_n_s8(128);
1445 for (
int j = range.start; j < range.end; ++j)
1447 int const inoff = j * inlinesize;
1448 int const outoff = j * outlinesize;
1450 unsigned char const * bayer = inImg.data + inoff;
1451 unsigned char const * bayer_end = bayer + inlinesize;
1452 int const bayer_step = inlinesize;
1453 unsigned char * dst = outImg + outoff;
1460 for( ; bayer <= bayer_end - 18; bayer += 14, dst += 28 )
1462 uint16x8_t r0 = vld1q_u16((
const ushort*)bayer);
1463 uint16x8_t r1 = vld1q_u16((
const ushort*)(bayer + bayer_step));
1464 uint16x8_t r2 = vld1q_u16((
const ushort*)(bayer + bayer_step*2));
1466 uint16x8_t b1 = vaddq_u16(vandq_u16(r0, masklo), vandq_u16(r2, masklo));
1467 uint16x8_t nextb1 = vextq_u16(b1, b1, 1);
1468 uint16x8_t b0 = vaddq_u16(b1, nextb1);
1470 uint8x8x2_t bb = vzip_u8(vrshrn_n_u16(b0, 2), vrshrn_n_u16(nextb1, 1));
1471 pix.val[2] = vcombine_u8(bb.val[0], bb.val[1]);
1473 uint16x8_t g0 = vaddq_u16(vshrq_n_u16(r0, 8), vshrq_n_u16(r2, 8));
1474 uint16x8_t g1 = vandq_u16(r1, masklo);
1475 g0 = vaddq_u16(g0, vaddq_u16(g1, vextq_u16(g1, g1, 1)));
1476 g1 = vextq_u16(g1, g1, 1);
1478 uint8x8x2_t gg = vzip_u8(vrshrn_n_u16(g0, 2), vmovn_u16(g1));
1479 pix.val[1] = vcombine_u8(gg.val[0], gg.val[1]);
1481 r0 = vshrq_n_u16(r1, 8);
1482 r1 = vaddq_u16(r0, vextq_u16(r0, r0, 1));
1484 uint8x8x2_t rr = vzip_u8(vmovn_u16(r0), vrshrn_n_u16(r1, 1));
1485 pix.val[0] = vcombine_u8(rr.val[0], rr.val[1]);
1490 uint8x8_t high_r = vget_high_u8(pix.val[2]);
1491 uint8x8_t low_r = vget_low_u8(pix.val[2]);
1492 uint8x8_t high_g = vget_high_u8(pix.val[1]);
1493 uint8x8_t low_g = vget_low_u8(pix.val[1]);
1494 uint8x8_t high_b = vget_high_u8(pix.val[0]);
1495 uint8x8_t low_b = vget_low_u8(pix.val[0]);
1496 int16x8_t signed_high_r = vreinterpretq_s16_u16(vaddl_u8(high_r, u8_zero));
1497 int16x8_t signed_low_r = vreinterpretq_s16_u16(vaddl_u8(low_r, u8_zero));
1498 int16x8_t signed_high_g = vreinterpretq_s16_u16(vaddl_u8(high_g, u8_zero));
1499 int16x8_t signed_low_g = vreinterpretq_s16_u16(vaddl_u8(low_g, u8_zero));
1500 int16x8_t signed_high_b = vreinterpretq_s16_u16(vaddl_u8(high_b, u8_zero));
1501 int16x8_t signed_low_b = vreinterpretq_s16_u16(vaddl_u8(low_b, u8_zero));
1507 uint8x8_t scalar = vdup_n_u8(76);
1510 int16x8_t signed_scalar = vdupq_n_s16(-43);
1513 uint8x16x3_t pixel_yuv;
1518 high_y = vmull_u8(high_r, scalar);
1519 low_y = vmull_u8(low_r, scalar);
1521 high_u = vmulq_s16(signed_high_r, signed_scalar);
1522 low_u = vmulq_s16(signed_low_r, signed_scalar);
1524 signed_scalar = vdupq_n_s16(127);
1525 high_v = vmulq_s16(signed_high_r, signed_scalar);
1526 low_v = vmulq_s16(signed_low_r, signed_scalar);
1528 scalar = vdup_n_u8(150);
1529 high_y = vmlal_u8(high_y, high_g, scalar);
1530 low_y = vmlal_u8(low_y, low_g, scalar);
1532 signed_scalar = vdupq_n_s16(-84);
1533 high_u = vmlaq_s16(high_u, signed_high_g, signed_scalar);
1534 low_u = vmlaq_s16(low_u, signed_low_g, signed_scalar);
1536 signed_scalar = vdupq_n_s16(-106);
1537 high_v = vmlaq_s16(high_v, signed_high_g, signed_scalar);
1538 low_v = vmlaq_s16(low_v, signed_low_g, signed_scalar);
1540 scalar = vdup_n_u8(29);
1541 high_y = vmlal_u8(high_y, high_b, scalar);
1542 low_y = vmlal_u8(low_y, low_b, scalar);
1544 signed_scalar = vdupq_n_s16(127);
1545 high_u = vmlaq_s16(high_u, signed_high_b, signed_scalar);
1546 low_u = vmlaq_s16(low_u, signed_low_b, signed_scalar);
1548 signed_scalar = vdupq_n_s16(-21);
1549 high_v = vmlaq_s16(high_v, signed_high_b, signed_scalar);
1550 low_v = vmlaq_s16(low_v, signed_low_b, signed_scalar);
1554 high_y = vaddq_u16(high_y, u16_rounding);
1555 low_y = vaddq_u16(low_y, u16_rounding);
1557 high_u = vaddq_s16(high_u, s16_rounding);
1558 low_u = vaddq_s16(low_u, s16_rounding);
1560 high_v = vaddq_s16(high_v, s16_rounding);
1561 low_v = vaddq_s16(low_v, s16_rounding);
1563 pixel_yuv.val[0] = vcombine_u8(vqshrn_n_u16(low_y, 8), vqshrn_n_u16(high_y, 8));
1565 u = vcombine_s8(vqshrn_n_s16(low_u, 8), vqshrn_n_s16(high_u, 8));
1567 v = vcombine_s8(vqshrn_n_s16(low_v, 8), vqshrn_n_s16(high_v, 8));
1569 u = vaddq_s8(u, s8_rounding);
1570 pixel_yuv.val[1] = vreinterpretq_u8_s8(u);
1572 v = vaddq_s8(v, s8_rounding);
1573 pixel_yuv.val[2] = vreinterpretq_u8_s8(v);
1578 vst3q_u8(dst, pixel_yuv);
1584 cv::Mat
const & inImg;
1585 unsigned char * outImg;
1586 int inlinesize, outlinesize;
1595 if (src.
fmt != V4L2_PIX_FMT_SRGGB8)
LFATAL(
"src format must be V4L2_PIX_FMT_SRGGB8");
1596 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1601 #ifdef FIXME__ARM_NEON__
1603 cv::parallel_for_(cv::Range(0, cvsrc.rows), bayerToYUYV(cvsrc, dst.
pixelsw<
unsigned char>(), dst.
width));
1607 cv::cvtColor(cvsrc, xx, cv::COLOR_BayerBG2BGR);
1608 cv::parallel_for_(cv::Range(0, xx.rows), bgrToYUYV(xx, cvdst.data, cvdst.cols));
1615 if (src.
fmt != V4L2_PIX_FMT_GREY)
LFATAL(
"src format must be V4L2_PIX_FMT_GREY");
1616 if (dst.
fmt != V4L2_PIX_FMT_YUYV)
LFATAL(
"dst format must be V4L2_PIX_FMT_YUYV");
1620 convertCvGRAYtoYUYV(cvsrc, dst);
1628 if (newdims.width == img.cols && newdims.height == img.rows)
1630 else if (newdims.width > img.cols || newdims.height > img.rows)
1631 cv::resize(img, scaled, newdims, 0, 0, cv::INTER_LINEAR);
1633 cv::resize(img, scaled, newdims, 0, 0, cv::INTER_AREA);