原 薦 Java基於百度AI+JavaCV+OpenCV 實現攝像頭人數動態統計
【Java】人流量統計-動態版之視訊轉圖識別請訪問 http://ai.baidu.com/forum/topic/show/940413
本文是基於上一篇進行迭代的。本文主要是以攝像頭畫面進行人流量統計。並對返回影象進行展示。需要額外瞭解 JavaCV OpenCV swing awt等
也許JavaCV OpenCV 不需要也可以實現效果。但是小帥丶就先用這樣的方式實現了。別的方式大家就自己嘗試吧
專案程式碼地址 https://gitee.com/xshuai/bodyTrack
- 注意的問題
1.動態識別的area引數為矩陣的4個頂點的xy座標(即畫素) 順序是 上左下右 也就是順時針一圈4個點的座標點 2.case_init 為int 請不要給大於int範圍的值。或非int型別的值 即正整數就行 3.area的值不要大於圖片本身的寬高
- 需要用到的jar 通過maven引入(下載的jar較多。需要等待較長時間)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <ffmpeg.version>3.2.1-1.3</ffmpeg.version> <javacv.version>1.4.1</javacv.version> </properties> <dependencies> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>ffmpeg-platform</artifactId> <version>${ffmpeg.version}</version> </dependency> <!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.35</version> </dependency> <dependency> <groupId>org.bytedeco</groupId> <artifactId>javacv</artifactId> <version>${javacv.version}</version> </dependency> <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>opencv-platform</artifactId> <version>3.4.1-1.4.1</version> </dependency> </dependencies>
- 需要用到的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 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 = "true"; String area = "10,10,630,10,630,470,10,469"; String 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; } }
- 攝像頭中的內容截圖示意(本人頭像就不直接顯示了。萬一嚇著大家呢) 也不要用去馬賽克的技術還原圖片哦。
還是很好玩的、不需要自己去整OpenCV一套就能實現統計攝像頭中的人數。
