Java+OpenCV调用摄像头实现拍照功能

目录
  • 环境准备
  • 制作主界面
    • 整体结构介绍
  • 核心代码与知识点讲解
    • JPanel中如何显示摄像头的图像
    • OpenCV调用摄像头
    • 使用摄像头拍照
  • 完整代码
    • OpenCVUtil.java
    • ImageUtils.java
    • FileBean.java
    • VideoPanel.java
    • TakePhotoProcess.java
    • FaceRecognize.java(核心主类)

随着我们对环境、Mat基本使用越来越熟练、Java Swing也逐步熟悉了起来。今天我们开始进入OpenCV驱动摄像头的几个使用场景。

环境准备

1.准备好一个USB外接摄像头,我这边使用的有两种,一种是普通的罗技摄像头,一种是双目摄像头(将来用来做活检);

2.eclipse 2021-12版;

3.JDK 11+,因为我们编写swing要使用到Window Builder窗体设计器这个插件。在eclipse 2021-12版里要驱动Windows Builder窗体设计器我们必须要用JDK11及+;

4.使用Windows10环境编程。当然我们也可以使用Mac,但是Mac下如果是JAVA驱动摄像头有一个这样的梗:那就是直接你在eclipse里无法直接调用摄像头,它会报一个“This app has crashed because it attempted to access privacy-sensitive data without a usage description”或者是

OpenCV: not authorized to capture video (status 0), requesting...
OpenCV: can not spin main run loop from other thread, set OPENCV_AVFOUNDATION_SKIP_AUTH=1 to disable authorization request and perform it in your application.
OpenCV: camera failed to properly initialize

这样的错误,这些错误都是因为Mac OS的权限问题导致,它意指你在Mac下没权限去调用Mac内置的一些设备。如果你用的是XCode写Swift那么你可以通过info.plist来解决此问题。但因为是eclipse里启动java main函数,目前在Mac OS下无法解决eclipse内运行驱动Mac外设这一类问题。如果你在Mac OS内,要运行OpenCV Java并驱动摄像头,你必须把项目打成可执行的jar包并且在command窗口下用java -jar 这样的命令去启动它。在启动时你的Mac OS会提示你给这个command窗口要授权,请点击【是】并且用指纹或者是密码授权,然后再次在command窗口运行java -jar opencv应用,你就可以在Mac OS下使用java去驱动摄像头了。因此这为我们的编码调试带来极大的不便,这就是为什么我们使用Windows10环境下开发opencv java的主要原因。

制作主界面

我们的主界面是一个Java Swing的JFrame应用,它长成这个样子

整体结构介绍

我们把屏幕分成上下两个区域,布局使用的是1024*768,带有点击关闭按钮即关闭程序的自由布局:

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 1024, 768);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);

上部区域

我们使用一个JPanel来分组叫cameraGroup,这个JPanel也是自由布局

JPanel cameraGroup = new JPanel();
cameraGroup.setBounds(10, 10, 988, 580);
contentPane.add(cameraGroup);
cameraGroup.setLayout(null);

然后在这个cameraGroup以左大右小,放置了两个额外的JPanel:

  • videoCamera
  • videoPreview

其中的videoCamera是自定义的JPanel

protected static VideoPanel videoCamera = new VideoPanel();

它是用来显示摄像头开启时不断的把摄像头内取到的图像“刷”到JPanel上显示用的,代码如下:

package org.mk.opencv;

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

import org.mk.opencv.util.ImageUtils;
import org.mk.opencv.util.OpenCVUtil;
import org.opencv.core.Mat;

public class VideoPanel extends JPanel {

    private Image image;

    public void setImageWithMat(Mat mat) {
        image = OpenCVUtil.matToBufferedImage(mat);
        this.repaint();
    }

    public void SetImageWithImg(Image img) {
        image = img;
    }

    public Mat getMatFromImage() {
        Mat faceMat = new Mat();
        BufferedImage bi = ImageUtils.toBufferedImage(image);
        faceMat = OpenCVUtil.bufferedImageToMat(bi);
        return faceMat;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null)
            g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), this);
    }

    public static VideoPanel show(String title, int width, int height, int open) {
        JFrame frame = new JFrame(title);
        if (open == 0) {
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        } else {
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        }

        frame.setSize(width, height);
        frame.setBounds(0, 0, width, height);
        VideoPanel videoPanel = new VideoPanel();
        videoPanel.setSize(width, height);
        frame.setContentPane(videoPanel);
        frame.setVisible(true);
        return videoPanel;
    }
}

下部区域

下部区域我们放置了一个buttonGroup。这个buttonGroup用的是“网袋布局”,上面放置三个按钮。

