Browse Source

drawing api and stb_image (#2913)

* drawing api

* add drawing test

* yuv420sp drawing

* enable simpleocv in webassembly build
tags/20210525
nihui GitHub 5 years ago
parent
commit
49f3e1ea09
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 16216 additions and 80 deletions
  1. +4
    -4
      .github/workflows/release.yml
  2. +3
    -3
      .github/workflows/web-assembly.yml
  3. +3
    -0
      .restyled.yaml
  4. +1
    -0
      CMakeLists.txt
  5. +6
    -4
      codeformat.sh
  6. +1
    -0
      src/CMakeLists.txt
  7. +52
    -0
      src/mat.h
  8. +1527
    -0
      src/mat_pixel_drawing.cpp
  9. +3911
    -0
      src/mat_pixel_drawing_font.h
  10. BIN
      src/mat_pixel_drawing_font.png
  11. +1
    -0
      src/platform.h.in
  12. +303
    -34
      src/simpleocv.cpp
  13. +195
    -35
      src/simpleocv.h
  14. +7762
    -0
      src/stb_image.h
  15. +1690
    -0
      src/stb_image_write.h
  16. +4
    -0
      tests/CMakeLists.txt
  17. +753
    -0
      tests/test_mat_pixel_drawing.cpp

+ 4
- 4
.github/workflows/release.yml View File

@@ -1279,7 +1279,7 @@ jobs:
source emsdk/emsdk_env.sh
mkdir build && cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install -DNCNN_VERSION_STRING="${{ needs.setup.outputs.VERSION }}" \
-DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF \
-DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF \
-DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_BENCHMARK=OFF ..
cmake --build . -j 2
cmake --build . --target install
@@ -1288,7 +1288,7 @@ jobs:
source emsdk/emsdk_env.sh
mkdir build-simd && cd build-simd
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install -DNCNN_VERSION_STRING="${{ needs.setup.outputs.VERSION }}" \
-DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF \
-DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF \
-DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_BENCHMARK=OFF ..
cmake --build . -j 2
cmake --build . --target install
@@ -1297,7 +1297,7 @@ jobs:
source emsdk/emsdk_env.sh
mkdir build-threads && cd build-threads
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install -DNCNN_VERSION_STRING="${{ needs.setup.outputs.VERSION }}" \
-DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF \
-DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF \
-DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_BENCHMARK=OFF ..
cmake --build . -j 2
cmake --build . --target install
@@ -1306,7 +1306,7 @@ jobs:
source emsdk/emsdk_env.sh
mkdir build-simd-threads && cd build-simd-threads
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=install -DNCNN_VERSION_STRING="${{ needs.setup.outputs.VERSION }}" \
-DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF \
-DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF \
-DNCNN_BUILD_TOOLS=OFF -DNCNN_BUILD_EXAMPLES=OFF -DNCNN_BUILD_BENCHMARK=OFF ..
cmake --build . -j 2
cmake --build . --target install


+ 3
- 3
.github/workflows/web-assembly.yml View File

@@ -25,7 +25,7 @@ jobs:
run: |
source emsdk/emsdk_env.sh
mkdir build-basic && cd build-basic
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=OFF -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake --build . -j 2
- name: test-basic
run: |
@@ -35,7 +35,7 @@ jobs:
run: |
source emsdk/emsdk_env.sh
mkdir build-simd && cd build-simd
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=OFF -DNCNN_OPENMP=OFF -DNCNN_SIMPLEOMP=OFF -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake --build . -j 2
- name: test-simd
run: |
@@ -45,7 +45,7 @@ jobs:
run: |
source emsdk/emsdk_env.sh
mkdir build-simd-omp && cd build-simd-omp
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake -DCMAKE_TOOLCHAIN_FILE=../emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DNCNN_THREADS=ON -DNCNN_OPENMP=ON -DNCNN_SIMPLEOMP=ON -DNCNN_SIMPLEOCV=ON -DNCNN_RUNTIME_CPU=OFF -DNCNN_SSE2=ON -DNCNN_AVX2=OFF -DNCNN_BUILD_TESTS=ON ..
cmake --build . -j 2
- name: test-simd-omp
run: |


+ 3
- 0
.restyled.yaml View File

@@ -7,6 +7,9 @@ pull_requests: true
commit_template: |
[skip ci] Restyled by ${restyler.name}

exclude:
- "src/stb_image*"

statuses:
differences: true
no_differences: true


+ 1
- 0
CMakeLists.txt View File

@@ -70,6 +70,7 @@ option(NCNN_PLATFORM_API "build with platform api candy" ON)
option(NCNN_PIXEL "convert and resize from/to image pixel" ON)
option(NCNN_PIXEL_ROTATE "rotate image pixel orientation" ON)
option(NCNN_PIXEL_AFFINE "warp affine image pixel" ON)
option(NCNN_PIXEL_DRAWING "draw basic figure and text" ON)
option(NCNN_CMAKE_VERBOSE "print verbose cmake messages" OFF)
option(NCNN_VULKAN "vulkan compute support" OFF)
option(NCNN_SYSTEM_GLSLANG "use system glslang library" OFF)


+ 6
- 4
codeformat.sh View File

@@ -2,10 +2,12 @@

# we run clang-format and astyle twice to get stable format output

find src/ tools/ tests/ examples/ benchmark/ python/ -type f -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' | grep -v python/pybind11 | xargs -i clang-format -i {}
astyle -n -r "benchmark/*.h,*.cpp,*.cc" "src/*.h,*.cpp,*.cc" "tests/*.h,*.cpp,*.cc" "tools/*.h,*.cpp,*.cc" "examples/*.h,*.cpp,*.cc"
find src/ tools/ tests/ examples/ benchmark/ python/ -type f -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' | grep -v python/pybind11 | grep -v stb_image | xargs -i clang-format -i {}
astyle -n -r "benchmark/*.h,*.cpp,*.cc" "tests/*.h,*.cpp,*.cc" "tools/*.h,*.cpp,*.cc" "examples/*.h,*.cpp,*.cc"
astyle -n -r "src/*.h,*.cpp,*.cc" --exclude=src/stb_image.h --exclude=src/stb_image_write.h
astyle -n -r "python/*.h,*.cpp,*.cc" --exclude=python/pybind11

find src/ tools/ tests/ examples/ benchmark/ python/ -type f -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' | grep -v python/pybind11 | xargs -i clang-format -i {}
astyle -n -r "benchmark/*.h,*.cpp,*.cc" "src/*.h,*.cpp,*.cc" "tests/*.h,*.cpp,*.cc" "tools/*.h,*.cpp,*.cc" "examples/*.h,*.cpp,*.cc"
find src/ tools/ tests/ examples/ benchmark/ python/ -type f -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' | grep -v python/pybind11 | grep -v stb_image | xargs -i clang-format -i {}
astyle -n -r "benchmark/*.h,*.cpp,*.cc" "tests/*.h,*.cpp,*.cc" "tools/*.h,*.cpp,*.cc" "examples/*.h,*.cpp,*.cc"
astyle -n -r "src/*.h,*.cpp,*.cc" --exclude=src/stb_image.h --exclude=src/stb_image_write.h
astyle -n -r "python/*.h,*.cpp,*.cc" --exclude=python/pybind11

+ 1
- 0
src/CMakeLists.txt View File

@@ -27,6 +27,7 @@ set(ncnn_SRCS
mat.cpp
mat_pixel.cpp
mat_pixel_affine.cpp
mat_pixel_drawing.cpp
mat_pixel_resize.cpp
mat_pixel_rotate.cpp
modelbin.cpp


+ 52
- 0
src/mat.h View File

@@ -601,6 +601,58 @@ NCNN_EXPORT void warpaffine_bilinear_c4(const unsigned char* src, int srcw, int
// image pixel bilinear warpaffine, convenient wrapper for yuv420sp(nv21/nv12), set -233 for transparent border color, the color YUV_ is little-endian encoded
NCNN_EXPORT void warpaffine_bilinear_yuv420sp(const unsigned char* src, int srcw, int srch, unsigned char* dst, int w, int h, const float* tm, int type = 0, unsigned int v = 0);
#endif // NCNN_PIXEL_AFFINE
#if NCNN_PIXEL_DRAWING
// draw rectangle, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
// draw rectangle with stride(bytes-per-row) parameter, set thickness -1 for filled rectangle, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_rectangle_c1(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c2(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c3(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
NCNN_EXPORT void draw_rectangle_c4(unsigned char* pixels, int w, int h, int stride, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
// draw rectangle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled rectangle, the color YUV_ is little-endian encoded
NCNN_EXPORT void draw_rectangle_yuv420sp(unsigned char* yuv420sp, int w, int h, int rx, int ry, int rw, int rh, unsigned int color, int thickness);
// draw circle, set thickness -1 for filled circle, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness);
// draw circle with stride(bytes-per-row) parameter, set thickness -1 for filled circle, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_circle_c1(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c2(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c3(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness);
NCNN_EXPORT void draw_circle_c4(unsigned char* pixels, int w, int h, int stride, int cx, int cy, int radius, unsigned int color, int thickness);
// draw circle, convenient wrapper for yuv420sp(nv21/nv12), set thickness -1 for filled circle, the color YUV_ is little-endian encoded
NCNN_EXPORT void draw_circle_yuv420sp(unsigned char* yuv420sp, int w, int h, int cx, int cy, int radius, unsigned int color, int thickness);
// draw line, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
// draw line with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_line_c1(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c2(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c3(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
NCNN_EXPORT void draw_line_c4(unsigned char* pixels, int w, int h, int stride, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
// draw line, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded
NCNN_EXPORT void draw_line_yuv420sp(unsigned char* yuv420sp, int w, int h, int x0, int y0, int x1, int y1, unsigned int color, int thickness);
// resolve text bounding box size
NCNN_EXPORT void get_text_drawing_size(const char* text, int fontpixelsize, int* w, int* h);
// draw ascii printables and newline, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color);
// draw ascii printables and newline with stride(bytes-per-row) parameter, the color RGBA is little-endian encoded
NCNN_EXPORT void draw_text_c1(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c2(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c3(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color);
NCNN_EXPORT void draw_text_c4(unsigned char* pixels, int w, int h, int stride, const char* text, int x, int y, int fontpixelsize, unsigned int color);
// draw ascii printables and newline, convenient wrapper for yuv420sp(nv21/nv12), the color YUV_ is little-endian encoded
NCNN_EXPORT void draw_text_yuv420sp(unsigned char* yuv420sp, int w, int h, const char* text, int x, int y, int fontpixelsize, unsigned int color);
#endif // NCNN_PIXEL_DRAWING

// type conversion
// convert float to half precision floating point


+ 1527
- 0
src/mat_pixel_drawing.cpp
File diff suppressed because it is too large
View File


+ 3911
- 0
src/mat_pixel_drawing_font.h
File diff suppressed because it is too large
View File


BIN
src/mat_pixel_drawing_font.png View File

Before After
Width: 20  |  Height: 3800  |  Size: 14 kB

+ 1
- 0
src/platform.h.in View File

@@ -26,6 +26,7 @@
#cmakedefine01 NCNN_PIXEL
#cmakedefine01 NCNN_PIXEL_ROTATE
#cmakedefine01 NCNN_PIXEL_AFFINE
#cmakedefine01 NCNN_PIXEL_DRAWING
#cmakedefine01 NCNN_VULKAN
#cmakedefine01 NCNN_RUNTIME_CPU
#cmakedefine01 NCNN_AVX2


+ 303
- 34
src/simpleocv.cpp View File

@@ -18,65 +18,197 @@

#include <stdio.h>

#define STB_IMAGE_IMPLEMENTATION
#define STBI_NO_THREAD_LOCALS
#define STBI_ONLY_JPEG
#define STBI_ONLY_PNG
#define STBI_ONLY_BMP
#define STBI_ONLY_PNM
#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

namespace cv {

Mat imread(const std::string& path, int flags)
{
(void)flags;
int desired_channels = 0;
if (flags == IMREAD_UNCHANGED)
{
desired_channels = 0;
}
else if (flags == IMREAD_GRAYSCALE)
{
desired_channels = 1;
}
else if (flags == IMREAD_COLOR)
{
desired_channels = 3;
}
else
{
// unknown flags
return Mat();
}

// read pgm/ppm
FILE* fp = fopen(path.c_str(), "rb");
if (!fp)
int w;
int h;
int c;
unsigned char* pixeldata = stbi_load(path.c_str(), &w, &h, &c, desired_channels);
if (!pixeldata)
{
// load failed
return Mat();
}

Mat m;
if (desired_channels)
{
c = desired_channels;
}

char magic[3];
int w, h;
int nscan = fscanf(fp, "%2s\n%d %d\n255\n", magic, &w, &h);
if (nscan == 3 && magic[0] == 'P' && (magic[1] == '5' || magic[1] == '6'))
// copy pixeldata to Mat
Mat img;
if (c == 1)
{
if (magic[1] == '5')
{
m.create(h, w, CV_8UC1);
}
else if (magic[1] == '6')
img.create(h, w, CV_8UC1);
}
else if (c == 3)
{
img.create(h, w, CV_8UC3);
}
else if (c == 4)
{
img.create(h, w, CV_8UC4);
}
else
{
// unexpected channels
stbi_image_free(pixeldata);
return Mat();
}

memcpy(img.data, pixeldata, w * h * c);

stbi_image_free(pixeldata);

// // resolve exif orientation
// {
// std::ifstream ifs;
// ifs.open(filename.c_str(), std::ifstream::in);
//
// if (ifs.good())
// {
// ExifReader exif_reader(ifs);
// if (exif_reader.parse())
// {
// ExifEntry_t e = exif_reader.getTag(ORIENTATION);
// int orientation = e.field_u16;
// if (orientation >= 1 && orientation <= 8)
// rotate_by_orientation(img, img, orientation);
// }
// }
//
// ifs.close();
// }

// rgb to bgr
if (c == 3)
{
uchar* p = img.data;
for (int i = 0; i < w * h; i++)
{
m.create(h, w, CV_8UC3);
std::swap(p[0], p[2]);
p += 3;
}
if (m.empty())
}
if (c == 4)
{
uchar* p = img.data;
for (int i = 0; i < w * h; i++)
{
fclose(fp);
return Mat();
std::swap(p[0], p[2]);
p += 4;
}

fread(m.data, 1, m.total(), fp);
}

fclose(fp);

return m;
return img;
}

void imwrite(const std::string& path, const Mat& m)
bool imwrite(const std::string& path, const Mat& m, const std::vector<int>& params)
{
// write pgm/ppm
FILE* fp = fopen(path.c_str(), "wb");
if (!fp)
return;
const char* _ext = strrchr(path.c_str(), '.');
if (!_ext)
{
// missing extension
return false;
}

std::string ext = _ext;
Mat img = m.clone();

if (m.channels() == 1)
// bgr to rgb
int c = 0;
if (img.type() == CV_8UC1)
{
fprintf(fp, "P5\n%d %d\n255\n", m.cols, m.rows);
c = 1;
}
else if (m.channels() == 3)
else if (img.type() == CV_8UC3)
{
fprintf(fp, "P6\n%d %d\n255\n", m.cols, m.rows);
c = 3;
uchar* p = img.data;
for (int i = 0; i < img.cols * img.rows; i++)
{
std::swap(p[0], p[2]);
p += 3;
}
}
else if (img.type() == CV_8UC4)
{
c = 4;
uchar* p = img.data;
for (int i = 0; i < img.cols * img.rows; i++)
{
std::swap(p[0], p[2]);
p += 4;
}
}
else
{
// unexpected image channels
return false;
}

bool success = false;

fwrite(m.data, 1, m.total(), fp);
if (ext == ".jpg" || ext == ".jpeg" || ext == ".JPG" || ext == ".JPEG")
{
int quality = 95;
for (size_t i = 0; i < params.size(); i += 2)
{
if (params[i] == IMWRITE_JPEG_QUALITY)
{
quality = params[i + 1];
break;
}
}
success = stbi_write_jpg(path.c_str(), img.cols, img.rows, c, img.data, quality);
}
else if (ext == ".png" || ext == ".PNG")
{
success = stbi_write_png(path.c_str(), img.cols, img.rows, c, img.data, 0);
}
else if (ext == ".bmp" || ext == ".BMP")
{
success = stbi_write_bmp(path.c_str(), img.cols, img.rows, c, img.data);
}
else
{
// unknown extension type
return false;
}

fclose(fp);
return success;
}

#if NCNN_PIXEL
@@ -120,6 +252,143 @@ void resize(const Mat& src, Mat& dst, const Size& size, float sw, float sh, int
}
#endif // NCNN_PIXEL

#if NCNN_PIXEL_DRAWING

void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness)
{
Rect rec;
rec.x = std::min(pt1.x, pt2.x);
rec.y = std::min(pt1.y, pt2.y);
rec.width = std::max(pt1.x, pt2.x) - rec.x;
rec.height = std::max(pt1.y, pt2.y) - rec.y;
rectangle(img, rec, color, thickness);
}

void rectangle(Mat& img, Rect rec, const Scalar& _color, int thickness)
{
unsigned int color = 0;
unsigned char* border_color = (unsigned char*)&color;

if (img.c == 1)
{
border_color[0] = _color[0];
ncnn::draw_rectangle_c1(img.data, img.cols, img.rows, rec.x, rec.y, rec.width, rec.height, color, thickness);
}
else if (img.c == 3)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
ncnn::draw_rectangle_c3(img.data, img.cols, img.rows, rec.x, rec.y, rec.width, rec.height, color, thickness);
}
else if (img.c == 4)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
border_color[3] = _color[3];
ncnn::draw_rectangle_c4(img.data, img.cols, img.rows, rec.x, rec.y, rec.width, rec.height, color, thickness);
}
}

void circle(Mat& img, Point center, int radius, const Scalar& _color, int thickness)
{
unsigned int color = 0;
unsigned char* border_color = (unsigned char*)&color;

if (img.c == 1)
{
border_color[0] = _color[0];
ncnn::draw_circle_c1(img.data, img.cols, img.rows, center.x, center.y, radius, color, thickness);
}
else if (img.c == 3)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
ncnn::draw_circle_c3(img.data, img.cols, img.rows, center.x, center.y, radius, color, thickness);
}
else if (img.c == 4)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
border_color[3] = _color[3];
ncnn::draw_circle_c4(img.data, img.cols, img.rows, center.x, center.y, radius, color, thickness);
}
}

void line(Mat& img, Point p0, Point p1, const Scalar& _color, int thickness)
{
unsigned int color = 0;
unsigned char* border_color = (unsigned char*)&color;

if (img.c == 1)
{
border_color[0] = _color[0];
ncnn::draw_line_c1(img.data, img.cols, img.rows, p0.x, p0.y, p1.x, p1.y, color, thickness);
}
else if (img.c == 3)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
ncnn::draw_line_c3(img.data, img.cols, img.rows, p0.x, p0.y, p1.x, p1.y, color, thickness);
}
else if (img.c == 4)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
border_color[3] = _color[3];
ncnn::draw_line_c4(img.data, img.cols, img.rows, p0.x, p0.y, p1.x, p1.y, color, thickness);
}
}

void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar _color, int thickness)
{
const int fontpixelsize = 20 * fontScale;

unsigned int color = 0;
unsigned char* border_color = (unsigned char*)&color;

if (img.c == 1)
{
border_color[0] = _color[0];
ncnn::draw_text_c1(img.data, img.cols, img.rows, text.c_str(), org.x, org.y - fontpixelsize * 2, fontpixelsize, color);
}
else if (img.c == 3)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
ncnn::draw_text_c3(img.data, img.cols, img.rows, text.c_str(), org.x, org.y - fontpixelsize * 2, fontpixelsize, color);
}
else if (img.c == 4)
{
border_color[0] = _color[0];
border_color[1] = _color[1];
border_color[2] = _color[2];
border_color[3] = _color[3];
ncnn::draw_text_c4(img.data, img.cols, img.rows, text.c_str(), org.x, org.y - fontpixelsize * 2, fontpixelsize, color);
}
}

Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine)
{
const int fontpixelsize = 20 * fontScale;

int w;
int h;
ncnn::get_text_drawing_size(text.c_str(), fontpixelsize, &w, &h);

*baseLine = 0;

return Size(w, h);
}

