图像处理:基础——使用 inRange 进行阈值化操作 OpenCV v4.8.0

上一个教程基本阈值处理操作

下一个教程制作自己的线性滤波器

原作者Lorena García
兼容性Rishiraj Surti

目标

在本教程中,您将学习如何

  • 使用 OpenCV cv::inRange 函数执行基本的阈值处理操作。
  • 根据 HSV 色彩空间中的像素值范围检测物体。

理论知识

  • 在上一教程中,我们学习了如何使用 cv::threshold 函数执行阈值处理。
  • 在本教程中,我们将学习如何使用 cv::inRange 函数执行阈值处理。
  • 概念保持不变,但现在我们要添加所需的像素值范围。

HSV 色彩空间

HSV(色相、饱和度、值)色彩空间是一种表示色彩空间的模型,类似于 RGB 色彩模型。由于色调通道是颜色类型的模型,因此在需要根据颜色分割对象的图像处理任务中非常有用。饱和度的变化范围从不饱和到代表灰色阴影,再到完全饱和(无白色成分)。值通道描述颜色的亮度或强度。下一张图片显示的是 HSV 柱状图。

在这里插入图片描述

由 SharkDderivative 制作: SharkD [CC BY-SA 3.0 or GFDL], via Wikimedia Commons
由于 RGB 色彩空间中的颜色是使用三个通道编码的,因此根据颜色分割图像中的物体会更加困难。

在这里插入图片描述

由 SharkD [GFDL 或 CC BY-SA 4.0] 提供,取自维基共享资源使用

cv::cvtColor 函数从一个色彩空间转换到另一个色彩空间所用的公式在**色彩转换**中进行了描述

代码

C++

教程代码如下所示。您也可以从此处下载

#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;
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[])
{
 VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);
 namedWindow(window_capture_name);
 namedWindow(window_detection_name);
 // 设置 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);
 char key = (char) waitKey(30);
 if (key == 'q' || key == 27)
 {
 break;
 }
 }
 return 0;
}

Java

