形态学滤波还可以进行边缘和角点的检测
边缘检测:
在形态学检测边缘时,可以使用opencv库中自带的函数morphologyEx,并将其中的参数设置为MORPH_GRADIENT
实现上,先定义一个MorphoFeatures类,getEdges方法通过morphologyEx函数可以很容易地得到边缘。代码如下:
class MorphoFeatures { private: int threshold; public: void setThreshold(int t); cv::Mat getEdges(const cv::Mat &image); void applyThreshold(cv::Mat &result); };
void MorphoFeatures::setThreshold(int t) { threshold = t; } cv::Mat MorphoFeatures::getEdges(const cv::Mat &image) { cv::Mat result; cv::Mat element = cv::getStructuringElement(0, cv::Size(5, 5), cv::Point(3, 3)); cv::morphologyEx(image, result, cv::MORPH_GRADIENT, element); applyThreshold(result); return result; } void MorphoFeatures::applyThreshold(cv::Mat &result) { if (threshold > 0) { cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY); } }
int main() { cv::Mat image = cv::imread("F:\\building.jpg", 0); MorphoFeatures morpho; morpho.setThreshold(80); cv::Mat edges; edges = morpho.getEdges(image); cv::imshow("1", edges); cv::waitKey(0); return 0; }
即可很容易得到边缘图片
角点检测:
由于opencv没有直接实现形态学检测角点,因而我们需要使用非方形结构,包括菱形、十字、X型等等,这在类中会有体现。
在MorphoFeatures类的最开始,使用重构,初始化private中的变量;然后再进行创建元素
原理想法:
如果将图像以灰度图的形式显示, 那么边缘可以看作是明亮和灰暗像素的快速过渡,可以看作陡峭的悬崖
因而,在角点检测的时候,可以采取:
十字膨胀+菱形腐蚀->结果1
X型膨胀+方形腐蚀->结果2
二者相减得到角点图片
(具体原理等我搞明白数学之后补充)
在这之后,我改动了书上的代码,使用了另一种形式:
采用二值化图像+0判断选取角点,具体代码如下:
MorphoFeatures类:
class MorphoFeatures { private: int threshold; cv::Mat cross; cv::Mat diamond; cv::Mat square; cv::Mat x; public: void setThreshold(int t); cv::Mat getEdges(const cv::Mat &image); void applyThreshold(cv::Mat &result); MorphoFeatures():threshold(-1), cross(5, 5, CV_8U, cv::Scalar(0)), diamond(5, 5, CV_8U, cv::Scalar(1)), square(5, 5, CV_8U, cv::Scalar(1)), x(5, 5, CV_8U, cv::Scalar(0)) { for (int i = 0; i<5; i++) { cross.at<uchar>(2, i) = 1; cross.at<uchar>(i, 2) = 1; } diamond.at<uchar>(0, 0) = 0; diamond.at<uchar>(0, 1) = 0; diamond.at<uchar>(1, 0) = 0; diamond.at<uchar>(4, 4) = 0; diamond.at<uchar>(3, 4) = 0; diamond.at<uchar>(4, 3) = 0; diamond.at<uchar>(4, 0) = 0; diamond.at<uchar>(4, 1) = 0; diamond.at<uchar>(3, 0) = 0; diamond.at<uchar>(0, 4) = 0; diamond.at<uchar>(0, 3) = 0; diamond.at<uchar>(1, 4) = 0; for (int i = 0; i<5; i++) { x.at<uchar>(i, i) = 1; x.at<uchar>(4 - i, i) = 1; } } cv::Mat getCorners(const cv::Mat &image); void drawOnImage(const cv::Mat& binary, cv::Mat& image); }; MorphoFeatures的cpp:
void MorphoFeatures::setThreshold(int t) { threshold = t; } cv::Mat MorphoFeatures::getEdges(const cv::Mat &image) { cv::Mat result; cv::Mat element = cv::getStructuringElement(0, cv::Size(5, 5), cv::Point(3, 3)); cv::morphologyEx(image, result, cv::MORPH_GRADIENT, element); applyThreshold(result); return result; } void MorphoFeatures::applyThreshold(cv::Mat &result) { if (threshold > 0) { cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY); } } cv::Mat MorphoFeatures::getCorners(const cv::Mat &image) { cv::Mat result; cv::dilate(image, result, cross); cv::erode(result, result, diamond); cv::Mat result2; cv::dilate(image, result2, x); cv::erode(result2, result2, square); cv::absdiff(result2, result, result); applyThreshold(result); return result; } void MorphoFeatures::drawOnImage(const cv::Mat& binary, cv::Mat& image) { for (int i = 0; i < binary.rows; i++) { for (int j = 0; j < binary.cols; j++) { if (binary.at<uchar>(i, j) != 0) { cv::circle(image, cv::Point(j, i), 5, cv::Scalar(255, 0, 0)); } } } }
主函数:
int main() { cv::Mat image = cv::imread("F:\\building.jpg", 0); cv::Mat image2 = cv::imread("F:\\building.jpg"); cv::Mat corners; cv::Mat twoValue; MorphoFeatures morpho; corners = morpho.getCorners(image); cv::imshow("1", corners); cv::threshold(corners, twoValue, 30, 255, 0); morpho.drawOnImage(twoValue, image2); cv::imshow("12", image2); cv::waitKey(0); return 0; }
先这样吧,接着看数学了。。