#endif // NCNN_PIXEL_DRAWING

} // namespace cv

#endif // NCNN_SIMPLEOCV

+ 195
- 35
src/simpleocv.h View File

@@ -19,6 +19,9 @@

#if NCNN_SIMPLEOCV

#include <limits.h>
#include <string.h>
#include "allocator.h"
#include "mat.h"

#if defined(_MSC_VER) || defined(__GNUC__)
@@ -28,24 +31,125 @@
#undef max
#endif

#ifndef NCNN_XADD
using ncnn::NCNN_XADD;
#endif

typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;

enum
{
CV_LOAD_IMAGE_UNCHANGED = -1,
CV_LOAD_IMAGE_GRAYSCALE = 0,
CV_LOAD_IMAGE_COLOR = 1,
};

enum
{
CV_IMWRITE_JPEG_QUALITY = 1
};

// minimal opencv style data structure implementation
namespace cv {

struct NCNN_EXPORT Size
template<typename _Tp>
static inline _Tp saturate_cast(int v)
{
return _Tp(v);
}
template<>
inline uchar saturate_cast<uchar>(int v)
{
return (uchar)((unsigned)v <= UCHAR_MAX ? v : v > 0 ? UCHAR_MAX : 0);
}

template<typename _Tp>
struct Scalar_
{
Size()
Scalar_()
{
v[0] = 0;
v[1] = 0;
v[2] = 0;
v[3] = 0;
}
Scalar_(_Tp _v0)
{
v[0] = _v0;
v[1] = 0;
v[2] = 0;
v[3] = 0;
}
Scalar_(_Tp _v0, _Tp _v1, _Tp _v2)
{
v[0] = _v0;
v[1] = _v1;
v[2] = _v2;
v[3] = 0;
}
Scalar_(_Tp _v0, _Tp _v1, _Tp _v2, _Tp _v3)
{
v[0] = _v0;
v[1] = _v1;
v[2] = _v2;
v[3] = _v3;
}

const _Tp operator[](const int i) const
{
return v[i];
}

_Tp operator[](const int i)
{
return v[i];
}

_Tp v[4];
};

typedef Scalar_<uchar> Scalar;

template<typename _Tp>
struct Point_
{
Point_()
: x(0), y(0)
{
}
Point_(_Tp _x, _Tp _y)
: x(_x), y(_y)
{
}

_Tp x;
_Tp y;
};

typedef Point_<int> Point;
typedef Point_<float> Point2f;

template<typename _Tp>
struct Size_
{
Size_()
: width(0), height(0)
{
}
Size(int _w, int _h)
Size_(_Tp _w, _Tp _h)
: width(_w), height(_h)
{
}

int width;
int height;
_Tp width;
_Tp height;
};

typedef Size_<int> Size;
typedef Size_<float> Size2f;

template<typename _Tp>
struct Rect_
{
@@ -57,6 +161,10 @@ struct Rect_
: x(_x), y(_y), width(_w), height(_h)
{
}
Rect_(Point_<_Tp> _p, Size_<_Tp> _size)
: x(_p.x), y(_p.y), width(_size.width), height(_size.height)
{
}

_Tp x;
_Tp y;
@@ -111,25 +219,6 @@ static inline Rect_<_Tp> operator|(const Rect_<_Tp>& a, const Rect_<_Tp>& b)
typedef Rect_<int> Rect;
typedef Rect_<float> Rect2f;

template<typename _Tp>
struct Point_
{
Point_()
: x(0), y(0)
{
}
Point_(_Tp _x, _Tp _y)
: x(_x), y(_y)
{
}

_Tp x;
_Tp y;
};

typedef Point_<int> Point;
typedef Point_<float> Point2f;

#define CV_8UC1 1
#define CV_8UC3 3
#define CV_8UC4 4
@@ -194,6 +283,23 @@ struct NCNN_EXPORT Mat
return *this;
}

Mat& operator=(const Scalar& s)
{
if (total() > 0)
{
uchar* p = data;
for (int i = 0; i < cols * rows; i++)
{
for (int j = 0; j < c; j++)
{
*p++ = s[j];
}
}
}

return *this;
}

void create(int _rows, int _cols, int flags)
{
release();
@@ -206,8 +312,8 @@ struct NCNN_EXPORT Mat
{
// refcount address must be aligned, so we expand totalsize here
size_t totalsize = (total() + 3) >> 2 << 2;
data = (unsigned char*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount));
refcount = (int*)(((unsigned char*)data) + totalsize);
data = (uchar*)ncnn::fastMalloc(totalsize + (int)sizeof(*refcount));
refcount = (int*)(((uchar*)data) + totalsize);
*refcount = 1;
}
}
@@ -251,21 +357,38 @@ struct NCNN_EXPORT Mat
return c;
}

