Java基于百度AI+JavaCV+OpenCV 实现摄像头人数动态统计

Wesley13
• 阅读 648

Java基于百度AI+JavaCV+OpenCV 实现摄像头人数动态统计

【Java】人流量统计-动态版之视频转图识别请访问 http://ai.baidu.com/forum/topic/show/940413

本文是基于上一篇进行迭代的。本文主要是以摄像头画面进行人流量统计。并对返回图像进行展示。需要额外了解JavaCV OpenCV swing awt等

也许JavaCV OpenCV  不需要也可以实现效果。但是小帅丶就先用这样的方式实现了。别的方式大家就自己尝试吧

有可能显示的in out不对。请设置帧率试试。鄙人不是专业的。所以对帧率也不是很懂。以下代码加入也没有明显的变化。

grabber.setFrameRate(10);
grabber.setFrameNumber(10);

项目代码地址 https://gitee.com/xshuai/bodyTrack

  • 注意的问题

    1.动态识别的area参数为矩阵的4个顶点的xy坐标(即像素) 顺序是 上左下右 也就是顺时针一圈4个点的坐标点 2.case_id 为int 请不要给大于int范围的值。或非int类型的值 即正整数就行 3.area的值不要大于图片本身的宽高

  • 需要用到的jar 通过maven引入(下载的jar较多。需要等待较长时间)

    UTF-8 1.8 1.8 3.2.1-1.3 1.4.1 org.bytedeco.javacpp-presets ffmpeg-platform ${ffmpeg.version} com.alibaba fastjson 1.2.35 org.bytedeco javacv ${javacv.version}
    <dependency>
        <groupId>org.bytedeco.javacpp-presets</groupId>
        <artifactId>opencv-platform</artifactId>
        <version>3.4.1-1.4.1</version>
    </dependency>
    
  • 需要用到的Java工具类

