- 操作系統:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 編程語言:C++11
1.算法描述
在OpenCV的G-API模塊中,圖像和通道合成(composition)函數允許用戶對圖像進行復雜的操作,如合并多個單通道圖像為一個多通道圖像,或者從一個多通道圖像中提取特定的通道。這些功能是通過G-API的Graph API實現的,旨在高效處理圖像數據流。
2.相關函數
2.1水平方向上拼接兩個圖像函數concatHor
對給定的矩陣應用水平拼接。
該函數將兩個具有相同行數的 GMat 矩陣進行水平拼接。
GMat A = { 1, 4,2, 5,3, 6 };
GMat B = { 7, 10,8, 11,9, 12 };
GMat C = gapi::concatHor(A, B);
//C:
//[1, 4, 7, 10;
// 2, 5, 8, 11;
// 3, 6, 9, 12]
輸出矩陣必須與 src1 和 src2 具有相同的行數和深度,并且列數是 src1 和 src2 列數之和。支持的矩陣數據類型包括:CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1。
注意:
函數的文字ID是 “org.opencv.imgproc.transform.concatHor”
2.1.1函數原型
GMat cv::gapi::concatHor
(const GMat & src1,const GMat & src2
)
2.1.2參數:
- 參數 src1:第一個輸入矩陣,用于水平拼接。
- 參數 src2:第二個輸入矩陣,用于水平拼接。
2.1.3 代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像cv::Mat src1 = (cv::Mat_<uchar>(3, 3) << 1, 2, 3,4, 5, 6,7, 8, 9);cv::Mat src2 = (cv::Mat_<uchar>(3, 2) << 10, 11,12, 13,14, 15);// 定義G-API計算圖cv::GComputation concatComp( []() {cv::GMat in1, in2;auto out = cv::gapi::concatHor( in1, in2 ); // 水平拼接兩張圖像return cv::GComputation( cv::GIn( in1, in2 ), cv::GOut( out ) );} );try{// 執行計算圖并獲取結果cv::Mat dst;concatComp.apply( cv::gin( src1, src2 ), cv::gout( dst ) );// 打印結果std::cout << "Concatenated image: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.1.4運行結果
Concatenated image:
[ 1, 2, 3, 10, 11;4, 5, 6, 12, 13;7, 8, 9, 14, 15]
2.2 垂直方向上拼接兩個圖像(矩陣)函數concatVert()
對給定的矩陣應用垂直拼接。
該函數將兩個具有相同列數(寬度)的 GMat 矩陣進行垂直拼接。
GMat A = { 1, 7,2, 8,3, 9 };
GMat B = { 4, 10,5, 11,6, 12 };
GMat C = gapi::concatVert(A, B);
//C:
//[1, 7;
// 2, 8;
// 3, 9;
// 4, 10;
// 5, 11;
// 6, 12]
輸出矩陣必須與 src1 和 src2 具有相同的列數和深度,并且行數是 src1 和 src2 行數之和。支持的矩陣數據類型包括:CV_8UC1, CV_8UC3, CV_16UC1, CV_16SC1, CV_32FC1。
注意:
函數的文字ID是 “org.opencv.imgproc.transform.concatVert”
2.2.1函數原型
GMat cv::gapi::concatVert
(const GMat & src1,const GMat & src2
)
2.2.2 參數:
- 參數 src1:第一個輸入矩陣,用于垂直拼接。
- 參數 src2:第二個輸入矩陣,用于垂直拼接。
2.2.3 代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像cv::Mat src1 = (cv::Mat_<uchar>(3, 3) << 1, 2, 3,4, 5, 6,7, 8, 9);cv::Mat src2 = (cv::Mat_<uchar>(2, 3) << 10, 11, 12,13, 14, 15);// 定義G-API計算圖cv::GComputation concatComp( []() {cv::GMat in1, in2;auto out = cv::gapi::concatVert( in1, in2 ); // 垂直拼接兩張圖像return cv::GComputation( cv::GIn( in1, in2 ), cv::GOut( out ) );} );try{// 執行計算圖并獲取結果cv::Mat dst;concatComp.apply( cv::gin( src1, src2 ), cv::gout( dst ) );// 打印結果std::cout << "Concatenated image: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.2.4運行結果
Concatenated image:
[ 1, 2, 3;4, 5, 6;7, 8, 9;10, 11, 12;13, 14, 15]
2.3將輸入矩陣 src 轉換為指定的數據深度函數convertTo()
將一個矩陣轉換為另一種數據深度,并可選擇進行縮放。
該方法將源像素值轉換為目標數據深度。最終應用 saturate_cast<> 以避免可能出現的溢出:
m ( x , y ) = s a t u r a t e _ c a s t < r T y p e > ( α ( ? t h i s ) ( x , y ) + β ) m(x,y) = saturate \_ cast<rType>( \alpha (*this)(x,y) + \beta ) m(x,y)=saturate_cast<rType>(α(?this)(x,y)+β)
輸出矩陣必須與輸入矩陣具有相同的大小。
注意:
函數的文字ID是 “org.opencv.core.transform.convertTo”
2.3.1函數原型
GMat cv::gapi::convertTo
(const GMat & src,int rdepth,double alpha = 1,double beta = 0
)
2.3.2參數
- 參數src:要從中轉換的輸入矩陣。
- 參數rdepth:期望的輸出矩陣深度,或者更確切地說是深度,因為通道數與輸入相同;如果 rdepth 為負值,則輸出矩陣將具有與輸入相同的深度。
- 參數alpha:可選的比例因子。
- 參數beta:可選的加到縮放值上的增量。
2.3.3代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像cv::Mat src = (cv::Mat_<uchar>(3, 3) << 10, 20, 30,40, 50, 60,70, 80, 90);int rdepth = CV_32F; // 將數據類型轉換為32位浮點數double alpha = 1.0; // 縮放因子double beta = 0.0; // 偏移量// 定義G-API計算圖cv::GComputation convertComp( [ = ]() { // 使用 [=] 捕獲所有外部變量cv::GMat in;auto out = cv::gapi::convertTo( in, rdepth, alpha, beta ); // 轉換數據類型return cv::GComputation( cv::GIn( in ), cv::GOut( out ) );}() );try{// 執行計算圖并獲取結果cv::Mat dst;convertComp.apply( cv::gin( src ), cv::gout( dst ) );// 打印結果std::cout << "Converted image: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.3.4運行結果
Converted image:
[10, 20, 30;40, 50, 60;70, 80, 90]
2.4創建一個輸入矩陣 in 的副本函數copy()
制作輸入圖像的副本。請注意,這個副本可能不是實際的(沒有實際復制數據)。使用此函數以維持圖的約定,例如當圖的輸入需要直接傳遞到輸出時,就像在流模式下一樣。
注意:
函數的文字ID是 “org.opencv.streaming.copy”
2.4.1函數原型
GMat cv::gapi::copy
(const GMat & in
)
2.4.2參數
- 參數 in:輸入圖像
2.4.3代碼示例
include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像cv::Mat src = (cv::Mat_<uchar>(3, 3) << 10, 20, 30,40, 50, 60,70, 80, 90);// 定義G-API計算圖cv::GComputation copyComp([](){cv::GMat in;auto out = cv::gapi::copy(in); // 復制輸入矩陣return cv::GComputation(cv::GIn(in), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;copyComp.apply(cv::gin(src), cv::gout(dst));// 打印結果std::cout << "Copied image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.4.4運行結果
Copied image:
[ 10, 20, 30;40, 50, 60;70, 80, 90]
2.5從輸入矩陣 src 中裁剪出一個指定的矩形區域函數 crop()
裁剪一個二維矩陣。
該函數根據給定的 cv::Rect 裁剪矩陣。
輸出矩陣必須與輸入矩陣具有相同的深度,大小由給定的矩形大小指定。
注意:
函數的文字ID是 “org.opencv.core.transform.crop”
2.5.1函數原型
GMat cv::gapi::crop
(const GMat & src,const Rect & rect
)
2.5.2參數
- 參數src:輸入矩陣。
- 參數rect:用于裁剪矩陣的矩形區域。
2.5.3代碼示例
include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像cv::Mat src = (cv::Mat_<uchar>(5, 5) << 1, 2, 3, 4, 5,6, 7, 8, 9, 10,11, 12, 13, 14, 15,16, 17, 18, 19, 20,21, 22, 23, 24, 25);// 定義要裁剪的矩形區域cv::Rect rect(1, 1, 3, 3); // x=1, y=1, width=3, height=3// 定義G-API計算圖cv::GComputation cropComp([](){cv::GMat in;cv::GMat out = cv::gapi::crop(in, cv::Rect(1, 1, 3, 3)); // 裁剪輸入矩陣return cv::GComputation(cv::GIn(in), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;cropComp.apply(cv::gin(src), cv::gout(dst));// 打印結果std::cout << "Cropped image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.5.4運行結果
Cropped image:
[ 7, 8, 9;12, 13, 14;17, 18, 19]
2.6根據指定的翻轉代碼 flipCode 翻轉輸入矩陣 src函數flip()
圍繞垂直軸、水平軸或兩個軸翻轉一個二維矩陣。
該函數以三種不同的方式之一翻轉矩陣(行和列的索引是從0開始的):
dst i j = { src src.rows ? i ? 1 , j i f flipCode = 0 src i , src.cols ? j ? 1 i f flipCode > 0 src src.rows ? i ? 1 , src.cols ? j ? 1 i f flipCode < 0 \texttt{dst} _{ij} = \left\{ \begin{array}{l l} \texttt{src} _{\texttt{src.rows}-i-1,j} & if\; \texttt{flipCode} = 0 \\ \texttt{src} _{i, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} > 0 \\ \texttt{src} _{ \texttt{src.rows} -i-1, \texttt{src.cols} -j-1} & if\; \texttt{flipCode} < 0 \\ \end{array} \right. dstij?=? ? ??srcsrc.rows?i?1,j?srci,src.cols?j?1?srcsrc.rows?i?1,src.cols?j?1??ifflipCode=0ifflipCode>0ifflipCode<0?
使用此函數的一些示例場景包括:圖像的垂直翻轉(flipCode == 0),以在左上角和左下角圖像原點之間切換。這是在Microsoft Windows*操作系統上進行視頻處理時的典型操作。接著進行水平位移并計算絕對差值以檢查垂直軸對稱性的圖像水平翻轉(flipCode > 0)。接著進行位移并計算絕對差值以檢查中心對稱性的同時水平和垂直翻轉圖像(flipCode < 0)。反轉點數組的順序(flipCode > 0 或 flipCode == 0)。輸出圖像必須與輸入圖像具有相同的深度,尺寸應根據給定的 flipCode 正確設置。
注意:
函數的文字ID是 “org.opencv.core.transform.flip”
2.6.1函數原型
GMat cv::gapi::flip
(const GMat & src,int flipCode
)
2.6.2參數
- 參數 src:輸入矩陣。
- 參數 flipCode:指定如何翻轉數組的一個標志;0表示繞x軸翻轉,正值(例如1)表示繞y軸翻轉。負值(例如-1)表示同時繞兩個軸翻轉。
2.6.3代碼示例
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/opencv.hpp>int main()
{// 創建示例輸入圖像cv::Mat src = ( cv::Mat_< uchar >( 3, 3 ) << 1, 2, 3, 4, 5, 6, 7, 8, 9 );// 定義翻轉代碼:這里選擇水平翻轉int flipCode = 1; // 水平翻轉// 定義G-API計算圖cv::GComputation flipComp( [ flipCode ]() {cv::GMat in;auto out = cv::gapi::flip( in, flipCode ); // 根據flipCode翻轉輸入矩陣return cv::GComputation( cv::GIn( in ), cv::GOut( out ) );} );try{// 執行計算圖并獲取結果cv::Mat dst;flipComp.apply( cv::gin( src ), cv::gout( dst ) );// 打印結果std::cout << "Flipped image: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.6.4運行結果
Flipped image:
[ 3, 2, 1;6, 5, 4;9, 8, 7]
2.7對輸入矩陣 src 應用查找表(Look-Up Table, LUT)函數LUT()
對一個矩陣執行查找表變換。
LUT 函數使用查找表中的值填充輸出矩陣。查找表的索引取自輸入矩陣。也就是說,該函數處理 src 的每個元素的方式如下:
支持的矩陣數據類型是 CV_8UC1。輸出矩陣與 src 具有相同的大小和通道數,并且與 lut 具有相同的深度。
注意:
函數的文字ID是 “org.opencv.core.transform.LUT”
2.7.1函數原型
GMat cv::gapi::LUT
(const GMat & src,const Mat & lut
)
2.7.2參數
- 參數 src: 輸入矩陣,元素為8位。
- 參數 lut: 查找表,包含256個元素;在多通道輸入數組的情況下,查找表應該要么只有一個通道(在這種情況下,所有通道使用相同的查找表)或者與輸入矩陣具有相同數量的通道。
2.7.3代碼示例
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/opencv.hpp>int main()
{// 創建示例輸入圖像cv::Mat src = ( cv::Mat_< uchar >( 3, 3 ) << 0, 50, 100, 150, 200, 250, 255, 128, 64 );// 創建查找表cv::Mat lut( 1, 256, CV_8U );uchar* p = lut.ptr< uchar >();for ( int i = 0; i < 256; ++i ){p[ i ] = static_cast< uchar >( 255 - i ); // 反轉查找表}// 定義G-API計算圖cv::GComputation lutComp( [ = ]() {cv::GMat in;cv::GMat out = cv::gapi::LUT( in, lut ); // 正確地應用查找表return cv::GComputation( cv::GIn( in ), cv::GOut( out ) );} );try{// 執行計算圖并獲取結果cv::Mat dst;lutComp.apply( cv::gin( src ), cv::gout( dst ) );// 打印結果std::cout << "Image after LUT: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.7.4運行結果
Image after LUT:
[255, 205, 155;105, 55, 5;0, 127, 191]
2.8 將三個單通道的 GMat 圖像合并成一個多通道(三通道)的圖像函數merge3()
從3個單通道矩陣創建一個3通道矩陣。
該函數將多個矩陣合并為一個多通道矩陣。也就是說,輸出矩陣的每個元素將是輸入矩陣元素的串聯,其中第 i 個輸入矩陣的元素被視為 mv[i].channels() 元素向量。輸出矩陣必須是 CV_8UC3 類型。
函數 split3 執行相反的操作。
注意:
函數的文字ID是 “org.opencv.core.transform.merge3”
2.8.1函數原型
GMat cv::gapi::merge3
(const GMat & src1,const GMat & src2,const GMat & src3
)
2.8.2參數
- 參數src1: 首個需要合并的輸入 CV_8UC1 矩陣。
- 參數 src2: 第二個需要合并的輸入 CV_8UC1 矩陣。
- 參數 src3: 第三個需要合并的輸入 CV_8UC1 矩陣。
2.8.3代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像(單通道)cv::Mat src1 = (cv::Mat_<uchar>(3, 3) << 10, 20, 30,40, 50, 60,70, 80, 90);cv::Mat src2 = (cv::Mat_<uchar>(3, 3) << 100, 110, 120,130, 140, 150,160, 170, 180);cv::Mat src3 = (cv::Mat_<uchar>(3, 3) << 190, 200, 210,220, 230, 240,250, 260, 270);// 定義G-API計算圖cv::GComputation mergeComp([](){cv::GMat in1, in2, in3;auto out = cv::gapi::merge3(in1, in2, in3); // 合并三個單通道圖像return cv::GComputation(cv::GIn(in1, in2, in3), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;mergeComp.apply(cv::gin(src1, src2, src3), cv::gout(dst));// 打印結果std::cout << "Merged image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.8.4運行結果
Merged image:
[ 10, 100, 190, 20, 110, 200, 30, 120, 210;40, 130, 220, 50, 140, 230, 60, 150, 240;70, 160, 250, 80, 170, 4, 90, 180, 14]
2.9將四個單通道的 GMat 圖像合并成一個多通道(四通道)的圖像函數merge4()
從4個單通道矩陣創建一個4通道矩陣。
該函數將多個矩陣合并為一個多通道矩陣。也就是說,輸出矩陣的每個元素將是輸入矩陣元素的串聯,其中第 i 個輸入矩陣的元素被視為 mv[i].channels() 元素向量。輸出矩陣必須是 CV_8UC4 類型。
函數 split4 執行相反的操作。
注意:
函數的文字ID是 “org.opencv.core.transform.merge4”
2.9.1函數原型
GMat cv::gapi::merge4
(const GMat & src1,const GMat & src2,const GMat & src3,const GMat & src4
)
2.9.2參數
- 參數src1: 首個需要合并的輸入 CV_8UC1 矩陣。
- 參數src2: 第二個需要合并的輸入 CV_8UC1 矩陣。
- 參數src3: 第三個需要合并的輸入 CV_8UC1 矩陣。
- 參數src4: 第四個需要合并的輸入 CV_8UC1 矩陣
2.9.3代碼示例
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/opencv.hpp>int main()
{// 創建示例輸入圖像(單通道)cv::Mat src1 = ( cv::Mat_< uchar >( 2, 2 ) << 10, 20, 30, 40 );cv::Mat src2 = ( cv::Mat_< uchar >( 2, 2 ) << 50, 60, 70, 80 );cv::Mat src3 = ( cv::Mat_< uchar >( 2, 2 ) << 90, 100, 110, 120 );cv::Mat src4 = ( cv::Mat_< uchar >( 2, 2 ) << 130, 140, 150, 160 );// 定義G-API計算圖cv::GComputation mergeComp( []() {cv::GMat in1, in2, in3, in4;auto out = cv::gapi::merge4( in1, in2, in3, in4 ); // 合并四個單通道圖像return cv::GComputation( cv::GIn( in1, in2, in3, in4 ), cv::GOut( out ) );} );try{// 執行計算圖并獲取結果cv::Mat dst;mergeComp.apply( cv::gin( src1, src2, src3, src4 ), cv::gout( dst ) );// 打印結果std::cout << "Merged image: \n" << dst << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.9.4運行結果
Merged image:
[ 10, 50, 90, 130, 20, 60, 100, 140;30, 70, 110, 150, 40, 80, 120, 160]
2.10對輸入矩陣 src 進行歸一化操作函數normalize()
歸一化數組的范數或值范圍。
該函數通過縮放和移位輸入數組元素來實現歸一化,使得
∥ dst ∥ L p = alpha \| \texttt{dst} \| _{L_p}= \texttt{alpha} ∥dst∥Lp??=alpha
其中 p=Inf, 1 或 2)當 normType 分別為 NORM_INF, NORM_L1 或 NORM_L2 時;或者使得
min ? I dst ( I ) = alpha , max ? I dst ( I ) = beta \min _I \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I \texttt{dst} (I)= \texttt{beta} Imin?dst(I)=alpha,Imax?dst(I)=beta
當 normType 為 NORM_MINMAX 時(僅適用于密集數組)。
注意:
函數的文字ID是 “org.opencv.core.normalize”
2.10.1函數原型
GMat cv::gapi::normalize
(const GMat & src,double alpha,double beta,int norm_type,int ddepth = -1
)
2.10.2參數
- 參數src: 輸入數組。
- 參數 alpha: 歸一化的目標范數值,或者在范圍歸一化時的下界。
- 參數 beta: 在范圍歸一化時的上界;在范數歸一化時不使用。
- 參數 norm_type: 歸一化類型(參見 cv::NormTypes)。
- 參數 ddepth: 當為負值時,輸出數組與 src 類型相同;否則,它具有與 src 相同的通道數且深度為 ddepth。
2.10.3 代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像(單通道)cv::Mat src = (cv::Mat_<float>(3, 3) << 1.0f, 2.0f, 3.0f,4.0f, 5.0f, 6.0f,7.0f, 8.0f, 9.0f);// 定義歸一化參數double alpha = 0.0;double beta = 1.0;int norm_type = cv::NORM_MINMAX;int ddepth = -1; // 使用與輸入相同的深度// 定義G-API計算圖cv::GComputation normalizeComp([=]() {cv::GMat in;auto out = cv::gapi::normalize(in, alpha, beta, norm_type, ddepth); // 歸一化操作return cv::GComputation(cv::GIn(in), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;normalizeComp.apply(cv::gin(src), cv::gout(dst));// 打印結果std::cout << "Normalized image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.10.4運行結果
Normalized image:
[0, 0.125, 0.25;0.375, 0.5, 0.625;0.75, 0.875, 1]
2.11對輸入圖像 src 進行重映射(remapping)函數remap()
應用一個通用的幾何變換到圖像上。
該函數使用指定的映射對源圖像進行變換:
dst ( x , y ) = src ( m a p x ( x , y ) , m a p y ( x , y ) ) \texttt{dst} (x,y) = \texttt{src} (map_x(x,y),map_y(x,y)) dst(x,y)=src(mapx?(x,y),mapy?(x,y))
其中,具有非整數坐標的像素值將使用一種可用的插值方法計算。mapx 和 mapy 可以分別編碼為 map1 和 map2 中的獨立浮點映射,或者在 map1 中交錯存儲的 (x,y) 浮點映射,或者通過使用 convertMaps 創建的定點映射。你可能希望從浮點表示轉換到定點表示的原因是它們可以顯著加快(高達2倍)重映射操作。在轉換后的情況下,map1 包含 (cvFloor(x), cvFloor(y)) 對,而 map2 包含插值系數表中的索引。輸出圖像必須與輸入圖像具有相同的大小和深度。
注意:
函數的文字ID是 “org.opencv.core.transform.remap”
由于當前實現的限制,輸入和輸出圖像的尺寸應小于 32767x32767。
2.11.1函數原型
GMat cv::gapi::remap
(const GMat & src,const Mat & map1,const Mat & map2,int interpolation,int borderMode = BORDER_CONSTANT,const Scalar & borderValue = Scalar()
)
2.11.2參數
- 參數src: 源圖像。
- 參數 map1: 第一個映射,包含 (x,y) 點或僅 x 值,類型為 CV_16SC2, CV_32FC1 或 CV_32FC2。
- 參數 map2: 第二個映射,包含 y 值,類型為 CV_16UC1, CV_32FC1,或者如果 map1 是 (x,y) 點則為空。
- 參數 interpolation: 插值方法(參見 cv::InterpolationFlags)。此函數不支持 INTER_AREA 和 INTER_LINEAR_EXACT 方法。
- 參數 borderMode: 像素外推方法(參見 cv::BorderTypes)。當 borderMode=BORDER_TRANSPARENT 時,這意味著目標圖像中對應于源圖像“異常值”的像素不會被函數修改。
- 參數 borderValue: 在使用常量邊界模式時使用的值,默認為 0。
2.11.3代碼示例
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像(單通道)cv::Mat src = (cv::Mat_<uchar>(3, 3) << 1, 2, 3,4, 5, 6,7, 8, 9);// 創建映射表cv::Mat map1 = (cv::Mat_<float>(3, 3) << 0.0f, 1.0f, 2.0f,0.0f, 1.0f, 2.0f,0.0f, 1.0f, 2.0f);cv::Mat map2 = (cv::Mat_<float>(3, 3) << 0.0f, 0.0f, 0.0f,1.0f, 1.0f, 1.0f,2.0f, 2.0f, 2.0f);// 定義插值方法和邊界模式int interpolation = cv::INTER_LINEAR;int borderMode = cv::BORDER_CONSTANT;cv::Scalar borderValue(0); // 默認值// 定義G-API計算圖cv::GComputation remapComp([=]() {cv::GMat in;auto out = cv::gapi::remap(in, map1, map2, interpolation, borderMode, borderValue); // 重映射操作return cv::GComputation(cv::GIn(in), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;remapComp.apply(cv::gin(src), cv::gout(dst));// 打印結果std::cout << "Remapped image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;
**加粗樣式** return -1;}return 0;
}
2.11.4運行結果
Remapped image:
[ 1, 2, 3;4, 5, 6;7, 8, 9]
2.12 調整輸入圖像 src 的大小函數resize()
調整圖像大小。
該函數將圖像 src 調整到指定大小,可以是縮小或放大。
輸出圖像的大小將會是 dsize(當 dsize 非零時)或者根據 src.size()、fx 和 fy 計算得出;輸出圖像的深度與 src 相同。
如果你想調整 src 的大小以適合預先創建的 dst,你可以這樣調用函數:
// explicitly specify dsize=dst.size(); fx and fy will be computed from that.
resize(src, dst, dst.size(), 0, 0, interpolation);
如果你想在每個方向上按比例縮小圖像因子為 2,你可以這樣調用函數:
// specify fx and fy and let the function compute the destination image size.
resize(src, dst, Size(), 0.5, 0.5, interpolation);
為了縮小圖像,通常使用 cv::INTER_AREA 插值方法效果最佳;而要放大圖像,通常使用 cv::INTER_CUBIC(較慢)或 cv::INTER_LINEAR(較快但仍看起來不錯)插值方法效果最佳。
注意:
函數的文字ID是 “org.opencv.imgproc.transform.resize”
2.12.1函數原型
GMat cv::gapi::resize
(const GMat & src,const Size & dsize,double fx = 0,double fy = 0,int interpolation = INTER_LINEAR
)
2.12.2參數
- 參數 src: 輸入圖像。
- 參數 dsize: 輸出圖像大小;如果其等于零,則根據以下公式計算:
2.12.3示例代碼
#include <opencv2/opencv.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi.hpp>int main() {// 創建示例輸入圖像(單通道)cv::Mat src = (cv::Mat_<uchar>(2, 2) << 1, 2,3, 4);// 定義目標尺寸cv::Size dsize(4, 4); // 將原圖放大到4x4// 定義縮放因子(不使用時設為0)double fx = 0;double fy = 0;// 定義插值方法int interpolation = cv::INTER_LINEAR;// 定義G-API計算圖cv::GComputation resizeComp([=]() {cv::GMat in;auto out = cv::gapi::resize(in, dsize, fx, fy, interpolation); // 調整大小操作return cv::GComputation(cv::GIn(in), cv::GOut(out));});try {// 執行計算圖并獲取結果cv::Mat dst;resizeComp.apply(cv::gin(src), cv::gout(dst));// 打印結果std::cout << "Resized image: \n" << dst << std::endl;} catch (const std::exception &e) {std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.12.4運行結果
Resized image:
[ 1, 1, 2, 2;2, 2, 2, 3;3, 3, 3, 4;3, 3, 4, 4]
2.13 調整打包像素格式(Planar, GMatP)圖像大小的函數resizeP()
該函數將圖像 src 調整到指定大小,可以是縮小或放大。打包圖像的內存布局是三個平面在內存中連續排列,因此圖像的高度應該是 plane_height * plane_number,圖像類型為 CV_8UC1。
輸出圖像的大小將會是 dsize,輸出圖像的深度與 src 相同。
注意:
函數的文字ID是 “org.opencv.imgproc.transform.resizeP”
2.13.1函數原型
GMatP cv::gapi::resizeP
(const GMatP & src,const Size & dsize,int interpolation = cv::INTER_LINEAR
)
2.13.2參數
- 參數src: 輸入圖像,必須是 CV_8UC1 類型;
- 參數 dsize: 輸出圖像大小;
- 參數 interpolation: 插值方法,目前僅支持 cv::INTER_LINEAR。
2.13.3示例代碼
沒有寫出正確的代碼,后續加上。。。。。
2.14將一個多通道的 GMat 拆分為三個單通道的 GMat函數split3()
將一個3通道矩陣拆分為3個單通道矩陣。
該函數將一個3通道矩陣拆分為3個單通道矩陣:
mv [ c ] ( I ) = src ( I ) c \texttt{mv} [c](I) = \texttt{src} (I)_c mv[c](I)=src(I)c?
所有輸出矩陣必須是 CV_8UC1 類型。
函數 merge3 執行相反的操作。
注意
函數的文本標識符是 “org.opencv.core.transform.split3”
2.14.1函數原型
std::tuple<GMat, GMat, GMat> cv::gapi::split3
(const GMat & src
)
2.14.2參數
- 參數src 輸入的 CV_8UC3 矩陣。
2.14.3代碼示例
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi/imgproc.hpp> // 包含其他可能需要的G-API模塊
#include <opencv2/opencv.hpp>int main()
{// 創建或加載示例輸入圖像(假設是三通道BGR圖像)cv::Mat src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png" ); // 加載實際圖像if ( src.empty() ){std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定義G-API計算圖來拆分圖像cv::GComputation comp( []() {cv::GMat in; // 輸入:多通道GMatauto [ b, g, r ] = cv::gapi::split3( in ); // 使用split3函數拆分圖像return cv::GComputation( cv::GIn( in ), cv::GOut( b, g, r ) );} );// 輸出結果cv::Mat b, g, r;try{// 執行計算圖并傳入實際的cv::Mat數據comp.apply( cv::gin( src ), cv::gout( b, g, r ) );// 打印每個通道的信息std::cout << "Blue channel:\n" << b << "\nGreen channel:\n" << g << "\nRed channel:\n" << r << std::endl;}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.14.4運行結果
輸出太占屏幕,不展示了
2.15將一個四通道的 GMat 拆分為四個單通道的 GMat函數split4()
將一個4通道矩陣拆分為4個單通道矩陣。
該函數將一個4通道矩陣拆分為4個單通道矩陣:
mv [ c ] ( I ) = src ( I ) c \texttt{mv} [c](I) = \texttt{src} (I)_c mv[c](I)=src(I)c?
所有輸出矩陣必須是 CV_8UC1 類型。
函數 merge4 執行相反的操作。
注意
函數的文本標識符是 “org.opencv.core.transform.split4”
2.15.1函數原型
std::tuple<GMat, GMat, GMat,GMat> cv::gapi::split4
(const GMat & src
)
2.15.2參數
- 參數 src 輸入的 CV_8UC4 矩陣。
2.15.3示例代碼
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/opencv.hpp>int main()
{// 創建或加載示例輸入圖像(假設是四通道RGBA圖像)cv::Mat src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png", cv::IMREAD_UNCHANGED ); // 加載實際圖像,確保包含alpha通道if ( src.empty() ){std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}if (src.channels() == 3) { // 如果圖像是三通道std::vector<cv::Mat> channels;cv::split(src, channels); // 分離BGR通道cv::Mat alpha(src.size(), CV_8UC1, cv::Scalar(255)); // 創建一個全透明的Alpha通道channels.push_back(alpha); // 添加Alpha通道cv::merge(channels, src); // 合并通道回到四通道圖像}// 確保輸入是CV_8UC4類型if ( src.type() != CV_8UC4 ){std::cerr << "Error: Input image must be of type CV_8UC4!" << std::endl;return -1;}// 定義G-API計算圖來拆分圖像cv::GComputation comp( []() {cv::GMat in; // 輸入:多通道GMatauto [ b, g, r, a ] = cv::gapi::split4( in ); // 使用split4函數拆分圖像return cv::GComputation( cv::GIn( in ), cv::GOut( b, g, r, a ) );} );// 輸出結果cv::Mat b, g, r, a;try{// 執行計算圖并傳入實際的cv::Mat數據comp.apply( cv::gin( src ), cv::gout( b, g, r, a ) );// 確保輸出是CV_8UC1類型if ( b.type() != CV_8UC1 || g.type() != CV_8UC1 || r.type() != CV_8UC1 || a.type() != CV_8UC1 ){std::cerr << "Error: Output images must be of type CV_8UC1!" << std::endl;return -1;}// 可視化結果(可選)cv::imshow( "Blue Channel", b );cv::imshow( "Green Channel", g );cv::imshow( "Red Channel", r );cv::imshow( "Alpha Channel", a );cv::waitKey( 0 ); // 等待按鍵事件}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.15.4運行結果
2.16仿射變換函數warpAffine()
應用仿射變換到圖像。
函數 warpAffine 使用指定的矩陣對源圖像進行變換:
dst ( x , y ) = src ( M 11 x + M 12 y + M 13 , M 21 x + M 22 y + M 23 ) \texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23}) dst(x,y)=src(M11?x+M12?y+M13?,M21?x+M22?y+M23?)
當設置了標志 WARP_INVERSE_MAP 時。否則,首先使用 invertAffineTransform 反轉變換,然后將其放入上述公式中代替 MM。該函數不能就地操作(即輸入圖像和輸出圖像不能是同一個對象)。
2.16.1函數原型
GMat cv::gapi::warpAffine
(const GMat & src,const Mat & M,const Size & dsize,int flags = cv::INTER_LINEAR,int borderMode = cv::BORDER_CONSTANT,const Scalar & borderValue = Scalar()
)
2.16.2參數
- 參數 src: 輸入圖像。
- 參數 M: 2×3 的變換矩陣。
- 參數 dsize: 輸出圖像的尺寸。
- 參數 flags: 插值方法的組合(參見 InterpolationFlags)以及可選的標志 WARP_INVERSE_MAP,表示 MM 是逆變換(從 dst 到 src)。
- 參數 borderMode: 像素外推方法(參見 BorderTypes);不支持 BORDER_TRANSPARENT。
- 參數 borderValue: 在使用常量邊界模式時使用的值;默認為 0。
2.16.3代碼示例
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi/imgproc.hpp> // 包含imgproc模塊,可能需要的其他G-API模塊
#include <opencv2/opencv.hpp>int main()
{// 加載輸入圖像cv::Mat src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png" );if ( src.empty() ){std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定義仿射變換矩陣 Mdouble angle = 45.0;double scale = 1.0;cv::Point2f center( src.cols / 2.0, src.rows / 2.0 );cv::Mat M = cv::getRotationMatrix2D( center, angle, scale );// 定義輸出尺寸cv::Size dsize = src.size();// 定義G-API計算圖來應用仿射變換cv::GComputation comp( [ dsize, &M ]() { // 捕獲 dsize 和 Mcv::GMat in; // 輸入:源圖像int flags = cv::INTER_LINEAR; // 插值方法int borderMode = cv::BORDER_CONSTANT; // 邊界模式cv::Scalar borderValue = cv::Scalar(); // 邊界填充顏色,默認為黑色cv::GMat out = cv::gapi::warpAffine( in, M, dsize, flags, borderMode, borderValue );return cv::GComputation( cv::GIn( in ), cv::GOut( out ) );} );// 輸出結果cv::Mat dst;try{// 執行計算圖并傳入實際的cv::Mat數據comp.apply( cv::gin( src ), cv::gout( dst ) );// 顯示結果cv::imshow( "Original Image", src );cv::imshow( "Transformed Image", dst );cv::waitKey( 0 ); // 等待按鍵事件}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.16.4 運行結果
2.17透視變換函數warpPerspective()
應用透視變換到圖像。
函數 warpPerspective 使用指定的矩陣對源圖像進行變換:
dst ( x , y ) = src ( M 11 x + M 12 y + M 13 M 31 x + M 32 y + M 33 , M 21 x + M 22 y + M 23 M 31 x + M 32 y + M 33 ) \texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right ) dst(x,y)=src(M31?x+M32?y+M33?M11?x+M12?y+M13??,M31?x+M32?y+M33?M21?x+M22?y+M23??)
當設置了標志 WARP_INVERSE_MAP 時。否則,首先使用 invert 反轉變換,然后將其放入上述公式中代替 MM。該函數不能就地操作(即輸入圖像和輸出圖像不能是同一個對象)。
2.17.1函數原型
GMat cv::gapi::warpPerspective
(const GMat & src,const Mat & M,const Size & dsize,int flags = cv::INTER_LINEAR,int borderMode = cv::BORDER_CONSTANT,const Scalar & borderValue = Scalar()
)
2.17.2參數
- 參數 src: 輸入圖像。
- 參數 M: 3×3 的變換矩陣。
- 參數 dsize: 輸出圖像的尺寸。
- 參數 flags: 插值方法的組合(INTER_LINEAR 或 INTER_NEAREST)以及可選的標志 WARP_INVERSE_MAP,設置 MM 作為逆變換(從 dst 到 src)。
- 參數 borderMode: 像素外推方法(BORDER_CONSTANT 或 BORDER_REPLICATE)。
- 參數 borderValue: 在使用常量邊界模式時使用的值;默認等于 0。
2.17.3示例代碼
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp> // 包含G-API核心功能
#include <opencv2/gapi/imgproc.hpp> // 包含imgproc模塊,可能需要的其他G-API模塊
#include <opencv2/opencv.hpp>int main()
{// 加載輸入圖像cv::Mat src = cv::imread( "/media/dingxin/data/study/OpenCV/sources/images/Lenna.png" );if ( src.empty() ){std::cerr << "Error: Image cannot be loaded!" << std::endl;return -1;}// 定義透視變換矩陣 M// 這里以簡單變換為例,你可以根據需要修改此矩陣cv::Point2f srcPoints[] = { { 50, 50 }, { 200, 50 }, { 50, 200 }, { 200, 200 } };cv::Point2f dstPoints[] = { { 30, 30 }, { 180, 20 }, { 60, 180 }, { 220, 180 } };cv::Mat M = cv::getPerspectiveTransform( srcPoints, dstPoints );// 定義輸出尺寸cv::Size dsize = src.size();// 定義G-API計算圖來應用透視變換cv::GComputation comp( [ dsize, &M ]() { // 捕獲 dsize 和 Mcv::GMat in; // 輸入:源圖像int flags = cv::INTER_LINEAR; // 插值方法int borderMode = cv::BORDER_CONSTANT; // 邊界模式cv::Scalar borderValue = cv::Scalar(); // 邊界填充顏色,默認為黑色cv::GMat out = cv::gapi::warpPerspective( in, M, dsize, flags, borderMode, borderValue );return cv::GComputation( cv::GIn( in ), cv::GOut( out ) );} );// 輸出結果cv::Mat dst;try{// 執行計算圖并傳入實際的cv::Mat數據comp.apply( cv::gin( src ), cv::gout( dst ) );// 顯示結果cv::imshow( "Original Image", src );cv::imshow( "Transformed Image", dst );cv::waitKey( 0 ); // 等待按鍵事件}catch ( const std::exception& e ){std::cerr << "Exception: " << e.what() << std::endl;return -1;}return 0;
}
2.17.4運行結果
------------------------------完結