JPanel buttonGroup = new JPanel();
buttonGroup.setBounds(65, 610, 710, 35);
contentPane.add(buttonGroup);
buttonGroup.setLayout(new GridLayout(1, 0, 0, 0));

今天我们就要实现photoButton里的功能。

说完了布局下面进入核心代码讲解。

核心代码与知识点讲解

(最后会上全代码)

JPanel中如何显示摄像头的图像

JPanel这种组件一般是套在JFrame的contentPanel里的(这是用图形化设计器生成的JFrame自带的一个用来“盛”其它组件的容器)。

contentPane大家可以认为是一种容器。它一般是这样的一层关系:

JFrame(我们的主类)->contentPane->我们自己的上半部JPanel->videoCamera(JPanel)。

在Java Swing里有一个方法叫repaint()方法,这个方法 一旦被调用,这个组件的“子组件”内的

protected void paintComponent(Graphics g)

都会自动被依次调用一遍。

因此,我们才自定义了一个JPanel叫VideoPanel,然后我们覆写了它里面的paintComponent方法

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null)
            g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), this);
    }

这样,我们在我们的主类“FaceRecognize”里在通过摄像头得到了图像后把图像通过VideoPanel里的“setImageWithMat”方法set后,马上调用FaceRecognize自自的repaint方法,然后“父”事件一路向下传导,依次逐级把子组件进行“刷新”-子组件的paintComponent都会被触发一遍。

摄像头得到图像显示在videoCamera区域的过程就是:

  • 不断通过FaceRecognize类里通过摄像头读到Mat对象;
  • 把Mat对象set到VideoPanel里;
  • 不断调用FaceRecognize里的repaint方法迫使VideoPanel里“刷新”出摄像头拍的内容;
  • 每显示一次,sleep(50毫秒);

为了取得良好的刷新、连续不断的显示效果,你可以把上述方法套在一个“单线程”内。

OpenCV调用摄像头

OpenCV是使用以下这个类来驱动摄像头的。

private static VideoCapture capture = new VideoCapture();

然后打开摄像头,读入摄像头内容如下

capture.open(0);
Scalar color = new Scalar(0, 255, 0);
MatOfRect faces = new MatOfRect();
if (capture.isOpened()) {
    logger.info(">>>>>>video camera in working");
    Mat faceMat = new Mat();
    while (true) {
        capture.read(faceMat);
        if (!faceMat.empty()) {
            faceCascade.detectMultiScale(faceMat, faces);
            Rect[] facesArray = faces.toArray();
            if (facesArray.length >= 1) {
                for (int i = 0; i < facesArray.length; i++) {
                    Imgproc.rectangle(faceMat, facesArray[i].tl(), facesArray[i].br(), color, 2);
                    videoPanel.setImageWithMat(faceMat);
                    frame.repaint();
                }
            }
        } else {
            logger.info(">>>>>>not found anyinput");
            break;
        }
        Thread.sleep(80);
    }
}

通过上述代码我们可以看到我上面描述的4步。

  • capture.open(0)代表读取你的计算机当前连接的第1个摄像头,如果在mac上运行这一句一些mac都带有内嵌摄像头的,因此这一句代码就会驱动mac的默认内置摄像头;
  • if(capture.isOpened()),必须要有,很多网上教程跳过了这一步检测,导致摄像头一直不出内容其实最后才知道是摄像头驱动有误或者坏了,而不是代码问题,最终耗费了太多的排错时间,其实结果是换一个摄像头就好了;
  • while(true)后跟着capture.read(faceMat),这一句就是不断的读取摄像头的内容,并把摄像头的内容读到一个Mat对象中去;

前面说了,为了让这个过程更“顺滑”、“丝滑”,我把这个过程套到了一个单线程里让它单独运行以不阻塞Java Swing的主界面。同时用“绿色”的方框把人脸在画面里“框”出来。为此我制作了一个函数如下:

    public void invokeCamera(JFrame frame, VideoPanel videoPanel) {
        new Thread() {
            public void run() {
                CascadeClassifier faceCascade = new CascadeClassifier();
                faceCascade.load(cascadeFileFullPath);
                try {
                    capture.open(0);
                    Scalar color = new Scalar(0, 255, 0);
                    MatOfRect faces = new MatOfRect();
                    // Mat faceFrames = new Mat();
                    if (capture.isOpened()) {
                        logger.info(">>>>>>video camera in working");
                        Mat faceMat = new Mat();
                        while (true) {
                            capture.read(faceMat);
                            if (!faceMat.empty()) {
                                faceCascade.detectMultiScale(faceMat, faces);
                                Rect[] facesArray = faces.toArray();
                                if (facesArray.length >= 1) {
                                    for (int i = 0; i < facesArray.length; i++) {
                                        Imgproc.rectangle(faceMat, facesArray[i].tl(), facesArray[i].br(), color, 2);
                                        videoPanel.setImageWithMat(faceMat);
                                        frame.repaint();
                                        // videoPanel.repaint();
                                    }
                                }
                            } else {
                                logger.info(">>>>>>not found anyinput");
                                break;
                            }
                            Thread.sleep(80);
                        }
                    }
                } catch (Exception e) {
                    logger.error("invoke camera error: " + e.getMessage(), e);
                }
            }
        }.start();
    }

