Windows系统使用javacv获取USB摄像头图像并保存_java通过uvc协议控制获取摄像头名称-程序员宅基地

技术标签: Java  java  jar  camera  windows  eclipse  

目标:获取Windows系统笔记本自带摄像头,或者连接Windows系统的usb摄像头视频画面,并保存图像到电脑。

一、依赖库说明

源码git地址:bytedeco/javacv: Java interface to OpenCV, FFmpeg, and more (github.com)https://github.com/bytedeco/javacv

javacv jar包下载地址:Releases · bytedeco/javacv (github.com)https://github.com/bytedeco/javacv/releases

二、使用方法如下代码

类名:UvcCameraUtils

//package com.xx.xx
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.WindowConstants;
import org.bytedeco.javacv.CanvasFrame;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.FrameGrabber;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameGrabber;
import org.bytedeco.javacv.VideoInputFrameGrabber;
import javax.swing.JOptionPane;
import org.bytedeco.javacv.FrameGrabber.Exception;

public class UvcCameraUtils {
    public static int frameIndex = 0;
    // videoDeviceName:USB/内置摄像头名称, 本例设成"Integrated Webcam",是电脑内置摄像头名,可在设备管理器--相机,查看名称,此处以打开电脑内置摄像头为例。要打开USB摄像头,可插上摄像头后,在设备管理器中查看,并修改此变量值即可打开USB摄像头。
    private static final String videoDeviceName = "Integrated Webcam";
    
    /**以打开电脑内置摄像头为例**/
    public static void showUvcCameraFrame() throws InterruptedException,         
        FrameGrabber.Exception {
        // 0表示摄像头id
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        grabber.start();//开始获取摄像头数据
        CanvasFrame canvas = new CanvasFrame("电脑摄像头");//新建一个窗口
        canvas.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        canvas.setAlwaysOnTop(true);
        while (true) {
            if (!canvas.isDisplayable()) {//窗口是否关闭
                grabber.stop();//停止抓取
                grabber.close();
                System.exit(-1);//退出
            }

            Frame frame = grabber.grab();
            canvas.showImage(frame);//获取摄像头图像并放到窗口上显示, 这里的Frame frame=grabber.grab(); frame是一帧视频图像
            Thread.sleep(50);//50毫秒刷新一次图像
        }
    }
    
    /**根据名称显示摄像头视频画面**/
    public static void showUvcCameraFrame(boolean isSaveImage) throws FrameGrabber.Exception, InterruptedException {
        frameIndex = 0;
        int deviceIndex = -1;
        // 获取设备名称
        String[] deStrings = VideoInputFrameGrabber.getDeviceDescriptions();
        if (deStrings != null && deStrings.length > 0) {
            for (int i=0; i < deStrings.length; i++) {
                System.out.println("descriptions index=" + i + ", value=" + deStrings[i]);
                if (videoDeviceName.equals(deStrings[i])) {
                    deviceIndex = i;
                    break;
                }
            }
        }
        if (deviceIndex < 0) {
            JOptionPane.showMessageDialog(null, "<html><font size=8>" + "没有找到指定设备");
            return;
        }
        // 参数根据设备管理器中,Cameras下面,设备的摄像头排次,如果是第二个参数为1
        VideoInputFrameGrabber grabber = VideoInputFrameGrabber.createDefault(deviceIndex);
        // 摄像头画面宽高
        grabber.setImageWidth(360);
        grabber.setImageHeight(640);
        // 图像格式
        grabber.setFormat("YUY2");
        grabber.start();
        CanvasFrame canvasFrame = new CanvasFrame("摄像头:" + videoDeviceName);
        canvasFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        canvasFrame.setAlwaysOnTop(true);
        while (true) {
            if (!canvasFrame.isDisplayable()) {
                grabber.stop();
                grabber.close();
                System.exit(-1);
            }
            Frame frame = null;
            try {
                frame = grabber.grab();
            } catch (Exception e) {
                System.out.println("showUvcCameraFrame error=" + e.getMessage() + ", isSaveImage=" + isSaveImage);
            }
            if (frame != null) {
                canvasFrame.showImage(frame);
                // 在D盘保存两张图
                if (isSaveImage && frameIndex < 2) {
                    writeFrameToFile(frame, "index_" + frameIndex);
                    frameIndex++;
                }
            }
            Thread.sleep(30);
        }
    }

