I was reading this article on how to create compact builds for applications using OpenCV.
But, this article includes only GCC related optimizations. I am looking for equivalent options in Visual Studio, but am able to find only the option to minimize size (/Os) and the option /LTCG.
I am building a very simple OpenCV console application (code is below) using OpenCV static libraries built from source. The issue is the size of executable is too large (37 MB in Debug build and 19 MB in Release build). I want to reduce that size to a few MBs and I am looking for ways to do that - I found that article while researching about this.
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
int main()
{
cv::Mat m = cv::imread("sample.jpg");
cv::imwrite("output.jpg", m);
std::cout << "Hello World!\n" << m.rows << " " << m.cols;
return 0;
}
Just in case anyone wants to know, I am including following libraries (the below are for Release mode):
opencv_core430.lib
opencv_imgproc430.lib
opencv_imgcodecs430.lib
libjpeg-turbo.lib
libpng.lib
libtiff.lib
libwebp.lib
ippiw.lib
zlib.lib
IlmImf.lib
libjasper.lib
ittnotify.lib
ippicvmt.lib
If anyone has any ideas what equivalent options are in Visual Studio, it would be of great help.
Also, is there anyone who was successful to reduce the executable size using static OpenCV libraries on Visual Studio?
I encountered the same issue and I found two things which make a big difference: performance libraries/frameworks and unnecessary file types.
Since you are building from source, you should be able to use cmake-gui to adjust the configuration to disable these:
WITH_IPP
WITH_ITT
WITH_OPENCL
Then, disable these additional image types if you need only JPG:
WITH_JASPER
WITH_PNG
WITH_OPENJPEG
WITH_WEBP
WITH_TIFF
WITH_OPENEXR
WITH_IMGCODEC_HDR
WITH_IMGCODEC_SUNRASTER
WITH_IMGCODEC_PXM
WITH_IMGCODEC_PFM
Since imread and imwrite determine the file type based on the given string, the linker has no way of knowing that the code for the other unnecessary image formats can be removed.
When I apply these changes and compile your program using Visual Studio 2022 it comes out to about 1.7 MB in release mode. (Starting with the default configuration and disabling only BUILD_SHARED_LIBS, I had seen the same 19 MB executable that you had reported.)
You can build as per your modules requirements, details in the blog.
The simplest way to build is using OpenCV cmake example:
cmake
-D WITH_CUDA=OFF \
-D WITH_MATLAB=OFF \
-D BUILD_ANDROID_EXAMPLES=OFF \
-D BUILD_DOCS=OFF \
-D BUILD_PERF_TESTS=OFF \
-D BUILD_TESTS=OFF \
-D BUILD_SHARED_LIBS=OFF \
-D BUILD_opencv_objdetect=OFF \
-D BUILD_opencv_video=OFF \
-D BUILD_opencv_videoio=OFF \
-D BUILD_opencv_features2d=OFF \
-D BUILD_opencv_flann=OFF \
-D BUILD_opencv_ml=OFF \
-D BUILD_opencv_photo=OFF \
-D BUILD_opencv_python=OFF \
-D BUILD_opencv_shape=OFF \
-D BUILD_opencv_stitching=OFF \
-D BUILD_opencv_superres=OFF \
-D BUILD_opencv_ts=OFF \
-D BUILD_opencv_videostab=OFF \
-D BUILD_opencv_highgui=ON \
-D BUILD_opencv_imgproc=ON \
..
For static linking, you can pick and choice the module(s) by un-archiving .a to .o and bundle them in single .a.
CAUTION: be very sure that you do not break the dependencies.
Example:
to unarchive a .a using ar -x libopencv_imgproc.a and to archive again
ar -rc libopencv_custom.a *.o
Related
I want to know how much my code is faster with CUDA, so I compile OpenCV with below switches (including cuda)
cmake CMAKE_BUILD_TYPE=RELEASE \
CMAKE_INSTALL_PREFIX=/usr/local \
WITH_CUDA=ON \
ENABLE_FAST_MATH=1 \
CUDA_FAST_MATH=1 \
WITH_CUBLAS=1 \
INSTALL_PYTHON_EXAMPLES=OFF \
OPENCV_EXTRA_MODULES_PATH=/home/saeed/opencv_contrib/modules \
BUILD_EXAMPLES=OFF ..
and I'm working on Linux based machine and with dedicated GPU on my system so how I can measure gpu usage for opencv code? I did that with using
$ nvidia-smi
command,which give me general information about gpu usage and etc (in bash) .
for trace this output I use
$ watch -n 0.1 nvidia-smi
command,which updates informations every 0.1 second(0.1 second is minimum)
So I have a code like below in opencv(You can see I don't use any cuda function in it)
#include "opencv2/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
int main()
{
cv::Mat src(1500,1500,CV_8UC3),res;
for (int var = 0; var < 70; ++var)
{
Canny(src,res,50,150,5);
}
}
So when i run above code I take a screen shot in my nvidia-smi page(to know how much gpu ram is in use)
As you can see there is 23 MiB is in use !!! so why this happen !!if it is normal how we could stop that !? How to stop GPU for this problem
You can make the CUDA runtime indicate that there are no available GPUs with the following environment variable:
CUDA_VISIBLE_DEVICES="" ./my_opencv_code_that_wont_use_gpu
If you want OpenCV to actually not do anything with the GPU, my best guess would be to compile it without CUDA support:
cmake CMAKE_BUILD_TYPE=RELEASE \
CMAKE_INSTALL_PREFIX=/usr/local \
WITH_CUDA=ON \ ********MODIFY
ENABLE_FAST_MATH=1 \
CUDA_FAST_MATH=1 \ ********MODIFY
WITH_CUBLAS=1 \ ********MODIFY
INSTALL_PYTHON_EXAMPLES=OFF \
OPENCV_EXTRA_MODULES_PATH=/home/saeed/opencv_contrib/modules \
BUILD_EXAMPLES=OFF ..
After unzip opencv3.1.0, I was cmake with:
sudo cmake -D CMAKE_BUILD_TYPE=RELEASE -D INSTALL_C_EXAMPLES=ON –D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=ON -D WITH_QT=ON -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_CUDA=ON -D CUDA_FAST_MATH=1 -D WITH_CUBLAS=1 -D WITH_OPENGL=ON -D WITH_V4L=ON –D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_TBB=ON ..
But when I run opencv-3.1.0/sample/gpu/video_reader.cpp with compile :
sudo g++ $(pkg-config --libs --cflags opencv) -o stream video_reader.cpp
I have received notice:
OpenCV was built without CUDA Video decoding support
I'm using Raspberry 3. Thanks all !
Raspberry Pi 3 has no NVIDIA GPU, therefore CUDA is not supported.
From NVIDIA page:
CUDA® is a parallel computing platform and programming model invented by NVIDIA. It enables dramatic increases in computing performance by harnessing the power of the graphics processing unit (GPU). - See more at: http://www.nvidia.com/object/cuda_home_new.html#sthash.5wWaGnZI.dpuf
From answer related to similar question:
Q: Is it possible to use the GPU for calculations? (e.g. CUDA/OpenCL)
A: Not at present - there is only a framebuffer interface for display purposes. There is no OpenCL and no plans for it nor is there documentation available to create OpenCL. CUDA is Nvida only so isn't applicable. Once an OpenGL driver becomes available you may be able to engineer some calculations via the GPU but how useful that will be remains to be seen.
Instead you can use OpenGL ES or OpenVG to write code using GPU. Raspberry PI video api
I need a definitive answer because this is still unclear to me and I can't find an explicit answer anywhere in the docs.
Assuming that I have a working gcc toolchain where
host x86_64-linux-gnu
target x86_64-linux-gnu
, the question is can I possibly configure and build gcc from sources with ?
host x86_64-linux-gnu
build x86_64-linux-gnu
target arm-gnu-eabi
The reason why I would like an answer on this is about whether or not I should spend time trying different configurations for my libraries and whether or whether or not the scripts used to build gcc are capable of some implicit stage 1 build that can potentially bootstrap an ARM compiler for me temporarily on this x64, so I can generate the toolchain that I need for the target that I want .
"Can I build gcc for ARM with an X64 one?"
Yes, you can. I have described this process for a suse linux host development system in a blog post of mine.
==================================================================================
I'm going to replicate the steps here:
1. Ensure to have the necessary headers & libraries installed
I have used YAST's 'Install Software' feature, to install the following packages that will be necessary to complete all the build steps (just search for the package names, select and accept):
gmp-devel
mpfr-devel
mpc-devel
texinfo
ncurses-devel
termcap
2. Create a directory skeleton
cd ~
mkdir arm-none-eabi arm-none-eabi-src
cd arm-none-eabi
mkdir src build
cd ~/arm-none-eabi-src
mkdir src build
3. Download the the source packages and extract them
I'm using gcc-4.7.1 here, but the same process will of course apply for newer versions of GCC.
cd ~/arm-none-eabi-src/src
wget ftp://ftp.gnu.org/gnu/gcc/gcc-4.7.1/gcc-4.7.1.tar.bz2
wget ftp://ftp.gnu.org/gnu/binutils/binutils-2.22.tar.bz2
wget ftp://ftp.gnu.org/gnu/gdb/gdb-7.4.tar.bz2
wget ftp://sources.redhat.com/pub/newlib/newlib-1.20.0.tar.gz
tar -xf gcc-4.7.1.tar.bz2
tar -xf binutils-2.22.tar.bz2
tar -xf gdb-7.4.tar.bz2
tar -xf newlib-1.20.0.tar.gz
4. Build the binutils
cd ~/arm-none-eabi-src/build
mkdir binutils-2.22
cd binutils-2.22
../../src/binutils-2.22/configure \
--target=arm-none-eabi \
--prefix=$HOME/arm-none-eabi \
--with-cpu=cortex-m3 \
--with-no-thumb-interwork \
--with-mode=thumb
make all install
export PATH="$PATH:$HOME/arm-none-eabi/bin"
5. Build GCC (Part1)
cd ~/arm-none-eabi-src/build
mkdir gcc-4.7.1
cd gcc-4.7.1
../../src/gcc-4.7.1/configure --target=arm-none-eabi \
--prefix=$HOME/arm-none-eabi --with-cpu=cortex-m3 \
--with-mode=thumb --disable-multilib \
--with-no-thumb-interwork \
--enable-languages="c,c++" --with-newlib \
--with-headers=../../src/newlib-1.20.0/newlib/libc/include
make all-gcc install-gcc
The --enable-cxx-flags configure option might be additionally used to control the build flags of the libstdc++ (included in this step):
--enable-cxx-flags='-fno-exceptions \
-ffunction-sections -fno-omit-frame-pointer'
In general the same C++ compile flags should be used as they'll appear when building the intended target code.
6. Build GCC newlib with the cross compiler (Part2)
cd ~/arm-none-eabi-src/build
mkdir newlib-1.20.0
cd newlib-1.20.0
../../src/newlib-1.20.0/configure --target=arm-none-eabi \
--prefix=$HOME/arm-none-eabi --disable-multilib \
--disable-newlib-supplied-syscalls
make all install
A note about the --disable-newlib-supplied-syscalls option:
Disabling the default newlib syscall stub implementation is generally a good idea when you intend to compile for targets without using a linux like operating system, or no OS at all. It will leave you with linker errors on unimplemented stub functions you'll need to provide for newlib.
Removing the option will still enable you to override the newlib provided stubs with your own implementations.
Though, when you plan to use the cross-toolchain in conjunction with CMake, you should omit this option. CMake does some basic tests using the specified compiler definitions (e.g. from a toolchain.cmake file), that'll fail without the default stub implementations supplied.
7. Complete installing GCC
cd ~/arm-none-eabi-src/build/gcc-4.7.1
make all install
8. Build GDB
cd ~/arm-none-eabi-src/build
mkdir gdb-7.4
cd gdb-7.4
../../src/gdb-7.4/configure --target=arm-none-eabi \
--prefix=$HOME/arm-none-eabi
make all install
UPDATE
The same works pretty well for GCC 4.8.2 also.
I am trying to build gcc 4.7.2 using a custom prefix $PREFIX
I have built and installed all the prerequisites into my prefix location, and then successfully configured, built and installed gcc.
The problem that I now have is that $PREFIX is not in the library search path, and therefore the shared libraries cannot be found.
$PREFIX/bin $ ./g++ ~/main.cpp
$PREFIX/libexec/gcc/x86_64-suse-linux/4.7.2/cc1plus: \
error while loading shared libraries: \
libcloog-isl.so.1: \
cannot open shared object file: No such file or directory
What works, but isn't ideal
If I export LD_LIBRARY_PATH=$PREFIX/lib then it works, but I'm looking for something which works without having to set environment variables.
If I use patchelf to set the RPATH on all the gcc binaries then it also works; however this involves searching out all elf binaries and iterating over them calling patchelf, I would rather have something more permanent.
What I think would be ideal for my purposes
So I'm hoping there is a way to have -Wl,-rpath,$PREFIX/lib passed to make during the build process.
Since I know the paths won't need to be changed this seems like the most robust solution, and can be also be used for when we build the next gcc version.
Is configuring the build process to hard code the RPATH possible?
What I have tried, but doesn't work
Setting LDFLAGS_FOR_TARGET prior to calling configure:
All of these fail:
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib -R$PREFIX/lib"
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib"
export LDFLAGS_FOR_TARGET="-L$PREFIX/lib -Wl,-rpath,$PREFIX/lib"
Setting LDFLAGS prior to calling configure:
export LDFLAGS="-L$PREFIX/lib -Wl,-rpath,$PREFIX/lib"
In any event I worry that these will override any of the LDFLAGS gcc would have had, so I'm not sure these are a viable option even if they could be made to work?
My configure line
For completeness here is the line I pass to configure:
./configure \
--prefix=$PREFIX \
--build=x86_64-suse-linux \
--with-pkgversion='SIG build 12/10/2012' \
--disable-multilib \
--enable-cloog-backend=isl \
--with-mpc=$PREFIX \
--with-mpfr=$PREFIX \
--with-gmp=$PREFIX \
--with-cloog=$PREFIX \
--with-ppl=$PREFIX \
--with-gxx-include-dir=$PREFIX/include/c++/4.7.2
I've found that copying the source directories for gmp, mpfr, mpc, isl, cloog, etc. into the top level gcc source directory (or using symbolic links with the same name) works everywhere. This is in fact the preferred way.
You need to copy (or link) to those source directory names without the version numbers for this to work.
The compilers do not need LD_LIBRARY_PATH (although running applications built with the compilers will need an LD_LIBRARY_PATH to the $PREFIX/lib64 or something like that - but that's different)
Start in a source directory where you'll keep all your sources.
In this source directory you have your gcc directory either by unpacking a tarball or svn...
I use subversion.
Also in this top level directory you have, say, the following source tarballs:
gmp-5.1.0.tar.bz2
mpfr-3.1.1.tar.bz2
mpc-1.0.1.tar.gz
isl-0.11.1.tar.bz2
cloog-0.18.0.tar.gz
I just download these and update to the latest tarballs periodically.
In script form:
# Either:
svn checkout svn://gcc.gnu.org/svn/gcc/trunk gcc_work
# Or:
bunzip -c gcc-4.8.0.tar.bz2 | tar -xvf -
mv gcc-4.8.0 gcc_work
# Uncompress sources.. (This will produce version numbered directories).
bunzip -c gmp-5.1.0.tar.bz2 | tar -xvf -
bunzip -c mpfr-3.1.1.tar.bz2 | tar -xvf -
gunzip -c mpc-1.0.1.tar.gz | tar -xvf -
bunzip -c isl-0.11.1.tar.bz2 | tar -xvf -
gunzip -c cloog-0.18.0.tar.gz | tar -xvf -
# Link outside source directories into the top level gcc directory.
cd gcc_work
ln -s ../gmp-5.1.0 gmp
ln -s ../mpfr-3.1.1 mpfr
ln -s ../mpc-1.0.1 mpc
ln -s ../isl-0.11.1 isl
ln -s ../cloog-0.18.0 cloog
# Get out of the gcc working directory and create a build directory. I call mine obj_work.
# I configure the gcc binary and other outputs to be bin_work in the top level directory. Your choice. But I have this:
# home/ed/projects
# home/ed/projects/gcc_work
# home/ed/projects/obj_work
# home/ed/projects/bin_work
# home/ed/projects/gmp-5.1.0
# home/ed/projects/mpfr-3.1.1
# home/ed/projects/mpc-1.0.1
# home/ed/projects/isl-0.11.1
# home/ed/projects/cloog-0.18.0
mkdir obj_work
cd obj_work
../gcc_work/configure --prefix=../bin_work <other options>
# Your <other options> shouldn't need to involve anything about gmp, mpfr, mpc, isl, cloog.
# The gcc build system will find the directories you linked,
# then configure and compile the needed libraries with the necessary flags and such.
# Good luck.
I've been using this configure option with gcc-4.8.0, on FreeBSD, after building and installing gmp, isl and cloog:
LD_LIBRARY_PATH=/path/to/isl/lib ./configure (lots of other options) \
--with-stage1-ldflags="-rpath /path/to/isl/lib -rpath /path/to/cloog/lib -rpath /path/to/gmp/lib"
and the resulting gcc binary does not need any LD_LIBRARY_PATH. The LD_LIBRARY_PATH for configure is needed because it compiles a test program to check for the ISL version, which would fail if it didn't find the ISL shared lib.
I tried it on Linux (Ubuntu) where it failed during configuring because the -rpath args were passed to gcc instead of ld. I could fix this by using
--with-stage1-ldflags="-Wl,-rpath,/path/to/isl/lib,-rpath,/path/to/cloog/lib,-rpath,/path/to/gmp/lib"
instead.
Just using configure --with-stage1-ldflags="-Wl,-rpath,/path/to/lib" was not enough for me to build gcc 4.9.2, bootstrap failed in stage 2. What works is to pass he flags directly to make via
make BOOT_LDFLAGS="-Wl,-rpath,/path/to/lib"
I got this from https://gcc.gnu.org/ml/gcc/2008-09/msg00214.html
While it still involves setting environment variables, what I do is that I define LD_RUN_PATH, which sets the rpath. That way the rest of the system can keep using the system provided libraries instead of using the ones that your gcc build generates.
I am going to make a suggestion that I believe solves your problem, although it definitely does not answer your question. Let's see how many downvotes I get.
Writing a generic wrapper script to set LD_LIBRARY_PATH and then to run the executable is easy; see https://stackoverflow.com/a/7101577/768469.
The idea is to pass something like --prefix=$PREFIX/install to configure, building an install tree that looks like this:
$PREFIX/
install/
lib/
libcloogXX.so
libgmpYY.so
...
bin/
gcc
emacs
...
bin/
.wrapper
gcc -> .wrapper
emacs -> .wrapper
.wrapper is a simple shell script:
#!/bin/sh
here="${0%/*}" # or use $(dirname "$0")
base="${0##*/}" # or use $(basename "$0")
libdir="$here"/../install/lib
if [ "$LD_LIBRARY_PATH"x = x ] ; then
LD_LIBRARY_PATH="$libdir"
else
LD_LIBRARY_PATH="$libdir":"$LD_LIBRARY_PATH"
fi
export LD_LIBRARY_PATH
exec "$here"/../install/bin/"$base" "$#"
This will forward all arguments correctly, handle spaces in arguments or directory names, and so forth. For practical purposes, it is indistinguishable from setting the rpath like you want.
Also, you can use this approach not only for gcc, but for your entire my-personal-$PREFIX tree. I do this all the time in environments where I want an up-to-date suite of GNU tools, but I do not have (or want to admit to have) root access.
Try to add your $PREFIX to /etc/ld.so.conf and then run ldconfig:
# echo $PREFIX >> /etc/ld.so.conf
# ldconfig
This will recreate cache that is used by runtime linker and it will pick up your libraries.
WARNING: This operation will cause ALL applications to use your newly compiled libraries in $PREFIX instead of default location
I'm getting this error:
OpenCV-2.4.3/modules/features2d/src/freak.cpp:437: error: unable to
find a register to spill in class 'GENERAL_REGS'
After doing:
tar xfj OpenCV-2.4.3.tar.bz2
cd OpenCV-2.4.3
mkdir release
cd release
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D BUILD_NEW_PYTHON_SUPPORT=ON -D BUILD_EXAMPLES=ON ..
make
The same procedure works on another machine. Any ideas?
You need to dig into the Makefiles to remove -O for freak.cpp.
UPDATE:
This is exactly how one should do it (tested with 2.4.3 and 2.4.4).
you need to edit
YOUR_BUILD_DIR/modules/features2d/CMakeFiles/opencv_features2d.dir/build.make
Search for freak.cpp. You find three blocks: Building CXX..., Preprocessing CXX..., and Compiling CX.... I just needed to change the Building part. The last line of that block looks like this:
.... YOUR_COMPILER $(CXX_DEFINES) $(CXX_FLAGS) ...
and if you check you find out that CXX_FLAGS has a -O3 in it. If you add -O0 after CXX_FLAGS it suppresses the O3. So your lines should look like this.
.... YOUR_COMPILER $(CXX_DEFINES) $(CXX_FLAGS) -O0 ...
This is at least working here!
I struggled with this for quite a few hours as well on my CentOS 5.x boxen, and here's my solution.
It's apparent you need to update 'gcc' but natively upgrading via RPM or just grabbing RPM's at random causing some serious config mgmt issues on your server. I don't have time to compile gcc/g++ via source right now either. After grazing out in the repo for a while, I found that there is, indeed, an 4.x release of gcc in the base repo.
Do this (or someone with 'root' to do it in case of OP who doesn't have access):
# yum install gcc44 gcc44-c++ -y
...CentOS/RHEL have bundled a preview RPM of gcc-4.4.6.
Then when you go to do 'cmake' to build your release environment, do at least the following (your cmake params may vary):
# cd /path/to/OpenCV-2.4.3
# mkdir release && cd release
# env CC=/usr/bin/gcc44 CXX=/usr/bin/g++44 cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/place/to/install/ -D BUILD_PYTHON_SUPPORT=ON /path/to/OpenCV-2.4.3/
That will give you a successful build of OpenCV-2.4.3 natively with CenOS/RHEL 5.x.
Had the same problem and solved it like wisehippy with one slight change:
# yum install gcc44 gcc44-c++ -y
# mkdir release && cd release
# cmake -D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_CXX_COMPILER=/usr/bin/g++44 -DCMAKE_C_COMPILER=/usr/bin/gcc44 <OpenCV_Dir>
I found the problem to be solved once I updated my c++ to point to g++44, instead of the default g++ which was 4.1.
As root verify that the files are the same before doing this step, it may not be necessary for you.
diff /usr/bin/c++ /usr/bin/g++
There should be nothing returned if the files are the same. If this is the case, continue.
Backup your old file. You can delete the file as well because it's the same as g++, but I like to be careful.
mv /usr/bin/c++ /usr/bin/c++4.1
Create a link so that C++ points to your g++44. You could use symbolic link here as well.
ln /usr/bin/g++44 /usr/bin/c++
Done.