配合上我们的main方法就是这样用的:

    public static void main(String[] args) {
        FaceRecognize frame = new FaceRecognize();
        frame.setVisible(true);
        frame.invokeCamera(frame, videoCamera);
    }

使用摄像头拍照

这一章节我们在OpenCV Java入门四 认出这是“一张脸”里其实已经讲过了,就是把一个Mat输出到一个jpg文件中。

在本篇章节中,我们为了做得效果好一点会做这么几件事:

  • 等比例把摄像头拿到的Mat对象缩到“videoPreview”上;
  • 把摄像头当前的Mat输出到外部文件;
  • 把上述过程也套到了一个单线程里以不阻塞主类的显示界面;

等比例缩放图片

位于ImageUtils类,它得到一个Mat,然后转成java.awt.Image对象;

再利用Image里的AffineTransformOp根据ratio(图像原比例)基于指定尺寸(宽:165, 高:200)的等比例缩放。再把Image转成BufferedImage;

再把BufferedImage转回Mat给到FaceRecognize主类用来作VideoPanel的“显示”来显示到我们的preview区域,而preview区域其实也是用到了VideoPanel这个类来声明的;

为此我们对photoButton进行事件编程

JButton photoButton = new JButton("Take Photo");
        photoButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                logger.info(">>>>>>take photo performed");
                StringBuffer photoPathStr = new StringBuffer();
                photoPathStr.append(photoPath);
                try {
                    if (capture.isOpened()) {
                        Mat myFace = new Mat();
                        while (true) {
                            capture.read(myFace);
                            if (!myFace.empty()) {
                                Image previewImg = ImageUtils.scale2(myFace, 165, 200, true);// 等比例缩放
                                TakePhotoProcess takePhoto = new TakePhotoProcess(photoPath.toString(), myFace);
                                takePhoto.start();// 照片写盘
                                videoPreview.SetImageWithImg(previewImg);// 在预览界面里显示等比例缩放的照片
                                videoPreview.repaint();// 让预览界面重新渲染
                                break;
                            }
                        }
                    }
                } catch (Exception ex) {
                    logger.error(">>>>>>take photo error: " + ex.getMessage(), ex);
                }
            }
        });

TakePhotoProcess是一个单线程,代码如下:

package org.mk.opencv.sample;

import org.apache.log4j.Logger;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;

public class TakePhotoProcess extends Thread {
    private static Logger logger = Logger.getLogger(TakePhotoProcess.class);

    private String imgPath;
    private Mat faceMat;
    private final static Scalar color = new Scalar(0, 0, 255);

    public TakePhotoProcess(String imgPath, Mat faceMat) {
        this.imgPath = imgPath;
        this.faceMat = faceMat;
    }

