知识点:
直线检测:原图膨胀-原图腐蚀
角点检测:result1 = 膨胀(十字)+腐蚀(菱形)(对原图进行的连续形态学滤波)
result2 = 膨胀(x 型 )+腐蚀(方形)(对原图进行的连续形态学运算)
result = abs(result1 - result2)
具体语言叙述:
1.直线检测:计算膨胀后的图像与腐蚀后图像的差值。由于这两个变换的图像不同的地方主要在边缘处,图像边缘将通过求差得到强化。这整是cv::morphologyEx在参数cv::MORPH_GRADIENT的作用原理
2.角点检测:原理是使用膨胀来进行闭运算,并使用两种不同的结构元素来应用腐蚀运算。挑选的这些元素可以确保连续的边缘不受改变,但是由于他们的重复效应,角点出的边缘仍受到影响。
MorphoFeatures.cpp:
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
class MorphoFeatures {
private:
// threshold to produce binary image
//生成二值图像的阈值
int threshold;
// structuring elements used in corner detection
//角点检测中用到的结构元素
cv::Mat cross;
cv::Mat diamond;
cv::Mat square;
cv::Mat x;
//获取二值的边缘图像
void applyThreshold(cv::Mat& result) {
// Apply threshold on result
//使用阈值化
if (threshold>0)
cv::threshold(result, result, threshold, 255, cv::THRESH_BINARY_INV);
}
public:
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))
//初始化列表,括号内为初始值,更适用于成员变量的常量const型。
{
// Creating the cross-shaped structuring element
for (int i = 0; i<5; i++) {
cross.at<uchar>(2, i) = 1;
cross.at<uchar>(i, 2) = 1;
}
// Creating the diamond-shaped structuring element
//菱形
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;
// Creating the x-shaped structuring element
for (int i = 0; i<5; i++) {
x.at<uchar>(i, i) = 1;
x.at<uchar>(4 - i, i) = 1;
}
}
void setThreshold(int t) {
threshold = t;
}
int getThreshold() const {
return threshold;
}
//直线的检测
cv::Mat getEdges(const cv::Mat &image) {
// Get the gradient image 形态学梯度=膨胀-腐蚀
//得到梯度图
cv::Mat result;
cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());
// Apply threshold to obtain a binary image 阈值化以得到二值化图像
applyThreshold(result);
return result;
}
cv::Mat getCorners(const cv::Mat &image) {
cv::Mat result;
// Dilate with a cross
//十字膨胀
cv::dilate(image, result, cross);
// Erode with a diamond
cv::erode(result, result, diamond);
cv::Mat result2;
// Dilate with a X
cv::dilate(image, result2, x);
// Erode with a square
cv::erode(result2, result2, square);
// Corners are obtained by differencing
// the two closed images
cv::absdiff(result2, result, result);
// Apply threshold to obtain a binary image
applyThreshold(result);
return result;
}
//为了更好的可视化,在二值图像中的每个监测点上绘制圆
void drawOnImage(const cv::Mat& binary, cv::Mat& image) {
cv::Mat_<uchar>::const_iterator it = binary.begin<uchar>();
cv::Mat_<uchar>::const_iterator itend = binary.end<uchar>();
// for each pixel
for (int i = 0; it != itend; ++it, ++i) {
if (!*it)
cv::circle(image, cv::Point(i%image.step, i / image.step), 5, cv::Scalar(255, 0, 0));
}
}
};
main.cpp:
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include "MorphoFeatures.cpp"
using namespace std;
using namespace cv;
int main()
{
// Read input image
cv::Mat image = cv::imread("D:/test.jpg", 0);
if (!image.data)
return 0;
// Display the image
cv::namedWindow("Image");
cv::imshow("Image", image);
// Create the morphological features instance
MorphoFeatures morpho;
morpho.setThreshold(40);
// Get the edges
//得到边缘图像
cv::Mat edges;
edges = morpho.getEdges(image);
// Display the edge image
cv::namedWindow("Edge Image");
cv::imshow("Edge Image", edges);
cv::Mat corners;
corners = morpho.getCorners(image);
morpho.drawOnImage(corners, image);
cv::namedWindow("Corners on Image");
cv::imshow("Corners on Image", image);
cv::waitKey();
return 0;
}