教程代码如下所示。您也可以从此处下载

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingWorker;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;
import org.opencv.videoio.VideoCapture;
public class ThresholdInRange {
 private static int MAX_VALUE = 255;
 private static int MAX_VALUE_H = 360/2;
 private static final String WINDOW_NAME = "Thresholding Operations using inRange demo";
 private static final String LOW_H_NAME = "Low H";
 private static final String LOW_S_NAME = "Low S";
 private static final String LOW_V_NAME = "Low V";
 private static final String HIGH_H_NAME = "High H";
 private static final String HIGH_S_NAME = "High S";
 private static final String HIGH_V_NAME = "High V";
 private JSlider sliderLowH;
 private JSlider sliderHighH;
 private JSlider sliderLowS;
 private JSlider sliderHighS;
 private JSlider sliderLowV;
 private JSlider sliderHighV;
 private VideoCapture cap;
 private Mat matFrame = new Mat();
 private JFrame frame;
 private JLabel imgCaptureLabel;
 private JLabel imgDetectionLabel;
 private CaptureTask captureTask;
 public ThresholdInRange(String[] args) {
 int cameraDevice = 0;
 if (args.length > 0) {
 cameraDevice = Integer.parseInt(args[0]);
 }
 cap = new VideoCapture(cameraDevice);
 if (!cap.isOpened()) {
 System.err.println("Cannot open camera: " + cameraDevice);
 System.exit(0);
 }
 if (!cap.read(matFrame)) {
 System.err.println("Cannot read camera stream.");
 System.exit(0);
 }
 // 创建并设置窗口。
 frame = new JFrame(WINDOW_NAME);
 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 frame.addWindowListener(new WindowAdapter() {
 @Override
 public void windowClosing(WindowEvent windowEvent) {
 captureTask.cancel(true);
 }
 });
 // 设置内容窗格。
 Image img = HighGui.toBufferedImage(matFrame);
 addComponentsToPane(frame.getContentPane(), img);
 // 使用内容窗格的默认边框布局。无需
 // setLayout(new BorderLayout());
 // 显示窗口。
 frame.pack();
 frame.setVisible(true);
 captureTask = new CaptureTask();
 captureTask.execute();
 }
 private class CaptureTask extends SwingWorker<Void, Mat> {
 @Override
 protected Void doInBackground() {
 Mat matFrame = new Mat();
 while (!isCancelled()) {
 if (!cap.read(matFrame)) {
 break;
 }
 publish(matFrame.clone());
 }
 return null;
 }
 @Override
 protected 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);
 }
 }
 private void addComponentsToPane(Container pane, Image img) {
 if (!(pane.getLayout() instanceof BorderLayout)) {
 pane.add(new JLabel("Container doesn't use BorderLayout!"));
 return;
 }
 JPanel sliderPanel = new JPanel();
 sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
 sliderPanel.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);
 sliderLowH.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valH = Math.min(sliderHighH.getValue()-1, source.getValue());
 sliderLowH.setValue(valH);
 }
 });
 sliderHighH.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valH = Math.max(source.getValue(), sliderLowH.getValue()+1);
 sliderHighH.setValue(valH);
 }
 });
 sliderLowS.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valS = Math.min(sliderHighS.getValue()-1, source.getValue());
 sliderLowS.setValue(valS);
 }
 });
 sliderHighS.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valS = Math.max(source.getValue(), sliderLowS.getValue()+1);
 sliderHighS.setValue(valS);
 }
 });
 sliderLowV.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valV = Math.min(sliderHighV.getValue()-1, source.getValue());
 sliderLowV.setValue(valV);
 }
 });
 sliderHighV.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valV = Math.max(source.getValue(), sliderLowV.getValue()+1);
 sliderHighV.setValue(valV);
 }
 });
 pane.add(sliderPanel, BorderLayout.PAGE_START);
 JPanel framePanel = new JPanel();
 imgCaptureLabel = new JLabel(new ImageIcon(img));
 framePanel.add(imgCaptureLabel);
 imgDetectionLabel = new JLabel(new ImageIcon(img));
 framePanel.add(imgDetectionLabel);
 pane.add(framePanel, BorderLayout.CENTER);
 }
 private void update(Mat imgCapture, Mat imgThresh) {
 imgCaptureLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgCapture)));
 imgDetectionLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgThresh)));
 frame.repaint();
 }
 public static void main(String[] args) {
 // 加载本地 OpenCV 库
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME)// 为事件派发线程安排任务:
 // 创建并显示此应用程序的图形用户界面。
 javax.swing.SwingUtilities.invokeLater(new Runnable() {
 @Override
 public void run() {
 new ThresholdInRange(args);
 }
 });
 }
}

Python

教程代码如下所示。您也可以从此处下载

from __future__ import print_function
import cv2 as cv
import argparse
max_value = 255
max_value_H = 360//2
low_H = 0
low_S = 0
low_V = 0
high_H = max_value_H
high_S = max_value
high_V = max_value
window_capture_name = 'Video Capture'
window_detection_name = 'Object Detection'
low_H_name = 'Low H'
low_S_name = 'Low S'
low_V_name = 'Low V'
high_H_name = 'High H'
high_S_name = 'High S'
high_V_name = 'High V'
def on_low_H_thresh_trackbar(val):
 global low_H
 global high_H
 low_H = val
 low_H = min(high_H-1, low_H)
 cv.setTrackbarPos(low_H_name, window_detection_name, low_H)
def on_high_H_thresh_trackbar(val):
 global low_H
 global high_H
 high_H = val
 high_H = max(high_H, low_H+1)
 cv.setTrackbarPos(high_H_name, window_detection_name, high_H)
def on_low_S_thresh_trackbar(val):
 global low_S
 global high_S
 low_S = val
 low_S = min(high_S-1, low_S)
 cv.setTrackbarPos(low_S_name, window_detection_name, low_S)
def on_high_S_thresh_trackbar(val):
 global low_S
 global high_S
 high_S = val
 high_S = max(high_S, low_S+1)
 cv.setTrackbarPos(high_S_name, window_detection_name, high_S)
def on_low_V_thresh_trackbar(val):
 global low_V
 global high_V
 low_V = val
 low_V = min(high_V-1, low_V)
 cv.setTrackbarPos(low_V_name, window_detection_name, low_V)