    public void run() {
        try {
            long currentTime = System.currentTimeMillis();
            StringBuffer samplePath = new StringBuffer();
            samplePath.append(imgPath).append(currentTime).append(".jpg");
            Imgcodecs.imwrite(samplePath.toString(), faceMat);
            logger.info(">>>>>>write image into->" + samplePath.toString());

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

}

另外两个按钮“trainButton”和"identifyButton"我们留到后面2个篇章里去讲,我们一步一步来,这样大家才能夯实基础。

最终这个FaceRecognize运行起来,然后点击photoButton后的效果如下图所示:

完整代码

OpenCVUtil.java

package org.mk.opencv.util;

import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.io.File;

import org.apache.log4j.Logger;
import org.opencv.core.CvType;
import org.opencv.core.Mat;

public class OpenCVUtil {
    private static Logger logger = Logger.getLogger(OpenCVUtil.class);

    public static Image matToImage(Mat matrix) {
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (matrix.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
        byte[] buffer = new byte[bufferSize];
        matrix.get(0, 0, buffer); // 获取所有的像素点
        BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
        return image;
    }

    public static List<String> getFilesFromFolder(String folderPath) {
        List<String> fileList = new ArrayList<String>();
        File f = new File(folderPath);
        if (f.isDirectory()) {
            File[] files = f.listFiles();
            for (File singleFile : files) {
                fileList.add(singleFile.getPath());
            }
        }
        return fileList;
    }

    public static String randomFileName() {
        StringBuffer fn = new StringBuffer();
        fn.append(System.currentTimeMillis()).append((int) (System.currentTimeMillis() % (10000 - 1) + 1))
                .append(".jpg");
        return fn.toString();
    }

    public static List<FileBean> getPicFromFolder(String rootPath) {
        List<FileBean> fList = new ArrayList<FileBean>();
        int fileNum = 0, folderNum = 0;
        File file = new File(rootPath);
        if (file.exists()) {
            LinkedList<File> list = new LinkedList<File>();
            File[] files = file.listFiles();
            for (File file2 : files) {
                if (file2.isDirectory()) {
                    // logger.info(">>>>>>文件夹:" + file2.getAbsolutePath());
                    list.add(file2);
                    folderNum++;
                } else {
                    // logger.info(">>>>>>文件:" + file2.getAbsolutePath());
                    FileBean f = new FileBean();
                    String fileName = file2.getName();
                    String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
                    File fParent = new File(file2.getParent());
                    String parentFolderName = fParent.getName();
                    f.setFileFullPath(file2.getAbsolutePath());
                    f.setFileType(suffix);
                    f.setFolderName(parentFolderName);
                    fList.add(f);
                    fileNum++;
                }
            }
            File temp_file;
            while (!list.isEmpty()) {
                temp_file = list.removeFirst();
                files = temp_file.listFiles();
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        // System.out.println("文件夹:" + file2.getAbsolutePath());
                        list.add(file2);
                        folderNum++;
                    } else {
                        // logger.info(">>>>>>文件:" + file2.getAbsolutePath());
                        FileBean f = new FileBean();
                        String fileName = file2.getName();
                        String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
                        File fParent = new File(file2.getParent());
                        String parentFolderName = fParent.getName();
                        f.setFileFullPath(file2.getAbsolutePath());
                        f.setFileType(suffix);
                        f.setFolderName(parentFolderName);
                        fList.add(f);
                        fileNum++;
                    }
                }
            }
        } else {
            logger.info(">>>>>>文件不存在!");
        }
        // logger.info(">>>>>>文件夹共有:" + folderNum + ",文件共有:" + fileNum);
        return fList;
    }

    public static BufferedImage matToBufferedImage(Mat matrix) {
        int cols = matrix.cols();
        int rows = matrix.rows();
        int elemSize = (int) matrix.elemSize();
        byte[] data = new byte[cols * rows * elemSize];
        int type;
        matrix.get(0, 0, data);
        switch (matrix.channels()) {
        case 1:
            type = BufferedImage.TYPE_BYTE_GRAY;
            break;
        case 3:
            type = BufferedImage.TYPE_3BYTE_BGR;
            // bgr to rgb
            byte b;
            for (int i = 0; i < data.length; i = i + 3) {
                b = data[i];
                data[i] = data[i + 2];
                data[i + 2] = b;
            }
            break;
        default:
            return null;
        }
        BufferedImage image2 = new BufferedImage(cols, rows, type);
        image2.getRaster().setDataElements(0, 0, cols, rows, data);
        return image2;
    }

    public static Mat bufferedImageToMat(BufferedImage bi) {
        Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
        byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
        mat.put(0, 0, data);
        return mat;
    }
}

ImageUtils.java

package org.mk.opencv.util;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Transparency;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.ImageIcon;

import org.opencv.core.Mat;

public class ImageUtils {

    /**
     * 几种常见的图片格式
     */
    public static String IMAGE_TYPE_GIF = "gif";// 图形交换格式
    public static String IMAGE_TYPE_JPG = "jpg";// 联合照片专家组
    public static String IMAGE_TYPE_JPEG = "jpeg";// 联合照片专家组
    public static String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式
    public static String IMAGE_TYPE_PNG = "png";// 可移植网络图形
    public static String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop

