您的位置:首页 > 编程语言

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

2016-09-03 16:26 381 查看
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):将突出比原轮廓暗的部分。



目前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 <typeinfo>
#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<typename _Tp, int chs>
int morphologyEx(const Mat_<_Tp, chs>& src, Mat_<_Tp, chs>& dst, int op, const 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);
}

Mat_<uchar, 1> kernel_ = kernel;
if (kernel_.empty()) {
kernel_ = Mat_<uchar, 1>(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_<uchar, 1> k1 = (kernel_ == Mat_<uchar, 1>(kernel_.rows, kernel_.cols, Scalar::all(1)));
Mat_<uchar, 1> k2 = (kernel_ == Mat_<int, 1>(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 <assert.h>

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

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_<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::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_<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::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_<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_<uchar, 1> mat1(height, width, matSrc.data);
fbc::Mat_<uchar, 1> 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;
}

GitHubhttps://github.com/fengbingchun/OpenCV_Test
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: