Feature request: Lite/mini version of opencv4?
I have been using Opencvsharp4 for a long time and it's really cool, but I think it's a bit too big. The compressed package is over 50MB and it expands to more than 130MB after extraction. Additionally, due to its comprehensive functionality, it has quite a few dependencies.
I use Opencvsharp4 for pre-processing and post-processing in deep learning inference. For me, and I believe for many others, keeping only the imgproc module of OpenCV is sufficient. Especially, I don't think we need the FFmpeg, GUI, and Tesseract OCR modules because:
- The FFmpeg DLL is very large, but the actual functionality provided by the OpenCV wrapper is limited. We don't need to use a separate library like Sdcb.FFmpeg, which only increases the size.
- The GUI seems convenient for debugging, but its functionality is limited and not suitable for deep learning inference.
- Tesseract OCR appears useful, but its actual performance is subpar compared to PaddleOCR (I have created a .NET PaddleOCR wrapper for PaddleSharp), and it doesn't offer as many features as calling the Tesseract DLL directly.
Therefore, I suggest providing a NuGet package like "opencvsharp4.runtime.win-mini" that can significantly reduce its size.
I would find this very useful for a different reason: reducing security maintenance burden.
We have custom docker images just to add the Opencv dependencies, which is fine, except on Ubuntu FFmpeg and Tesseract bring in something like 75% of the CVEs.
I've been playing with doing custom builds of opencv without the deps which is a quick fix, but even if that works it might be odd to have the modules included in the API but not usable.
I would also be very interested in this, but isn't that an issue for opencv https://github.com/opencv/opencv itself and not the wrapper here? Is there already an issue there which adresses that feature request?
I too have always felt this issue. I am fed up with the uncontrolled addition of new features to OpenCV 🤔
The current way of distributing statically-linked library (OpenCvSharpExtern.dll/.so) makes it difficult to deal with this issue, but if we change to dynamically-linked library, there will be frequent DllImport errors on the user side. It's a tough problem.
I have recently been prototyping a new project for the purpose of wrapping just the core functionality of OpenCV. https://github.com/shimat/opencvsharp5
The current way of distributing statically-linked library (OpenCvSharpExtern.dll/.so) makes it difficult to deal with this issue
While it makes it hard to create an easy way for users to have any arbitrary mixture of modules, I don't think it would take a huge amount of change to make it fairly easy for determined users to use custom builds of opencv.
In my experimentation the C# appears to be lazy in its checking of whether the native library actually has the methods. This means we only need to adapt the OpenCvSharpExtern project to create a minimal build.
The big downside is that all the C# methods are still there, they'll just fail if you try to use them :)
FROM mcr.microsoft.com/dotnet/aspnet:7.0-jammy as builder
ENV DEBIAN_FRONTEND=noninteractive
ENV OPENCV_VERSION=4.7.0
WORKDIR /
# Install opencv dependencies
RUN apt-get update && apt-get -y install --no-install-recommends \
apt-transport-https \
software-properties-common \
wget \
unzip \
ca-certificates \
build-essential \
cmake \
git \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists/*
# Setup opencv and opencv-contrib source
RUN wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \
unzip ${OPENCV_VERSION}.zip && \
rm ${OPENCV_VERSION}.zip && \
mv opencv-${OPENCV_VERSION} opencv && \
wget https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \
unzip ${OPENCV_VERSION}.zip && \
rm ${OPENCV_VERSION}.zip && \
mv opencv_contrib-${OPENCV_VERSION} opencv_contrib
# Build OpenCV
# core, imgproc, imgcodecs are only used modules
# PNG and TIFF are included for our usage and for opencvsharp tests respectively
# Rest are things turned off as they have LDD deps
RUN cd opencv && mkdir build && cd build && \
cmake \
-D CMAKE_BUILD_TYPE=RELEASE \
-D BUILD_SHARED_LIBS=OFF \
-D ENABLE_CXX11=ON \
-D BUILD_EXAMPLES=OFF \
-D BUILD_DOCS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_JAVA=OFF \
-D BUILD_LIST=core,imgproc,imgcodecs \
-D BUILD_PNG=ON \
-D BUILD_TIFF=ON \
-D WITH_GSTREAMER=OFF \
-D WITH_ADE=OFF \
-D WITH_FFMPEG=OFF \
-D WITH_V4L=OFF \
-D WITH_1394=OFF \
-D WITH_GTK=OFF \
-D WITH_OPENEXR=OFF \
-D WITH_PROTOBUF=OFF \
-D WITH_QUIRC=OFF \
-D OPENCV_ENABLE_NONFREE=ON \
.. && make -j$(nproc) && make install && ldconfig
# Download OpenCvSharp
RUN git clone https://github.com/shimat/opencvsharp.git && cd opencvsharp && git checkout 4.7.0.20230114
# Remove includes of modules we don't need
RUN sed -i '41s/.*/ /;43,69s/.*/ /' /opencvsharp/src/OpenCvSharpExtern/include_opencv.h
# Remove helper types that use extra modules
RUN sed -i '451,585s/.*/ /' /opencvsharp/src/OpenCvSharpExtern/std_vector.h
# Only include the c++ files we need
RUN sed -i '12s/.*/file(GLOB OPENCVSHARP_FILES core*.cpp imgp*.cpp imgc*.cpp std*.cpp)/' /opencvsharp/src/OpenCvSharpExtern/CMakeLists.txt
# Install the Extern lib.
RUN mkdir /opencvsharp/make && cd /opencvsharp/make && \
cmake -D CMAKE_INSTALL_PREFIX=/opencvsharp/make /opencvsharp/src && \
make -j$(nproc) && make install && \
mkdir /artifacts && \
cp /opencvsharp/make/OpenCvSharpExtern/libOpenCvSharpExtern.so /artifacts/
# Test OpenCvSharpExtern
RUN cp artifacts/libOpenCvSharpExtern.so /usr/lib/ && \
echo "\n\
#include <stdio.h> \n\
int core_Mat_sizeof(); \n\
int main(){ \n\
int i = core_Mat_sizeof(); \n\
printf(\"sizeof(Mat) = %d\", i); \n\
return 0; \n\
}" > /test.c && \
gcc -I./ -L./ test.c -o test -lOpenCvSharpExtern && \
LD_LIBRARY_PATH=. ./test && \
rm -f /test*
######### Build runtime image
FROM mcr.microsoft.com/dotnet/aspnet:7.0-jammy as runtime
RUN apt-get update && apt-get -y install --no-install-recommends \
libjpeg-turbo8 \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists/*
######### Test .NET class libraries ##########
FROM runtime as test
COPY --from=builder /artifacts /usr/lib
RUN apt-get update && \
apt-get install -y dotnet-sdk-6.0 \
git \
libgdiplus \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists/*
# Install Build the C# part of OpenCvSharp
RUN git clone https://github.com/shimat/opencvsharp.git && cd opencvsharp && git checkout 4.7.0.20230114
RUN cd /opencvsharp/src/OpenCvSharp && \
dotnet build -c Release -f net6.0 && \
cd /opencvsharp/src/OpenCvSharp.Extensions && \
dotnet build -c Release -f net6.0
# Only run the tests for our modules
RUN dotnet test --filter "(FullyQualifiedName~OpenCvSharp.Tests.Core|FullyQualifiedName~OpenCvSharp.Tests.ImgCodecs|FullyQualifiedName~OpenCvSharp.Tests.ImgProc)&FullyQualifiedName!=OpenCvSharp.Tests.Core.AlgorithmTest.GetDefaultName" /opencvsharp/test/OpenCvSharp.Tests/OpenCvSharp.Tests.csproj -c Release -f net6.0 --runtime ubuntu.22.04-x64 --logger "trx;LogFileName=test-results.trx" < /dev/null
FROM scratch
COPY --from=builder /artifacts/libOpenCvSharpExtern.so .
This build has no dependencies (except libjpeg-turbo8, which may be optional, but we wanted). It includes only:
- core, imgproc, imgcodecs
- png (we need it)
- tiff (opencvsharp tests need it)
I didn't want to fork the whole repo, so the three changes I had to patch were:
- remove all the includes of modules except the three needed from
include_opencv.h - remove the module specific helper methods in
stc_vector.h - update
CMakeLists.txtto only compile the core, imgproc, imgcodec, and std files
Amazingly, this just seems to work.
The native library is much much smaller, and all of the reported FFMPEG vulnerabilities are gone :)
I'm not sure how to make this approach practical for other. I suppose a lot of ifdefs could make it easier to turn on/off modules, but if you wanted a user-friendly alternative: I'm not sure if there is a minimal set of opencv features that everyone would agree on. I don't need TIFF, but someone else might not want JPEG and just use opencv for raw mats.
That sounds very interesting, how big is the dll/so at the end? How is the memory reduction with you at the end.
Must have a closer look at it. I would also need openvino for the dnn module for an application under Windows.
@tboby it's a great dockerfile, can you also write a Windows version of dockerfile?
Here is 3 docker I created for your startup, if you interested
- sdflysha/msvc2017:core
- sdflysha/msvc2019:core
- sdflysha/msvc2022:core
It's based on windows server ltsc2022 image, contained different versions of Visual C++ (of course), and cmake, python, vcpkg, git
I'm pretty appreciate it if you can help.
@tboby I follow your code style, wrote the latest version of opencvsharp 4.8 and confirmed it works in all combination of Debian11/Ubuntu22 x64/ARM64:
FROM mcr.microsoft.com/dotnet/aspnet:7.0 as builder
ENV DEBIAN_FRONTEND=noninteractive
ENV OPENCV_VERSION=4.8.0
WORKDIR /
# Install opencv dependencies
RUN apt-get update && apt-get -y install --no-install-recommends \
apt-transport-https \
software-properties-common \
wget \
unzip \
ca-certificates \
build-essential \
cmake \
git \
&& apt-get -y clean \
&& rm -rf /var/lib/apt/lists/*
# Setup opencv and opencv-contrib source
RUN wget https://github.com/opencv/opencv/archive/${OPENCV_VERSION}.zip && \
unzip ${OPENCV_VERSION}.zip && \
rm ${OPENCV_VERSION}.zip && \
mv opencv-${OPENCV_VERSION} opencv && \
wget https://github.com/opencv/opencv_contrib/archive/${OPENCV_VERSION}.zip && \
unzip ${OPENCV_VERSION}.zip && \
rm ${OPENCV_VERSION}.zip && \
mv opencv_contrib-${OPENCV_VERSION} opencv_contrib
# Build OpenCV
# core, imgproc, imgcodecs are only used modules
# PNG and TIFF are included for our usage and for opencvsharp tests respectively
# Rest are things turned off as they have LDD deps
RUN cd opencv && mkdir build && cd build && \
cmake \
-D CMAKE_BUILD_TYPE=RELEASE \
-D BUILD_SHARED_LIBS=OFF \
-D ENABLE_CXX11=ON \
-D BUILD_EXAMPLES=OFF \
-D BUILD_DOCS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_JAVA=OFF \
-D BUILD_LIST=core,imgproc,imgcodecs \
-D BUILD_PNG=ON \
-D BUILD_TIFF=ON \
-D WITH_GSTREAMER=OFF \
-D WITH_ADE=OFF \
-D WITH_FFMPEG=OFF \
-D WITH_V4L=OFF \
-D WITH_1394=OFF \
-D WITH_GTK=OFF \
-D WITH_OPENEXR=OFF \
-D WITH_PROTOBUF=OFF \
-D WITH_QUIRC=OFF \
-D OPENCV_ENABLE_NONFREE=ON \
.. && make -j$(nproc) && make install && ldconfig
# Download OpenCvSharp
RUN git clone https://github.com/shimat/opencvsharp.git && cd opencvsharp && git checkout 4.8.0.20230711
# Remove includes of modules we don't need
RUN sed -i '42s/.*/ /;44,70s/.*/ /' /opencvsharp/src/OpenCvSharpExtern/include_opencv.h
# Remove helper types that use extra modules
RUN sed -i '451,585s/.*/ /' /opencvsharp/src/OpenCvSharpExtern/std_vector.h
# Only include the c++ files we need
RUN sed -i '12s/.*/file(GLOB OPENCVSHARP_FILES core*.cpp imgp*.cpp imgc*.cpp std*.cpp)/' /opencvsharp/src/OpenCvSharpExtern/CMakeLists.txt
# Install the Extern lib.
RUN mkdir /opencvsharp/make && cd /opencvsharp/make && \
cmake -D CMAKE_INSTALL_PREFIX=/opencvsharp/make /opencvsharp/src && \
make -j$(nproc) && make install && \
mkdir /artifacts && \
cp /opencvsharp/make/OpenCvSharpExtern/libOpenCvSharpExtern.so /artifacts/
# Test OpenCvSharpExtern
RUN cp artifacts/libOpenCvSharpExtern.so /usr/lib/ && \
echo "\n\
#include <stdio.h> \n\
int core_Mat_sizeof(); \n\
int main(){ \n\
int i = core_Mat_sizeof(); \n\
printf(\"sizeof(Mat) = %d\", i); \n\
return 0; \n\
}" > /test.c && \
gcc -I./ -L./ test.c -o test -lOpenCvSharpExtern && \
LD_LIBRARY_PATH=. ./test && \
rm -f /test*
Thanks for your initial code :)
Hey all, please try my self-compiled OpenCvSharp4 runtime, it's a mini runtime, only provided core, imgcodec, imgproc modules.
A detailed tutorial for minimizing OpenCvSharp(taking the wechatqrcode module as an example)
https://zhuanlan.zhihu.com/p/679705899
(in Chinese only)