拐角
OpenCV的goodFeaturesToTrack()函数实现了一个稳健的拐角检测器。使用了Shi和Tomasi提出的兴趣点检测算法。更多关于该函数的内部原理可以从此文档页面找到http://docs.opencv.org/modules/imgproc/doc/feature_detection.html?highlight=goodfeaturestotrack#goodfeaturestotrack.
该函数接受如下输入:
• 灰度图像
• 一个储存拐角坐标Point2d的标准向量
• 返回的拐角最大数量。如果算法检测到多于此数量的拐角,则仅仅返回最合适的拐角。
• 质量等级:认可拐角的质量最小值。拐角的质量是指图像在某一像素的亮度梯度矩阵的最小特征值或者(如果使用的是Harris拐角检测器)图像在该像素对Harris函数的反馈值。可以查阅文档看看cornerHarris()和cornerMinEigenVal()的详细信息。
• 返回的两拐角位置间的最小欧式距离。
• 一个标签来指示是否使用Harris拐角检测还是最小特征值检测(默认是最小特征值)。
• 如果使用Harris拐角检测,此参数则为了调整Harris检测器(查阅cornerHarris()的文档来了解此参数的使用)
例5-6 检测图像拐角
// Program to detect corners in an image
// Author: Samarth Manoj Brahmbhatt, University of Pennyslvania
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <stdlib.h>
using namespace std;
using namespace cv;
Mat image, image_gray;
int max_corners = 20;
void on_slider(int, void *) {
if(image_gray.empty()) return;
max_corners = max(1, max_corners);
setTrackbarPos("Max no. of corners", "Corners", max_corners);
float quality = 0.01;
int min_distance = 10;
vector<Point2d> corners;
goodFeaturesToTrack(image_gray, corners, max_corners, quality, min_distance);
// Draw the corners as little circles
Mat image_corners = image.clone();
for(int i = 0; i < corners.size(); i++) {
circle(image_corners, corners[i], 4, CV_RGB(255, 0, 0), -1);
}
imshow("Corners", image_corners);
}
int main() {
image = imread("building.jpg");
cvtColor(image, image_gray, CV_RGB2GRAY);
namedWindow("Corners");
on_slider(0, 0);
createTrackbar("Max. no. of corners", "Corners", &max_corners, 250, on_slider);
while(char(waitKey(1)) != 'q') {}
return 0;
}
这个程序里,我们通过滑块来改变可返回的拐角最大数量,观察如何使用circle()函数来在拐角位置绘制红色小填充圆形。程序输出显示如图5-11
图 5-11 不同max_corners值下的拐角
图像腐蚀和膨胀
腐蚀和膨胀是图像的两个基本形态学操作。顾名思义,形态学操作是基于图像的形式和结构的。 腐蚀是通过在一个图像上遍历使用一个矩形核。反馈值是核元素和核所在像素的叉积最大值。因为所有核元素都一样,所以应用此核代表替换每个像素值为该像素周围矩形区域的最小值。你可以想象这样会引起图像里黑色区域会“侵蚀”到白色区域(因为白色像素值比黑色的要高)。膨胀也一样,区别是反馈值是叉积的最大值。会引起白色区域侵蚀到黑色区域。核的大小会决定腐蚀或膨胀的量。
通过形态学的图像开启和关闭移除噪声
开启是通过先腐蚀图像后接着膨胀。这会有一个移除图像上微小的白色区域的效果。关闭是先膨胀再腐蚀,会有相反的效果。这两个操作经常用来移除图像里的噪声。开启移除微小白色像素而关闭移除微小黑色“洞口”。OpenCV的morphologyEX()可以用来高级的形态学操作像图像上开启和关闭。例5-8 对象检测代码
// Program to display a video from attached default camera device and detect colored blobs using simple
// R G and B thresholding
// Author: Samarth Manoj Brahmbhatt, University of Pennsylvania
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
Mat frame, frame_thresholded;
int rgb_slider = 0, low_slider = 30, high_slider = 100;
int low_r = 30, low_g = 30, low_b = 30, high_r = 100, high_g = 100, high_b = 100;
void on_rgb_trackbar(int, void *) {
switch(rgb_slider) {
case 0:
setTrackbarPos("Low threshold", "Segmentation", low_r);
setTrackbarPos("High threshold", "Segmentation", high_r);
break;
case 1:
setTrackbarPos("Low threshold", "Segmentation", low_g);
setTrackbarPos("High threshold", "Segmentation", high_g);
break;
case 2:
setTrackbarPos("Low threshold", "Segmentation", low_b);
setTrackbarPos("High threshold", "Segmentation", high_b);
break;
}
}
void on_low_thresh_trackbar(int, void *) {
switch(rgb_slider) {
case 0:
low_r = min(high_slider - 1, low_slider);
setTrackbarPos("Low threshold", "Segmentation", low_r);
break;
case 1:
low_g = min(high_slider - 1, low_slider);
setTrackbarPos("Low threshold", "Segmentation", low_g);
break;
case 2:
low_b = min(high_slider - 1, low_slider);
setTrackbarPos("Low threshold", "Segmentation", low_b);
break;
}
}
void on_high_thresh_trackbar(int, void *) {
switch(rgb_slider) {
case 0:
high_r = max(low_slider + 1, high_slider);
setTrackbarPos("High threshold", "Segmentation", high_r);
break;
case 1:
high_g = max(low_slider + 1, high_slider);
setTrackbarPos("High threshold", "Segmentation", high_g);
break;
case 2:
high_b = max(low_slider + 1, high_slider);
setTrackbarPos("High threshold", "Segmentation", high_b);
break;
}
}
int main()
{
// Create a VideoCapture object to read from video file
// 0 is the ID of the built-in laptop camera, change if you want to use other camera
VideoCapture cap(0);
//check if the file was opened properly
if(!cap.isOpened())
{
cout << "Capture could not be opened succesfully" << endl;
return -1;
}
namedWindow("Video");
namedWindow("Segmentation");
createTrackbar("0. R\n1. G\n2.B", "Segmentation", &rgb_slider, 2, on_rgb_trackbar);
createTrackbar("Low threshold", "Segmentation", &low_slider, 255, on_low_thresh_trackbar);
createTrackbar("High threshold", "Segmentation", &high_slider, 255, on_high_thresh_trackbar);
while(char(waitKey(1)) != 'q' && cap.isOpened())
{
cap >> frame;
// Check if the video is over
if(frame.empty())
{
cout << "Video over" << endl;
break;
}
inRange(frame, Scalar(low_b, low_g, low_r), Scalar(high_b, high_g, high_r),
frame_thresholded);
Mat str_el = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(frame_thresholded, frame_thresholded, MORPH_OPEN, str_el);
morphologyEx(frame_thresholded, frame_thresholded, MORPH_CLOSE, str_el);
imshow("Video", frame);
imshow("Segmentation", frame_thresholded);
}
return 0;
图 5-13 通过开启和关闭移除小块噪声像素