    /**
     * 缩放图像(按高度和宽度缩放)
     *
     * @param srcImageFile 源图像文件地址
     * @param result       缩放后的图像地址
     * @param height       缩放后的高度
     * @param width        缩放后的宽度
     * @param bb           比例不对时是否需要补白:true为补白; false为不补白;
     */
    public final synchronized static Image scale2(Mat mat, int height, int width, boolean bb) throws Exception {
        // boolean flg = false;
        Image itemp = null;
        try {
            double ratio = 0.0; // 缩放比例
            // File f = new File(srcImageFile);
            // BufferedImage bi = ImageIO.read(f);
            BufferedImage bi = OpenCVUtil.matToBufferedImage(mat);
            itemp = bi.getScaledInstance(width, height, bi.SCALE_SMOOTH);
            // 计算比例
            // if ((bi.getHeight() > height) || (bi.getWidth() > width)) {
            // flg = true;
            if (bi.getHeight() > bi.getWidth()) {
                ratio = Integer.valueOf(height).doubleValue() / bi.getHeight();
            } else {
                ratio = Integer.valueOf(width).doubleValue() / bi.getWidth();
            }
            AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(ratio, ratio), null);
            itemp = op.filter(bi, null);
            // }
            if (bb) {// 补白
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics2D g = image.createGraphics();
                g.setColor(Color.white);
                g.fillRect(0, 0, width, height);
                if (width == itemp.getWidth(null))
                    g.drawImage(itemp, 0, (height - itemp.getHeight(null)) / 2, itemp.getWidth(null),
                            itemp.getHeight(null), Color.white, null);
                else
                    g.drawImage(itemp, (width - itemp.getWidth(null)) / 2, 0, itemp.getWidth(null),
                            itemp.getHeight(null), Color.white, null);
                g.dispose();
                itemp = image;
            }
            // if (flg)
            // ImageIO.write((BufferedImage) itemp, "JPEG", new File(result));
        } catch (Exception e) {
            throw new Exception("scale2 error: " + e.getMessage(), e);
        }
        return itemp;
    }

    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }

        // 此代码确保在图像的所有像素被载入
        image = new ImageIcon(image).getImage();

        // 如果图像有透明用这个方法
//        boolean hasAlpha = hasAlpha(image);

        // 创建一个可以在屏幕上共存的格式的bufferedimage
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        try {
            // 确定新的缓冲图像类型的透明度
            int transparency = Transparency.OPAQUE;
            // if (hasAlpha) {
            transparency = Transparency.BITMASK;
            // }

            // 创造一个bufferedimage
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null), image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // 系统不会有一个屏幕
        }

        if (bimage == null) {
            // 创建一个默认色彩的bufferedimage
            int type = BufferedImage.TYPE_INT_RGB;
            // int type = BufferedImage.TYPE_3BYTE_BGR;//by wang
            // if (hasAlpha) {
            type = BufferedImage.TYPE_INT_ARGB;
            // }
            bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
        }

        // 把图像复制到bufferedimage上
        Graphics g = bimage.createGraphics();

        // 把图像画到bufferedimage上
        g.drawImage(image, 0, 0, null);
        g.dispose();

        return bimage;
    }
}

FileBean.java

package org.mk.opencv.util;

import java.io.Serializable;

public class FileBean implements Serializable {

    private String fileFullPath;
    private String folderName;
    private String fileType;

    public String getFileType() {
        return fileType;
    }

    public void setFileType(String fileType) {
        this.fileType = fileType;
    }

    public String getFileFullPath() {
        return fileFullPath;
    }

    public void setFileFullPath(String fileFullPath) {
        this.fileFullPath = fileFullPath;
    }

    public String getFolderName() {
        return folderName;
    }

    public void setFolderName(String folderName) {
        this.folderName = folderName;
    }

}

VideoPanel.java

package org.mk.opencv;

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

import org.mk.opencv.util.ImageUtils;
import org.mk.opencv.util.OpenCVUtil;
import org.opencv.core.Mat;

public class VideoPanel extends JPanel {

    private Image image;

    public void setImageWithMat(Mat mat) {
        image = OpenCVUtil.matToBufferedImage(mat);
        this.repaint();
    }

    public void SetImageWithImg(Image img) {
        image = img;
    }

    public Mat getMatFromImage() {
        Mat faceMat = new Mat();
        BufferedImage bi = ImageUtils.toBufferedImage(image);
        faceMat = OpenCVUtil.bufferedImageToMat(bi);
        return faceMat;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (image != null)
            g.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), this);
    }

    public static VideoPanel show(String title, int width, int height, int open) {
        JFrame frame = new JFrame(title);
        if (open == 0) {
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        } else {
            frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        }

        frame.setSize(width, height);
        frame.setBounds(0, 0, width, height);
        VideoPanel videoPanel = new VideoPanel();
        videoPanel.setSize(width, height);
        frame.setContentPane(videoPanel);
        frame.setVisible(true);
        return videoPanel;
    }
}

TakePhotoProcess.java

package org.mk.opencv.sample;

import org.apache.log4j.Logger;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.imgcodecs.Imgcodecs;

public class TakePhotoProcess extends Thread {
    private static Logger logger = Logger.getLogger(TakePhotoProcess.class);

