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

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),在形态学中称为结构元素。结构元素往往是由一个特殊的形状构成,如线条、矩形、圆等。

OpenCV中的dilate函数支持多通道,各个通道膨胀处理过程独立。膨胀针对白色部分(高亮部分)。膨胀即是求局部最大值的操作,图像A与核B作卷积运算,计算核B覆盖区域的像素点的最大值,并把这个值赋值给锚点(anchor point)指定的像素。

Dilation:

(1)、This operations consists of convoluting an image A with some kernel(B), which can have any shape or size, usually a square or circle.

(2)、The kernel B has a defined anchor point, usually being the center of the kernel.

(3)、As the kernel B is scanned over the image, we compute the maximal pixel value overlapped by B and replace the image pixel in the anchor point position with that maximal value. As you can deduce, this maximizing operation causes bright regions within an image to “grow” (therefore the name dilation).


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

实现代码dilate.cpp:

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

#ifndef FBC_CV_DILATE_HPP_
#define FBC_CV_DILATE_HPP_

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

#include <typeinfo>
#include "core/mat.hpp"
#include "imgproc.hpp"
#include "filterengine.hpp"
#include "core/core.hpp"
#include "morph.hpp"

namespace fbc {

// Dilates an image by using a specific structuring element
// \f[\texttt{dst} (x,y) =  \max _{(x',y'):  \, \texttt{element} (x',y') \ne0 } \texttt{src} (x+x',y+y')\f]
// In case of multi - channel images, each channel is processed independently.
// support type: uchar/float, multi-channels
template<typename _Tp, int chs>
int dilate(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, Mat_<uchar, 1>& 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);
	}

	Size ksize = !kernel.empty() ? kernel.size() : Size(3, 3);
	anchor = normalizeAnchor(anchor, ksize);

	if (iterations == 0 || kernel.rows * kernel.cols == 1) {
		src.copyTo(dst);
		return 0;
	}

	if (kernel.empty()) {
		kernel = Mat_<uchar, 1>(1 + iterations * 2, 1 + iterations * 2);
		getStructuringElement(kernel, MORPH_RECT, Size(1 + iterations * 2, 1 + iterations * 2));
		anchor = Point(iterations, iterations);
		iterations = 1;
	} else if (iterations > 1 && countNonZero(kernel) == kernel.rows * kernel.cols) {
		anchor = Point(anchor.x*iterations, anchor.y*iterations);
		kernel = Mat_<uchar, 1>(ksize.height + (iterations - 1)*(ksize.height - 1), ksize.width + (iterations - 1)*(ksize.width - 1));
		getStructuringElement(kernel, MORPH_RECT,
			Size(ksize.width + (iterations - 1)*(ksize.width - 1), ksize.height + (iterations - 1)*(ksize.height - 1)), anchor);
		iterations = 1;
	}

	anchor = normalizeAnchor(anchor, kernel.size());

	Ptr<BaseRowFilter> rowFilter;
	Ptr<BaseColumnFilter> columnFilter;
	Ptr<BaseFilter> filter2D;

	if (countNonZero(kernel) == kernel.rows*kernel.cols) {
		// rectangular structuring element
		rowFilter = getMorphologyRowFilter<_Tp, chs>(1, kernel.cols, anchor.x);
		columnFilter = getMorphologyColumnFilter<_Tp, chs>(1, kernel.rows, anchor.y);
	} else {
		filter2D = getMorphologyFilter<_Tp, chs>(1, kernel, anchor);
	}

	Scalar borderValue_ = borderValue;
	if (borderType == BORDER_CONSTANT && borderValue_ == Scalar::all(DBL_MAX)) {
		if (sizeof(_Tp) == 1) // CV_8U
			borderValue_ = Scalar::all(0.);
		else // CV_32F
			borderValue_ = Scalar::all(-FLT_MAX);
	}

	Ptr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>> f = makePtr<FilterEngine<_Tp, _Tp, _Tp, chs, chs, chs>>(filter2D, rowFilter, columnFilter, borderType, borderType, borderValue_);
	f->apply(src, dst);
	for (int i = 1; i < iterations; i++)
		f->apply(dst, dst);

	return 0;
}

} // namespace fbc

#endif // FBC_CV_DILATE_HPP_

测试代码test_dilate.cpp:

#include "test_dilate.hpp"
#include <assert.h>

#include <dilate.hpp>
#include <opencv2/opencv.hpp>

int test_getStructuringElement()
{
	for (int elem = 0; elem < 3; elem++) {
		for (int size = 0; size < 10; size++) {
			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_<uchar, 1> 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]);
					if (size == 5)
						fprintf(stderr, "%d  ", p1[x]);
				}
				if (size == 5)
					fprintf(stderr, "\n");
			}

			if (size == 5)
				fprintf(stderr, "\n");
		}
	}

	return 0;
}

int test_dilate_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 < 10; size++) {
			for (int iterations = 1; iterations < 5; iterations++) {
				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_<uchar, 1> 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::dilate(mat1, mat2, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

				cv::Mat mat1_(height, width, CV_8UC3, matSrc.data);
				cv::Mat mat2_;
				cv::dilate(mat1_, mat2_, 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_dilate_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 < 10; size++) {
			for (int iterations = 1; iterations < 5; iterations++) {
				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_<uchar, 1> 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_<float, 1> mat1(height, width, matSrc.data);
				fbc::Mat_<float, 1> mat2(height, width);
				fbc::dilate(mat1, mat2, element, fbc::Point(-1, -1), iterations, 0, fbc::Scalar::all(128));

				cv::Mat mat1_(height, width, CV_32FC1, matSrc.data);
				cv::Mat mat2_;
				cv::dilate(mat1_, mat2_, 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;
}

GitHubhttps://github.com/fengbingchun/OpenCV_Test

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值