int type() const
{
return c;
}

size_t total() const
{
return cols * rows * c;
}

const unsigned char* ptr(int y) const
const uchar* ptr(int y) const
{
return data + y * cols * c;
}

unsigned char* ptr(int y)
uchar* ptr(int y)
{
return data + y * cols * c;
}

template<typename _Tp>
const _Tp* ptr(int y) const
{
return (const _Tp*)data + y * cols * c;
}

template<typename _Tp>
_Tp* ptr(int y)
{
return (_Tp*)data + y * cols * c;
}

// roi
Mat operator()(const Rect& roi) const
{
@@ -277,8 +400,8 @@ struct NCNN_EXPORT Mat
int sy = roi.y;
for (int y = 0; y < roi.height; y++)
{
const unsigned char* sptr = ptr(sy) + roi.x * c;
unsigned char* dptr = m.ptr(y);
const uchar* sptr = ptr(sy) + roi.x * c;
uchar* dptr = m.ptr(y);
memcpy(dptr, sptr, roi.width * c);
sy++;
}
@@ -286,7 +409,7 @@ struct NCNN_EXPORT Mat
return m;
}

unsigned char* data;
uchar* data;

// pointer to the reference counter;
// when points to user-allocated data, the pointer is NULL
@@ -298,15 +421,52 @@ struct NCNN_EXPORT Mat
int c;
};