    private String imgPath;
    private Mat faceMat;
    private final static Scalar color = new Scalar(0, 0, 255);

    public TakePhotoProcess(String imgPath, Mat faceMat) {
        this.imgPath = imgPath;
        this.faceMat = faceMat;
    }

    public void run() {
        try {
            long currentTime = System.currentTimeMillis();
            StringBuffer samplePath = new StringBuffer();
            samplePath.append(imgPath).append(currentTime).append(".jpg");
            Imgcodecs.imwrite(samplePath.toString(), faceMat);
            logger.info(">>>>>>write image into->" + samplePath.toString());

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

}

FaceRecognize.java(核心主类)

package org.mk.opencv.sample;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

import org.apache.log4j.Logger;
import org.mk.opencv.VideoPanel;
import org.mk.opencv.face.TakePhotoProcess;
import org.mk.opencv.util.ImageUtils;
import org.mk.opencv.util.OpenCVUtil;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.videoio.VideoCapture;

import javax.swing.border.BevelBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class FaceRecognize extends JFrame {
    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }
    private static Logger logger = Logger.getLogger(FaceRecognize.class);
    private static final String cascadeFileFullPath = "D:\\opencvinstall\\build\\install\\etc\\lbpcascades\\lbpcascade_frontalface.xml";
    private static final String photoPath = "D:\\opencv-demo\\face\\";
    private JPanel contentPane;
    protected static VideoPanel videoCamera = new VideoPanel();
    private static final Size faceSize = new Size(165, 200);
    private static VideoCapture capture = new VideoCapture();

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        FaceRecognize frame = new FaceRecognize();
        frame.setVisible(true);
        frame.invokeCamera(frame, videoCamera);
    }

    public void invokeCamera(JFrame frame, VideoPanel videoPanel) {
        new Thread() {
            public void run() {
                CascadeClassifier faceCascade = new CascadeClassifier();
                faceCascade.load(cascadeFileFullPath);
                try {
                    capture.open(0);
                    Scalar color = new Scalar(0, 255, 0);
                    MatOfRect faces = new MatOfRect();
                    // Mat faceFrames = new Mat();
                    if (capture.isOpened()) {
                        logger.info(">>>>>>video camera in working");
                        Mat faceMat = new Mat();
                        while (true) {
                            capture.read(faceMat);
                            if (!faceMat.empty()) {
                                faceCascade.detectMultiScale(faceMat, faces);
                                Rect[] facesArray = faces.toArray();
                                if (facesArray.length >= 1) {
                                    for (int i = 0; i < facesArray.length; i++) {
                                        Imgproc.rectangle(faceMat, facesArray[i].tl(), facesArray[i].br(), color, 2);
                                        videoPanel.setImageWithMat(faceMat);
                                        frame.repaint();
                                        // videoPanel.repaint();
                                    }
                                }
                            } else {
                                logger.info(">>>>>>not found anyinput");
                                break;
                            }
                            Thread.sleep(80);
                        }
                    }
                } catch (Exception e) {
                    logger.error("invoke camera error: " + e.getMessage(), e);
                }
            }
        }.start();
    }

    /**
     * Create the frame.
     */

    public FaceRecognize() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 1024, 768);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(null);

        JPanel cameraGroup = new JPanel();
        cameraGroup.setBounds(10, 10, 988, 580);
        contentPane.add(cameraGroup);
        cameraGroup.setLayout(null);

        JLabel videoDescriptionLabel = new JLabel("Video");
        videoDescriptionLabel.setHorizontalAlignment(SwingConstants.CENTER);
        videoDescriptionLabel.setBounds(0, 10, 804, 23);
        cameraGroup.add(videoDescriptionLabel);

        videoCamera.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
        videoCamera.setBounds(10, 43, 794, 527);
        cameraGroup.add(videoCamera);

        // JPanel videoPreview = new JPanel();
        VideoPanel videoPreview = new VideoPanel();
        videoPreview.setBorder(new BevelBorder(BevelBorder.LOWERED, null, null, null, null));
        videoPreview.setBounds(807, 359, 171, 211);
        cameraGroup.add(videoPreview);

        JLabel lblNewLabel = new JLabel("Preview");
        lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
        lblNewLabel.setBounds(807, 307, 171, 42);
        cameraGroup.add(lblNewLabel);

        JPanel buttonGroup = new JPanel();
        buttonGroup.setBounds(65, 610, 710, 35);
        contentPane.add(buttonGroup);
        buttonGroup.setLayout(new GridLayout(1, 0, 0, 0));

        JButton photoButton = new JButton("Take Photo");
        photoButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                logger.info(">>>>>>take photo performed");
                StringBuffer photoPathStr = new StringBuffer();
                photoPathStr.append(photoPath);
                try {
                    if (capture.isOpened()) {
                        Mat myFace = new Mat();
                        while (true) {
                            capture.read(myFace);
                            if (!myFace.empty()) {
                                Image previewImg = ImageUtils.scale2(myFace, 165, 200, true);// 等比例缩放
                                TakePhotoProcess takePhoto = new TakePhotoProcess(photoPath.toString(), myFace);
                                takePhoto.start();// 照片写盘
                                videoPreview.SetImageWithImg(previewImg);// 在预览界面里显示等比例缩放的照片
                                videoPreview.repaint();// 让预览界面重新渲染
                                break;
                            }
                        }
                    }
                } catch (Exception ex) {
                    logger.error(">>>>>>take photo error: " + ex.getMessage(), ex);
                }
            }
        });
        buttonGroup.add(photoButton);

        JButton trainButton = new JButton("Train");
        buttonGroup.add(trainButton);

        JButton identifyButton = new JButton("Identify");
        buttonGroup.add(identifyButton);
    }
}

