OpenCV 图形API(23)图像和通道合成

  • 操作系统: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 矩阵进行水平拼接。

cpp 复制代码
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函数原型
cpp 复制代码
GMat cv::gapi::concatHor 
(
 	const GMat &  	src1,
	const GMat &  	src2 
) 	
2.1.2参数:
  • 参数 src1:第一个输入矩阵,用于水平拼接。
  • 参数 src2:第二个输入矩阵,用于水平拼接。
2.1.3 代码示例
cpp 复制代码
#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运行结果
bash 复制代码
Concatenated image: 
[  1,   2,   3,  10,  11;
   4,   5,   6,  12,  13;
   7,   8,   9,  14,  15]

2.2 垂直方向上拼接两个图像(矩阵)函数concatVert()

对给定的矩阵应用垂直拼接。

该函数将两个具有相同列数(宽度)的 GMat 矩阵进行垂直拼接。

cpp 复制代码
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函数原型
cpp 复制代码
GMat cv::gapi::concatVert 	
(
 	const GMat &  	src1,
	const GMat &  	src2 
) 		
2.2.2 参数:
  • 参数 src1:第一个输入矩阵,用于垂直拼接。
  • 参数 src2:第二个输入矩阵,用于垂直拼接。
2.2.3 代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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函数原型
cpp 复制代码
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代码示例
cpp 复制代码
#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运行结果
cpp 复制代码
Converted image: 
[10, 20, 30;
 40, 50, 60;
 70, 80, 90]

2.4创建一个输入矩阵 in 的副本函数copy()

制作输入图像的副本。请注意,这个副本可能不是实际的(没有实际复制数据)。使用此函数以维持图的约定,例如当图的输入需要直接传递到输出时,就像在流模式下一样。

注意:

函数的文字ID是 "org.opencv.streaming.copy"

2.4.1函数原型
cpp 复制代码
GMat cv::gapi::copy 	
(
 	const GMat &  	in
) 	
2.4.2参数
  • 参数 in:输入图像
2.4.3代码示例
cpp 复制代码
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运行结果
bash 复制代码
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函数原型
cpp 复制代码
GMat cv::gapi::crop 	
(
 	const GMat &  	src,
	const Rect &  	rect 
) 	
2.5.2参数
  • 参数src:输入矩阵。
  • 参数rect:用于裁剪矩阵的矩形区域。
2.5.3代码示例
cpp 复制代码
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运行结果
bash 复制代码
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,jsrci,src.cols−j−1srcsrc.rows−i−1,src.cols−j−1ifflipCode=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函数原型
cpp 复制代码
GMat cv::gapi::flip 	
(
 	const GMat &  	src,
	int  	flipCode 
) 	
2.6.2参数
  • 参数 src:输入矩阵。
  • 参数 flipCode:指定如何翻转数组的一个标志;0表示绕x轴翻转,正值(例如1)表示绕y轴翻转。负值(例如-1)表示同时绕两个轴翻转。
2.6.3代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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函数原型
cpp 复制代码
GMat cv::gapi::LUT 	
(
 	const GMat &  	src,
	const Mat &  	lut 
) 		
2.7.2参数
  • 参数 src: 输入矩阵,元素为8位。
  • 参数 lut: 查找表,包含256个元素;在多通道输入数组的情况下,查找表应该要么只有一个通道(在这种情况下,所有通道使用相同的查找表)或者与输入矩阵具有相同数量的通道。
2.7.3代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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函数原型
cpp 复制代码
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代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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函数原型
cpp 复制代码
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代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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} Imindst(I)=alpha,Imaxdst(I)=beta

当 normType 为 NORM_MINMAX 时(仅适用于密集数组)。

注意:

函数的文字ID是 "org.opencv.core.normalize"

2.10.1函数原型
cpp 复制代码
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 代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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函数原型
cpp 复制代码
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代码示例
cpp 复制代码
#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运行结果
bash 复制代码
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,你可以这样调用函数:

cpp 复制代码
// explicitly specify dsize=dst.size(); fx and fy will be computed from that.
resize(src, dst, dst.size(), 0, 0, interpolation);

如果你想在每个方向上按比例缩小图像因子为 2,你可以这样调用函数:

cpp 复制代码
// 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函数原型
cpp 复制代码
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示例代码
cpp 复制代码
#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运行结果
cpp 复制代码
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函数原型
cpp 复制代码
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函数原型
cpp 复制代码
std::tuple<GMat, GMat, GMat> cv::gapi::split3
(
 	const GMat &  	src
) 	
2.14.2参数
  • 参数src 输入的 CV_8UC3 矩阵。
2.14.3代码示例
cpp 复制代码
#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;                                // 输入:多通道GMat
        auto [ 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函数原型
cpp 复制代码
std::tuple<GMat, GMat, GMat,GMat> cv::gapi::split4
(
 	const GMat &  	src
) 	
2.15.2参数
  • 参数 src 输入的 CV_8UC4 矩阵。
2.15.3示例代码
cpp 复制代码
#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;                                   // 输入:多通道GMat
        auto [ 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(M11x+M12y+M13,M21x+M22y+M23)

当设置了标志 WARP_INVERSE_MAP 时。否则,首先使用 invertAffineTransform 反转变换,然后将其放入上述公式中代替 MM。该函数不能就地操作(即输入图像和输出图像不能是同一个对象)。

2.16.1函数原型
cpp 复制代码
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代码示例
cpp 复制代码
#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
    double 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 和 M
        cv::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(M31x+M32y+M33M11x+M12y+M13,M31x+M32y+M33M21x+M22y+M23)

当设置了标志 WARP_INVERSE_MAP 时。否则,首先使用 invert 反转变换,然后将其放入上述公式中代替 MM。该函数不能就地操作(即输入图像和输出图像不能是同一个对象)。

2.17.1函数原型
cpp 复制代码
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示例代码
cpp 复制代码
#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 和 M
        cv::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运行结果

------------------------------完结

相关推荐
飞火流星020271 小时前
BERT、T5、ViT 和 GPT-3 架构概述及代表性应用
人工智能·gpt-3·bert·t5·vit·人工智能模型架构
程序小K1 小时前
自然语言处理Hugging Face Transformers
人工智能·自然语言处理
恒拓高科WorkPlus1 小时前
BeeWorks:打造安全可控的企业内网即时通讯平台
大数据·人工智能·安全
爱数模的小驴2 小时前
2025 年“认证杯”数学中国数学建模网络挑战赛 C题 化工厂生产流程的预测和控制
深度学习·算法·计算机视觉
newxtc2 小时前
【指纹浏览器系列-chromium编译】
人工智能·安全
轻闲一号机2 小时前
【机器学习】机器学习笔记
人工智能·笔记·机器学习
光锥智能2 小时前
傅利叶发布首款开源人形机器人N1:开发者可实现完整复刻
人工智能
恒拓高科WorkPlus3 小时前
一款安全好用的企业即时通讯平台,支持统一门户
大数据·人工智能·安全
天下琴川3 小时前
Dify智能体平台源码二次开发笔记(5) - 多租户的SAAS版实现(2)
人工智能·笔记
qq_365911603 小时前
中英文提示词对AI IDE编程能力影响有多大?
人工智能