OpenCVコード抽出:merge/split関数の実装

9648 ワード

OpenCVの中のmerge/split関数を実現して、テストして、OpenCV 3と.1結果は完全に一致した.
merge実装コードmerge.hpp:
// fbc_cv is free software and uses the same licence as OpenCV
// Email: [email protected]

#ifndef FBC_CV_MERGE_HPP_
#define FBC_CV_MERGE_HPP_

/* reference: include/opencv2/core.hpp
              core/src/convert.cpp
              core/src/merge.cpp
*/

#include <vector>
#include "core/mat.hpp"

#ifndef __cplusplus
	#error merge.hpp header must be compiled as C++
#endif

namespace fbc {

// merge several arrays to make a single multi-channel array
template<typename _Tp, int chs1, int chs2>
int merge(const std::vector<Mat_<_Tp, chs1>>& src, Mat_<_Tp, chs2>& dst)
{
	FBC_Assert(dst.data != NULL);
	FBC_Assert((src.size() > 0) && (src.size() == dst.channels) && (src.size() <= FBC_CN_MAX));
	int width = src[0].cols;
	int height = src[0].rows;
	FBC_Assert((dst.cols == width) && (dst.rows == height));
	for (int i = 0; i < src.size(); i++) {
		FBC_Assert(src[i].data != NULL);
		FBC_Assert((src[i].cols == width) && src[i].rows == height);
		FBC_Assert(src[i].channels == 1);
	}

	if (src.size() == 1) {
		memcpy(dst.data, src[0].data, dst.step * dst.rows);
		return 0;
	}

	_Tp* pDst = (_Tp*)dst.data;
	int len = width * height;
	int cn = dst.channels;

	for (int i = 0; i < src.size(); i++) {
		_Tp* pSrc = (_Tp*)src[i].data;

		for (int j = 0; j < len; j++) {
			pDst[j * cn + i] = pSrc[j];
		}
	}

	return 0;
}

} // namespace fbc

#endif // FBC_CV_MERGE_HPP_

split実装コードsplit.hpp:
// fbc_cv is free software and uses the same licence as OpenCV
// Email: [email protected]

#ifndef FBC_CV_SPLIT_HPP_
#define FBC_CV_SPLIT_HPP_

/* reference: include/opencv2/core.hpp
              core/src/convert.cpp
	      core/src/split.cpp
*/

#include <vector>
#include "core/mat.hpp"

#ifndef __cplusplus
	#error split.hpp header must be compiled as C++
#endif

namespace fbc {

// split a multi-channel array into separate single-channel arrays
template<typename _Tp, int chs1, int chs2>
int split(const Mat_<_Tp, chs1>& src, std::vector<Mat_<_Tp, chs2>>& dst)
{
	FBC_Assert(src.data != NULL);
	FBC_Assert((dst.size() == chs1) && (chs2 == 1));
	for (int i = 0; i < dst.size(); i++) {
		FBC_Assert((dst[i].data != NULL) && (dst[i].rows == src.rows) && (dst[i].cols == src.cols));
	}

	int cn = src.channels;
	if (cn == 1) {
		memcpy(dst[0].data, src.data, src.step * src.rows);
		return 0;
	}

	_Tp* pSrc = (_Tp*)src.data;
	int len = src.rows * src.cols;

	for (int i = 0; i < cn; i++) {
		_Tp* pDst = (_Tp*)dst[i].data;

		for (int j = 0; j < len; j++) {
			pDst[j] = pSrc[j * cn + i];
		}
	}

	return 0;
}

} // namespace fbc

#endif // FBC_CV_SPLIT_HPP_

mergeテストコード:
#include <assert.h>
#include <vector>
#include <core/mat.hpp>
#include <merge.hpp>

#include <opencv2/opencv.hpp>

#include "test_merge.hpp"

