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

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中的erode函数支持多通道,各个通道腐蚀处理过程独立。腐蚀针对白色部分(高亮部分)。腐蚀即求局部最小值的操作,图像A与核B作卷积运算,计算核B覆盖区域的像素点的最小值,并把这个值赋值给锚点(anchor point)指定的像素。

Erosion:

(1)、This operation is the sister of dilation. What this does is to compute a local minimum over the area of the kernel.

(2)、As the kernel B is scanned over the image, we compute the minimal pixel value overlapped by B and replace the image pixel under the anchor point with that minimal value.


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

实现代码erode.hpp:

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

#ifndef FBC_CV_ERODE_HPP_
#define FBC_CV_ERODE_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 {

// Erodes an image by using a specific structuring element
// \f[\texttt{ dst } (x, y) = \min _{ (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.
// Erosion can be applied several ( iterations ) times.
// support type: uchar/float, multi-channels
template<typename _Tp, int chs>
int erode(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>(0, kernel.cols, anchor.x);
		columnFilter = getMorphologyColumnFilter<_Tp, chs>(0, kernel.rows, anchor.y);
	} else {
		filter2D = getMorphologyFilter<_Tp, chs>(0, kernel, anchor);
	}

	Scalar borderValue_ = borderValue;
	if (borderType == BORDER_CONSTANT && borderValue_ == Scalar::all(DBL_MAX)) {
		if (sizeof(_Tp) == 1) // CV_8U
			borderValue_ = Scalar::all((double)UCHAR_MAX);
		else // CV_32F
			borderValue_ = Scalar::all((double)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_ERODE_HPP_

测试代码test_erode.cpp:

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

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

int test_erode_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::erode(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::erode(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_erode_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::erode(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::erode(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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值