OpenCV代码提取:morphologyEx函数的实现

Morphological Operations: A set of operations that process images based on shapes.Morphological operations apply a structuring element to an input image and generate an output image.

The most basic morphological operations are two: Erosion and Dilation. They have a wide array of uses, i.e.:

(1)、Removing noise.

(2)、Isolation of individual elements and joining disparate elements in an image.

(3)、Finding of intensity bumps or holes in an image.

数学形态学可以理解为一种滤波行为,因此也称为形态学滤波。滤波中用到的滤波器(kernal),在形态学中称为结构元素。结构元素往往是由一个特殊的形状构成,如线条、矩形、圆等。

         开运算(open):先腐蚀后膨胀的过程。开运算可以用来消除小黑点,在纤细点处分离物体、平滑较大物体的边界的同时并不明显改变其面积。

         闭运算(close):先膨胀后腐蚀的过程。闭运算可以用来排除小黑洞。

         形态学梯度(morph-grad):可以突出团块(blob)的边缘,保留物体的边缘轮廓。

         顶帽(top-hat):将突出比原轮廓亮的部分。

         黑帽(black-hat):将突出比原轮廓暗的部分。

OpenCV代码提取:morphologyEx函数的实现_第1张图片

目前fbc_cv库中支持uchar和float两种数据类型,经测试,与OpenCV3.1结果完全一致。

实现代码morphologyEx.hpp:

// fbc_cv is free software and uses the same licence as OpenCV
// Email: fengbingchun@163.com

#ifndef FBC_CV_MORPHOLOGYEX_HPP_
#define FBC_CV_MORPHOLOGYEX_HPP_

/* reference: include/opencv2/imgproc.hpp
              modules/imgproc/src/morph.cpp
*/

#include 
#include "erode.hpp"
#include "dilate.hpp"

namespace fbc {

// perform advanced morphological transformations using an erosion and dilation as basic operations
// In case of multi - channel images, each channel is processed independently.
// morphologyEx can be applied several ( iterations ) times.
// op ==> enum MorphTypes
// support type: uchar/float, multi-channels
template
int morphologyEx(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int op, const Mat_& kernel,
	Point anchor = Point(-1, -1), int iterations = 1, int borderType = BORDER_CONSTANT, const Scalar& borderValue = Scalar::all(DBL_MAX))
{
	FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() || typeid(float).name() == typeid(_Tp).name()); // uchar || float
	if (dst.empty()) {
		dst = Mat_<_Tp, chs>(src.rows, src.cols);
	} else {
		FBC_Assert(src.rows == dst.rows && src.cols == dst.cols);
	}

	Mat_ kernel_ = kernel;
	if (kernel_.empty()) {
		kernel_ = Mat_(3, 3);
		getStructuringElement(kernel_, MORPH_RECT, Size(3, 3), Point(1, 1));
	}

	switch (op) {
		case MORPH_ERODE: {
			erode(src, dst, kernel_, anchor, iterations, borderType, borderValue);
			break;
		}
		case MORPH_DILATE: {
			dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);
			break;
		}
		case MORPH_OPEN: {
			erode(src, dst, kernel_, anchor, iterations, borderType, borderValue);
			dilate(dst, dst, kernel_, anchor, iterations, borderType, borderValue);
			break;
		}
		case CV_MOP_CLOSE: {
			dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);
			erode(dst, dst, kernel_, anchor, iterations, borderType, borderValue);
			break;
		}
		case CV_MOP_GRADIENT: {
			Mat_<_Tp, chs> temp(src.rows, src.cols);
			erode(src, temp, kernel_, anchor, iterations, borderType, borderValue);
			dilate(src, dst, kernel_, anchor, iterations, borderType, borderValue);
			dst -= temp;
			break;
		}
		case CV_MOP_TOPHAT: {
			Mat_<_Tp, chs> temp(src.rows, src.cols);
			if (src.data != dst.data)
				temp = dst;
			erode(src, temp, kernel_, anchor, iterations, borderType, borderValue);
			dilate(temp, temp, kernel_, anchor, iterations, borderType, borderValue);
			dst = src - temp;
			break;
		}
		case CV_MOP_BLACKHAT: {
			Mat_<_Tp, chs> temp(src.rows, src.cols);
			if (src.data != dst.data)
				temp = dst;
			dilate(src, temp, kernel_, anchor, iterations, borderType, borderValue);
			erode(temp, temp, kernel_, anchor, iterations, borderType, borderValue);
			dst = temp - src;
			break;
		}
		case MORPH_HITMISS: {
			FBC_Assert(typeid(uchar).name() == typeid(_Tp).name() && chs == 1);
			Mat_ k1 = (kernel_ == Mat_(kernel_.rows, kernel_.cols, Scalar::all(1)));
			Mat_ k2 = (kernel_ == Mat_(kernel_.rows, kernel_.cols, Scalar::all(-1)));
			Mat_<_Tp, chs> e1, e2;

			if (countNonZero(k1) <= 0)
				e1 = src;
			else
				erode(src, e1, k1, anchor, iterations, borderType, borderValue);
			if (countNonZero(k2) <= 0) {
				e2 = src;
			} else {
				Mat_<_Tp, chs> src_complement;
				bitwise_not(src, src_complement);
				erode(src_complement, e2, k2, anchor, iterations, borderType, borderValue);
			}
			bitwise_and(e1, e2, dst);
			break;
		}
		default:
			FBC_Assert("unknown morphological operation");
	}

	return 0;
}

} // namespace fbc