到此这篇关于Java+OpenCV调用摄像头实现拍照功能的文章就介绍到这了,更多相关Java OpenCV拍照内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java+OpenCV实现图片中的人脸识别

    目录 MatOfRect.detectMultiScale函数 实现代码 ImageViewer.java DetectFace.java 运行 把识别出来的脸存成文件 经过前三个教程,我们可以知道了OpenCV的基本使用了. 今天,我们就要讲OpenCV中认出,这是一个人脸是怎么做的. MatOfRect.detectMultiScale函数 OpenCV用的是detectMultiScale来认出这是一个脸的.记得,这只是认出这是一个脸,而不是这个脸是谁. 这个脸是谁我们会逐步展开,前面勿求

  • java+opencv实现人脸识别功能

    背景:最近需要用到人脸识别,但又不花钱使用现有的第三方人脸识别接口,为此使用opencv结合java进行人脸识别(ps:opencv是开源的,使用它来做人脸识别存在一定的误差,效果一般). 1.安装opencv 官网地址:https://opencv.org/ , 由于官网下载速度是真的慢 百度网盘: 链接: https://pan.baidu.com/s/1RpsP-I7v8pP2dkqALDw7FQ 提取码: pq7v 如果是官网下载,就无脑安装就行了,安装完毕后. 将图一的两个文件复制到图

  • 详解使用JavaCV/OpenCV抓取并存储摄像头图像

    本程序通过JFrame实时显示本机摄像头图像,并将图像存储到一个缓冲区,当用户用鼠标点击JFrame中任何区域时,显示抓取图像的简单动画,同时保存缓冲区的图像到磁盘文件中.点击JFrame关闭按钮可以退出程序. 实现: import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; imp

  • Java OpenCV4.0.0实现实时人脸识别

    本文实例为大家分享了javaOpenCV-4.0.0 实时人脸识别,供大家参考,具体内容如下 package com.xu.opencv; import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Point; import org.opencv.core.Rect; import org.opencv.core.Scalar;

  • python+opencv打开摄像头,保存视频、拍照功能的实现方法

    以下代码是保存视频 # coding:utf-8 import cv2 import sys reload(sys) sys.setdefaultencoding('utf8') cap = cv2.VideoCapture(0) cap.set(3,640) cap.set(4,480) cap.set(1, 10.0) #此处fourcc的在MAC上有效,如果视频保存为空,那么可以改一下这个参数试试, 也可以是-1 fourcc = cv2.cv.CV_FOURCC('m', 'p', '4

  • 基于Opencv实现双目摄像头拍照程序

    本文实例为大家分享了Opencv实现双目摄像头拍照程序的具体代码,供大家参考,具体内容如下 我用的双目摄像头是一根usb线接入电脑.运行环境是vc2015,opencv3.0.将左右两个摄像头拍到的图片分别保存起来. 贴出代码(C++) #include"stdafx.h" #include<iostream> #include<string> #include<sstream> #include<opencv2/core.hpp> #i

  • Java+OpenCV调用摄像头实现拍照功能

    目录 环境准备 制作主界面 整体结构介绍 核心代码与知识点讲解 JPanel中如何显示摄像头的图像 OpenCV调用摄像头 使用摄像头拍照 完整代码 OpenCVUtil.java ImageUtils.java FileBean.java VideoPanel.java TakePhotoProcess.java FaceRecognize.java(核心主类) 随着我们对环境.Mat基本使用越来越熟练.Java Swing也逐步熟悉了起来.今天我们开始进入OpenCV驱动摄像头的几个使用场景

  • Vue2.0实现调用摄像头进行拍照功能 exif.js实现图片上传功能

    本文实例为大家分享了Vue2.0实现调用摄像头进行拍照功能的具体代码,以及图片上传功能引用exif.js,供大家参考,具体内容如下 可以在github 上下载demo链接 vue组件代码 <template> <div> <div style="padding:20px;"> <div class="show"> <div class="picture" :style="'backg

  • C#调用摄像头实现拍照功能的示例代码

    前言 老师要求我们学生做一套拍照身份验证系统,经过长时间的学习,有了这篇文章,希望能帮到读者们. 正文 首先介绍本文的主角:AForge 创建一个C#项目,引用必备的几个DLL AForge.dll AForge.Controls.dll AForge.Imaging.dll AForge.Math.dll AForge.Video.DirectShow.dll AForge.Video.dll 这些DLL读者们可以在文末下载我附带的Demon 引用必要的命名空间 using AForge.Co

  • 微信小程序调用摄像头实现拍照功能

    本文实例为大家分享了微信小程序调用摄像头实现拍照的具体代码,供大家参考,具体内容如下 微信小程序开发文档 首先,需要用户授权摄像头权限,这一步是必须的 具体步骤: 1.获取用户当前授权状态,看是否已经授权,如果已经授权直接显示摄像头2.如果用户还没有授权,则调起授权弹框,用户允许授权则显示摄像头3.如果用户不允许,则提示用户去设置页面打开摄像头权限 用户授权之后,就可以进行拍摄了,微信的camera组件无法显示为圆形,我这里是用一张图片遮盖了 上代码: wxml: <view class='ca

  • Android实现调用摄像头进行拍照功能

    现在Android智能手机的像素都会提供照相的功能,大部分的手机的摄像头的像素都在1000万以上的像素,有的甚至会更高.它们大多都会支持光学变焦.曝光以及快门等等. 下面的程序Demo实例示范了使用Camera v2来进行拍照,当用户按下拍照键时,该应用会自动对焦,当对焦成功时拍下照片. layout/activity_main.xml界面布局代码如下: <?xml version="1.0" encoding="utf-8"?> <manifes

  • Python OpenCV 调用摄像头并截图保存功能的实现代码

    0x01 OpenCV安装 通过命令pip install opencv-python 安装 pip install opencv-python 0x02  示例 import cv2 cap = cv2.VideoCapture(0) #打开摄像头 while(1): # get a frame ret, frame = cap.read() # show a frame cv2.imshow("capture", frame) #生成摄像头窗口 if cv2.waitKey(1)

  • vue调用本地摄像头实现拍照功能

    前言: vue调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用https域名才可以使用.实现效果: 1.摄像头效果: 2.拍照效果: 实现代码: <template> <div class="camera_outer"> <video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay

  • Vue调用PC摄像头实现拍照功能

    本文实例为大家分享了Vue调用PC摄像头实现拍照功能的具体代码,供大家参考,具体内容如下 项目需求:可以本地上传头像,也可以选择拍摄头像上传. 组件: 1.Camera组件:实现 打开.关闭摄像头.绘制.显示图片.用于上传 2.CameraDialog组件:使用ElementUI dialog组件 展示摄像头UI效果 3.外部调用CameraDialog组件,实现拍摄头像上传功能 4.本地上传可使用原生input.也可使用ElementUI upload组件 操作逻辑: 1.新增时将头像图片转为

  • Python基于opencv调用摄像头获取个人图片的实现方法

    接触图像领域的应该对于opencv都不会感到陌生,这个应该算是功能十分强劲的一个算法库了,当然了,使用起来也是很方便的,之前使用Windows7的时候出现多该库难以安装成功的情况,现在这个问题就不存在了,需要安装包的话可以去我的资源中下载使用,使用pip安装方式十分地便捷. 今天主要是基于opencv模块来调用笔记本的内置摄像头,然后从视频流中获取到人脸的图像数据用于之后的人脸识别项目,也就是为了构建可用的数据集.整个实现过程并不复杂,具体如下: #!usr/bin/env python #en

  • python实现调用摄像头并拍照发邮箱

    项目地址: https://github.com/flygaga/camera 思路 1.通过opencv调用摄像头拍照保存图像到本地 2.用email库构造邮件内容,保存图片以附件形式插入邮件内容 3.用smtplib库发送邮件到指定邮箱 4.生成 .exe 文件 5.设置开机自启(每次开机自动运行,启动相机,拍下照片发送到指定邮箱) 导入工具 import cv2 # pip install opencv-python -i {指定镜像源} 控制摄像头 from email.mime.ima

随机推荐