本节使用inRange函数来实现阈值化。跟前面的阈值化方法一样,只不过在实现时用阈值范围来替代固定阈值。
本节还提供了一种物体检测的手段,用基于像素值范围的方法,在HSV色彩空间检测物体。
HSV色彩空间
HSV(hue,saturation,value的首字母,分别表示颜色的色相、饱和度、强度)色彩空间是一种类似于RGB的颜色表示方式。hue通道是颜色类型,在需要根据颜色来分割物体的应用中,非常有效。saturation 的变化从不饱和到完全饱和,对应下图中灰色过度到阴影(没有白色成分)。Value描述了颜色的强度或者说亮度。下面是HSV圆柱体,表示HSV的颜色空间。
HSV色彩空间By SharkDderivative work: SharkD [CC BY-SA 3.0 or GFDL], via Wikimedia Commons
由于RGB色彩空间是由三个来编码颜色,所以难以根据颜色来分割物体。
RGB色彩空间By SharkD [GFDL or CC BY-SA 4.0], from Wikimedia Commons
颜色空间的转换可使用cvtColor函数。
代码
// @tutorials imgproc module 10
// @文件 Threshold_inRange.cpp
// @主题 HSV图像的阈值分割,检测目标
// @修改 CVer
// @日期 2019年12月27日
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/videoio.hpp"
#include <iostream>
using namespace cv;
const int max_value_H = 360/2;
const int max_value = 255;
const String window_capture_name = "Video Capture";
const String window_detection_name = "Object Detection";
int low_H = 0, low_S = 0, low_V = 0;
int high_H = max_value_H, high_S = max_value, high_V = max_value;
//下面6个函数分别设置HSV三个通道分量的范围,每个通道最低值和最高值
static void on_low_H_thresh_trackbar(int, void *)
{
low_H = min(high_H-1, low_H);
setTrackbarPos("Low H", window_detection_name, low_H);
}
static void on_high_H_thresh_trackbar(int, void *)
{
high_H = max(high_H, low_H+1);
setTrackbarPos("High H", window_detection_name, high_H);
}
static void on_low_S_thresh_trackbar(int, void *)
{
low_S = min(high_S-1, low_S);
setTrackbarPos("Low S", window_detection_name, low_S);
}
static void on_high_S_thresh_trackbar(int, void *)
{
high_S = max(high_S, low_S+1);
setTrackbarPos("High S", window_detection_name, high_S);
}
static void on_low_V_thresh_trackbar(int, void *)
{
low_V = min(high_V-1, low_V);
setTrackbarPos("Low V", window_detection_name, low_V);
}
static void on_high_V_thresh_trackbar(int, void *)
{
high_V = max(high_V, low_V+1);
setTrackbarPos("High V", window_detection_name, high_V);
}
int main(int argc, char* argv[])
{//这里可以选择打开视频文件或者摄像头
String videofile = samples::findFile("D:/opencv/sources/doc/js_tutorials/js_assets/cup.mp4");
VideoCapture cap(videofile);//打开视频文件
//VideoCapture cap(0);//打开摄像头
namedWindow(window_capture_name);
namedWindow(window_detection_name);
//Trackbar分别设置HSV三个分量大小
createTrackbar("Low H", window_detection_name, &low_H, max_value_H, on_low_H_thresh_trackbar);
createTrackbar("High H", window_detection_name, &high_H, max_value_H, on_high_H_thresh_trackbar);
createTrackbar("Low S", window_detection_name, &low_S, max_value, on_low_S_thresh_trackbar);
createTrackbar("High S", window_detection_name, &high_S, max_value, on_high_S_thresh_trackbar);
createTrackbar("Low V", window_detection_name, &low_V, max_value, on_low_V_thresh_trackbar);
createTrackbar("High V", window_detection_name, &high_V, max_value, on_high_V_thresh_trackbar);
Mat frame, frame_HSV, frame_threshold;
while (true)
{//获取图像帧
cap >> frame;
if(frame.empty())
{
break;
}
// BGR转换到HSV色彩空间
cvtColor(frame, frame_HSV, COLOR_BGR2HSV);
// 根据HSV设置的范围,检测目标
inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);
// 显示分割结果
imshow(window_capture_name, frame);
imshow(window_detection_name, frame_threshold);
//按q或esc退出
char key = (char) waitKey(30);
if (key == 'q' || key == 27)
{
break;
}
}
return 0;
}
结果
程序运行后,通过trackbar分别设置HSV像素范围,截取部分处理结果如下图。可以看到设置不同的值,可以得到不同的分割效果。
分割得到手和手臂
分割得到杯子和手臂