#define CV_LOAD_IMAGE_GRAYSCALE 1
#define CV_LOAD_IMAGE_COLOR 3
NCNN_EXPORT Mat imread(const std::string& path, int flags);
NCNN_EXPORT void imwrite(const std::string& path, const Mat& m);
enum ImreadModes
{
IMREAD_UNCHANGED = -1,
IMREAD_GRAYSCALE = 0,
IMREAD_COLOR = 1
};

NCNN_EXPORT Mat imread(const std::string& path, int flags = IMREAD_COLOR);

enum ImwriteFlags
{
IMWRITE_JPEG_QUALITY = 1
};

NCNN_EXPORT bool imwrite(const std::string& path, const Mat& m, const std::vector<int>& params = std::vector<int>());

#if NCNN_PIXEL
NCNN_EXPORT void resize(const Mat& src, Mat& dst, const Size& size, float sw = 0.f, float sh = 0.f, int flags = 0);
#endif // NCNN_PIXEL

#if NCNN_PIXEL_DRAWING

enum
{
FILLED = -1
};

NCNN_EXPORT void rectangle(Mat& img, Point pt1, Point pt2, const Scalar& color, int thickness = 1);

NCNN_EXPORT void rectangle(Mat& img, Rect rec, const Scalar& color, int thickness = 1);

NCNN_EXPORT void circle(Mat& img, Point center, int radius, const Scalar& color, int thickness = 1);

NCNN_EXPORT void line(Mat& img, Point p0, Point p1, const Scalar& color, int thickness = 1);

enum
{
FONT_HERSHEY_SIMPLEX = 0
};

NCNN_EXPORT void putText(Mat& img, const std::string& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1);

NCNN_EXPORT Size getTextSize(const std::string& text, int fontFace, double fontScale, int thickness, int* baseLine);

#endif // NCNN_PIXEL_DRAWING

} // namespace cv

#if defined(_MSC_VER) || defined(__GNUC__)


+ 7762
- 0
src/stb_image.h
File diff suppressed because it is too large
View File


+ 1690
- 0
src/stb_image_write.h
File diff suppressed because it is too large
View File


+ 4
- 0
tests/CMakeLists.txt View File

@@ -30,6 +30,10 @@ if(NCNN_PIXEL_AFFINE)
ncnn_add_test(mat_pixel_affine)
endif()

if(NCNN_PIXEL_DRAWING)
ncnn_add_test(mat_pixel_drawing)
endif()

if(NCNN_PIXEL_ROTATE)
ncnn_add_test(mat_pixel_rotate)
endif()


+ 753
- 0
tests/test_mat_pixel_drawing.cpp View File

@@ -0,0 +1,753 @@
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "mat.h"
#include "prng.h"

