OpenCV開發筆記(四十六):紅胖子8分鐘帶你深入瞭解仿射變化(圖文並茂+淺顯易懂+程序源碼)

若該文爲原創文章,未經允許不得轉載
原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105691534
各位讀者,知識無窮而人力有窮,要麼改需求,要麼找專業人士,要麼自己研究

目錄

前言

相關博客

Demo

仿射變換

概述

原理

與重映射原理區別

計算二維三角變換矩陣函數原型

計算二維旋轉變換矩陣函數原型

Demo源碼

工程模板:對應版本號v1.41.0


紅胖子(紅模仿)的博文大全:開發技術集合(包含Qt實用技術、樹莓派、三維、OpenCV、OpenGL、ffmpeg、OSG、單片機、軟硬結合等等)持續更新中...(點擊傳送門).

OpenCV開發專欄(點擊傳送門)

 

    OpenCV開發筆記(四十六):紅胖子8分鐘帶你深入瞭解仿射變化(圖文並茂+淺顯易懂+程序源碼)

 

前言

      紅胖子來也!!!

      圖像處理中的仿射,仿射其實原理與重映射類似,其可以理解爲更高級的重映射變換。

 

相關博客

OpenCV開發筆記(八):OpenCV常用操作之計時、縮放、旋轉、鏡像

該文章中,也同樣實現了部分簡單重映射效果,使用的四個函數:

  • 旋轉函數1:cv::transpose,直接對矩陣進行順時鐘旋轉90°
  • 旋轉函數2:cv::rotate,三個枚舉可以旋轉90°,180°,270°
  • 翻轉函數:cv::flip,xy軸翻轉
  • 縮放函數:cv::resize,縮放

OpenCV開發筆記(四十五):紅胖子8分鐘帶你深入瞭解重映射(圖文並茂+淺顯易懂+程序源碼)

 

Demo

 

仿射變換

概述

仿射變換(仿射映射)是指在幾何中,一個響亮空間進行一次線性變換並接上一個平移,變換爲另一個向量空間的過程。

一個任意的仿射都能表示爲乘以一個矩陣再加上一個向量(平移)的形式(注:重映射可以理解爲是一種簡單的仿射變換)。

  • 旋轉:rotation,線性變換;
  • 平移:translation,向量加;
  • 縮放,scale,線性變換;

原理

      仿射是用矩陣表示變換的關係,通常使用的是2 x 3的矩陣來表示仿射變換。

      整個映射關係爲:

      dst = src * A + B

其中:

      A爲線性變換矩陣,B爲向量加矩陣;

      對應的每個像素的變換關係,則是:

      dst(x,y) = src(x,y) * A + B

      下面上圖解釋仿射(三個點就是函數提供計算仿射矩陣需要我們輸入的點):

與重映射原理區別

仿射變換的原理與重映射不同,重映射是直接對像素點的序號進行映射,可以做些拉長,特點像素着重等等(如哈哈鏡),而仿射變換是對原矩陣的標準變換,有適合各自的場景。

void warpAffine( InputArray src,
              OutputArray dst,
              InputArray M,
              Size dsize,
              int flags = INTER_LINEAR,
              int borderMode = BORDER_CONSTANT,
              const Scalar& borderValue = Scalar());
  • 參數一:InputArray類型的src,一般爲cv::Mat;
  • 參數二:OutputArray類型的dst,目標圖像。它的大小、類型與src相同。
  • 參數三:InputArray類型的M,即變換矩陣,大小爲2 x 3。
  • 參數四:Size類型的size,表示輸出圖像的尺寸;
  • 參數五:int類型的interpolation,使用的插值方法;

  • 參數六:int類型的borderMode,邊界處理方式;

  • 參數七:Scalar類型的borderValue,重映射後,離羣點的背景,需要broderMode設置爲BORDER_CONSTRANT時纔有效。

計算二維三角變換矩陣函數原型

Mat getAffineTransform( InputArray src,
                     InputArray dst );
  • 參數一:InputArray類型的src,原來三個點的座標;
  • 參數二:OutputArray類型的dst,映射後三個點的座標;

計算二維旋轉變換矩陣函數原型

Mat getRotationMatrix2D( Point2f center,
                       double angle,
                       double scale );
  • 參數一:Point2f類型的center,輸入的旋轉中心點;
  • 參數二:double類型的angle,旋轉的角度(逆時針旋轉角度,非弧度);
  • 參數三:double類型的scale,縮放係數;

 