HttpUtil https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
  • 调用接口示例代码(需要自己的电脑有摄像头哦)

    import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.WritableRaster; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.net.URLEncoder; import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder;

    import javax.imageio.ImageIO; import javax.swing.JFrame;

    import org.bytedeco.javacpp.BytePointer; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacv.CanvasFrame; import org.bytedeco.javacv.Frame; import org.bytedeco.javacv.Java2DFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter; import org.bytedeco.javacv.OpenCVFrameConverter.ToIplImage; import org.bytedeco.javacv.OpenCVFrameGrabber;

    import com.alibaba.fastjson.JSONObject;

    import cn.xsshome.body.util.HttpUtil; /**

    • 获取摄像头画面进行处理并回显图片在画面中
    • 人流量统计(动态版)JavaAPI示例代码
    • @author 小帅丶

    */ public class JavavcCameraTest {

    static OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
    //人流量统计(动态版)接口地址
    private static String BODY_TRACKING_URL="https://aip.baidubce.com/rest/2.0/image-classify/v1/body_tracking";
    
    private static String ACCESS_TOKEN ="";//接口的token
    /**
     * 每个case的初始化信号,为true时对该case下的跟踪算法进行初始化,为false时重载该case的跟踪状态。当为false且读取不到相应case的信息时,直接重新初始化
     * caseId=0 第一次请求  case_init=true  caseId>0 非第一次请求  case_init=false
     */
    static int caseId = 0;
    public static void main(String[] args) throws Exception,
            InterruptedException {
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        grabber.start(); // 开始获取摄像头数据
        CanvasFrame canvas = new CanvasFrame("人流量实时统计");// 新建一个窗口
        canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas.setAlwaysOnTop(true);
        int ex = 0;
        while (true) {
            if (!canvas.isDisplayable()) {// 窗口是否关闭
                grabber.stop();// 停止抓取
                System.exit(2);// 退出
                grabber.close();
            }
            // canvas.showImage(grabber.grab());//显示摄像头抓取的画面
            Java2DFrameConverter java2dFrameConverter = new Java2DFrameConverter();
            // 摄像头抓取的画面转BufferedImage
            BufferedImage bufferedImage = java2dFrameConverter.getBufferedImage(grabber.grabFrame());
            // bufferedImage 请求API接口 检测人流量
            String result = getBodyTrack(bufferedImage);
            BufferedImage bufferedImageAPI = getAPIResult(result);
            // 如果识别为空 则显示摄像头抓取的画面
            if (null == bufferedImageAPI) {
                canvas.showImage(grabber.grab());
            } else {
                // BufferedImage转IplImage
                IplImage iplImageAPI = BufImgToIplData(bufferedImageAPI);
                // 将IplImage转为Frame 并显示在窗口中
                Frame convertFrame = converter.convert(iplImageAPI);
                canvas.showImage(convertFrame);
            }
            ex++;
    

    // Thread.sleep(100);// 100毫秒刷新一次图像.因为接口返回需要时间。所以看到的画面还是会有一定的延迟 } } /** * BufferedImage转IplImage * @param bufferedImageAPI * @return / private static IplImage BufImgToIplData(BufferedImage bufferedImageAPI) { IplImage iplImage = null; ToIplImage iplConverter = new OpenCVFrameConverter.ToIplImage(); Java2DFrameConverter java2dConverter = new Java2DFrameConverter(); iplImage = iplConverter.convert(java2dConverter.convert(bufferedImageAPI)); return iplImage; } /* * IplImage 转 BufferedImage * @param mat * @return BufferedImage / public static BufferedImage iplToBufImgData(IplImage mat) { if (mat.height() > 0 && mat.width() > 0) { //TYPE_3BYTE_BGR 表示一个具有 8 位 RGB 颜色分量的图像,对应于 Windows 风格的 BGR 颜色模型,具有用 3 字节存储的 Blue、Green 和 Red 三种颜色。 BufferedImage image = new BufferedImage(mat.width(), mat.height(),BufferedImage.TYPE_3BYTE_BGR); WritableRaster raster = image.getRaster(); DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer(); byte[] data = dataBuffer.getData(); BytePointer bytePointer = new BytePointer(data); mat.imageData(bytePointer); return image; } return null; } /* * 接口结果转bufferimage * @param result * @return BufferedImage * @throws Exception */ private static BufferedImage getAPIResult(String result) throws Exception { JSONObject object = JSONObject.parseObject(result); BufferedImage bufferedImage = null; if(object.getInteger("person_num")>=1){ Decoder decoder = Base64.getDecoder(); byte [] b = decoder.decode(object.getString("image")); ByteArrayInputStream in = new ByteArrayInputStream(b);
    bufferedImage = ImageIO.read(in);

            ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
            ImageIO.write(bufferedImage,"jpg", baos); 
             byte[] imageInByte = baos.toByteArray(); 
            // Base64解码
            for (int i = 0; i < imageInByte.length; ++i) {
                if (imageInByte[i] < 0) {// 调整异常数据
                    imageInByte[i] += 256;
                }
             }
             OutputStream out = new FileOutputStream("G:/testimg/xiaoshuairesult.jpg");//接口返回的渲染图
             out.write(imageInByte);
             out.flush();
             out.close();
            return bufferedImage;
        }else{
            return null;
        }
    }
    /**
     * 获取接口处理结果图
     * @param bufferedImage
     * @return String
     * @throws Exception
     */
    public static String getBodyTrack(BufferedImage bufferedImage) throws Exception{
         ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
         ImageIO.write(bufferedImage,"jpg",baos); 
         byte[] imageInByte = baos.toByteArray(); 
         Encoder base64 = Base64.getEncoder();
         String imageBase64 = base64.encodeToString(imageInByte);
        // Base64解码
        for (int i = 0; i < imageInByte.length; ++i) {
            if (imageInByte[i] < 0) {// 调整异常数据
                imageInByte[i] += 256;
            }
         }
         // 生成jpeg图片
         OutputStream out = new FileOutputStream("G:/testimg/xiaoshuai.jpg");// 新生成的图片
         out.write(imageInByte);
         out.flush();
         out.close();
         System.out.println("保存成功");  
         baos.flush();       
         baos.close();
         String access_token = ACCESS_TOKEN;
                String case_id = "2018";
         String case_init = "";
         String area = "10,10,630,10,630,470,10,469";
         String params = "";
         if(caseId==0){
            case_init = "true";
            params = "image=" + URLEncoder.encode(imageBase64, "utf-8")
                     + "&dynamic=true&show=true&case_id=" + case_id
                     + "&case_init="+case_init +"&area="+area;
         }else{
             case_init = "false";
             params = "image=" + URLEncoder.encode(imageBase64, "utf-8")
                     + "&dynamic=true&show=true&case_id=" + case_id
                     + "&case_init="+case_init +"&area="+area; 
         }
         //静态识别
    

    // String params = "image=" + URLEncoder.encode(imageBase64, "utf-8")+"&dynamic=false&show=true"; String result = HttpUtil.post(BODY_TRACKING_URL, access_token, params); System.out.println("接口内容==>"+result); return result; } /** * IplImage 转 BufferedImage * @param mat * @return BufferedImage */ public static BufferedImage bufferimgToBase64(IplImage mat) { if (mat.height() > 0 && mat.width() > 0) { BufferedImage image = new BufferedImage(mat.width(), mat.height(),BufferedImage.TYPE_3BYTE_BGR); WritableRaster raster = image.getRaster(); DataBufferByte dataBuffer = (DataBufferByte) raster.getDataBuffer(); byte[] data = dataBuffer.getData(); BytePointer bytePointer = new BytePointer(data); mat.imageData(bytePointer); return image; } return null; } }

  • 摄像头中的内容截图示意(本人头像就不直接显示了。万一吓着大家呢) 也不要用去马赛克的技术还原图片哦。

Java基于百度AI+JavaCV+OpenCV 实现摄像头人数动态统计

还是很好玩的、不需要自己去整OpenCV一套就能实现统计摄像头中的人数。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
Java爬虫之JSoup使用教程
title:Java爬虫之JSoup使用教程date:201812248:00:000800update:201812248:00:000800author:mecover:https://imgblog.csdnimg.cn/20181224144920712(https://www.oschin
Wesley13 Wesley13
2年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
2年前
P2P技术揭秘.P2P网络技术原理与典型系统开发
Modular.Java(2009.06)\.Craig.Walls.文字版.pdf:http://www.t00y.com/file/59501950(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.t00y.com%2Ffile%2F59501950)\More.E
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Docker 部署SpringBoot项目不香吗?
  公众号改版后文章乱序推荐,希望你可以点击上方“Java进阶架构师”,点击右上角,将我们设为★“星标”!这样才不会错过每日进阶架构文章呀。  !(http://dingyue.ws.126.net/2020/0920/b00fbfc7j00qgy5xy002kd200qo00hsg00it00cj.jpg)  2
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这