#include <string.h>

static struct prng_rand_t g_prng_rand_state;
#define SRAND(seed) prng_srand(seed, &g_prng_rand_state)
#define RAND() prng_rand(&g_prng_rand_state)

static int RandomInt(int a, int b)
{
float random = ((float)RAND()) / (float)uint64_t(-1); //RAND_MAX;
int diff = b - a;
float r = random * diff;
return a + (int)r;
}

static int RandomInt2(int a, int b)
{
float random = ((float)RAND()) / (float)uint64_t(-1); //RAND_MAX;
int diff = b - a;
float r = random * diff;
return (a + (int)r + 1) / 2 * 2;
}

static int test_mat_pixel_drawing_c1(int w, int h)
{
ncnn::Mat a(w, h, 1u, 1);
ncnn::Mat b(h, w, 1u, 1);

int _color = 0;
unsigned char* color = (unsigned char*)&_color;

// fill with color
color[0] = 255;
ncnn::draw_rectangle_c1(a, w, h, 0, 0, w, h, _color, -1);
ncnn::draw_rectangle_c1(b, h, w, 0, 0, h, w, _color, -1);

// draw rectangle
int rx = RandomInt(0, w);
int ry = RandomInt(0, h);
int rw = RandomInt(0, w - rx);
int rh = RandomInt(0, h - ry);
color[0] = 100;
ncnn::draw_rectangle_c1(a, w, h, rx, ry, rw, rh, _color, 3);
ncnn::draw_rectangle_c1(b, h, w, ry, rx, rh, rw, _color, 3);

// draw filled rectangle out of image
color[0] = 144;
ncnn::draw_rectangle_c1(a, w, h, w - 10, -10, 20, 30, _color, -1);
ncnn::draw_rectangle_c1(b, h, w, -10, w - 10, 30, 20, _color, -1);
color[0] = 166;
ncnn::draw_rectangle_c1(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c1(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw rectangle out of image
color[0] = 44;
ncnn::draw_rectangle_c1(a, w, h, rx + w / 2, ry + h / 2, rw, rh, _color, 1);
ncnn::draw_rectangle_c1(b, h, w, ry + h / 2, rx + w / 2, rh, rw, _color, 1);
color[0] = 66;
ncnn::draw_rectangle_c1(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c1(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw filled circle
int cx = RandomInt(0, w);
int cy = RandomInt(0, h);
int radius = RandomInt(0, std::min(w, h));
color[0] = 20;
ncnn::draw_circle_c1(a, w, h, cx, cy, radius, _color, -1);
ncnn::draw_circle_c1(b, h, w, cy, cx, radius, _color, -1);

// draw filled circle out of image
color[0] = 230;
ncnn::draw_circle_c1(a, w, h, 10, -4, 6, _color, -1);
ncnn::draw_circle_c1(b, h, w, -4, 10, 6, _color, -1);

// draw circle out of image
color[0] = 130;
ncnn::draw_circle_c1(a, w, h, cx, cy, radius + std::min(w, h) / 2, _color, 5);
ncnn::draw_circle_c1(b, h, w, cy, cx, radius + std::min(w, h) / 2, _color, 5);

// draw line
int x0 = RandomInt(0, w);
int y0 = RandomInt(0, h);
int x1 = RandomInt(0, w);
int y1 = RandomInt(0, h);
color[0] = 233;
ncnn::draw_line_c1(a, w, h, x0, y0, x1, y1, _color, 7);
ncnn::draw_line_c1(b, h, w, y0, x0, y1, x1, _color, 7);

// draw line out of image
color[0] = 192;
ncnn::draw_line_c1(a, w, h, x0 - w, y0 - h, x1 + w, y1 + h, _color, 1);
ncnn::draw_line_c1(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1);

// transpose b
ncnn::Mat c(w, h, 1u, 1);
ncnn::kanna_rotate_c1(b, h, w, c, w, h, 5);

// draw text
const char text[] = "saJIEWdl\nj43@o";
int tx = RandomInt(0, w / 2);
int ty = RandomInt(0, h / 2);
int fontpixelsize = 10;
color[0] = 128;
ncnn::draw_text_c1(a, w, h, text, tx, ty, fontpixelsize, _color);
int tw;
int th;
ncnn::get_text_drawing_size(text, fontpixelsize, &tw, &th);
const int len = strlen(text);
for (int i = 0; i < 8; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c1(c, w, h, ch, tx + tw / 8 * i, ty, fontpixelsize, _color);
}
for (int i = 9; i < len; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c1(c, w, h, ch, tx + tw / 8 * (i - 9), ty + th / 2, fontpixelsize, _color);
}

// draw text out of image
fontpixelsize = std::max(w, h) / 2;
color[0] = 228;
ncnn::draw_text_c1(a, w, h, "QAQ", -3, -5, fontpixelsize, _color);
ncnn::get_text_drawing_size("QAQ", fontpixelsize, &tw, &th);
ncnn::draw_text_c1(c, w, h, "Q", -3, -5, fontpixelsize, _color);
ncnn::draw_text_c1(c, w, h, "A", -3 + tw / 3, -5, fontpixelsize, _color);
ncnn::draw_text_c1(c, w, h, "Q", -3 + tw / 3 * 2, -5, fontpixelsize, _color);

if (memcmp(a, c, w * h) != 0)
{
fprintf(stderr, "test_mat_pixel_drawing_c1 failed w=%d h=%d\n", w, h);
return -1;
}

return 0;
}

static int test_mat_pixel_drawing_c2(int w, int h)
{
ncnn::Mat a(w, h, 2u, 2);
ncnn::Mat b(h, w, 2u, 2);

int _color = 0;
unsigned char* color = (unsigned char*)&_color;

// fill with color
color[0] = 255;
color[1] = 251;
ncnn::draw_rectangle_c2(a, w, h, 0, 0, w, h, _color, -1);
ncnn::draw_rectangle_c2(b, h, w, 0, 0, h, w, _color, -1);

// draw rectangle
int rx = RandomInt(0, w);
int ry = RandomInt(0, h);
int rw = RandomInt(0, w - rx);
int rh = RandomInt(0, h - ry);
color[0] = 100;
color[1] = 130;
ncnn::draw_rectangle_c2(a, w, h, rx, ry, rw, rh, _color, 3);
ncnn::draw_rectangle_c2(b, h, w, ry, rx, rh, rw, _color, 3);

// draw filled rectangle out of image
color[0] = 144;
color[1] = 133;
ncnn::draw_rectangle_c2(a, w, h, w - 10, -10, 20, 30, _color, -1);
ncnn::draw_rectangle_c2(b, h, w, -10, w - 10, 30, 20, _color, -1);
color[0] = 166;
color[1] = 133;
ncnn::draw_rectangle_c2(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c2(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw rectangle out of image
color[0] = 44;
color[1] = 33;
ncnn::draw_rectangle_c2(a, w, h, rx + w / 2, ry + h / 2, rw, rh, _color, 1);
ncnn::draw_rectangle_c2(b, h, w, ry + h / 2, rx + w / 2, rh, rw, _color, 1);
color[0] = 66;
color[1] = 44;
ncnn::draw_rectangle_c2(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c2(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw filled circle
int cx = RandomInt(0, w);
int cy = RandomInt(0, h);
int radius = RandomInt(0, std::min(w, h));
color[0] = 20;
color[1] = 120;
ncnn::draw_circle_c2(a, w, h, cx, cy, radius, _color, -1);
ncnn::draw_circle_c2(b, h, w, cy, cx, radius, _color, -1);

// draw filled circle out of image
color[0] = 230;
color[1] = 130;
ncnn::draw_circle_c2(a, w, h, 10, -4, 6, _color, -1);
ncnn::draw_circle_c2(b, h, w, -4, 10, 6, _color, -1);

// draw circle out of image
color[0] = 130;
color[1] = 30;
ncnn::draw_circle_c2(a, w, h, cx, cy, radius + std::min(w, h) / 2, _color, 5);
ncnn::draw_circle_c2(b, h, w, cy, cx, radius + std::min(w, h) / 2, _color, 5);

// draw line
int x0 = RandomInt(0, w);
int y0 = RandomInt(0, h);
int x1 = RandomInt(0, w);
int y1 = RandomInt(0, h);
color[0] = 233;
color[1] = 233;
ncnn::draw_line_c2(a, w, h, x0, y0, x1, y1, _color, 7);
ncnn::draw_line_c2(b, h, w, y0, x0, y1, x1, _color, 7);

// draw line out of image
color[0] = 192;
color[1] = 192;
ncnn::draw_line_c2(a, w, h, x0 - w, y0 - h, x1 + w, y1 + h, _color, 1);
ncnn::draw_line_c2(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1);

// transpose b
ncnn::Mat c(w, h, 2u, 2);
ncnn::kanna_rotate_c2(b, h, w, c, w, h, 5);

// draw text
const char text[] = "Q`~\\=f\nPN\'/<DSA";
int tx = RandomInt(0, w / 2);
int ty = RandomInt(0, h / 2);
int fontpixelsize = 12;
color[0] = 0;
color[1] = 128;
ncnn::draw_text_c2(a, w, h, text, tx, ty, fontpixelsize, _color);
int tw;
int th;
ncnn::get_text_drawing_size(text, fontpixelsize, &tw, &th);
const int len = strlen(text);
for (int i = 0; i < 6; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c2(c, w, h, ch, tx + tw / 8 * i, ty, fontpixelsize, _color);
}
for (int i = 7; i < len; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c2(c, w, h, ch, tx + tw / 8 * (i - 7), ty + th / 2, fontpixelsize, _color);
}

// draw text out of image
fontpixelsize = std::max(w, h) / 3;
color[0] = 228;
color[1] = 0;
ncnn::draw_text_c2(a, w, h, "!@#$%^&", -1, -2, fontpixelsize, _color);
ncnn::get_text_drawing_size("!@#$%^&", fontpixelsize, &tw, &th);
ncnn::draw_text_c2(c, w, h, "!@#", -1, -2, fontpixelsize, _color);
ncnn::draw_text_c2(c, w, h, "$", -1 + tw / 7 * 3, -2, fontpixelsize, _color);
ncnn::draw_text_c2(c, w, h, "%^&", -1 + tw / 7 * 4, -2, fontpixelsize, _color);

if (memcmp(a, c, w * h * 2) != 0)
{
fprintf(stderr, "test_mat_pixel_drawing_c2 failed w=%d h=%d\n", w, h);
return -1;
}

return 0;
}

static int test_mat_pixel_drawing_c3(int w, int h)
{
ncnn::Mat a(w, h, 3u, 3);
ncnn::Mat b(h, w, 3u, 3);

int _color = 0;
unsigned char* color = (unsigned char*)&_color;

// fill with color
color[0] = 255;
color[1] = 251;
color[2] = 244;
ncnn::draw_rectangle_c3(a, w, h, 0, 0, w, h, _color, -1);
ncnn::draw_rectangle_c3(b, h, w, 0, 0, h, w, _color, -1);

// draw rectangle
int rx = RandomInt(0, w);
int ry = RandomInt(0, h);
int rw = RandomInt(0, w - rx);
int rh = RandomInt(0, h - ry);
color[0] = 100;
color[1] = 130;
color[2] = 150;
ncnn::draw_rectangle_c3(a, w, h, rx, ry, rw, rh, _color, 3);
ncnn::draw_rectangle_c3(b, h, w, ry, rx, rh, rw, _color, 3);

// draw filled rectangle out of image
color[0] = 144;
color[1] = 133;
color[2] = 122;
ncnn::draw_rectangle_c3(a, w, h, w - 10, -10, 20, 30, _color, -1);
ncnn::draw_rectangle_c3(b, h, w, -10, w - 10, 30, 20, _color, -1);
color[0] = 166;
color[1] = 133;
color[2] = 122;
ncnn::draw_rectangle_c3(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c3(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw rectangle out of image
color[0] = 44;
color[1] = 33;
color[2] = 22;
ncnn::draw_rectangle_c3(a, w, h, rx + w / 2, ry + h / 2, rw, rh, _color, 1);
ncnn::draw_rectangle_c3(b, h, w, ry + h / 2, rx + w / 2, rh, rw, _color, 1);
color[0] = 66;
color[1] = 44;
color[2] = 33;
ncnn::draw_rectangle_c3(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c3(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw filled circle
int cx = RandomInt(0, w);
int cy = RandomInt(0, h);
int radius = RandomInt(0, std::min(w, h));
color[0] = 20;
color[1] = 120;
color[2] = 220;
ncnn::draw_circle_c3(a, w, h, cx, cy, radius, _color, -1);
ncnn::draw_circle_c3(b, h, w, cy, cx, radius, _color, -1);

// draw filled circle out of image
color[0] = 230;
color[1] = 130;
color[2] = 110;
ncnn::draw_circle_c3(a, w, h, 10, -4, 6, _color, -1);
ncnn::draw_circle_c3(b, h, w, -4, 10, 6, _color, -1);

// draw circle out of image
color[0] = 130;
color[1] = 30;
color[2] = 230;
ncnn::draw_circle_c3(a, w, h, cx, cy, radius + std::min(w, h) / 2, _color, 5);
ncnn::draw_circle_c3(b, h, w, cy, cx, radius + std::min(w, h) / 2, _color, 5);

// draw line
int x0 = RandomInt(0, w);
int y0 = RandomInt(0, h);
int x1 = RandomInt(0, w);
int y1 = RandomInt(0, h);
color[0] = 233;
color[1] = 233;
color[2] = 233;
ncnn::draw_line_c3(a, w, h, x0, y0, x1, y1, _color, 7);
ncnn::draw_line_c3(b, h, w, y0, x0, y1, x1, _color, 7);

// draw line out of image
color[0] = 192;
color[1] = 192;
color[2] = 0;
ncnn::draw_line_c3(a, w, h, x0 - w, y0 - h, x1 + w, y1 + h, _color, 1);
ncnn::draw_line_c3(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1);

// transpose b
ncnn::Mat c(w, h, 3u, 3);
ncnn::kanna_rotate_c3(b, h, w, c, w, h, 5);

// draw text
const char text[] = "Q`~\\=f\nPN\'/<DSA";
int tx = RandomInt(0, w / 2);
int ty = RandomInt(0, h / 2);
int fontpixelsize = 12;
color[0] = 0;
color[1] = 128;
color[2] = 128;
ncnn::draw_text_c3(a, w, h, text, tx, ty, fontpixelsize, _color);
int tw;
int th;
ncnn::get_text_drawing_size(text, fontpixelsize, &tw, &th);
const int len = strlen(text);
for (int i = 0; i < 6; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c3(c, w, h, ch, tx + tw / 8 * i, ty, fontpixelsize, _color);
}
for (int i = 7; i < len; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c3(c, w, h, ch, tx + tw / 8 * (i - 7), ty + th / 2, fontpixelsize, _color);
}

// draw text out of image
fontpixelsize = std::max(w, h) / 2;
color[0] = 228;
color[1] = 0;
color[2] = 128;
ncnn::draw_text_c3(a, w, h, "qwqwqwq", -13, -15, fontpixelsize, _color);
ncnn::get_text_drawing_size("qwqwqwq", fontpixelsize, &tw, &th);
ncnn::draw_text_c3(c, w, h, "qwq", -13, -15, fontpixelsize, _color);
ncnn::draw_text_c3(c, w, h, "w", -13 + tw / 7 * 3, -15, fontpixelsize, _color);
ncnn::draw_text_c3(c, w, h, "qwq", -13 + tw / 7 * 4, -15, fontpixelsize, _color);

if (memcmp(a, c, w * h * 3) != 0)
{
fprintf(stderr, "test_mat_pixel_drawing_c3 failed w=%d h=%d\n", w, h);
return -1;
}

return 0;
}

static int test_mat_pixel_drawing_c4(int w, int h)
{
ncnn::Mat a(w, h, 4u, 4);
ncnn::Mat b(h, w, 4u, 4);

int _color = 0;
unsigned char* color = (unsigned char*)&_color;

// fill with color
color[0] = 255;
color[1] = 255;
color[2] = 255;
color[3] = 0;
ncnn::draw_rectangle_c4(a, w, h, 0, 0, w, h, _color, -1);
ncnn::draw_rectangle_c4(b, h, w, 0, 0, h, w, _color, -1);

// draw rectangle
int rx = RandomInt(0, w);
int ry = RandomInt(0, h);
int rw = RandomInt(0, w - rx);
int rh = RandomInt(0, h - ry);
color[0] = 100;
color[1] = 20;
color[2] = 200;
color[3] = 100;
ncnn::draw_rectangle_c4(a, w, h, rx, ry, rw, rh, _color, 3);
ncnn::draw_rectangle_c4(b, h, w, ry, rx, rh, rw, _color, 3);

// draw filled rectangle out of image
color[0] = 144;
color[1] = 133;
color[2] = 122;
color[3] = 30;
ncnn::draw_rectangle_c4(a, w, h, w - 10, -10, 20, 30, _color, -1);
ncnn::draw_rectangle_c4(b, h, w, -10, w - 10, 30, 20, _color, -1);
color[0] = 166;
color[1] = 133;
color[2] = 122;
color[3] = 20;
ncnn::draw_rectangle_c4(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c4(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw rectangle out of image
color[0] = 44;
color[1] = 144;
color[2] = 44;
color[3] = 144;
ncnn::draw_rectangle_c4(a, w, h, rx + w / 2, ry + h / 2, rw, rh, _color, 1);
ncnn::draw_rectangle_c4(b, h, w, ry + h / 2, rx + w / 2, rh, rw, _color, 1);
color[0] = 66;
color[1] = 44;
color[2] = 33;
color[3] = 112;
ncnn::draw_rectangle_c4(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 7);
ncnn::draw_rectangle_c4(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 7);

// draw filled circle
int cx = RandomInt(0, w);
int cy = RandomInt(0, h);
int radius = RandomInt(0, std::min(w, h));
color[0] = 10;
color[1] = 2;
color[2] = 200;
color[3] = 20;
ncnn::draw_circle_c4(a, w, h, cx, cy, radius, _color, -1);
ncnn::draw_circle_c4(b, h, w, cy, cx, radius, _color, -1);

// draw filled circle out of image
color[0] = 230;
color[1] = 130;
color[2] = 110;
color[3] = 5;
ncnn::draw_circle_c4(a, w, h, 10, -4, 6, _color, -1);
ncnn::draw_circle_c4(b, h, w, -4, 10, 6, _color, -1);

// draw circle out of image
color[0] = 130;
color[1] = 255;
color[2] = 130;
color[3] = 255;
ncnn::draw_circle_c4(a, w, h, cx, cy, radius + std::min(w, h) / 2, _color, 5);
ncnn::draw_circle_c4(b, h, w, cy, cx, radius + std::min(w, h) / 2, _color, 5);

// draw line
int x0 = RandomInt(0, w);
int y0 = RandomInt(0, h);
int x1 = RandomInt(0, w);
int y1 = RandomInt(0, h);
color[0] = 233;
color[1] = 233;
color[2] = 233;
color[3] = 233;
ncnn::draw_line_c4(a, w, h, x0, y0, x1, y1, _color, 7);
ncnn::draw_line_c4(b, h, w, y0, x0, y1, x1, _color, 7);

// draw line out of image
color[0] = 192;
color[1] = 22;
color[2] = 1;
color[3] = 0;
ncnn::draw_line_c4(a, w, h, x0 - w, y0 - h, x1 + w, y1 + h, _color, 1);
ncnn::draw_line_c4(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 1);

// transpose b
ncnn::Mat c(w, h, 4u, 4);
ncnn::kanna_rotate_c4(b, h, w, c, w, h, 5);

// draw text
const char text[] = "!@)\n($ 34\n2]\"M,";
int tx = RandomInt(0, w / 2);
int ty = RandomInt(0, h / 2);
int fontpixelsize = 23;
color[0] = 11;
color[1] = 128;
color[2] = 12;
color[3] = 128;
ncnn::draw_text_c4(a, w, h, text, tx, ty, fontpixelsize, _color);
int tw;
int th;
ncnn::get_text_drawing_size(text, fontpixelsize, &tw, &th);
const int len = strlen(text);
for (int i = 0; i < 3; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c4(c, w, h, ch, tx + tw / 5 * i, ty, fontpixelsize, _color);
}
for (int i = 4; i < 9; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c4(c, w, h, ch, tx + tw / 5 * (i - 4), ty + th / 3, fontpixelsize, _color);
}
for (int i = 10; i < len; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_c4(c, w, h, ch, tx + tw / 5 * (i - 10), ty + th / 3 * 2, fontpixelsize, _color);
}

// draw text out of image
fontpixelsize = std::max(w, h) / 3;
color[0] = 228;
color[1] = 0;
color[2] = 128;
color[3] = 200;
ncnn::draw_text_c4(a, w, h, "=_+!//zzzz", -13, -15, fontpixelsize, _color);
ncnn::get_text_drawing_size("=_+!//zzzz", fontpixelsize, &tw, &th);
ncnn::draw_text_c4(c, w, h, "=_+", -13, -15, fontpixelsize, _color);
ncnn::draw_text_c4(c, w, h, "!", -13 + tw / 10 * 3, -15, fontpixelsize, _color);
ncnn::draw_text_c4(c, w, h, "//zzzz", -13 + tw / 10 * 4, -15, fontpixelsize, _color);

if (memcmp(a, c, w * h * 4) != 0)
{
fprintf(stderr, "test_mat_pixel_drawing_c4 failed w=%d h=%d\n", w, h);
return -1;
}

return 0;
}

static int test_mat_pixel_drawing_0()
{
return 0
|| test_mat_pixel_drawing_c1(22, 33)
|| test_mat_pixel_drawing_c2(22, 23)
|| test_mat_pixel_drawing_c3(32, 23)
|| test_mat_pixel_drawing_c4(42, 13)

|| test_mat_pixel_drawing_c1(202, 303)
|| test_mat_pixel_drawing_c2(202, 203)
|| test_mat_pixel_drawing_c3(302, 203)
|| test_mat_pixel_drawing_c4(402, 103);
}

static int test_mat_pixel_drawing_yuv420sp(int w, int h)
{
ncnn::Mat a(w, h * 3 / 2, 1u, 1);
ncnn::Mat b(h, w * 3 / 2, 1u, 1);

int _color = 0;
unsigned char* color = (unsigned char*)&_color;

// fill with color
color[0] = 255;
color[1] = 255;
color[2] = 255;
ncnn::draw_rectangle_yuv420sp(a, w, h, 0, 0, w, h, _color, -1);
ncnn::draw_rectangle_yuv420sp(b, h, w, 0, 0, h, w, _color, -1);

// draw rectangle
int rx = RandomInt2(0, w);
int ry = RandomInt2(0, h);
int rw = RandomInt2(0, w - rx);
int rh = RandomInt2(0, h - ry);
color[0] = 100;
color[1] = 20;
color[2] = 200;
ncnn::draw_rectangle_yuv420sp(a, w, h, rx, ry, rw, rh, _color, 4);
ncnn::draw_rectangle_yuv420sp(b, h, w, ry, rx, rh, rw, _color, 4);

// draw filled rectangle out of image
color[0] = 144;
color[1] = 133;
color[2] = 122;
ncnn::draw_rectangle_yuv420sp(a, w, h, w - 10, -10, 20, 30, _color, -1);
ncnn::draw_rectangle_yuv420sp(b, h, w, -10, w - 10, 30, 20, _color, -1);
color[0] = 166;
color[1] = 133;
color[2] = 122;
ncnn::draw_rectangle_yuv420sp(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 8);
ncnn::draw_rectangle_yuv420sp(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 8);

// draw rectangle out of image
color[0] = 44;
color[1] = 144;
color[2] = 44;
ncnn::draw_rectangle_yuv420sp(a, w, h, rx + w / 2, ry + h / 2, rw, rh, _color, 2);
ncnn::draw_rectangle_yuv420sp(b, h, w, ry + h / 2, rx + w / 2, rh, rw, _color, 2);
color[0] = 66;
color[1] = 44;
color[2] = 33;
ncnn::draw_rectangle_yuv420sp(a, w, h, -rw / 2, -rh / 3, rw, rh, _color, 8);
ncnn::draw_rectangle_yuv420sp(b, h, w, -rh / 3, -rw / 2, rh, rw, _color, 8);

// draw filled circle
int cx = RandomInt2(0, w);
int cy = RandomInt2(0, h);
int radius = RandomInt2(0, std::min(w, h));
color[0] = 10;
color[1] = 2;
color[2] = 200;
ncnn::draw_circle_yuv420sp(a, w, h, cx, cy, radius, _color, -1);
ncnn::draw_circle_yuv420sp(b, h, w, cy, cx, radius, _color, -1);

// draw filled circle out of image
color[0] = 230;
color[1] = 130;
color[2] = 110;
ncnn::draw_circle_yuv420sp(a, w, h, 10, -4, 6, _color, -1);
ncnn::draw_circle_yuv420sp(b, h, w, -4, 10, 6, _color, -1);

// draw circle out of image
color[0] = 130;
color[1] = 255;
color[2] = 130;
ncnn::draw_circle_yuv420sp(a, w, h, cx, cy, radius + std::min(w, h) / 2, _color, 6);
ncnn::draw_circle_yuv420sp(b, h, w, cy, cx, radius + std::min(w, h) / 2, _color, 6);

// draw line
int x0 = RandomInt2(0, w);
int y0 = RandomInt2(0, h);
int x1 = RandomInt2(0, w);
int y1 = RandomInt2(0, h);
color[0] = 233;
color[1] = 233;
color[2] = 233;
ncnn::draw_line_yuv420sp(a, w, h, x0, y0, x1, y1, _color, 8);
ncnn::draw_line_yuv420sp(b, h, w, y0, x0, y1, x1, _color, 8);

// draw line out of image
color[0] = 192;
color[1] = 22;
color[2] = 1;
ncnn::draw_line_yuv420sp(a, w, h, x0 - w, y0 - h, x1 + w, y1 + h, _color, 2);
ncnn::draw_line_yuv420sp(b, h, w, y0 - h, x0 - w, y1 + h, x1 + w, _color, 2);

// transpose b
ncnn::Mat c(w, h * 3 / 2, 1u, 1);
ncnn::kanna_rotate_yuv420sp(b, h, w, c, w, h, 5);

// draw text
const char text[] = "!@)\n($ 34\n2]\"M,";
int tx = RandomInt2(0, w / 2);
int ty = RandomInt2(0, h / 2);
int fontpixelsize = 24;
color[0] = 11;
color[1] = 128;
color[2] = 12;
ncnn::draw_text_yuv420sp(a, w, h, text, tx, ty, fontpixelsize, _color);
int tw;
int th;
ncnn::get_text_drawing_size(text, fontpixelsize, &tw, &th);
const int len = strlen(text);
for (int i = 0; i < 3; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_yuv420sp(c, w, h, ch, tx + tw / 5 * i, ty, fontpixelsize, _color);
}
for (int i = 4; i < 9; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_yuv420sp(c, w, h, ch, tx + tw / 5 * (i - 4), ty + th / 3, fontpixelsize, _color);
}
for (int i = 10; i < len; i++)
{
const char ch[2] = {text[i], '\0'};
ncnn::draw_text_yuv420sp(c, w, h, ch, tx + tw / 5 * (i - 10), ty + th / 3 * 2, fontpixelsize, _color);
}

// draw text out of image
fontpixelsize = (std::max(w, h) / 3 + 1) / 2 * 2;
color[0] = 228;
color[1] = 0;
color[2] = 128;
ncnn::draw_text_yuv420sp(a, w, h, "=_+!//zzzz", -14, -12, fontpixelsize, _color);
ncnn::get_text_drawing_size("=_+!//zzzz", fontpixelsize, &tw, &th);
ncnn::draw_text_yuv420sp(c, w, h, "=_+", -14, -12, fontpixelsize, _color);
ncnn::draw_text_yuv420sp(c, w, h, "!", -14 + tw / 10 * 3, -12, fontpixelsize, _color);
ncnn::draw_text_yuv420sp(c, w, h, "//zzzz", -14 + tw / 10 * 4, -12, fontpixelsize, _color);

if (memcmp(a, c, w * h * 3 / 2) != 0)
{
fprintf(stderr, "test_mat_pixel_drawing_yuv420sp failed w=%d h=%d\n", w, h);
return -1;
}

return 0;
}

static int test_mat_pixel_drawing_1()
{
return 0
|| test_mat_pixel_drawing_yuv420sp(10, 10)
|| test_mat_pixel_drawing_yuv420sp(120, 160)
|| test_mat_pixel_drawing_yuv420sp(220, 340);
}

int main()
{
SRAND(7767517);

return 0
|| test_mat_pixel_drawing_0()
|| test_mat_pixel_drawing_1();
}

Loading…
Cancel
Save