diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1c0357e127fb94c639387be1b49f21a71aa87eb2..5206c9831750d3eb3306c1e767aadf592e4ce12b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -227,7 +227,7 @@ ubuntu-xdk-qa-code-coverage:
                ctest -V -S CI/main_qa.cmake
                      -DIMAGE_NAME:string=ubuntu-18.04-llvm-qa
                      -DQA:BOOL=ON
-    - gcovr -x -o build/coverage_report.xml -r . --gcov-executable="llvm-cov gcov" build
+    - ./CI/otb_coverage.sh
     - saxon-xslt -o build/ctest_report.xml
                  build/Testing/`head -n 1 build/Testing/TAG`/Test.xml
                  CI/ctest2junit.xsl
diff --git a/CI/otb_coverage.sh b/CI/otb_coverage.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8c9a194949248049420c49122e043710ca65fd73
--- /dev/null
+++ b/CI/otb_coverage.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# usage : call CI/otb_coverage.sh from source dir
+OTB_DIR="$(dirname $0)/.."
+OTB_DIR="$(readlink -f $OTB_DIR)"
+
+if [ -z "$BUILD_DIR" ]; then
+BUILD_DIR=${OTB_DIR}/build
+fi
+
+cd $BUILD_DIR
+mkdir cov_filter
+
+echo Generating gcov reports in $BUILD_DIR ...
+find $BUILD_DIR -name "*.gcda" -exec llvm-cov gcov -p '{}' > /dev/null \; 
+find . -maxdepth 1 -regex '.*#Modules#[a-zA-Z0-9]+#[a-zA-Z0-9]+#\(include\|src\|app\)#.*\.gcov' -exec mv '{}' cov_filter \;
+rm *.gcov
+cd $OTB_DIR
+
+echo Filtered $(ls $BUILD_DIR/cov_filter | wc -l) gcov reports
+
+echo Generating $BUILD_DIR/coverage_report.xml ...
+
+gcovr -r $OTB_DIR -x -g --object-directory=$BUILD_DIR/cov_filter > $BUILD_DIR/coverage_report.xml