記事ディレクトリ
-
- 1.チャンネル分離関数split()
- 2. チャネルマージ関数 merge()
-
- 関数プロトタイプ:
-
- (1) 関数プロトタイプ 1: 入力は Mat 配列形式の画像データ `Mat mvbegin[3]` です
- (2) 関数プロトタイプ 2: 入力はベクトルコンテナ `vector <Mat>` 形式の画像データです
- (3) 例 1: まず、split() を使用して画像の 3 つのチャネルを分離し、Mat 型配列 `Mat mvbegin[3]` を使用して分離した画像を格納し、その後 merge() で 3 チャネルの画像を結合します。 、関数プロトタイプ 1 に対応します。
- (4) 例 2: まず、split() を使用して画像の 3 つのチャネルを分離し、ベクトル コンテナ `vector <Mat>` を使用して分離された画像を保存し、次に merge() を使用して 3 チャネルの画像をマージします。関数プロトタイプ 2 に対応。
- 3. チャンネルミキシング mixChannels()
opencv のデフォルトの imread 関数は画像ファイルをロードし、ロードされた画像は 3 チャネルのカラー画像で、色空間は RGB カラー空間で、チャネルの順序は BGR (青、緑、赤) です。 , OpenCV は 3 つの API を提供します。この関数は、チャンネル分離の split()、merge()、mixChannels() を実現するために使用されます。
opencv の Mat における RGB 画像、ピクセルデータ、ストレージ構造、チャネル分離の動作関係図は以下のとおりです。
1.チャンネル分離関数split()
関数プロトタイプ:
2 つの関数プロトタイプの使い方は同じで、マルチチャンネル画像をいくつかのシングルチャンネル画像に分離するために使用されます。2 つの関数プロトタイプの違いは、分離された Mat 型のシングルチャンネル画像が Mat に格納されることです。 -type 配列;
Mat mvbegin[3]
または ベクトル コンテナに格納されますvector <Mat> mv
。
OpenCV 4 の Split() 関数には、2 つのオーバーロードされたプロトタイプがあります。
(1) 関数プロトタイプ 1:Mat mvbegin[3]
分離された画像を格納するために Mat 型配列を使用します。
void split( const Mat &src, Mat *mvbegin )
入力パラメータ:
- src: 分離対象の画像、Mat 型マルチチャネル行列。
- mvbegin: Mat タイプの配列に格納された、分離された Mat タイプの単一チャネル画像。
Mat mvbegin[3]
配列サイズを定義するときは、元の画像のチャネル数を知る必要があります。配列サイズ = 元の画像のチャネル数。 - 分離された画像は Mat 型配列に格納されます
Mat mvbegin[3]
。配列内の 3 つの要素はすべて image.rows X image.cols のサイズを持つ Mat 型行列であり、画像の B、G、および R 成分のデータが格納されます。順番に元の画像を取得し、配列を取得します。内部の要素は、[]
によってのみ評価できます。 ; によっては評価できませんat()
。
(2) 関数プロトタイプ 2: ベクトル コンテナを使用してvector <Mat>
分離された画像を格納します。
void split( InputArray m, OutputArrayOfArrays mv )
入力パラメータ:
- m: 分離対象の画像、Mat 型マルチチャネル行列。
- mv: ベクトル コンテナに格納される分離された Mat タイプの単一チャネル画像。
vector <Mat> mv
元の画像のチャネル数を知る必要はありません。 - 分離された画像はベクターコンテナに格納されます
vector <Mat> mv
mvコンテナには要素が3つあり、各要素のサイズはimage.rows X image.colsのMat型行列でB、G、R成分が格納されますデータ、各要素は[]
値またはat()
値によって取得できます。
(3) 例:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
// 读取图像,BGR存储在Mat矩阵里
Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
if (src.empty()) {
printf("could not load image..../n");
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
// 用Mat型数组,存储分离后的图像,只能用 [] 访问
// Mat mvbegin[3];
// split(src, mvbegin);
// imshow("B", mvbegin[0]);
// imshow("G", mvbegin[1]);
// imshow("R", mvbegin[2]);
// 用vector容器,存储分离后的图像,用 [] 访问
// vector<Mat> mv;
// split(src, mv);
// imshow("B", mv[0]);
// imshow("G", mv[1]);
// imshow("R", mv[2]);
// 用vector容器,存储分离后的图像,用 at() 访问
vector<Mat> mv;
split(src, mv);
imshow("B", mv.at(0));
imshow("G", mv.at(1));
imshow("R", mv.at(2));
waitKey();
destroyAllWindows();
return 0;
}
操作結果:
2. チャネルマージ関数 merge()
- 2 つの関数プロトタイプの使用法は同じで、複数の画像 (単一チャネルまたはマルチチャネル画像) をマルチチャネル画像に結合するために使用されます。2 つの関数プロトタイプの違いは、入力が画像データであることです。 Mat 配列の形式、
Mat mvbegin[3]
またはベクトル コンテナの形式の画像データvector <Mat>
。split() 関数のプロトタイプに対応します。- 結合関数の出力はマルチチャネル画像であり、そのチャネル数はすべての入力画像のチャネル数の合計です。結合に使用される画像はすべて単一チャネルであるわけではなく、マルチチャネルである場合もあります。画像。入力画像のチャネル数は異なる場合があります。同じですが、すべての画像が同じサイズとデータ型である必要があります。
関数プロトタイプ:
(1) 関数プロトタイプ 1: 入力は Mat 配列形式の画像データMat mvbegin[3]
void merge( const Mat *mvbegin, size_tcount, OutputArray dst )
入力パラメータ:
- mvbegin: マージする必要がある単一チャネルまたはマルチチャネル画像。入力は Mat 配列形式の 1 つの画像データです
mvbegin[3]
。 - size_tcount: 入力画像配列の長さ。その値は 0 より大きくなければなりません。
- dst: マージされたイメージ。
(2) 関数プロトタイプ 2: 入力はベクトルコンテナ形式の画像データvector <Mat>
void merge( InputArrayOfArrays mv, OutputArray dst )
入力パラメータ:
- mv: マージする必要がある単一チャネルまたはマルチチャネルの画像。入力は、ベクトル コンテナーの形式の 1 つの画像データであり、
vector <Mat>
各画像は同じサイズとデータ型を持つ必要があります。 - dst: マージされた画像は
mv[0]
同じサイズとデータ型を持ち、チャネル数はすべての入力画像のチャネル数の合計に等しくなります。
Mat mvbegin[3]
(3) 例1: 関数プロトタイプ 1 に対応する、split() を使用して画像を 3 つのチャネルに分離し、分離した画像を Mat 型配列に格納した後、merge() で 3 つのチャネルの画像をマージします。
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
// 读取图像,BGR存储在Mat矩阵里
Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
if (src.empty()) {
printf("could not load image..../n");
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
// 通道分离,用Mat型数组存储分离后的图像
Mat mvbegin[3];
split(src, mvbegin);
Mat BlueChannel = mvbegin[0];
Mat GreenChannel = mvbegin[1];
Mat RedChannel = mvbegin[2];
// 将R通道全部置0
Mat r = mvbegin[2].clone();
r.setTo(0);
// 需要合并的Mat型数组
Mat newChannel[3] = {
BlueChannel , GreenChannel , r };
// 合并通道
Mat dst;
merge(newChannel, 3, dst);
// 显示
imshow("Merged", dst);
waitKey();
destroyAllWindows();
return 0;
}
操作結果:
(4) 例 2: まず、split() を使用して画像の 3 つのチャネルを分離し、ベクトル コンテナを使用してvector <Mat>
分離された画像を保存し、次に関数プロトタイプ 2 に対応する merge() で 3 チャネルの画像をマージします。
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
// 读取图像,BGR存储在Mat矩阵里
Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
if (src.empty()) {
printf("could not load image..../n");
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
// 通道分离
vector<Mat> mv;
split(src, mv);
Mat BlueChannel = mv.at(0);
Mat GreenChannel = mv.at(1);
Mat RedChannel = mv.at(2);
// 将B通道全部置0
Mat b = mv.at(0).clone();
b.setTo(0);
vector<Mat> newChannel;
newChannel.push_back(b);
newChannel.push_back(GreenChannel);
newChannel.push_back(RedChannel);
//通道合并
Mat mergedImage;
merge(newChannel, mergedImage);
// 显示
imshow("Merged", mergedImage);
waitKey();
destroyAllWindows();
return 0;
}
操作結果:
3. チャンネルミキシング mixChannels()
関数プロトタイプ:
(1) 関数プロトタイプ 1:
void cv::mixChannels (
InputArrayOfArrays src,
InputOutputArrayOfArrays dst,
const std::vector< int > &fromTo
)
入力パラメータ:
- src: 入力行列。すべての行列は同じサイズと深さでなければなりません。
- dst: 出力行列。サイズと深さは
src[0]
同じでなければなりません。 - fromTo: 入力行列のどのチャネルがコピーされ、出力行列のどのチャネルがコピーされるかを示すインデックス ペア。例: {
0, 2, 1, 1, 2, 0 } は、
src カラー チャネル 0 が dst Color にコピーされることを意味します。チャンネル 2
ソース カラー チャンネル 1 を dst カラー チャンネル 1 に
コピー ソース カラー チャンネル 2 を dst カラー チャンネル 0 にコピー
(2) 関数プロトタイプ 2:
この関数プロトタイプでは次のようになります。
- 入力行列と出力行列が両方とも 1 の場合、最初の関数プロトタイプと一致します。
- 1 でない場合は、複数の行列を結合したり、行列を複数の行列や他の関数に分割したりできます。
void cv::mixChannels
(
const Mat *src,
size_t nsrcs,
Mat *dst,
size_t ndsts,
const int *fromTo,
size_t npairs
)
入力パラメータ:
- src: 入力行列。すべての行列は同じサイズと深さでなければなりません。
- ndsts: 行列の数。
- dst: 出力行列。サイズと深さは
src[0]
同じでなければなりません。 - fromTo: 入力行列のどのチャネルがコピーされるか、出力行列のどのチャネルがコピーされるかを示すインデックス ペア。
- ndsts: 行列の数。
- npairs: fromTo 内のインデックス ペアの数。
(3) 例 1: カラー チャネル交換シアン (255, 255, 0) イエロー (0, 255, 255)
元のイメージのシアン色 (255, 255, 0) は、指定されたチャネルを通じて出力イメージにコピーされ、黄色 (0, 255, 255) になります。
チャンネル対応:
インデックス ペア from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 } の意味:
- bg のチャネル 0、out[] のチャネル 2、つまり bgr のチャネル 0 にコピーされます。
- bgra のチャネル 1、out[] のチャネル 1、つまり bgr のチャネル 1 にコピーされます。
- bgra のチャネル 2。out[] のチャネル 0、つまり bgr のチャネル 2 にコピーされます。
- bgra の 3 つのチャネルは、out[] の 3 つのチャネル、つまり bgr のアルファ チャネルにコピーされます。
サンプルコード:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
// 读取图像,BGR存储在Mat矩阵里
Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
if (src.empty()) {
printf("could not load image..../n");
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
Mat bgra(200, 200, CV_8UC4, Scalar(255, 255, 0, 255));
Mat bgr(bgra.rows, bgra.cols, CV_8UC3);
Mat alpha(bgra.rows, bgra.cols, CV_8UC1);
Mat out[] = {
bgr, alpha };
int from_to[] = {
0, 2, 1, 1, 2, 0, 3, 3 };
mixChannels(&bgra, 1, out, 2, from_to, 4);
imshow("bgra", bgra);
imshow("bgr", bgr);
waitKey();
destroyAllWindows();
return 0;
}
操作結果:
(4) 例 2: 画像の分割
4 チャネル マトリックス (BGRA 画像) を 3 チャネル マトリックス (BGR 画像) と単一チャネル マトリックス (アルファ チャネル画像) に分割します。
チャネル対応: インデックスペア、int fromTo[] = { 0, 2, 1, 1, 2, 0, 3, 3 }
- bgra のチャネル 0、bgr のチャネル 2 にコピー。
- bgra のチャネル 1、bgr のチャネル 1 にコピーされました。
- bgra のチャネル 2。bgr のチャネル 0 にコピーされます。
- bgra のチャネル 3、alpha のチャネル 0 にコピー。
サンプルコード:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
Mat bgra( 200, 200, CV_8UC4, Scalar(255, 0, 0, 255) );
Mat bgr( bgra.rows, bgra.cols, CV_8UC3 );
Mat alpha( bgra.rows, bgra.cols, CV_8UC1 );
Mat out[] = {
bgr,alpha };
// 通道对应关系
int fromTo[] = {
0, 2, 1, 1, 2, 0, 3, 3 };
mixChannels(&bgra, 1, out, 2, fromTo, 4);
imshow("bgra", bgra);
imshow("bgr", bgr);
imshow("alpha", alpha);
waitKey();
destroyAllWindows();
return 0;
}
操作結果:
(5) 例 3: HSV チャネルの取得
mixChannels() 関数を使用して指定したチャンネルをコピーすると、HSV カラー スペースで 3 つのチャンネルの詳細を確認できます。
HSV色空間:
- 色相 (色相): 0 から 360 度で測定される色を表します (赤、黄、緑、シアン、青、マゼンタ)。
- 彩度 (彩度、彩度): 色の深さを指します。彩度はグレーと色相の比率を表し、0% (グレー) から 100% (完全な彩度) まで測定されます。S=0 の場合、グレーのみが存在します。規模;
- 値 (色相): 色の明るさ V=1。RGB モデルの R=1、G=1、B=1 の 3 つの面を含み、表現される色はより明るくなります。
サンプルコード:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
// 读取图像,BGR存储在Mat矩阵里
Mat src = cv::imread("C:\\cpp\\image\\suzy1.jpg");
if (src.empty()) {
printf("could not load image..../n");
return -1;
}
namedWindow("src", WINDOW_AUTOSIZE);
imshow("src", src);
Mat hsv, dst;
cvtColor(src, hsv, COLOR_BGR2HSV);
dst.create( hsv.size(), hsv.depth() );
//分离Hue,色相通道
int ch[] = {
0, 0 };
mixChannels(&hsv, 1, &dst, 1, ch, 1);
imshow("H channel", dst);
//分离Saturation,饱和度通道
int ch1[] = {
1, 0 };
mixChannels(&hsv, 1, &dst, 1, ch1, 1);
imshow("S channel", dst);
//分离Value,色调通道
int ch2[] = {
2, 0 };
mixChannels(&hsv, 1, &dst, 1, ch2, 1);
imshow("V channel", dst);
waitKey();
destroyAllWindows();
return 0;
}