def on_high_V_thresh_trackbar(val):
 global low_V
 global high_V
 high_V = val
 high_V = max(high_V, low_V+1)
 cv.setTrackbarPos(high_V_name, window_detection_name, high_V)
parser = argparse.ArgumentParser(description='Code for Thresholding Operations using inRange tutorial.')
parser.add_argument('--camera', help='Camera divide number.', default=0, type=int)
args = parser.parse_args()
cap = cv.VideoCapture(args.camera)
cv.namedWindow(window_capture_name)
cv.namedWindow(window_detection_name)
cv.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)
while True:
 
 ret, frame = cap.read()
 if frame is None:
 break
 frame_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))
 
 
 cv.imshow(window_capture_name, frame)
 cv.imshow(window_detection_name, frame_threshold)
 
 key = cv.waitKey(30)
 if key == ord('q') or key == 27:
 break

说明

让我们来看看程序的总体结构:

  • 从默认或提供的捕捉设备捕捉视频流。
    C++
 VideoCapture cap(argc > 1 ? atoi(argv[1]) : 0);

Java

 cap = new VideoCapture(cameraDevice);

Python

cap = cv.VideoCapture(args.camera)
  • 创建一个窗口,显示默认帧和阈值帧。
    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() {
 @Override
 public 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);

Python

cv.namedWindow(window_capture_name)
cv.namedWindow(window_detection_name)
  • 创建轨迹条以设置 HSV 值范围
    C++
 // Trackbars to set thresholds for HSV values
 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);

Java

 sliderPanel.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);

Python

cv.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)
  • 在用户希望程序退出之前,执行以下操作
    C++
 cap >> frame;
 if(frame.empty())
 {
 break;
 }
 // Convert from BGR to HSV colorspace
 cvtColor(frame, frame_HSV, COLOR_BGR2HSV);
 // Detect the object based on HSV Range Values
 inRange(frame_HSV, Scalar(low_H, low_S, low_V), Scalar(high_H, high_S, high_V), frame_threshold);

Java

 private class CaptureTask extends SwingWorker<Void, Mat> {
 @Override
 protected Void doInBackground() {
 Mat matFrame = new Mat();
 while (!isCancelled()) {
 if (!cap.read(matFrame)) {
 break;
 }
 publish(matFrame.clone());
 }
 return null;
 }
 @Override
 protected 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);
 }
 }

Python

 ret, frame = cap.read()
 if frame is None:
 break
 frame_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))
  • 显示图像
    C++
 // Show the frames
 imshow(window_capture_name, frame);
 imshow(window_detection_name, frame_threshold);

Java

 imgCaptureLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgCapture)));
 imgDetectionLabel.setIcon(new ImageIcon(HighGui.toBufferedImage(imgThresh)));
 frame.repaint();

Python

 cv.imshow(window_capture_name, frame)
 cv.imshow(window_detection_name, frame_threshold)
  • 对于控制较低范围的轨迹条,例如色调值:
    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);
}
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);
}

Java

 sliderLowH.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valH = Math.min(sliderHighH.getValue()-1, source.getValue());
 sliderLowH.setValue(valH);
 }
 });
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);
}

Python

def on_low_H_thresh_trackbar(val):
 global low_H
 global high_H
 low_H = val
 low_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);
}
  • 对于控制上限范围的轨迹条,例如色调值:
    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);
}

Java

 sliderHighH.addChangeListener(new ChangeListener() {
 @Override
 public void stateChanged(ChangeEvent e) {
 JSlider source = (JSlider) e.getSource();
 int valH = Math.max(source.getValue(), sliderLowH.getValue()+1);
 sliderHighH.setValue(valH);
 }
 });

Python

def on_high_H_thresh_trackbar(val):
 global low_H
 global high_H
 high_H = val
 high_H = max(high_H, low_H+1)
 cv.setTrackbarPos(high_H_name, window_detection_name, high_H)
  • 有必要找到最大值和最小值,以避免阈值的高值小于低值等差异。

运行结果

  • 编译此程序后,运行它。程序将打开两个窗口
  • 当您在轨迹栏上设置范围值时,在另一个窗口中将看到结果帧。

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值