龙空技术网

使用OpenCV Java创建Windows摄像头扫码程序

yushulx 161

前言:

目前朋友们对“opencv430安装教程”大概比较注重,咱们都需要分析一些“opencv430安装教程”的相关知识。那么小编在网上收集了一些对于“opencv430安装教程””的相关资讯,希望小伙伴们能喜欢,看官们一起来学习一下吧!

OpenCV提供了一些基本的Webcam控制接口。用OpenCV C/C++或者Python,可以在任意平台快速创建一个摄像头预览应用。然而使用Java,情况就复杂的多,因为OpenCV Java并没有提供一个类似于imshow的窗口显示接口。想要创建一个带界面的应用,就需要通过OpenCV接口获取数据,并转换成对应的格式,然后通过Java的UI组件显示出来。

OpenCV Java安装

在OpenCV官网下载最新的Windows安装包()。

安装后找到目录opencv-4.3\opencv\build\java。

如果用Eclipse,可以直接导入工程。如果用Maven,需要先安装到Maven的本地仓库:

mvn install:install-file -Dfile=opencv-430.jar -DgroupId=org -DartifactId=opencv -Dversion=4.3.0 -Dpackaging=jar

然后在pom.xml文件里添加依赖:

<dependency>  <groupId>org</groupId>  <artifactId>opencv</artifactId>  <version>4.3.0</version></dependency>

还有一个问题就是dll文件怎么加载。如果找不到,会看到错误信息:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no opencv_java430 in java.library.path        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)        at java.lang.Runtime.loadLibrary0(Runtime.java:870)        at java.lang.System.loadLibrary(System.java:1122)        at com.java.barcode.App.main(App.java:65)

解决方法有几种:

查看系统中的Java库加载路径。把dll文件放到对应的路径下即可:System.out.println(System.getProperty("java.library.path"));使用全路径加载:System.load("D:/opencv-4.3/opencv/build/java/x64/opencv_java430.dll");启动程序的时候指定dll路径:java -Djava.library.path=<dll path> -cp target/opencv-dotcode-1.0-SNAPSHOT-jar-with-dependencies.jar com.java.barcode.App摄像头视频窗口

在OpenCV Java的文档中提供了一份基于JavaFX的示例代码。

参考逻辑之后,也可以把代码移植到Java Swing中。我这里用JLable来显示视频帧:

public void updateViewer(final BufferedImage image) {        if (!SwingUtilities.isEventDispatchThread()) {            SwingUtilities.invokeLater(new Runnable() {                @Override                public void run() {                    mImage.setIcon(new ImageIcon(image));                }            });            return;        }    } Runnable frameGrabber = new Runnable() {                     @Override                    public void run() {                        Mat frame = grabFrame();                        byte[] data = Utils.matToByteArray(frame);                         if (!status.get()) {                            status.set(true);                            barcodeTimer.schedule(new BarcodeRunnable(frame, mBarcodeReader, callback, status), 0, TimeUnit.MILLISECONDS);                        }                                             BufferedImage bufferedImage = Utils.byteToBufferedImage(data, frame.width(), frame.height(), frame.channels());                        if (isRunning) updateViewer(bufferedImage);                    }                };this.timer = Executors.newSingleThreadScheduledExecutor();this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);

OpenCV接口运行在独立的线程中,需要通过SwingUtilities来更新UI。

示例:DotCode解码

在pom.xml中添加Dynamsoft Barcode Reader SDK:

<repositories>  <repository>    <id>dbr</id>    <url>;/url>  </repository></repositories><dependencies>  <dependency>    <groupId>com.dynamsoft</groupId>    <artifactId>dbr</artifactId>    <version>7.4.0</version>  </dependency></dependencies>

然后像OpenCV一样创建一条线程来做条形码解码。

barcodeTimer = Executors.newSingleThreadScheduledExecutor();

Runnable中的代码:

public void run() {        // TODO Auto-generated method stub        try {            TextResult[] results = reader.decodeBuffer(Utils.matToByteArray(frame), frame.width(), frame.height(), (int)frame.step1(), EnumImagePixelFormat.IPF_BGR_888, "");            if (results != null && results.length > 0) {                if (callback != null) {                    callback.onResult(results, Utils.matToBufferedImage(frame));                }            }            else {                status.set(false);            }                    } catch (BarcodeReaderException e) {        // TODO Auto-generated catch block        e.printStackTrace();        }    }

OpenCV获取的数据类型是Mat。

条形码解码的时候要把Mat转换成byte[]:

public static byte[] matToByteArray(Mat original){    int width = original.width(), height = original.height(), channels = original.channels();    byte[] sourcePixels = new byte[width * height * channels];    original.get(0, 0, sourcePixels);    return sourcePixels;}

而在显示画面的时候,要把数据再转成BufferedImage:

public static BufferedImage byteToBufferedImage(byte[] sourcePixels, int width, int height, int channels){    BufferedImage image = null;         if (channels > 1)    {        image = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);    }    else    {        image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);    }    final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();    System.arraycopy(sourcePixels, 0, targetPixels, 0, sourcePixels.length);         return image;}

最后通过自定义的JLable来绘制条形码的区域:

private ArrayList<Point[]> data = new ArrayList<>(); @Overrideprotected void paintComponent(Graphics g) {    super.paintComponent(g);    Graphics2D g2d = (Graphics2D) g.create();    if (data.size() > 0) {        g2d.setColor(Color.RED);        for (Point[] points : data) {            for (int i = 0; i < points.length; ++i) {                if (i == 3) {                    g2d.drawLine(points[i].x, points[i].y, points[0].x, points[0].y);                } else {                    g2d.drawLine(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y);                }            }        }     }    g2d.dispose();} public void appendPoints(Point[] points) {    data.add(points);} public void clearPoints() {    data.clear();}
源码

标签: #opencv430安装教程