    public static void writeFrameToFile(Frame frame, String fileNamePrefix) {
        writeFrameToFile("D:\\", frame, fileNamePrefix);
    }
    
    public static void writeFrameToFile(String filePatn, Frame frame, String fileNamePrefix) {
        if (filePatn == null || "".equals(filePatn)) {
            return;
        } else if (!isFileExist(filePatn)) {
            File file = new File(filePatn);
            file.mkdirs();
        }
        File targetFile = new File(filePatn + File.separator + fileNamePrefix + ".jpg");
        String imgSuffix = "jpg";
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage srcBi = converter.getBufferedImage(frame);
        int owidth = srcBi.getWidth();
        int oheight = srcBi.getHeight();
        int width = owidth;
        int height = oheight;
        BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
        Image image = srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        bi.getGraphics().drawImage(image, 0, 0, null);
        try {
            ImageIO.write(bi, imgSuffix, targetFile);
        } catch (IOException e) {
            System.out.println("writeFrameToFile image write error=" + e.getMessage() 
            + ", frame=" + frame + ", fileNamePrefix=" + fileNamePrefix);
            e.printStackTrace();
        }
        if (converter != null) {
            converter.close();
        }
    }

    /**从帧数据中获取Image对象**/
    public static Image getImageFromFrame(Frame frame) {
        Java2DFrameConverter converter = new Java2DFrameConverter();
        BufferedImage srcBi = converter.getBufferedImage(frame);
        int owidth = srcBi.getWidth();
        int oheight = srcBi.getHeight();
        // 对截取的帧进行等比例缩放
        int width = owidth;
        int height = oheight;// (int) (((double) width / owidth) * oheight);
        Image image = srcBi.getScaledInstance(width, height, Image.SCALE_SMOOTH);
        if (converter != null) {
            converter.close();
        }
        return image;
    }
    
    /**文件是否存在**/
    public static boolean isFileExist(String pathname) {
        File file = new File(pathname);
        return isFileExist(file);
    }
    
    /**文件是否存在**/
    public static boolean isFileExist(File file) {
        if (null != file) {
            if (file.exists()) {
                return true;
            }
        }
        return false;
    }
}

2022年11月1日------------------------------------------------------------------------------------------------------------

添加需要的jar包资源:javawindows桌面程序,显示usb相机预览需要的库-桌面系统文档类资源-CSDN文库

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zzhceo/article/details/124381189

智能推荐

linux c之syscall使用例子_linux futex syscall-程序员宅基地

文章浏览阅读8.6k次。#include extern char **__environ; /* pointer to array of char * strings that define the current environment variables */extern int errno;extern char _end, _edata, _etext, __executable_start;in_linux futex syscall

电信光猫DDNS的设置经历-程序员宅基地

文章浏览阅读1.9w次。最近换了个中兴F650A的网关,上网、电话等都设置好了,花生壳的DDNS弄了很久都没弄好,记录一下过程,也给遇到类似情况的朋友提个醒。设置按默认的参数就可以了,如下图:刚开始弄了很久,卡在输入的主机名保存后,切换其它界面,再回去主机名又被清空了,也没有任何提示信息,反复试了多次都这样,网上搜索了很久也没找到什么有用的信息。后来无意中用 sendcmd 1 DB p DDNSClient 查看配置参数时发现有个 “Status”的字段有个认证错误之类的信息,再联想起花生壳主页上似乎看到过有需要实名认证,没_光猫ddns

fragment类onresume里面刷新操作处理-程序员宅基地

文章浏览阅读392次。今天项目中涉及fragment中嵌套多个fragment,但是要根据tag去展示对应的fragment,而不是默认展示的第一个fragment,如果使用activity很容易想到onpause(),onResume()中进行处理,但是你会发现fragment的onpause和onresume只调用一次,因此,需要通过重写onHiddenChanged来进行处理,该方法当fragment隐..._onresume 刷新数据源,怎么优化

前端HTML5+CSS3静态页面开发-博文尚美_博文尚美网站-程序员宅基地

