OpenCV4.3 Java 编程入门: HighGUI 窗口中使用滑块

1 opencv_highgui

滑块 (TrackBar)是 OpenCV 动态调参时常用的便捷工具,它依附于窗口而存在。

opencv 提供了支持添加窗口组件的方法,这些方法都在 cv 命名空间下,对应在 Java 项目中的 org.bytedeco.opencv.global.opencv_highgui 类中。
在这里插入图片描述
该类中,封装了很多 cv 命名空间中的静态方法:

在这里插入图片描述

2 添加滑块:使用 createTrackbar 方法

使用 btyedeco opencv 项目中提供的 createTrackbar() 方法:

在这里插入图片描述
代码:

import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.javacpp.Loader;
import org.bytedeco.javacpp.Pointer;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.global.opencv_highgui;
import org.bytedeco.opencv.global.opencv_imgcodecs;
import org.bytedeco.opencv.opencv_core.Mat;
import org.bytedeco.opencv.opencv_highgui.TrackbarCallback;
import org.junit.Test;

import static org.bytedeco.opencv.global.opencv_core.CV_8UC4;

public class TrackBarTest {
    static {
        Loader.load(org.bytedeco.opencv.opencv_java.class);
    }

    private String WINDOW_NAME = "trackbar";
    private IntPointer alphaVal = new IntPointer(70);
    private int position = 0;
    private Mat matImg;
    private Mat dst = new Mat();

    @Test
    public void trackTest() throws Throwable{
        matImg = opencv_imgcodecs.imread("./images/longmao.jpeg", CV_8UC4);
        matImg.convertTo(dst, CV_8UC4, 1, 0);

        opencv_highgui.namedWindow(WINDOW_NAME);
        opencv_highgui.createTrackbar("tracker", WINDOW_NAME, alphaVal, 100, new TrackbarCallback() {
            @Override
            public void call(int pos, Pointer userdata) {
                if (pos != position) {
                    position = pos;
                    double alpha = pos/100.0;
                    matImg.convertTo(dst, CV_8UC4, alpha, 0);
                    opencv_highgui.imshow(WINDOW_NAME, dst);
                }
            }
        }, null);

        opencv_highgui.imshow(WINDOW_NAME, dst);
        opencv_highgui.waitKey();
    }
}

createTrackbar 函数用于创建一个可以调整整数值的滑动条,并将滑动条附加到指定的窗口上,使用起来很方便。它一般会和一个回调函数配合使用。

函数原型:

public static native int createTrackbar(@Str String trackbarname, @Str String winname,
                              IntPointer value, int count,
                              TrackbarCallback onChange/*=0*/,
                              Pointer userdata/*=0*/);
  • 参数1: 滑动条名称
  • 参数2:目标窗口的名称
  • 参数3: 一个指向整数的指针,表示滑块的位置,在创建时,滑块的初始位置就是该变量的当前值;
  • 参数4:整数值,表示滑块可达的最大值。滑块最小值为0。
  • 参数5:滑块变动时的回调函数;
  • 参数6:自定义数据;

3 添加滑块:使用 JFrame

使用 org.bytedeco.opencv 中的功能,需要了解 javaCpp 的机制,了解 Pointer 等相关的数据结构和操作。当然,如果不使用 bytedeco 功能,仅使用 org.opencv 模块中的功能,通过 JFrame 也可以实现界面操作。


import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
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.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.bytedeco.javacpp.Loader;
import org.junit.Assert;
import org.junit.Test;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;

public class TrackerTest {
    static {
        Loader.load(org.bytedeco.opencv.opencv_java.class);
    }

    private static final int ALPHA_SLIDER_MAX = 100;
    private int alphaVal = 0;
    private Mat matImgSrc1;
    private Mat matImgSrc2;
    private Mat matImgDst = new Mat();
    private JFrame frame;
    private JLabel imgLabel;

    private void addComponentsToPane(Container container, Image img) {
        // 必须为 BorderLayout 布局
        Assert.assertTrue(container.getLayout() instanceof BorderLayout);

        // 新建看板: slider 滑块看板
        JPanel sliderPanel = new JPanel();
        sliderPanel.setLayout(new BoxLayout(sliderPanel, BoxLayout.PAGE_AXIS));
        sliderPanel.add(new JLabel(String.format("Alpha x %d", ALPHA_SLIDER_MAX)));

        // 新增组件:slider 滑块组件
        JSlider slider = new JSlider(0, ALPHA_SLIDER_MAX, 0);
        slider.setMajorTickSpacing(20);
        slider.setMinorTickSpacing(5);
        slider.setPaintTicks(true);
        slider.setPaintLabels(true);

        // 添加监听事件
        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                alphaVal = source.getValue();

                // 更新状态,并重新渲染窗口内容
                double alpha = alphaVal / (double) ALPHA_SLIDER_MAX;
                double beta = 1.0 - alpha;

                // 两张图片,加权融合
                Core.addWeighted(matImgSrc1, alpha, matImgSrc2, beta, 0, matImgDst);
                Image img = HighGui.toBufferedImage(matImgDst);
                imgLabel.setIcon(new ImageIcon(img));
                frame.repaint();
            }
        });

        sliderPanel.add(slider);
        container.add(sliderPanel, BorderLayout.PAGE_START);
        imgLabel = new JLabel(new ImageIcon(img));
        container.add(imgLabel, BorderLayout.CENTER);
    }

    @Test
    public void showTest() throws Throwable{
        String imagePath1 = "./images/longmao.jpeg";
        String imagePath2 = "./images/longmao.jpeg";

        matImgSrc1 = Imgcodecs.imread(imagePath1).submat(new Rect(0, 0, 500, 500));
        matImgSrc2 = Imgcodecs.imread(imagePath2).submat(new Rect(500, 200, 500, 500));

        Assert.assertNotNull(matImgSrc1);
        Assert.assertNotNull(matImgSrc2);

        // 创建窗口
        frame = new JFrame("trackbar");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 将图片添加至窗口
        Image img = HighGui.toBufferedImage(matImgSrc2);
        addComponentsToPane(frame.getContentPane(), img);
        frame.pack();
        frame.setVisible(true); // 显示窗口

        while (frame.isValid()) {
            Thread.sleep(10000);
        }
    }
}

这里主要是使用 HighGui.toBufferedImage() 方法,将 Mat 类型的图像,转换为 Image 类型,然后在 JFrame 中显示。

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值