使用轮廓检测,我们可以检测目标的边界,并在图像中定位它们。轮廓检测有着很多应用场景,例如图像前景提取,图像分割、检测和识别等等。
1.什么是图像的轮廓?
当我们连接图像中某个目标边界上的所有点时,就得到了一个轮廓。通常轮廓是指具有相同颜色和强度的边界像素。
在之前我们有学过Canny边缘检测, 那么边缘和轮廓的区别在哪里呢?通常来说,轮廓是一系列相连的点组成的曲线,描绘了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全部连续。
2.使用OpenCV进行轮廓检测
使用OpenCV进行轮廓检测非常简单 。步骤如下:
1) 读取图像并将其转换为灰度格式
读取图像并将图像转换为灰度格式。将图像转换为单通道灰度图像是为了方便做阈值处理,这是轮廓检测算法的第一步。
2) 应用二进制阈值
在寻找轮廓时,首先总是对灰度图像应用二值阈值或 Canny 边缘检测。在这里,我们使用二值阈值。
这会将彩色图像转换为二值图像,使轮廓检测算法变得容易。边缘检测使图像中对象的边界完全变白,所有像素都具有相同的强度。该算法现在可以从这些白色像素中检测对象的边界。
此时,可能会出现一个问题。如果我们使用 R(红色)、G(绿色)或 B(蓝色)等单通道而不是灰度(阈值)图像会怎样?答案是在这种情况下,轮廓检测算法将无法正常工作。Canny边缘检测算是利用像素强度(亮度)的值来检测出边界的。而通常灰度图比单个 (RGB) 颜色通道图像更好地提供亮度信息。
3) 找到轮廓
使用findContours()函数检测图像中的轮廓。
4) 在原始 图像上绘制轮廓。
识别轮廓后,使用该drawContours()函数将轮廓叠加在原始 RGB 图像上。
3.OpenCV代码演示
#include<opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
//读取原始图片
Mat image = imread("C:/Users/LeLe/Desktop/opencv/images/car.jpeg");
//转换为灰度图
Mat img_gray;
cvtColor(image, img_gray, COLOR_BGR2GRAY);
imshow("origin", image);
//通过阈值转换为二值图像
//注意这里对于不同的图像,可以不断调整阈值来得到更好的二值图像。这里我设置的阈值是150。
Mat thresh;
threshold(img_gray, thresh, 150, 255, THRESH_BINARY);
//边缘检测
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(thresh, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
//将检测到的边缘画在原始图像上
Mat image_copy = image.clone();
drawContours(image_copy, contours, -1, Scalar(0, 255, 0), 2);
imshow("None approximation", image_copy);
waitKey(0);
}
结果显示。左边和右边分别为原始图像和原始图像叠加轮廓的图像。