本節使用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像素範圍,截取部分處理結果如下圖。可以看到設定不同的值,可以得到不同的分割效果。
分割得到手和手臂
分割得到杯子和手臂