diff --git a/modules/quality/include/opencv2/quality.hpp b/modules/quality/include/opencv2/quality.hpp
index 8470f08fefc..2322dcc0f20 100644
--- a/modules/quality/include/opencv2/quality.hpp
+++ b/modules/quality/include/opencv2/quality.hpp
@@ -11,5 +11,6 @@
 #include "quality/qualityssim.hpp"
 #include "quality/qualitygmsd.hpp"
 #include "quality/qualitybrisque.hpp"
+#include "quality/qualitymae.hpp"
 
 #endif
\ No newline at end of file
diff --git a/modules/quality/include/opencv2/quality/qualitymae.hpp b/modules/quality/include/opencv2/quality/qualitymae.hpp
new file mode 100644
index 00000000000..7c967300d9f
--- /dev/null
+++ b/modules/quality/include/opencv2/quality/qualitymae.hpp
@@ -0,0 +1,88 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef OPENCV_QUALITY_MAE_HPP
+#define OPENCV_QUALITY_MAE_HPP
+
+#include "qualitybase.hpp"
+
+
+namespace cv
+{
+
+namespace quality
+{
+
+/** @brief Flags to choose which algorithm MAE should use.
+ */
+enum MAEStatsFlags
+{
+    MAE_MAX,
+    MAE_MEAN
+};
+
+/** @brief This class implement two algorithm which commonly refered as MAE in the litterature.
+Both definition shares the absolute error, which can be defined as: \f[ absolute\_error(x,y) = |I_{ref}(x,y) - I_{cmp}(x,y)|\f].
+The two algorithms follows the mathematic:
+-   **MAE_MAX**
+    \f[score =  \fork{\texttt{absolute\_error(x,y)}}{if \(src(x,y) > score\)}{score}{otherwise}\f]
+-   **MAE_MEAN**
+    \f[score = \frac{\sum_{r=0}^{nb\_rows}\sum_{c=0}^{nb\_cols} \texttt{absolute\_error(r,c)}}{nb\_rows \times \nb\_cols}\f]
+More informations about the the Mean of Absolute Error can be found here: https://en.wikipedia.org/wiki/Mean_absolute_error
+*/
+class CV_EXPORTS_W QualityMAE : public QualityBase
+{
+public:
+    /** @brief Computes MAE for reference images supplied in class constructor and provided comparison images
+    @param cmpImgs Comparison image(s)
+    @returns cv::Scalar with per-channel quality values.  Values range from 0 (best) to potentially max float (worst)
+    */
+    CV_WRAP Scalar compute( InputArray cmpImgs ) CV_OVERRIDE;
+
+    /** @brief Implements Algorithm::empty()  */
+    CV_WRAP bool empty() const CV_OVERRIDE { return _ref.empty() && QualityBase::empty(); }
+
+    /** @brief Implements Algorithm::clear()  */
+    CV_WRAP void clear() CV_OVERRIDE { _ref = _mat_type(); QualityBase::clear(); }
+
+    /**
+    @brief Create an object which calculates quality
+    @param ref input image to use as the reference for comparison
+    @param statsProc statistical method to apply on the error
+    */
+    CV_WRAP static Ptr<QualityMAE> create(InputArray ref, int statsProc = MAE_MEAN);
+
+    /**
+    @brief static method for computing quality
+    @param ref reference image
+    @param cmp comparison image=
+    @param qualityMap output quality map, or cv::noArray()
+    @param statsProc which statistical method should be apply on the absolute error
+    @returns cv::Scalar with per-channel quality values.  Values range from 0 (best) to max float (worst)
+    */
+    CV_WRAP static Scalar compute( InputArray ref, InputArray cmp, OutputArray qualityMap, int statsProc = MAE_MEAN );
+
+
+protected:
+
+    /** @brief Reference image, converted to internal mat type */
+    QualityBase::_mat_type _ref;
+
+    /** @brief What statistics analysis to apply on the absolute error */
+    int _flag;
+
+    /**
+    @brief Constructor
+    @param ref reference image, converted to internal type
+    @param statsProc statistical method to apply on the error
+    */
+    QualityMAE(QualityBase::_mat_type ref, int statsProc);
+
+};
+
+} // quality
+
+} // cv
+
+#endif // OPENCV_QUALITY_MAE_HPP
diff --git a/modules/quality/src/qualitymae.cpp b/modules/quality/src/qualitymae.cpp
new file mode 100644
index 00000000000..a5bce730797
--- /dev/null
+++ b/modules/quality/src/qualitymae.cpp
@@ -0,0 +1,77 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "precomp.hpp"
+#include "opencv2/quality/qualitymae.hpp"
+#include "opencv2/quality/quality_utils.hpp"
+
+namespace cv
+{
+
+namespace quality
+{
+
+using namespace quality_utils;
+
+
+// Static
+Ptr<QualityMAE> QualityMAE::create(InputArray ref, int statsProc)
+{
+    return Ptr<QualityMAE>(new QualityMAE(quality_utils::expand_mat<_mat_type>(ref), statsProc));
+}
+
+// Static
+Scalar QualityMAE::compute(InputArray ref, InputArray cmp, OutputArray qualityMap, int statsProc)
+{
+    CV_Assert_3(ref.channels() <= 4,
+                cmp.channels() <= 4,
+                (statsProc == MAE_MAX) || (statsProc == MAE_MEAN) );
+
+    _mat_type err;
+    int wdepth = std::max(std::max(ref.depth(), cmp.depth()), CV_32F);
+    int cn = ref.channels();
+    int wtype = CV_MAKETYPE(wdepth, cn);
+
+    absdiff(extract_mat<_mat_type>(ref, wtype), extract_mat<_mat_type>(cmp, wtype), err);
+
+    if(qualityMap.needed())
+        qualityMap.assign(statsProc == MAE_MAX ? err : err.clone());
+
+    if(statsProc == MAE_MEAN)
+    {
+        return mean(err);
+    }
+
+    Scalar scores;
+    _mat_type tmp = err.reshape(err.channels(), 1);
+
+    reduce(tmp, tmp, 1, REDUCE_MAX, wdepth);
+
+    tmp.convertTo(Mat(tmp.size(), CV_64FC(cn), scores.val), CV_64F);
+
+    return scores;
+}
+
+// Not static
+Scalar QualityMAE::compute( InputArray cmpImg )
+{
+    CV_Assert(cmpImg.isMat() || cmpImg.isUMat() || cmpImg.isMatx());
+
+    if(cmpImg.empty())
+        return Scalar();
+
+    // If the input is a set of images.
+    _mat_type cmp = extract_mat<_mat_type>(cmpImg, std::max(cmpImg.depth(), CV_32F));
+
+    return QualityMAE::compute(this->_ref, cmp, this->_qualityMap, this->_flag);
+}
+
+QualityMAE::QualityMAE(QualityBase::_mat_type ref, int flag)
+    : _ref(std::move(ref)),
+      _flag(flag)
+{}
+
+} // quality
+
+} // cv
diff --git a/modules/quality/test/test_mae.cpp b/modules/quality/test/test_mae.cpp
new file mode 100644
index 00000000000..ef7532729ee
--- /dev/null
+++ b/modules/quality/test/test_mae.cpp
@@ -0,0 +1,73 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "test_precomp.hpp"
+
+#define TEST_CASE_NAME CV_Quality_MAE
+
+namespace opencv_test
+{
+namespace quality_test
+{
+
+namespace
+{
+const cv::Scalar
+    MAE_MAX_EXPECTED_1 = { 203. },
+    MAE_MEAN_EXPECTED_1 = { 33.5824 },
+    MAE_MAX_EXPECTED_2 = { 138., 145., 156. },
+    MAE_MEAN_EXPECTED_2 = { 5.7918, 6.0645, 5.5609}
+    ;
+} // anonymous
+
+// static method
+TEST(TEST_CASE_NAME, static_max )
+{
+    // Max
+    cv::Mat qMat = {};
+    quality_expect_near(quality::QualityMAE::compute(get_testfile_1a(), get_testfile_1a(), qMat, quality::MAE_MAX), cv::Scalar(0.)); // ref vs ref == 0
+    check_quality_map(qMat);
+}
+
+// static method
+TEST(TEST_CASE_NAME, static_mean )
+{
+    // Mean
+    cv::Mat qMat = {};
+    quality_expect_near(quality::QualityMAE::compute(get_testfile_1a(), get_testfile_1a(), qMat, quality::MAE_MEAN), cv::Scalar(0.)); // ref vs ref == 0
+    check_quality_map(qMat);
+}
+
+// single channel, with and without opencl
+TEST(TEST_CASE_NAME, single_channel_max )
+{
+    auto fn = []() { quality_test(quality::QualityMAE::create(get_testfile_1a(), quality::MAE_MAX), get_testfile_1b(), MAE_MAX_EXPECTED_1); };
+
+    OCL_OFF( fn() );
+    OCL_ON( fn() );
+}
+
+// single channel, with and without opencl
+TEST(TEST_CASE_NAME, single_channel_mean )
+{
+    auto fn = []() { quality_test(quality::QualityMAE::create(get_testfile_1a(), quality::MAE_MEAN), get_testfile_1b(), MAE_MEAN_EXPECTED_1); };
+
+    OCL_OFF( fn() );
+    OCL_ON( fn() );
+}
+
+// multi-channel max
+TEST(TEST_CASE_NAME, multi_channel_max)
+{
+    quality_test(quality::QualityMAE::create(get_testfile_2a(), quality::MAE_MAX), get_testfile_2b(), MAE_MAX_EXPECTED_2);
+}
+
+// multi-channel mean
+TEST(TEST_CASE_NAME, multi_channel_mean)
+{
+    quality_test(quality::QualityMAE::create(get_testfile_2a(), quality::MAE_MEAN), get_testfile_2b(), MAE_MEAN_EXPECTED_2);
+}
+
+} // namespace quality_test
+} // namespace opencv_test