#endif // FBC_CV_MORPHOLOGYEX_HPP_
测试代码test_morphologyEx.cpp:

#include "test_erode.hpp"
#include 

#include 
#include 

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

	int width = matSrc.cols;
	int height = matSrc.rows;

	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 5; size++) {
			for (int iterations = 1; iterations < 3; iterations++) {
				for (int operation = 0; operation < 7; operation++) {
					int type;
					if (elem == 0){ type = fbc::MORPH_RECT; }
					else if (elem == 1){ type = fbc::MORPH_CROSS; }
					else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

					fbc::Mat_ element(2 * size + 1, 2 * size + 1);
					fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

					int type_;
					if (elem == 0){ type_ = cv::MORPH_RECT; }
					else if (elem == 1){ type_ = cv::MORPH_CROSS; }
					else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

					cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

					assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
					for (int y = 0; y < element.rows; y++) {
						const fbc::uchar* p1 = element.ptr(y);
						const uchar* p2 = element_.ptr(y);

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

					fbc::Mat3BGR mat1(height, width, matSrc.data);
					fbc::Mat3BGR mat2(height, width);
					fbc::morphologyEx(mat1, mat2, operation, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

					cv::Mat mat1_(height, width, CV_8UC3, matSrc.data);
					cv::Mat mat2_;
					cv::morphologyEx(mat1_, mat2_, operation, element_, cv::Point(-1, -1), iterations, 0, cv::Scalar::all(128));

					assert(mat2.rows == mat2_.rows && mat2.cols == mat2_.cols && mat2.step == mat2_.step);
					for (int y = 0; y < mat2.rows; y++) {
						const fbc::uchar* p1 = mat2.ptr(y);
						const uchar* p2 = mat2_.ptr(y);

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

	return 0;
}

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

	int width = matSrc.cols;
	int height = matSrc.rows;

	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 5; size++) {
			for (int iterations = 1; iterations < 3; iterations++) {
				for (int operation = 0; operation < 7; operation++) {
					int type;
					if (elem == 0){ type = fbc::MORPH_RECT; }
					else if (elem == 1){ type = fbc::MORPH_CROSS; }
					else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

					fbc::Mat_ element(2 * size + 1, 2 * size + 1);
					fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

					int type_;
					if (elem == 0){ type_ = cv::MORPH_RECT; }
					else if (elem == 1){ type_ = cv::MORPH_CROSS; }
					else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

					cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

					assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
					for (int y = 0; y < element.rows; y++) {
						const fbc::uchar* p1 = element.ptr(y);
						const uchar* p2 = element_.ptr(y);

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

					fbc::Mat_ mat1(height, width, matSrc.data);
					fbc::Mat_ mat2(height, width);
					fbc::morphologyEx(mat1, mat2, operation, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

					cv::Mat mat1_(height, width, CV_32FC1, matSrc.data);
					cv::Mat mat2_;
					cv::morphologyEx(mat1_, mat2_, operation, element_, cv::Point(-1, -1), iterations, 0, cv::Scalar::all(128));

					assert(mat2.rows == mat2_.rows && mat2.cols == mat2_.cols && mat2.step == mat2_.step);
					for (int y = 0; y < mat2.rows; y++) {
						const fbc::uchar* p1 = mat2.ptr(y);
						const uchar* p2 = mat2_.ptr(y);

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

	return 0;
}

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

	int width = matSrc.cols;
	int height = matSrc.rows;

	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 5; size++) {
			for (int iterations = 1; iterations < 3; iterations++) {
				int operation = 7;

				int type;
				if (elem == 0){ type = fbc::MORPH_RECT; }
				else if (elem == 1){ type = fbc::MORPH_CROSS; }
				else if (elem == 2) { type = fbc::MORPH_ELLIPSE; }

				fbc::Mat_ element(2 * size + 1, 2 * size + 1);
				fbc::getStructuringElement(element, type, fbc::Size(2 * size + 1, 2 * size + 1), fbc::Point(size, size));

				int type_;
				if (elem == 0){ type_ = cv::MORPH_RECT; }
				else if (elem == 1){ type_ = cv::MORPH_CROSS; }
				else if (elem == 2) { type_ = cv::MORPH_ELLIPSE; }

				cv::Mat element_ = cv::getStructuringElement(type_, cv::Size(2 * size + 1, 2 * size + 1), cv::Point(size, size));

				assert(element.rows == element_.rows && element.cols == element.cols && element.step == element_.step);
				for (int y = 0; y < element.rows; y++) {
					const fbc::uchar* p1 = element.ptr(y);
					const uchar* p2 = element_.ptr(y);

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

				fbc::Mat_ mat1(height, width, matSrc.data);
				fbc::Mat_ mat2(height, width);
				fbc::morphologyEx(mat1, mat2, operation, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

				cv::Mat mat1_(height, width, CV_8UC1, matSrc.data);
				cv::Mat mat2_;
				cv::morphologyEx(mat1_, mat2_, operation, element_, cv::Point(-1, -1), iterations, 0, cv::Scalar::all(128));

				assert(mat2.rows == mat2_.rows && mat2.cols == mat2_.cols && mat2.step == mat2_.step);
				for (int y = 0; y < mat2.rows; y++) {
					const fbc::uchar* p1 = mat2.ptr(y);
					const uchar* p2 = mat2_.ptr(y);

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

	return 0;
}

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

你可能感兴趣的:(OpenCV)