Opencv_CUDA应用之 基于形状的对象检测与跟踪
- 形状可以用作全局特征检测具有不同形状的物体,可以是直线、多边形、圆形或者任何其他不规则形状
- 利用对象边界、边缘和轮廓可以检测具有特定形状的对象
- 本文将使用Canny边缘检测算法和Hough变换来检测两个规则形状,即线和圆
1. Canny 边缘检测
-
Canny 结合了高斯滤波、梯度寻找、非极大值抑制和滞后阈值处理
-
高通滤波器对噪声非常敏感,在Canny边缘检测中,检测边缘之前完成高斯平滑,在检测到边缘后从结果中移除不必要的边缘之后,还具有非极大值抑制阶段
-
算法代码如下:
cpp
#include <cmath>
#include <iostream>
#include "opencv2/opencv.hpp"
#include<opencv2/cudaimgproc.hpp>
using namespace std;
using namespace cv;
using namespace cv::cuda;
int main()
{
Mat h_image = imread("images/drawing.JPG", 0);
if (h_image.empty())
{
cout << "can not open image" << endl;
return -1;
}
GpuMat d_edge, d_image;
Mat h_edge;
d_image.upload(h_image);
cv::Ptr<cv::cuda::CannyEdgeDetector> canny_edge = cv::cuda::createCannyEdgeDetector(2.0, 100.0, 3, false);
canny_edge->detect(d_image, d_edge);
d_edge.download(h_edge);
imshow("source", h_image);
imshow("detected edges", h_edge);
waitKey(0);
return 0;
}

2. 使用 Hough 变换进行直线检测
- hough变换常用于直线检测、圆检测
- 直线检测函数解析:
cpp
/*
cv::cuda::createCannyEdgeDetector 函数参数:
第一个r表示在Hough变换中参数的分辨率,通常为1像素
第二个参数是theta在弧度中的分辨率,取1弧度或者pi/180
第三个参数是形成一条线所需点的最小数量
第四个参数是两点之间的最大间隙被视为同一条直线
*/
Ptr<cuda::HoughSegmentDetector> hough =
cuda::createHoughSegmentDetector(1.0f, (float)(CV_PI / 180.0f), 50, 5);
- 实现代码如下:
cpp
#include <cmath>
#include <iostream>
#include "opencv2/opencv.hpp"
#include<opencv2/cudaimgproc.hpp>
using namespace std;
using namespace cv;
using namespace cv::cuda;
int main()
{
Mat h_image = imread("images/drawing.JPG", 0);
resize(h_image, h_image, h_image.size());
if (h_image.empty())
{
cout << "can not open image" << endl;
return -1;
}
Mat h_edge;
cv::Canny(h_image, h_edge, 100, 200, 3);
Mat h_imagec;
cv::cvtColor(h_edge, h_imagec, COLOR_GRAY2BGR);
Mat h_imageg = h_imagec.clone();
vector<Vec4i> h_lines;
{
const int64 start = getTickCount();
HoughLinesP(h_edge, h_lines, 1, CV_PI / 180, 50, 60, 5);
const double time_elapsed = (getTickCount() - start) / getTickFrequency();
cout << "CPU Time : " << time_elapsed * 1000 << " ms" << endl;
cout << "CPU FPS : " << (1 / time_elapsed) << endl;
}
for (size_t i = 0; i < h_lines.size(); ++i)
{
Vec4i line_point = h_lines[i];
line(h_imagec, Point(line_point[0], line_point[1]), Point(line_point[2], line_point[3]), Scalar(0, 0, 255), 2, LINE_AA);
}
GpuMat d_edge, d_lines;
d_edge.upload(h_edge);
{
const int64 start = getTickCount();
Ptr<cuda::HoughSegmentDetector> hough = cuda::createHoughSegmentDetector(1.0f, (float)(CV_PI / 180.0f), 50, 5);
hough->detect(d_edge, d_lines);
const double time_elapsed = (getTickCount() - start) / getTickFrequency();
cout << "GPU Time : " << time_elapsed * 1000 << " ms" << endl;
cout << "GPU FPS : " << (1 / time_elapsed) << endl;
}
//取出直线两个点
vector<Vec4i> lines_g;
if (!d_lines.empty())
{
lines_g.resize(d_lines.cols);
Mat h_lines(1, d_lines.cols, CV_32SC4, &lines_g[0]);
d_lines.download(h_lines);
}
for (size_t i = 0; i < lines_g.size(); ++i)
{
Vec4i line_point = lines_g[i];
line(h_imageg, Point(line_point[0], line_point[1]), Point(line_point[2], line_point[3]), Scalar(0, 0, 255), 2, LINE_AA);
}
imshow("source", h_image);
imshow("detected lines [CPU]", h_imagec);
imshow("detected lines [GPU]", h_imageg);
imwrite("hough_source.png", h_image);
imwrite("hough_cpu_line.png", h_imagec);
imwrite("hough_gpu_line.png", h_imageg);
waitKey(0);
return 0;
}

3. 对圆形进行检测
- 球检测或者硬币检测
- 圆检测函数解析:
cpp
/*
cv::cuda::createHoughCirclesDetector 参数
第一个参数是dp,表示累加器分辨率与图像分辨率的反比
第二个参数是检测到的圆中心之间的最小距离,调小会检测出其他错误圆,调大则可能丢失圆
第三个参数是Canny 阈值
第四个参数是累加器阈值
第五个和第六个参数是要检测的圆的最小和最大半径,不确定可以取0
*/
cv::Ptr<cv::cuda::HoughCirclesDetector> detector =
cv::cuda::createHoughCirclesDetector(1, 100, 122, 50, 1, max(h_image.size().width, h_image.size().height));
- 算法实现如下:
cpp
#include <iostream>
#include "opencv2/opencv.hpp"
#include<opencv2/cudaimgproc.hpp>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
Mat h_image = imread("images/eight.tif", IMREAD_COLOR);
Mat h_gray;
cvtColor(h_image, h_gray, COLOR_BGR2GRAY);
cuda::GpuMat d_gray, d_result;
std::vector<cv::Vec3f> d_Circles;
medianBlur(h_gray, h_gray, 5);
cv::Ptr<cv::cuda::HoughCirclesDetector> detector = cv::cuda::createHoughCirclesDetector(1, 100, 122, 50, 1, max(h_image.size().width, h_image.size().height));
d_gray.upload(h_gray);
detector->detect(d_gray, d_result);
d_Circles.resize(d_result.size().width);
if (!d_Circles.empty())
d_result.row(0).download(cv::Mat(d_Circles).reshape(3, 1));
cout << "No of circles: " << d_Circles.size() << endl;
for (size_t i = 0; i < d_Circles.size(); i++)
{
Vec3i cir = d_Circles[i];
circle(h_image, Point(cir[0], cir[1]), cir[2], Scalar(255, 0, 0), 2, LINE_AA);
}
imshow("detected circles", h_image);
waitKey(0);
return 0;
}