int test_merge_uchar()
{
	cv::Mat matSrc1 = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	cv::Mat matSrc2 = cv::imread("E:/GitCode/OpenCV_Test/test_images/1.jpg", 1);
	cv::Mat matSrc3 = cv::imread("E:/GitCode/OpenCV_Test/test_images/2.jpg", 1);
	if (!matSrc1.data || !matSrc2.data || !matSrc3.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}

	int width = 500, height = 600;

	cv::cvtColor(matSrc1, matSrc1, CV_BGR2GRAY);
	cv::cvtColor(matSrc2, matSrc2, CV_BGR2GRAY);
	cv::cvtColor(matSrc3, matSrc3, CV_BGR2GRAY);
	cv::resize(matSrc1, matSrc1, cv::Size(width, height));
	cv::resize(matSrc2, matSrc2, cv::Size(width, height));
	cv::resize(matSrc3, matSrc3, cv::Size(width, height));

	fbc::Mat_<fbc::uchar, 1> mat1(height, width, matSrc1.data);
	fbc::Mat_<fbc::uchar, 1> mat2(height, width, matSrc2.data);
	fbc::Mat_<fbc::uchar, 1> mat3(height, width, matSrc3.data);
	std::vector<fbc::Mat_<fbc::uchar, 1>> mat;
	mat.push_back(mat1);
	mat.push_back(mat2);
	mat.push_back(mat3);
	fbc::Mat_<fbc::uchar, 3> matDst(height, width);
	fbc::merge(mat, matDst);

	std::vector<cv::Mat> mat_;
	mat_.push_back(matSrc1);
	mat_.push_back(matSrc2);
	mat_.push_back(matSrc3);
	cv::Mat matDst_;
	cv::merge(mat_, matDst_);

	assert(matDst.channels == matDst_.channels());
	assert((matDst.rows == matDst_.rows) && (matDst.cols == matDst_.cols));
	assert(matDst.step == matDst_.step);

	for (int i = 0; i < matDst.rows; i++) {
		const fbc::uchar* p1 = matDst.ptr(i);
		const uchar* p2 = matDst_.ptr(i);

		for (int j = 0; j < matDst.step; j++) {
			assert(p1[j] == p2[j]);
		}
	}

	return 0;
}

int test_merge_float()
{
	cv::Mat matSrc1 = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	cv::Mat matSrc2 = cv::imread("E:/GitCode/OpenCV_Test/test_images/1.jpg", 1);
	cv::Mat matSrc3 = cv::imread("E:/GitCode/OpenCV_Test/test_images/2.jpg", 1);
	if (!matSrc1.data || !matSrc2.data || !matSrc3.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}

	int width = 500, height = 600;

	cv::cvtColor(matSrc1, matSrc1, CV_BGR2GRAY);
	cv::cvtColor(matSrc2, matSrc2, CV_BGR2GRAY);
	cv::cvtColor(matSrc3, matSrc3, CV_BGR2GRAY);
	cv::resize(matSrc1, matSrc1, cv::Size(width, height));
	cv::resize(matSrc2, matSrc2, cv::Size(width, height));
	cv::resize(matSrc3, matSrc3, cv::Size(width, height));
	matSrc1.convertTo(matSrc1, CV_32FC1);
	matSrc2.convertTo(matSrc2, CV_32FC1);
	matSrc3.convertTo(matSrc3, CV_32FC1);

	fbc::Mat_<float, 1> mat1(height, width, matSrc1.data);
	fbc::Mat_<float, 1> mat2(height, width, matSrc2.data);
	fbc::Mat_<float, 1> mat3(height, width, matSrc3.data);
	std::vector<fbc::Mat_<float, 1>> mat;
	mat.push_back(mat1);
	mat.push_back(mat2);
	mat.push_back(mat3);
	fbc::Mat_<float, 3> matDst(height, width);
	fbc::merge(mat, matDst);

	std::vector<cv::Mat> mat_;
	mat_.push_back(matSrc1);
	mat_.push_back(matSrc2);
	mat_.push_back(matSrc3);
	cv::Mat matDst_;
	cv::merge(mat_, matDst_);

	assert(matDst.channels == matDst_.channels());
	assert((matDst.rows == matDst_.rows) && (matDst.cols == matDst_.cols));
	assert(matDst.step == matDst_.step);

	for (int i = 0; i < matDst.rows; i++) {
		const fbc::uchar* p1 = matDst.ptr(i);
		const uchar* p2 = matDst_.ptr(i);

		for (int j = 0; j < matDst.step; j++) {
			assert(p1[j] == p2[j]);
		}
	}

	return 0;
}