Demo源碼

void OpenCVManager::testAffineMap()
{
    QString fileName1 =
"E:/qtProject/openCVDemo/openCVDemo/modules/openCVManager/images/1.jpg";
    cv::Mat srcMat = cv::imread(fileName1.toStdString());
    cv::Mat dstMat;
    int width = 400;
    int height = 300;

    cv::resize(srcMat, srcMat, cv::Size(width, height));

    cv::String windowName = _windowTitle.toStdString();
    cvui::init(windowName);

    cv::Mat windowMat = cv::Mat(cv::Size(srcMat.cols * 2, 
                                         srcMat.rows * 4),
                                srcMat.type());

    while(true)
    {
        windowMat = cv::Scalar(0, 0, 0);

        cv::Mat mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                                cv::Range(srcMat.cols * 0, srcMat.cols * 1));
        cv::addWeighted(mat, 0.0f, srcMat, 1.0f, 0.0f, mat);

        // 第一種旋轉180度
        {
            cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2, 
                                                          srcMat.rows / 2),
                                                180.0f,
                                                1.0f);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 0, srcMat.rows * 1),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }

        // 第二種旋轉45度,縮小1/2
        {
            cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2, 
                                                          srcMat.rows / 2),
                                                45.0f,
                                                0.5f);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第三種旋轉315度,縮小1/2
        {
            cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2, 
                                                          srcMat.rows / 2),
                                                315.0f,
                                                0.5f);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 1, srcMat.rows * 2),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第四種旋轉135度,縮小1/2
        {
            cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2, 
                                                          srcMat.rows / 2),
                                                135.0f,
                                                0.5f);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第五種旋轉225度,縮小1/2
        {
            cv::Mat M = cv::getRotationMatrix2D(cv::Point(srcMat.cols / 2, 
                                                          srcMat.rows / 2),
                                                225.0f,
                                                0.5f);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 2, srcMat.rows * 3),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第六種使用三角點進行仿射變換,沿着對角線翻轉
        {
            cv::Point2f srcTraingle[3];
            cv::Point2f dstTraingle[3];
            srcTraingle[0] = cv::Point2f(0, 0);
            srcTraingle[1] = cv::Point2f(srcMat.cols - 1, 0);
            srcTraingle[2] = cv::Point2f(0, srcMat.rows - 1);
            dstTraingle[0] = cv::Point2f(0, 0);
            dstTraingle[1] = cv::Point2f(0, srcMat.rows - 1);
            dstTraingle[2] = cv::Point2f(srcMat.cols - 1, 0);

            cv::Mat M = cv::getAffineTransform(srcTraingle, dstTraingle);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 0, srcMat.cols * 1));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 第七種使用三角點進行仿射變換
        {
            cv::Point2f srcTraingle[3];
            cv::Point2f dstTraingle[3];
            srcTraingle[0] = cv::Point2f(0, 0);
            srcTraingle[1] = cv::Point2f(srcMat.cols - 1, 0);
            srcTraingle[2] = cv::Point2f(0, srcMat.rows - 1);
            dstTraingle[0] = cv::Point2f(srcMat.cols / 4, srcMat.rows / 4);
            dstTraingle[1] = cv::Point2f(srcMat.cols / 4 * 3, srcMat.rows / 4 );
            dstTraingle[2] = cv::Point2f(srcMat.cols / 2, srcMat.rows - 1);

            cv::Mat M = cv::getAffineTransform(srcTraingle, dstTraingle);
            dstMat = srcMat.clone();
            dstMat = cv::Scalar(0, 0, 0);
            cv::warpAffine(srcMat, dstMat, M, cv::Size(srcMat.cols, srcMat.rows));
            mat = windowMat(cv::Range(srcMat.rows * 3, srcMat.rows * 4),
                            cv::Range(srcMat.cols * 1, srcMat.cols * 2));
            cv::addWeighted(mat, 0.0f, dstMat, 1.0f, 0.0f, mat);
        }
        // 更新
        cvui::update();
        // 顯示
        cv::imshow(windowName, windowMat);
        // esc鍵退出
        if(cv::waitKey(25) == 27)
        {
            break;
        }
    }
}

 

工程模板:對應版本號v1.41.0

      對應版本號v1.41.0


原博主博客地址:https://blog.csdn.net/qq21497936
原博主博客導航:https://blog.csdn.net/qq21497936/article/details/102478062
本文章博客地址:https://blog.csdn.net/qq21497936/article/details/105691534

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章