Table of Contents
Prev Tutorial: Basic Thresholding Operations
Next Tutorial: Making your own linear filters!
Original author | Lorena GarcĂa |
Compatibility | Rishiraj Surti |
Goal
In this tutorial you will learn how to:
- Perform basic thresholding operations using OpenCV cv::inRange function.
- Detect an object based on the range of pixel values in the HSV colorspace.
Theory
- In the previous tutorial, we learnt how to perform thresholding using cv::threshold function.
- In this tutorial, we will learn how to do it using cv::inRange function.
- The concept remains the same, but now we add a range of pixel values we need.
HSV colorspace
HSV (hue, saturation, value) colorspace is a model to represent the colorspace similar to the RGB color model. Since the hue channel models the color type, it is very useful in image processing tasks that need to segment objects based on its color. Variation of the saturation goes from unsaturated to represent shades of gray and fully saturated (no white component). Value channel describes the brightness or the intensity of the color. Next image shows the HSV cylinder.

Since colors in the RGB colorspace are coded using the three channels, it is more difficult to segment an object in the image based on its color.

Formulas used to convert from one colorspace to another colorspace using cv::cvtColor function are described in Color conversions
Code
The tutorial code's is shown lines below. You can also download it from here
The tutorial code's is shown lines below. You can also download it from here
The tutorial code's is shown lines below. You can also download it from here
Explanation
Let's check the general structure of the program:
Capture the video stream from default or supplied capturing device.
C++VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);Javacap = new VideoCapture(cameraDevice);Pythoncap = cv.VideoCapture(args.camera)Create a window to display the default frame and the threshold frame.
C++namedWindow(window_capture_name);namedWindow(window_detection_name);Java// Create and set up the window.frame = new JFrame(WINDOW_NAME);frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);frame.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent windowEvent) {captureTask.cancel(true);}});// Set up the content pane.Image img = HighGui.toBufferedImage(matFrame);addComponentsToPane(frame.getContentPane(), img);// Use the content pane's default BorderLayout. No need for// setLayout(new BorderLayout());// Display the window.frame.pack();frame.setVisible(true);Pythoncv.namedWindow(window_capture_name)cv.namedWindow(window_detection_name)Create the trackbars to set the range of HSV values
C++// Trackbars to set thresholds for HSV valuescreateTrackbar("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);JavasliderPanel.add(new JLabel(LOW_H_NAME));sliderLowH = new JSlider(0, MAX_VALUE_H, 0);sliderLowH.setMajorTickSpacing(50);sliderLowH.setMinorTickSpacing(10);sliderLowH.setPaintTicks(true);sliderLowH.setPaintLabels(true);sliderPanel.add(sliderLowH);sliderPanel.add(new JLabel(HIGH_H_NAME));sliderHighH = new JSlider(0, MAX_VALUE_H, MAX_VALUE_H);sliderHighH.setMajorTickSpacing(50);sliderHighH.setMinorTickSpacing(10);sliderHighH.setPaintTicks(true);sliderHighH.setPaintLabels(true);sliderPanel.add(sliderHighH);sliderPanel.add(new JLabel(LOW_S_NAME));sliderLowS = new JSlider(0, MAX_VALUE, 0);sliderLowS.setMajorTickSpacing(50);sliderLowS.setMinorTickSpacing(10);sliderLowS.setPaintTicks(true);sliderLowS.setPaintLabels(true);sliderPanel.add(sliderLowS);sliderPanel.add(new JLabel(HIGH_S_NAME));sliderHighS = new JSlider(0, MAX_VALUE, MAX_VALUE);sliderHighS.setMajorTickSpacing(50);sliderHighS.setMinorTickSpacing(10);sliderHighS.setPaintTicks(true);sliderHighS.setPaintLabels(true);sliderPanel.add(sliderHighS);sliderPanel.add(new JLabel(LOW_V_NAME));sliderLowV = new JSlider(0, MAX_VALUE, 0);sliderLowV.setMajorTickSpacing(50);sliderLowV.setMinorTickSpacing(10);sliderLowV.setPaintTicks(true);sliderLowV.setPaintLabels(true);sliderPanel.add(sliderLowV);sliderPanel.add(new JLabel(HIGH_V_NAME));sliderHighV = new JSlider(0, MAX_VALUE, MAX_VALUE);sliderHighV.setMajorTickSpacing(50);sliderHighV.setMinorTickSpacing(10);sliderHighV.setPaintTicks(true);sliderHighV.setPaintLabels(true);sliderPanel.add(sliderHighV);Pythoncv.createTrackbar(low_H_name, window_detection_name , low_H, max_value_H, on_low_H_thresh_trackbar)cv.createTrackbar(high_H_name, window_detection_name , high_H, max_value_H, on_high_H_thresh_trackbar)cv.createTrackbar(low_S_name, window_detection_name , low_S, max_value, on_low_S_thresh_trackbar)cv.createTrackbar(high_S_name, window_detection_name , high_S, max_value, on_high_S_thresh_trackbar)cv.createTrackbar(low_V_name, window_detection_name , low_V, max_value, on_low_V_thresh_trackbar)cv.createTrackbar(high_V_name, window_detection_name , high_V, max_value, on_high_V_thresh_trackbar)Until the user want the program to exit do the following
C++Javaprivate class CaptureTask extends SwingWorker<Void, Mat> {@Overrideprotected Void doInBackground() {Mat matFrame = new Mat();while (!isCancelled()) {if (!cap.read(matFrame)) {break;}publish(matFrame.clone());}return null;}@Overrideprotected void process(List<Mat> frames) {Mat frame = frames.get(frames.size() - 1);Mat frameHSV = new Mat();Imgproc.cvtColor(frame, frameHSV, Imgproc.COLOR_BGR2HSV);Mat thresh = new Mat();Core.inRange(frameHSV, new Scalar(sliderLowH.getValue(), sliderLowS.getValue(), sliderLowV.getValue()),new Scalar(sliderHighH.getValue(), sliderHighS.getValue(), sliderHighV.getValue()), thresh);update(frame, thresh);}}Pythonret, frame = cap.read()if frame is None:breakframe_HSV = cv.cvtColor(frame, cv.COLOR_BGR2HSV)frame_threshold = cv.inRange(frame_HSV, (low_H, low_S, low_V), (high_H, high_S, high_V))Show the images
C++// Show the framesimshow(window_capture_name, frame);imshow(window_detection_name, frame_threshold);JavaimgCaptureLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgCapture)));imgDetectionLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgThresh)));frame.repaint();PythonFor a trackbar which controls the lower range, say for example hue value:
C++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);}JavasliderLowH.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {JSlider source = (JSlider) e.getSource();int valH = Math.min(sliderHighH.getValue()-1, source.getValue());sliderLowH.setValue(valH);}});Pythondef on_low_H_thresh_trackbar(val):global low_Hglobal high_Hlow_H = vallow_H = min(high_H-1, low_H)cv.setTrackbarPos(low_H_name, window_detection_name, low_H)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);}For a trackbar which controls the upper range, say for example hue value:
C++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);}JavasliderHighH.addChangeListener(new ChangeListener() {@Overridepublic void stateChanged(ChangeEvent e) {JSlider source = (JSlider) e.getSource();int valH = Math.max(source.getValue(), sliderLowH.getValue()+1);sliderHighH.setValue(valH);}});Pythondef on_high_H_thresh_trackbar(val):global low_Hglobal high_Hhigh_H = valhigh_H = max(high_H, low_H+1)cv.setTrackbarPos(high_H_name, window_detection_name, high_H)- It is necessary to find the maximum and minimum value to avoid discrepancies such as the high value of threshold becoming less than the low value.
Results
- After compiling this program, run it. The program will open two windows
- As you set the range values from the trackbar, the resulting frame will be visible in the other window.