上一篇OpenCV-C++—CUDA-06-形态学二值化操作展示了二值图像、形态学在OpenCV-CUDA版本上的示例。本章我使用HSV颜色提取,以及形态学操作、联通区域来跟踪物体(跟踪下面偏黄色的小球)。
先给一张inRange颜色过滤表:
黑 | 灰 | 白 | 红 | 橙 | 黄 | 绿 | 青 | 蓝 | 紫 | |
---|---|---|---|---|---|---|---|---|---|---|
hmin | 0 | 0 | 0 | 0,156 | 11 | 26 | 35 | 78 | 100 | 125 |
hmax | 180 | 180 | 180 | 10 ,180 | 25 | 34 | 77 | 99 | 124 | 155 |
smin | 0 | 0 | 0 | 43 | 43 | 43 | 43 | 43 | 43 | 43 |
smax | 255 | 43 | 30 | 255 | 255 | 255 | 255 | 255 | 255 | 255 |
vmin | 0 | 46 | 221 | 46 | 46 | 46 | 46 | 46 | 46 | 46 |
vmax | 46 | 220 | 255 | 255 | 255 | 255 | 255 | 255 | 255 | 255 |
大致步骤是:
1)BGR转HSV;
2)通道分离;
3)根据颜色表求出h、s、v阈值;
4)求出h、s、v交集;
5)形态学去噪点(先开后闭操作/膨胀);
6)联通组件分析定位。
相关代码:
#include<opencv2/opencv.hpp>
#include<opencv2/cudaimgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc, char ** argv)
{
VideoCapture cap(0);
cap.open("F:\\test\\images_jia\\balltest.mp4");
Mat frame,result,dst;
cuda::GpuMat frame_gpu,hsv,mask;
vector<cuda::GpuMat>mv;
vector<cuda::GpuMat>thres(4);
while (true)
{
bool ret=cap.read(frame);
if (!ret)
{
break;
}
//imshow("input video", frame);
double t1 = getTickCount();
frame_gpu.upload(frame);
cuda::cvtColor(frame_gpu, hsv,COLOR_BGR2HSV);//BGR->HSV
//通道分离(cuda版本没有inRange()方法)
cuda::split(hsv, mv);
/*黄色26-34的h通道就被提取出来了*/
cuda::threshold(mv[0], thres[0], 26, 255, THRESH_BINARY);
cuda::threshold(mv[0], thres[3], 34, 255, THRESH_BINARY);
//============
cuda::threshold(mv[1], thres[1], 43, 255, THRESH_BINARY);
cuda::threshold(mv[2], thres[2], 46, 255, THRESH_BINARY);
cuda::bitwise_xor(thres[0], thres[3],thres[0]);//异或
//求它们三个的交集
cuda::bitwise_and(thres[1], thres[0], mask);
cuda::bitwise_and(mask, thres[2], mask);
//cuda::threshold(mask, mask, 100, 255, THRESH_BINARY);
//形态学操作
Mat se_open = cv::getStructuringElement(MORPH_RECT, Size(5, 5));
Mat se_close = cv::getStructuringElement(MORPH_RECT, Size(11,11));
auto morpy_open=cuda::createMorphologyFilter(MORPH_OPEN, mask.type(), se_open);//开操作
morpy_open->apply(mask, mask);
auto morpy_close = cuda::createMorphologyFilter(MORPH_CLOSE, mask.type(), se_close);//闭操作
morpy_close->apply(mask, mask);
//膨胀
//auto dilate=cuda::createMorphologyFilter(MORPH_DILATE, mask.type(), se_close);//膨胀
//dilate->apply(mask, mask);
mask.download(result);
//联通组件分析
Mat labels = Mat::zeros(mask.size(), CV_32S);
Mat stats, centroids; //状态、中心
int num_labels = cv::connectedComponentsWithStats(result, labels, stats, centroids, 4, 4);
for (int i = 1; i < num_labels; i++) //i=0时,是背景
{
//中心点坐标
int cx = centroids.at<double>(i, 0);
int cy = centroids.at<double>(i, 1);
//从状态里获取矩形坐标
int x = stats.at<int>(i, CC_STAT_LEFT);
int y = stats.at<int>(i, CC_STAT_TOP);
int width = stats.at<int>(i, CC_STAT_WIDTH);
int height = stats.at<int>(i, CC_STAT_HEIGHT);
if (width < 40 || height < 40) //过滤面积小的区域
{
continue;
}
circle(frame, Point(cx, cy), 3, Scalar(0, 0, 255), 2, 8, 0);
rectangle(frame, Point(x, y), Point(x + width, y + height), Scalar(0, 255, 0), 2, 8, 0);
}
double fps = getTickFrequency() / (getTickCount() - t1);
putText(frame, format("FPS:%.2f", fps), Point(50, 50), FONT_HERSHEY_PLAIN, 1.5, Scalar(0, 0, 255), 2, 8);
imshow("input video", frame);
imshow("result", result);
char c = waitKey(10);
if (c == 27)
{
break;
}
}
cv::destroyAllWindows();
return 0;
}
结果: