【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一套就能實現統計攝像頭中的人數。