splitテストコード:
#include <assert.h>
#include <vector>
#include <core/mat.hpp>
#include <split.hpp>

#include <opencv2/opencv.hpp>

#include "test_split.hpp"

int test_split_uchar()
{
	cv::Mat mat = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	if (!mat.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}
	//cv::cvtColor(mat, mat, CV_BGR2GRAY);

	int chs = mat.channels();
	int width = mat.cols;
	int height = mat.rows;

	fbc::Mat_<fbc::uchar, 3> mat1(height, width, mat.data);
	std::vector<fbc::Mat_<fbc::uchar, 1>> vecMat2;
	fbc::Mat_<fbc::uchar, 1>* mat2 = new fbc::Mat_<fbc::uchar, 1>[chs];
	for (int i = 0; i < chs; i++) {
		mat2[i] = fbc::Mat_<fbc::uchar, 1>(height, width);
		vecMat2.push_back(mat2[i]);
	}

	fbc::split(mat1, vecMat2);

	cv::Mat mat1_(height, width, CV_8UC3, mat.data);
	std::vector<cv::Mat> vecMat2_;
	cv::split(mat1_, vecMat2_);

	assert(vecMat2.size() == vecMat2_.size());
	for (int i = 0; i < vecMat2.size(); i++) {
		assert(vecMat2[i].rows == vecMat2_[i].rows && vecMat2[i].cols == vecMat2_[i].cols);
		assert(vecMat2[i].step == vecMat2_[i].step);
		assert(vecMat2[i].channels == vecMat2_[i].channels());

		for (int y = 0; y < vecMat2[i].rows; y++) {
			const fbc::uchar* p = vecMat2[i].ptr(y);
			const uchar* p_ = vecMat2_[i].ptr(y);

			for (int x = 0; x < vecMat2[i].step; x++) {
				assert(p[x] == p_[x]);
			}
		}
	}

	delete[] mat2;

	return 0;
}

int test_split_float()
{
	cv::Mat mat = cv::imread("E:/GitCode/OpenCV_Test/test_images/lena.png", 1);
	if (!mat.data) {
		std::cout << "read image fail" << std::endl;
		return -1;
	}
	mat.convertTo(mat, CV_32FC3);
	//cv::cvtColor(mat, mat, CV_BGR2GRAY);

	int chs = mat.channels();
	int width = mat.cols;
	int height = mat.rows;

	fbc::Mat_<float, 3> mat1(height, width, mat.data);
	std::vector<fbc::Mat_<float, 1>> vecMat2;
	fbc::Mat_<float, 1>* mat2 = new fbc::Mat_<float, 1>[chs];
	for (int i = 0; i < chs; i++) {
		mat2[i] = fbc::Mat_<float, 1>(height, width);
		vecMat2.push_back(mat2[i]);
	}

	fbc::split(mat1, vecMat2);

	cv::Mat mat1_(height, width, CV_32FC3, mat.data);
	std::vector<cv::Mat> vecMat2_;
	cv::split(mat1_, vecMat2_);

	assert(vecMat2.size() == vecMat2_.size());
	for (int i = 0; i < vecMat2.size(); i++) {
		assert(vecMat2[i].rows == vecMat2_[i].rows && vecMat2[i].cols == vecMat2_[i].cols);
		assert(vecMat2[i].step == vecMat2_[i].step);
		assert(vecMat2[i].channels == vecMat2_[i].channels());

		for (int y = 0; y < vecMat2[i].rows; y++) {
			const fbc::uchar* p = vecMat2[i].ptr(y);
			const uchar* p_ = vecMat2_[i].ptr(y);

			for (int x = 0; x < vecMat2[i].step; x++) {
				assert(p[x] == p_[x]);
			}
		}
	}

	delete[] mat2;

	return 0;
}

GitHub: https://github.com/fengbingchun/OpenCV_Test