文章浏览阅读7.8k次,点赞50次,收藏133次。前端html5+css3静态页面开发-博文尚美项目介绍博文尚美是一个设计网站, 此项目由html + css 布局完成页面,对前端基础知识的入门及掌握有非常好的提升效果,对html和css的使用及布局的体验能够建立起强大的信心。项目相关知识点HTML + CSS盒子模型 + 浮动 + 定位部分H5标签和C3属性项目演示图实现步骤1.在新建 index.html 中,创建基本框架,在标签里面使用标签引入 index.css。2.清除 css 默认样式,添加预设样式。代码如下:_博文尚美网站

oracle-listagg()函数实现列转行_oracle 列转行分隔符为换行符-程序员宅基地

文章浏览阅读1.5k次。oracle-listagg()函数实现列转行_oracle 列转行分隔符为换行符

Tkinter--Button和Scale样例_x *= self.scale_-程序员宅基地

文章浏览阅读3.1k次。#-*- coding: utf-8 -*-"""按扭操作"""import Tkinterclass Application(Tkinter.Frame): count = 0 def __init__(self, master=None): Tkinter.Frame.__init__(self, master)_x *= self.scale_

随便推点

前端学习笔记 // 设置背景颜色铺满页面以及去掉页面滚动条_前端铺满-程序员宅基地

文章浏览阅读893次。1.设置背景颜色铺满页面该点可参考以下文章:css如何让height:100%起作用?简单来说,就是如果你想让一个元素铺满页面,既设置 height:100%,那么你需要给这个元素的所有父元素的高度都设定一个有效值。因为浏览器在根据百分比来计算一个元素的高度时,需要先获取其父元素的高度,进而计算该元素的高度。<head> <style> html,body{ ..._前端铺满

mongoose对MongoDB数据库的增删查改-程序员宅基地

文章浏览阅读475次。专业课上,老师经常告诉我们,数据库的操作无非就是增删查改,即CURD,事实也正是如此,我们接下来看看mongoose操作no SQL数据库MongoDB的CURD。常见操作条件和API常见的查询条件$or 或关系 $nor 或关系取反$gt 大于$gte 大于等于$lt 小于$lte 小于等于$ne 不等于$in 在多个值范围内$nin 不在多个值范围内$all 匹配数组..._mongose 修改mongodb

python 1110: 最近共同祖先(函数专题)_cornell python 1110-程序员宅基地

文章浏览阅读134次。def common(x,y):if x==y:return xelif x>y:return common(x//2,y)else:return common(x,y//2)a,b=map(int,input().split())print(common(a,b))_cornell python 1110

ip地址转换省市_ip地址转省市区-程序员宅基地

文章浏览阅读1.1w次。前言最近开发一个支付系统,为了避免上游风控(路由规则限制),需要根据请求ip解析到对应物理地域信息,从而匹配到对应的地域商户,解决跨域消费问题。即将线上消费包装成线下消费。实例:支付宝线下商户不能线上交易。可用的api接口淘宝http://ip.taobao.com/service/getIpInfo.php?ip=61.183.230.xx{"code":0,"data":{"ip":"61.1..._ip地址转省市区

torch.load()加载模型时报错_torch.load('tensor.pt')加载出错-程序员宅基地

文章浏览阅读1.1w次,点赞6次,收藏3次。torch.load()加载模型时出现如下错误Traceback (most recent call last): File "demo_syncnet.py", line 26, in <module> s.loadParameters(opt.initial_model); File "/media/cj/75bb371d-0b6d-4995-bb72-060a4..._torch.load('tensor.pt')加载出错

ASP.Net TextBox 只读(ReadOnly)时后台不能赋值取值_asp.net后台文本框只读-程序员宅基地

文章浏览阅读801次。当把ASP.Net的自带控件TextBox设置为只读时,后台无法正常取值(取到的结果为“”)。解决办法如下:1. 不设置ReadOnly属性,添加事件onfocus=this.blur() 2、设置了ReadOnly属性后,通过Request来取值,如下:string Text = Request.Form["TextBox1"].Trim(); 3、在Pa_asp.net后台文本框只读

推荐文章

热门文章

相关标签