写在前面:理论的东西不多说,主要是做一一个实例的小笔记。
操作环境:Ubuntu 16.04, OpenCV 3.2,C++
定义
特征检测(feature detection)是图像处理和计算机视觉里的一个概念。它指的是使用计算机提取图像信息,决定每个图像的点是否属于一个图像特征。特征检测的结果是把图像上的点分为不同的子集,这些子集往往属于孤立的点、连续的曲线或者连续的区域。(摘自Wikipedia)
分类
- 边缘检测
边缘指组成两个图像区域之间边界(或边缘)的像素。
- 角检测
角指图像中点似的特征,在局部它有两维结构。
- 区域检测
与角不同的是区域描写一个图像中的一个区域性的结构,但是区域也可能仅由一个像素组成,因此许多区域检测也可以用来监测角。
*区域检测可以被想象为把一张图像缩小,然后在缩小的图像上进行角检测。
- 脊检测
长条形的物体被称为脊。在实践中脊可以被看作是代表对称轴的一维曲线,此外局部针对于每个脊像素有一个脊宽度。从灰梯度图像中提取脊要比提取边缘、角和区域困难。在空中摄影中往往使用脊检测来分辨道路,在医学图像中它被用来分辨血管。
今天主要介绍的实例是Harris角点检测,Canny边缘检测,Hough变换(直线和圆的检测)。
1. Harris角点检测
源码(C++):
#define _CRT_SECURE_NO_WARNINGS
运行结果:
这里用到一个OpenCV的函数:
void cv::goodFeaturesToTrack(
InputArray image, /* 输入矩阵,8位浮动点数 */
OutputArray corners, /* 输出矩阵,检测出的角点的矢量 */
int maxCorners, /* 检测角点的最大数的允许值 */
double qualityLevel, /* 角点检测的最低质量允许值 */
double minDistance /* 检测出的角点间最小欧式距离的允许值 */
);
2. Canny边缘检测
源码(C++):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
std::string win_src = "src";
std::string win_dst = "dst";
int main()
{
cv::Mat img_src = cv::imread("./01-02.jpg", 1);
cv::Mat img_gray, img_dst;
if (!img_src.data) {
std::cout << "error" << std::endl;
return -1;
}
//彩图转灰度图
cv::cvtColor(img_src, img_gray, cv::COLOR_BGR2GRAY);
// Canny边缘检测法
cv::Canny(img_gray, img_dst, 350, 1000);
// 生成界面窗口
cv::namedWindow(win_src, cv::WINDOW_AUTOSIZE);
cv::namedWindow(win_dst, cv::WINDOW_AUTOSIZE);
// 显示图片
cv::imshow(win_src, img_src);
cv::imshow(win_dst, img_dst);
cv::waitKey(0);
return 0;
}
运行结果:
这里用到一个OpenCV的函数:
void cv::Canny(
InputArray image, /* 输入矩阵,8位浮动点数,单通道 */
OutputArray edges, /* 输出矩阵,检测出的边缘,8为浮动点数,单通道 */
double threshold, /* Hysteresis参数1 */
double threshold /* Hysteresis参数2 */
);
3. Hough变化(直线检测)
源码(C++):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
std::string win_src = "src";
std::string win_edge = "edge";
std::string win_dst = "dst";
int main()
{
cv::Mat img_src = cv::imread("./01-03.jpg", 1);
cv::Mat img_gray, img_edge, img_dst;
if (!img_src.data) {
std::cout << "error" << std::endl;
return -1;
}
img_src.copyTo(img_dst);
cv::cvtColor(img_src, img_gray, cv::COLOR_BGR2GRAY);
cv::Canny(img_gray, img_edge, 200, 200);
std::vector<cv::Vec2f> lines;
// Hough变换检测直线
cv::HoughLines(img_edge, lines, 1, CV_PI / 180, 120);
for (int i = 0; i < lines.size(); i++) {
double rho = lines[i][0], theta = lines[i][1];
double a = cos(theta), b = sin(theta);
double x0 = a*rho, y0 = b*rho;
cv::line(img_dst,
cv::Point(x0 - img_dst.cols*b, y0 + img_dst.cols*a),
cv::Point(x0 + img_dst.cols*b, y0 - img_dst.cols*a),
cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
}
cv::namedWindow(win_src, cv::WINDOW_AUTOSIZE);
cv::namedWindow(win_dst, cv::WINDOW_AUTOSIZE);
cv::imshow(win_src, img_src);
cv::imshow(win_edge, img_edge);
cv::imshow(win_dst, img_dst);
cv::waitKey(0);
return 0;
}
运行结果:
这里用到一个OpenCV的函数:
void cv::HoughLines(
InputArray image, /* 输入矩阵,8位浮动点数,单通道,二值图像 */
OutputArray lines, /* 输出矩阵,检测出的直线 */
double rho, /* 像素距离 */
double theta /* 弧度制角度 */
double threshold /* 累加平面的阈值参数,大于阈值threshold的线段
才可以被检测通过并返回到结果中。 */
);
4. Hough变化(圆形检测)
源码(C++):
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <opencv2/opencv.hpp>
std::string win_src = "src";
std::string win_edge = "edge";
std::string win_dst = "dst";
int main()
{
cv::Mat img_src = cv::imread("./01-04.jpg", 1);
cv::Mat img_gray, img_edge, img_dst;
if (!img_src.data) {
std::cout << "error" << std::endl;
return -1;
}
img_src.copyTo(img_dst);
cv::cvtColor(img_src, img_gray, cv::COLOR_BGR2GRAY);
cv::Canny(img_gray, img_edge, 80, 120);
std::vector<cv::Vec3f> circles;
cv::HoughCircles(img_edge, circles, cv::HOUGH_GRADIENT, 50, 100);
for (int i = 0; i < circles.size(); i++) {
cv::Point center((int)circles[i][0], (int)circles[i][1]);
int radius = (int)circles[i][2];
cv::circle(img_dst, center, radius, cv::Scalar(0, 0, 255), 3);
}
cv::namedWindow(win_src, cv::WINDOW_AUTOSIZE);
cv::namedWindow(win_dst, cv::WINDOW_AUTOSIZE);
cv::imshow(win_src, img_src);
cv::imshow(win_edge, img_edge);
cv::imshow(win_dst, img_dst);
cv::waitKey(0);
return 0;
}
运行结果:
这里用到一个OpenCV的函数:
void cv::HoughCircles(
InputArray image, /* 输入矩阵,8位浮动点数,单通道,二值图像 */
OutputArray circles, /* 输出矩阵,用(x, y, radius)来表示 */
double method, /* 检测方法,现在OpenCV中只有霍夫梯度法(HOUGH_GRADIENT) */
double dp /* 累加器分辨率相对于图像分辨率的比率 */
double minDist /* 检测出的圆心之间的最小距离 */
);