cuda toolkit 安装见这篇文章
opencv with cuda环境安装见这篇文章
示例代码github地址
chapter 6
Basic Computer Vision Operations Using OpenCV and CUDA
- Accessing individual pixel intensities in OpenCV
- Histogram calculation and histogram equalization
- Image transformation
- Filtering operations on images
- Morphological operations on images
访问像素点
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::Scalar intensity = h_img1.at<uchar>(cv::Point(100, 50));
//修改某个像素点的值
//h_img1.at<uchar>(100, 50) = 128
std::cout << "Pixel Intensity of gray scale Image at (100,50) is:" << intensity.val[0] << std::endl;
cv::Mat h_img2 = cv::imread("images/autumn.tif", 1);
cv::Vec3b intensity1 = h_img2.at<cv::Vec3b>(cv::Point(100, 50));
std::cout << "Pixel Intensity of color Image at (100,50) is:" << intensity1 << std::endl;
return 0;
}
计算直方图与直方图均衡化
计算直方图函数
void cv::cuda::calcHist ( InputArray src, OutputArray hist)
直方图均衡化可以提升图片的质量
灰度图片直方图均衡化
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::cuda::GpuMat d_img1, d_result1;
d_img1.upload(h_img1);
cv::cuda::equalizeHist(d_img1, d_result1);
cv::Mat h_result1;
d_result1.download(h_result1);
cv::imshow("Original Image ", h_img1);
cv::imshow("Histogram Equalized Image", h_result1);
cv::imwrite("images/result_inversion.png", h_img1);
cv::imwrite("images/result_inversion.png", h_result1);
cv::waitKey();
return 0;
}
彩色图片直方图均衡化
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/autumn.tif");
cv::Mat h_img2, h_result1;
cvtColor(h_img1, h_img2, cv::COLOR_BGR2HSV);
//Split the image into 3 channels; H, S and V channels respectively and store it in a std::vector
std::vector<cv::Mat> vec_channels;
cv::split(h_img2, vec_channels);
//Equalize the histogram of only the V channel
cv::equalizeHist(vec_channels[2], vec_channels[2]);
//Merge 3 channels in the vector to form the color image in HSV color space.
cv::merge(vec_channels, h_img2);
//Convert the histogram equalized image from HSV to BGR color space again
cv::cvtColor(h_img2, h_result1, cv::COLOR_HSV2BGR);
cv::imshow("Original Image ", h_img1);
cv::imshow("Histogram Equalized Image", h_result1);
cv::waitKey();
return 0;
}
图片的旋转,放缩和平移
放缩
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::cuda::GpuMat d_img1, d_result1, d_result2;
d_img1.upload(h_img1);
int width = d_img1.cols;
int height = d_img1.size().height;
cv::cuda::resize(d_img1, d_result1, cv::Size(200, 100),
cv::INTER_CUBIC);
cv::cuda::resize(d_img1, d_result2, cv::Size(0.5 * width, 0.5 * height),
cv::INTER_LINEAR);
cv::Mat h_result1, h_result2;
d_result1.download(h_result1);
d_result2.download(h_result2);
cv::imshow("Original Image ", h_img1);
cv::imshow("Resized Image", h_result1);
cv::imshow("Resized Image 2", h_result2);
cv::waitKey();
return 0;
}
平移与旋转
平移操作用一个2*3的矩阵表示。
[ [1, 0, tx],
[0, 1, ty]]
其中tx和ty分别表示x方向和y方向的平移大小。
getRotationMatrix2D
函数用于旋转操作,接受三个参数,旋转点,旋转角度,放缩倍数
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::cuda::GpuMat d_img1, d_result1, d_result2;
d_img1.upload(h_img1);
int cols = d_img1.cols;
int rows = d_img1.size().height;
//Translation
cv::Mat trans_mat = (cv::Mat_<double>(2, 3) << 1, 0, 70, 0, 1, 50);
cv::cuda::warpAffine(d_img1, d_result1, trans_mat, d_img1.size());
//Rotation
cv::Point2f pt(d_img1.cols / 2., d_img1.rows / 2.);
cv::Mat rot_mat = cv::getRotationMatrix2D(pt, 45, 2.0);
cv::cuda::warpAffine(d_img1, d_result2, rot_mat, cv::Size(d_img1.cols, d_img1.rows));
cv::Mat h_result1, h_result2;
d_result1.download(h_result1);
d_result2.download(h_result2);
cv::imshow("Original Image ", h_img1);
cv::imshow("Translated Image", h_result1);
cv::imshow("Rotated Image", h_result2);
cv::waitKey();
return 0;
}
图片滤波
之前的所有操作都是针对单个像素点进行的。而滤波操作会涉及一个点的邻近点,有3x3,5x5,7x7等类型。
滤波是以卷积运算为基础的。当然更详细的我现在还不太懂,等以后慢慢学把
低通滤波
起到模糊降噪等效果
均值滤波 Averaging filters
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::cuda::GpuMat d_img1, d_result3x3, d_result5x5, d_result7x7;
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filter3x3, filter5x5, filter7x7;
filter3x3 = cv::cuda::createBoxFilter(CV_8UC1, CV_8UC1, cv::Size(3, 3));
filter3x3->apply(d_img1, d_result3x3);
filter5x5 = cv::cuda::createBoxFilter(CV_8UC1, CV_8UC1, cv::Size(5, 5));
filter5x5->apply(d_img1, d_result5x5);
filter7x7 = cv::cuda::createBoxFilter(CV_8UC1, CV_8UC1, cv::Size(7, 7));
filter7x7->apply(d_img1, d_result7x7);
cv::Mat h_result3x3, h_result5x5, h_result7x7;
d_result3x3.download(h_result3x3);
d_result5x5.download(h_result5x5);
d_result7x7.download(h_result7x7);
cv::imshow("Original Image ", h_img1);
cv::imshow("Blurred with kernel size 3x3", h_result3x3);
cv::imshow("Blurred with kernel size 5x5", h_result5x5);
cv::imshow("Blurred with kernel size 7x7", h_result7x7);
cv::imwrite("Blurred3x3.png", h_result3x3);
cv::imwrite("Blurred5x5.png", h_result5x5);
cv::imwrite("Blurred7x7.png", h_result7x7);
cv::waitKey();
return 0;
}
高斯滤波 Gaussian filters
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/cameraman.tif", 0);
cv::cuda::GpuMat d_img1, d_result3x3, d_result5x5, d_result7x7;
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filter3x3, filter5x5, filter7x7;
filter3x3 = cv::cuda::createGaussianFilter(CV_8UC1, CV_8UC1, cv::Size(3, 3), 1);
filter3x3->apply(d_img1, d_result3x3);
filter5x5 = cv::cuda::createGaussianFilter(CV_8UC1, CV_8UC1, cv::Size(5, 5), 1);
filter5x5->apply(d_img1, d_result5x5);
filter7x7 = cv::cuda::createGaussianFilter(CV_8UC1, CV_8UC1, cv::Size(7, 7), 1);
filter7x7->apply(d_img1, d_result7x7);
cv::Mat h_result3x3, h_result5x5, h_result7x7;
d_result3x3.download(h_result3x3);
d_result5x5.download(h_result5x5);
d_result7x7.download(h_result7x7);
cv::imshow("Original Image ", h_img1);
cv::imshow("Blurred with kernel size 3x3", h_result3x3);
cv::imshow("Blurred with kernel size 5x5", h_result5x5);
cv::imshow("Blurred with kernel size 7x7", h_result7x7);
cv::imwrite("gBlurred3x3.png", h_result3x3);
cv::imwrite("gBlurred5x5.png", h_result5x5);
cv::imwrite("gBlurred7x7.png", h_result7x7);
cv::waitKey();
return 0;
}
中值滤波 median filtering
当图片存在雪花点等噪声时,可以采用中值滤波
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/saltpepper.png", 0);
cv::Mat h_result;
cv::medianBlur(h_img1, h_result, 3);
cv::imshow("Original Image ", h_img1);
cv::imshow("Median Blur Result", h_result);
cv::waitKey();
return 0;
}
高通滤波 High-pass fitering
起到边缘检测等作用。
Sobel filters
有sobel-x,和sobel-y两个算子,相加即得到sobel-xy算子。
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/blobs.png", 0);
cv::cuda::GpuMat d_img1, d_resultx, d_resulty, d_resultxy;
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filterx, filtery, filterxy;
filterx = cv::cuda::createSobelFilter(CV_8UC1, CV_8UC1, 1, 0);
filterx->apply(d_img1, d_resultx);
filtery = cv::cuda::createSobelFilter(CV_8UC1, CV_8UC1, 0, 1);
filtery->apply(d_img1, d_resulty);
cv::cuda::add(d_resultx, d_resulty, d_resultxy);
cv::Mat h_resultx, h_resulty, h_resultxy;
d_resultx.download(h_resultx);
d_resulty.download(h_resulty);
d_resultxy.download(h_resultxy);
cv::imshow("Original Image ", h_img1);
cv::imshow("Sobel-x derivative", h_resultx);
cv::imshow("Sobel-y derivative", h_resulty);
cv::imshow("Sobel-xy derivative", h_resultxy);
cv::waitKey();
return 0;
}
Scharr filters
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/blobs.png", 0);
cv::cuda::GpuMat d_img1, d_resultx, d_resulty, d_resultxy;
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filterx, filtery;
filterx = cv::cuda::createScharrFilter(CV_8UC1, CV_8UC1, 1, 0);
filterx->apply(d_img1, d_resultx);
filtery = cv::cuda::createScharrFilter(CV_8UC1, CV_8UC1, 0, 1);
filtery->apply(d_img1, d_resulty);
cv::cuda::add(d_resultx, d_resulty, d_resultxy);
cv::Mat h_resultx, h_resulty, h_resultxy;
d_resultx.download(h_resultx);
d_resulty.download(h_resulty);
d_resultxy.download(h_resultxy);
cv::imshow("Original Image ", h_img1);
cv::imshow("Scharr-x derivative", h_resultx);
cv::imshow("Scharr-y derivative", h_resulty);
cv::imshow("Scharr-xy derivative", h_resultxy);
cv::waitKey();
return 0;
}
laplacian filters
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/blobs.png", 0);
cv::cuda::GpuMat d_img1, d_result1, d_result3;
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filter1, filter3;
filter1 = cv::cuda::createLaplacianFilter(CV_8UC1, CV_8UC1, 1);
filter1->apply(d_img1, d_result1);
filter3 = cv::cuda::createLaplacianFilter(CV_8UC1, CV_8UC1, 3);
filter3->apply(d_img1, d_result3);
cv::Mat h_result1, h_result3;
d_result1.download(h_result1);
d_result3.download(h_result3);
cv::imshow("Original Image ", h_img1);
cv::imshow("Laplacian filter 1", h_result1);
cv::imshow("Laplacian filter 3", h_result3);
cv::waitKey();
return 0;
}
其他一些图片运算
- Erosion
- Dilation
- Opening
- Closing
没太细看具体是啥操作,留着以后用到再研究吧
#include <iostream>
#include "opencv2/opencv.hpp"
int main()
{
cv::Mat h_img1 = cv::imread("images/blobs.png", 0);
cv::cuda::GpuMat d_img1, d_resulte, d_resultd, d_resulto, d_resultc;
cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));
d_img1.upload(h_img1);
cv::Ptr<cv::cuda::Filter> filtere, filterd, filtero, filterc;
filtere = cv::cuda::createMorphologyFilter(cv::MORPH_ERODE, CV_8UC1, element);
filtere->apply(d_img1, d_resulte);
filterd = cv::cuda::createMorphologyFilter(cv::MORPH_DILATE, CV_8UC1, element);
filterd->apply(d_img1, d_resultd);
filtero = cv::cuda::createMorphologyFilter(cv::MORPH_OPEN, CV_8UC1, element);
filtero->apply(d_img1, d_resulto);
filterc = cv::cuda::createMorphologyFilter(cv::MORPH_CLOSE, CV_8UC1, element);
filterc->apply(d_img1, d_resultc);
cv::Mat h_resulte, h_resultd, h_resulto, h_resultc;
d_resulte.download(h_resulte);
d_resultd.download(h_resultd);
d_resulto.download(h_resulto);
d_resultc.download(h_resultc);
cv::imshow("Original Image ", h_img1);
cv::imshow("Erosion", h_resulte);
cv::imshow("Dilation", h_resultd);
cv::imshow("Opening", h_resulto);
cv::imshow("closing", h_resultc);
cv::imwrite("erosion7.png", h_resulte);
cv::imwrite("dilation7.png", h_resultd);
cv::imwrite("opening7.png", h_resulto);
cv::imwrite("closing7.png", h_resultc);
cv::waitKey();
return 0;
}
chapter 7
Object Detection and Tracking Using OpenCV and CUDA
- Introduction to object detection and tracking
- Object detection and tracking based on color
- Object detection and tracking based on a shape
- Feature-based object detection
- Object detection using Haar cascade
- Background subtraction methods
目标检测与追踪
Object tracking is defined as the task of detecting objects in every frame of the video and establishing the correspondence between the detected objects from one frame to the other.
对象跟踪被定义为在视频的每一帧中检测对象并在检测到的对象之间从一帧到另一帧之间建立对应关系的任务。
基于颜色的目标检测与追踪
当目标颜色和背景色不同的时候,适用该检测方法。
RGB图片不区分颜色信息和强度信息,不适合用与目标检测。通常使用HSV和YCrCb。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main(int argc, char **argv)
{
VideoCapture cap(0); //capture the video from web cam
// if webcam is not available then exit the program
if (!cap.isOpened())
{
cout << "Cannot open the web cam" << endl;
return -1;
}
while (true)
{
Mat frame;
// read a new frame from webcam
bool flag = cap.read(frame);
if (!flag)
{
cout << "Cannot read a frame from webcam" << endl;
break;
}
cuda::GpuMat d_frame, d_frame_hsv, d_intermediate, d_result;
cuda::GpuMat d_frame_shsv[3];
cuda::GpuMat d_thresc[3];
Mat h_result;
d_frame.upload(frame);
//Transform image to HSV
cuda::cvtColor(d_frame, d_frame_hsv, COLOR_BGR2HSV);
//Split HSV 3 channels
cuda::split(d_frame_hsv, d_frame_shsv);
//Threshold HSV channels
cuda::threshold(d_frame_shsv[0], d_thresc[0], 110, 130, THRESH_BINARY);
cuda::threshold(d_frame_shsv[1], d_thresc[1], 50, 255, THRESH_BINARY);
cuda::threshold(d_frame_shsv[2], d_thresc[2], 50, 255, THRESH_BINARY);
//Bitwise AND the channels
cv::cuda::bitwise_and(d_thresc[0], d_thresc[1], d_intermediate);
cv::cuda::bitwise_and(d_intermediate, d_thresc[2], d_result);
d_result.download(h_result);
imshow("Thresholded Image", h_result);
imshow("Original", frame);
if (waitKey(1) == 'q')
{
break;
}
}
return 0;
}
基于形状的检测
可以利用目标的形状,线条,多边形,圆形以及不规则图形等。
Canny边缘检测
利用高通滤波器作为边缘检测的方法。
Canny edge detection algorithm combines Gaussian filtering, gradient finding, non-maximum suppression, and hysteresis thresholding
该算法计算量很大,在要求实时性的应用中难以应用,需要运用cuda进行加速
#include <cmath>
#include <iostream>
#include "opencv2/opencv.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;
}
利用Hough Transform检测直线
#include <cmath>
#include <iostream>
#include "opencv2/opencv.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;
}
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;
}
利用Hough Transform检测圆
#include "opencv2/opencv.hpp"
#include <iostream>
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;
}
The Hough transform is very sensitive to Gaussian and salt-pepper noise. So,
sometimes it is better to preprocess the image with Gaussian and median
filters before applying Hough transform. It will give more accurate results.
关键点检测器和描述子Key-point detectors and descriptors
Features from Accelerated Segment Test (FAST)算法
FAST算法不收图片旋转影响,但受放缩影响。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main()
{
Mat h_image = imread("images/drawing.JPG", 0);
//Detect the keypoints using FAST Detector
cv::Ptr<cv::cuda::FastFeatureDetector> detector = cv::cuda::FastFeatureDetector::create(100, true, 2);
std::vector<cv::KeyPoint> keypoints;
cv::cuda::GpuMat d_image;
d_image.upload(h_image);
detector->detect(d_image, keypoints);
cv::drawKeypoints(h_image, keypoints, h_image);
//Show detected keypoints
imshow("Final Result", h_image);
waitKey(0);
return 0;
}
Oriented FAST and Rotated BRIEF (ORB) 算法
之前接触过ORB-slam2,其关键点检测就是用的这个算法。
ORB算法效率很高,结合了FAST和BRIEF算法,是SURF和SIFT算法的高效替代。
#include <iostream>
#include "opencv2/opencv.hpp"
using namespace cv;
using namespace std;
int main()
{
Mat h_image = imread("images/drawing.JPG", 0);
cv::Ptr<cv::cuda::ORB> detector = cv::cuda::ORB::create();
std::vector<cv::KeyPoint> keypoints;
cv::cuda::GpuMat d_image;
d_image.upload(h_image);
detector->detect(d_image, keypoints);
cv::drawKeypoints(h_image, keypoints, h_image);
imshow("Final Result", h_image);
waitKey(0);
return 0;
}
Speeded up robust feature (SURF) detection and matching
#include <stdio.h>
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/features2d.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"
#include "opencv2/core/cuda.hpp"
#include "opencv2/cudaarithm.hpp"
#include "opencv2/cudafeatures2d.hpp"
#include "opencv2/xfeatures2d/cuda.hpp"
using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;
int main(int argc, char **argv)
{
Mat h_object_image = imread("images/object1.jpg", 0);
Mat h_scene_image = imread("images/scene1.jpg", 0);
cuda::GpuMat d_object_image;
cuda::GpuMat d_scene_image;
cuda::GpuMat d_keypoints_scene, d_keypoints_object;
vector<KeyPoint> h_keypoints_scene, h_keypoints_object;
cuda::GpuMat d_descriptors_scene, d_descriptors_object;
d_object_image.upload(h_object_image);
d_scene_image.upload(h_scene_image);
cuda::SURF_CUDA surf(100);
surf(d_object_image, cuda::GpuMat(), d_keypoints_object, d_descriptors_object);
surf(d_scene_image, cuda::GpuMat(), d_keypoints_scene, d_descriptors_scene);
Ptr<cuda::DescriptorMatcher> matcher = cuda::DescriptorMatcher::createBFMatcher();
vector<vector<DMatch>> d_matches;
matcher->knnMatch(d_descriptors_object, d_descriptors_scene, d_matches, 2);
surf.downloadKeypoints(d_keypoints_scene, h_keypoints_scene);
surf.downloadKeypoints(d_keypoints_object, h_keypoints_object);
std::vector<DMatch> good_matches;
for (int k = 0; k < std::min(h_keypoints_object.size() - 1, d_matches.size()); k++)
{
if ((d_matches[k][0].distance < 0.6 * (d_matches[k][1].distance)) &&
((int)d_matches[k].size() <= 2 && (int)d_matches[k].size() > 0))
{
good_matches.push_back(d_matches[k][0]);
}
}
std::cout << "size:" << good_matches.size();
Mat h_image_result;
drawMatches(h_object_image, h_keypoints_object, h_scene_image, h_keypoints_scene,
good_matches, h_image_result, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::DEFAULT);
std::vector<Point2f> object;
std::vector<Point2f> scene;
for (int i = 0; i < good_matches.size(); i++)
{
object.push_back(h_keypoints_object[good_matches[i].queryIdx].pt);
scene.push_back(h_keypoints_scene[good_matches[i].trainIdx].pt);
}
Mat Homo = findHomography(object, scene, RANSAC);
std::vector<Point2f> corners(4);
std::vector<Point2f> scene_corners(4);
corners[0] = Point(0, 0);
corners[1] = Point(h_object_image.cols, 0);
corners[2] = Point(h_object_image.cols, h_object_image.rows);
corners[3] = Point(0, h_object_image.rows);
perspectiveTransform(corners, scene_corners, Homo);
line(h_image_result, scene_corners[0] + Point2f(h_object_image.cols, 0), scene_corners[1] + Point2f(h_object_image.cols, 0), Scalar(255, 0, 0), 4);
line(h_image_result, scene_corners[1] + Point2f(h_object_image.cols, 0), scene_corners[2] + Point2f(h_object_image.cols, 0), Scalar(255, 0, 0), 4);
line(h_image_result, scene_corners[2] + Point2f(h_object_image.cols, 0), scene_corners[3] + Point2f(h_object_image.cols, 0), Scalar(255, 0, 0), 4);
line(h_image_result, scene_corners[3] + Point2f(h_object_image.cols, 0), scene_corners[0] + Point2f(h_object_image.cols, 0), Scalar(255, 0, 0), 4);
imshow("Good Matches & Object detection", h_image_result);
waitKey(0);
return 0;
}
Haar cascades算法
计算消耗少,速度快。常用于检测人脸、眼睛、车辆等目标。这是一个基于机器学习的算法,需要进行训练,opencv提供了训练好的模型(XML)格式
基于图片的人脸检测
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/cudaobjdetect.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main()
{
Mat h_image;
h_image = imread("images/lena_color_512.tif", 0);
Ptr<cuda::CascadeClassifier> cascade = cuda::CascadeClassifier::create("haarcascade_frontalface_alt2.xml");
cuda::GpuMat d_image;
cuda::GpuMat d_buf;
d_image.upload(h_image);
//cascadeGPU->setMinNeighbors(0);
//cascadeGPU->setScaleFactor(1.01);
cascade->detectMultiScale(d_image, d_buf);
std::vector<Rect> detections;
cascade->convert(d_buf, detections);
if (detections.empty())
std::cout << "No detection." << std::endl;
cvtColor(h_image, h_image, COLOR_GRAY2BGR);
for (int i = 0; i < detections.size(); ++i)
{
rectangle(h_image, detections[i], Scalar(0, 255, 255), 5);
}
imshow("Result image", h_image);
waitKey(0);
return 0;
}
基于camera video的人脸检测
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "Can not open video source";
return -1;
}
std::vector<cv::Rect> h_found;
cv::Ptr<cv::cuda::CascadeClassifier> cascade = cv::cuda::CascadeClassifier::create("haarcascade_frontalface_alt2.xml");
cv::cuda::GpuMat d_frame, d_gray, d_found;
while(1)
{
Mat frame;
if ( !cap.read(frame) ) {
cerr << "Can not read frame from webcam";
return -1;
}
d_frame.upload(frame);
cv::cuda::cvtColor(d_frame, d_gray, cv::COLOR_BGR2GRAY);
cascade->detectMultiScale(d_gray, d_found);
cascade->convert(d_found, h_found);
for(int i = 0; i < h_found.size(); ++i)
{
rectangle(frame, h_found[i], Scalar(0,255,255), 5);
}
imshow("Result", frame);
if (waitKey(1) == 'q') {
break;
}
}
return 0;
}
眼睛检测
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/cudaobjdetect.hpp"
#include <iostream>
#include <stdio.h>
using namespace std;
using namespace cv;
int main()
{
Mat h_image;
h_image = imread("images/lena_color_512.tif", 0);
Ptr<cuda::CascadeClassifier> cascade = cuda::CascadeClassifier::create("haarcascade_eye.xml");
cuda::GpuMat d_image;
cuda::GpuMat d_buf;
d_image.upload(h_image);
//cascadeGPU->setMinNeighbors(0);
//cascadeGPU->setScaleFactor(1.01);
cascade->detectMultiScale(d_image, d_buf);
std::vector<Rect> detections;
cascade->convert(d_buf, detections);
if (detections.empty())
std::cout << "No detection." << std::endl;
cvtColor(h_image, h_image, COLOR_GRAY2BGR);
for (int i = 0; i < detections.size(); ++i)
{
rectangle(h_image, detections[i], Scalar(0, 255, 255), 5);
}
imshow("Result image", h_image);
waitKey(0);
return 0;
}
背景去除
通常需要四步
- 图片处理
- 对背景建模
- 对前景检测
- 判断正确性
Mixture of Gaussian (MoG) method
#include <iostream>
#include <string>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
using namespace cv::cuda;
int main()
{
VideoCapture cap("abc.avi");
if (!cap.isOpened())
{
cerr << "can not open camera or video file" << endl;
return -1;
}
Mat frame;
cap.read(frame);
GpuMat d_frame;
d_frame.upload(frame);
Ptr<BackgroundSubtractor> mog = cuda::createBackgroundSubtractorMOG();
GpuMat d_fgmask, d_fgimage, d_bgimage;
Mat h_fgmask, h_fgimage, h_bgimage;
mog->apply(d_frame, d_fgmask, 0.01);
while (1)
{
cap.read(frame);
if (frame.empty())
break;
d_frame.upload(frame);
int64 start = cv::getTickCount();
mog->apply(d_frame, d_fgmask, 0.01);
mog->getBackgroundImage(d_bgimage);
double fps = cv::getTickFrequency() / (cv::getTickCount() - start);
std::cout << "FPS : " << fps << std::endl;
d_fgimage.create(d_frame.size(), d_frame.type());
d_fgimage.setTo(Scalar::all(0));
d_frame.copyTo(d_fgimage, d_fgmask);
d_fgmask.download(h_fgmask);
d_fgimage.download(h_fgimage);
d_bgimage.download(h_bgimage);
imshow("image", frame);
imshow("foreground mask", h_fgmask);
imshow("foreground image", h_fgimage);
imshow("mean background image", h_bgimage);
if (waitKey(1) == 'q')
break;
}
return 0;
}
GMG for background subtraction
#include <iostream>
#include <string>
#include "opencv2/opencv.hpp"
#include "opencv2/core.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/cudabgsegm.hpp"
#include "opencv2/cudalegacy.hpp"
#include "opencv2/video.hpp"
#include "opencv2/highgui.hpp"
using namespace std;
using namespace cv;
using namespace cv::cuda;
int main()
{
VideoCapture cap("abc.avi");
if (!cap.isOpened())
{
cerr << "can not open video file" << endl;
return -1;
}
Mat frame;
cap.read(frame);
GpuMat d_frame;
d_frame.upload(frame);
Ptr<BackgroundSubtractor> gmg = cuda::createBackgroundSubtractorGMG(40);
GpuMat d_fgmask, d_fgimage, d_bgimage;
Mat h_fgmask, h_fgimage, h_bgimage;
gmg->apply(d_frame, d_fgmask);
while (1)
{
cap.read(frame);
if (frame.empty())
break;
d_frame.upload(frame);
int64 start = cv::getTickCount();
gmg->apply(d_frame, d_fgmask, 0.01);
double fps = cv::getTickFrequency() / (cv::getTickCount() - start);
std::cout << "FPS : " << fps << std::endl;
d_fgimage.create(d_frame.size(), d_frame.type());
d_fgimage.setTo(Scalar::all(0));
d_frame.copyTo(d_fgimage, d_fgmask);
d_fgmask.download(h_fgmask);
d_fgimage.download(h_fgimage);
imshow("image", frame);
imshow("foreground mask", h_fgmask);
imshow("foreground image", h_fgimage);
if (waitKey(30) == 'q')
break;
}
return 0;
}