未验证 提交 4b455178 编写于 作者: W wangqun 提交者: GitHub

Merge pull request #1 from wangqunbaidu/master

[D][feature]paddleJS提交代码仓库
[中文版](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/web/README_cn.md)
# Web
Web project is an open source deep learning framework designed to work on web browser. It could run on nearly every browser with WebGL support.
## Key Features
### Modular
Web project is built on Atom system which is a versatile framework to support GPGPU operation on WebGL. It is quite modular and could be used to make computation tasks faster by utilizing WebGL.
### High Performance
Web project could run TinyYolo model in less than 30ms on chrome. This is fast enough to run deep learning models in many realtime scenarios.
### Browser Coverage
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
## How To Build & Deploy Demo
```bash
cd web # enter root directory for web project
npm i # install dependencies for npm
mkdir dist # create deployment directory
cd dist # enter deployment directory
git clone https://github.com/DerekYangMing/Paddle-Web-Models.git # get models
mv Paddle-Web-Models/separablemodel . # move models to specific directory
cd .. # return to root directory for web project
npm run testVideoDemo # start demo
```
## How To Preview Demo
1. Open chrome with url: https://localhost:8123/
2. Start demo by pressing the 【start detection】 button.
3. Ensure at least one face is recorded by the camera. The face detection rectangle should be displayed if everything goes fine.
## Feedback and Community Support
- Questions, reports, and suggestions are welcome through Github Issues!
- Forum: Opinions and questions are welcome at our [PaddlePaddle Forum](https://ai.baidu.com/forum/topic/list/168)
- QQ group chat: 696965088
# Paddle-JS [中文版](https://github.com/PaddlePaddle/Paddle-Lite/blob/develop/web/README_cn.md)
\ No newline at end of file
# Web
Paddle.js is an Web project for Baidu Paddle, which is an an open source deep learning framework designed to work on web browser. Load a pretrained paddle.js SavedModel or Paddle Hub module into the browser and run inference through Paddle.js. It could run on nearly every browser with WebGL support.
## Key Features
### Modular
Web project is built on Atom system which is a versatile framework to support GPGPU operation on WebGL. It is quite modular and could be used to make computation tasks faster by utilizing WebGL.
### High Performance
Web project could run TinyYolo model in less than 30ms on chrome. This is fast enough to run deep learning models in many realtime scenarios.
### Browser Coverage
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
### Supported operations
Currently Paddle.js only supports a limited set of Paddle Ops. See the full list. If your model uses unsupported ops, the Paddle.js script will fail and produce a list of the unsupported ops in your model. Please file issues to let us know what ops you need support with.
[Supported operations Pages](./src/factory/fshader/README.md)
## Loading and running in the browser
If the original model was a SavedModel, use paddle.load().
```bash
import * as tf from 'paddlejs';
let feed = io.process({
input: document.getElementById('image'),
params: {
gapFillWith: '#000', // What to use to fill the square part after zooming
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // Target shape changed its name to be compatible with previous logic
// shape: [3, 608, 608], // Preset sensor shape
mean: [117.001, 114.697, 97.404], // Preset mean
// std: [0.229, 0.224, 0.225] // Preset std
}
});
const MODEL_CONFIG = {
dir: `/${path}/`, // model URL
main: 'model.json', // main graph
};
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: true,
dataType: 'binary',
options: {
fileCount: 1, // How many model have been cut
getFileName(i) {
return 'chunk_' + i + '.dat';
}
}
}
});
model = await paddle.load();
//
let inst = model.execute({
input: feed
});
// There should be a fetch execution call or a fetch output
let result = await inst.read();
```
Please see feed documentation for details.
Please see fetch documentation for details.
## Run the converter script provided by the pip package:
The converter expects a Paddlejs SavedModel, Paddle Hub module, Tpaddle.js JSON format for input.
## Web-friendly format
The conversion script above produces 2 types of files:
- model.json (the dataflow graph and weight manifest file)
- group1-shard\*of\* (collection of binary weight files)
## Preview Demo
Paddle.js has some pre-converted models to Paddle.js format .There are some demos in the following URL, open a browser page with the demo.
[Supported Demo Pages](./examples/README.md)
## Feedback and Community Support
- Questions, reports, and suggestions are welcome through Github Issues!
- Forum: Opinions and questions are welcome at our [PaddlePaddle Forum](https://ai.baidu.com/forum/topic/list/168)
- QQ group chat: 696965088
# PaddleJS Examples
百度PaddleJS使用现成的或者通过转换工具转换的 JavaScript 友好的paddle模型以在浏览器中运行,在浏览器中实现在线推理能力。
## 演示
目前Web项目运行TinyYolo模型可以达到30ms以内,对于一般的实时场景已经足够应对。
### 模块化
## 浏览器覆盖面
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
## 构建部署
```bash
cd web # 进入根目录
npm i # 安装依赖
mkdir dist # 创建资源目录
cd dist # 进入资源目录
git clone https://github.com/DerekYangMing/Paddle-Web-Models.git # 获取模型
mv Paddle-Web-Models/separablemodel . # 移动模型到制定地点
cd .. # 返回根目录
npm run tinyYolo # 启动 tinyYolo 在线推理服务
```
## 如何预览 demo
1. 在浏览器中打开url: https://localhost:8123/
2. 点击【开始检测】按钮。
3. 将人脸对准摄像头,没有问题的话,可以正常检测到人脸。
## 效果
![image](./tinyYolo/demoshow.png)
# Web
该Web项目是致力于在浏览器中运行的开源深度学习框架,在支持WebGL的浏览器上即可直接运行。
## 主要特点
### 模块化
该Web项目建立于Atom组件之上。Atom组件在WebGL基础上进行了封装,可以方便的进行通用GPU计算任务。它是高度模块化的,不仅可以用于本项目,也可以用于其它的WebGL加速场景。
### 高性能
目前Web项目运行TinyYolo模型可以达到30ms以内,对于一般的实时场景已经足够应对。
### 浏览器覆盖面
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
## 如何构建部署 demo
```bash
cd web # 进入根目录
npm i # 安装依赖
mkdir dist # 创建资源目录
cd dist # 进入资源目录
git clone https://github.com/DerekYangMing/Paddle-Web-Models.git # 获取模型
mv Paddle-Web-Models/separablemodel . # 移动模型到制定地点
cd .. # 返回根目录
npm run testVideoDemo # 启动 demo 服务
```
## 如何预览 demo
1. 在浏览器中打开url: https://localhost:8123/
2. 点击【开始检测】按钮。
3. 将人脸对准摄像头,没有问题的话,可以正常检测到人脸。
## 交流与反馈
* 欢迎您通过Github Issues来提交问题、报告与建议
* QQ群: 696965088
* 论坛: 欢迎大家在[PaddlePaddle论坛](https://ai.baidu.com/forum/topic/list/168)分享在使用PaddlePaddle中遇到的问题和经验, 营造良好的论坛氛围
[中文版](./README_cn.md)
# PaddleJS Examples
Baidu paddlejs uses the ready-made JavaScript model or transforms the paddle model to run in the browser.
## Demonstration
At present, tiny Yolo model can run within 30ms for web project, which is enough for general real-time scenarios.
## Browser coverage
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
## Building deployment
```bash
cd web # Go to root
npm i # Installation dependency
mkdir dist # Create resource directory
cd dist # Enter resource directory
git clone https://github.com/DerekYangMing/Paddle-Web-Models.git # Get models
mv Paddle-Web-Models/separablemodel . # Move the model to the designated location
cd .. # Root directory
npm run tinyYolo # run tinyYolo
```
## Preview
1. Open url: https://localhost:端口号/
2. Click the upload picture button。
## Result
![image](./tinyYolo/demoshow.png)
# PaddleJS Examples
百度PaddleJS使用现成的 JavaScript 模型或转换 Paddle 模型以在浏览器中运行。
## 演示
目前Web项目运行TinyYolo模型可以达到30ms以内,对于一般的实时场景已经足够应对。
### 模块化
## 浏览器覆盖面
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
## 构建部署
```bash
cd web # 进入根目录
npm i # 安装依赖
mkdir dist # 创建资源目录
cd dist # 进入资源目录
git clone https://github.com/DerekYangMing/Paddle-Web-Models.git # 获取模型
mv Paddle-Web-Models/separablemodel . # 移动模型到制定地点
cd .. # 返回根目录
npm run tinyYolo # 启动 tinyYolo 在线推理服务
```
## 如何预览 demo
1. 在浏览器中打开url: https://localhost:端口号/
2. 点击【开始检测】按钮。
3. 将人脸对准摄像头,没有问题的话,可以正常检测到人脸。
## 效果
![image](./tinyYolo/demoshow.png)
import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle';
import IO from '../../src/feed/imageFeed';
import Utils from '../../src/utils/utils';
// 获取map表
import Map from '../../test/data/map';
/**
* @file model demo 入口文件
* @author wangqun@baidu.com
*
*/
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'separate': {
fw: 320,
fh: 320
}
};
const modelType = 'separate';
const {fw, fh} = feedShape[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
async function run(input) {
// const input = document.getElementById('mobilenet');
const io = new IO();
let feed = io.process({
input: input,
params: {
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
scale: 256, // 缩放尺寸
width: 224, height: 224, // 压缩宽高
shape: [3, 224, 224], // 预设tensor形状
mean: [0.485, 0.456, 0.406], // 预设期望
std: [0.229, 0.224, 0.225] // 预设方差
}});
console.dir(['feed', feed]);
const path = 'model/huangfan';
if (!loaded) {
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: false,
dataType: 'json'
}
});
model = await paddle.load();
}
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
console.dir(['result', result]);
let maxItem = Utils.getMaxItem(result);
document.getElementById('txt').innerHTML = Map['' + maxItem.index];
console.log('识别出的结果是' + Map['' + maxItem.index]);
// console.dir(['每个op耗时', window.statistic]);
// let total = statistic.reduce((all, cur) => {
// return all + cur.runTime;
// }, 0);
// console.log('op total = ' + total);
}
var image = '';
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
let reader = new FileReader();
reader.onload = function (evt) {
let img = document.getElementById('image');
img.src = evt.target.result;
img.onload = function () {
run(img);
};
image = evt.target.result;
};
reader.readAsDataURL(file.files[0]);
}
// selectImage
document.getElementById('uploadImg').onchange = function () {
selectImage(this);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>paddle web demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
</head>
<body>
<img id="image" src="https://m.baidu.com/se/static/img/iphone/logo.png" style="max-width: 100%;">
<input type="file" id="uploadImg">
<div id="txt"></div>
<script src="index.es6"></script>
</body>
</html>
\ No newline at end of file
import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle';
import IO from '../../src/feed/imageFeed';
/**
* @file model demo mnist 入口文件
* @author wangqun@baidu.com
*
*/
const pic = document.getElementById('pic');
const io = new IO();
let model = {};
async function run() {
let feed = io.process({
input: pic,
params: {
targetShape: [1, 3, 320, 320], // 目标形状 为了兼容之前的逻辑所以改个名
scale: 256, // 缩放尺寸
width: 224, height: 224, // 压缩宽高
shape: [3, 224, 224], // 预设tensor形状
mean: [0.485, 0.456, 0.406], // 预设期望
std: [0.229, 0.224, 0.225] // 预设方差
}});
console.dir(['feed', feed]);
const path = 'model/mnist';
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: false,
dataType: 'json'
}
});
model = await paddle.load();
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
// let inst = model.execute({input: cat});
// let res = inst.read();
console.dir(['result', result]);
// var fileDownload = require('js-file-download');
// fileDownload(res, 'result.csv');
}
run();
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>paddle web demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
</head>
<body>
<div>
<img id="pic" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAcABwBAREA/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEBAAA/APn+vTPDHwP8TeJ9DtdXiuLCzt7kbo0uWcOU7NgKRgjkc81i+O/hvrPgW8xco1zp7ELHfIm1HYqCRjJIPUc9cHFcbSgEnABJ9BXaafH8Rrrw3NpdjBrkmjohLQLE/l7c5OOPUHgV6Fcw3um/sxXNt4hZo7qW5X7FDdLtlRfOU7QG5zgSH/dPpXhFel/Bzxj4a8H6vfzeILZy86ILe6WLzPI27i3HUZ+XkA9PQ16Pc/Hfw7pM91LaXusa20wDRxSQRQww9eAdob35DfWuNg+Ny67Dfab430SDUNLuQxjW2UK8BwcAZPPOPmyCOvPSvH6KKKK//9k=" >
</div>
<script src="index.es6"></script>
</body>
</html>
import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle';
import IO from '../../src/feed/imageFeed';
import Utils from '../../src/utils/utils';
// 获取map表
import Map from '../../test/data/map';
/**
* @file model demo 入口文件
* @author wangqun@baidu.com
*
*/
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'separate': {
fw: 244,
fh: 244
}
};
const modelType = 'separate';
const {fw, fh} = feedShape[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
async function run(input) {
// const input = document.getElementById('mobilenet');
const io = new IO();
let feed = io.process({
input: input,
params: {
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
scale: 256, // 缩放尺寸
width: 224, height: 224, // 压缩宽高
shape: [3, 224, 224], // 预设tensor形状
mean: [0.485, 0.456, 0.406], // 预设期望
std: [0.229, 0.224, 0.225] // 预设方差
}});
console.log('feed', feed);
const path = 'model/mobileNet';
if (!loaded) {
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: true,
dataType: 'json'
}
});
model = await paddle.load();
}
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
console.dir(['result', result]);
// let maxItem = Utils.getMaxItem(result);
// document.getElementById('txt').innerHTML = Map['' + maxItem.index];
// console.log('识别出的结果是' + Map['' + maxItem.index]);
// console.dir(['每个op耗时', window.statistic]);
// let total = statistic.reduce((all, cur) => {
// return all + cur.runTime;
// }, 0);
// console.log('op total = ' + total);
};
var image = '';
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
let reader = new FileReader();
reader.onload = function (evt) {
let img = document.getElementById('image');
img.src = evt.target.result;
img.onload = function() {
run(img);
};
image = evt.target.result;
}
reader.readAsDataURL(file.files[0]);
}
// selectImage
document.getElementById("uploadImg").onchange = function () {
selectImage(this);
};
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>paddle web demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
</head>
<body>
<img id="image" src="https://m.baidu.com/se/static/img/iphone/logo.png" style="max-width: 100%;">
<input type="file" id="uploadImg">
<div id="txt"></div>
<script src="index.es6"></script>
</body>
</html>
\ No newline at end of file
export default class Camera {
constructor(option) {
this.video = option.videoDom;
this.videoOption = option.videoOption;
}
// 访问用户媒体设备的兼容方法
getUserMedia(constraints, success, error) {
if (navigator.mediaDevices.getUserMedia) {
// 最新的标准API
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
}
else if (navigator.webkitGetUserMedia) {
// webkit核心浏览器
navigator.webkitGetUserMedia(constraints, success, error);
}
else if (navigator.mozGetUserMedia) {
// firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
}
else if (navigator.getUserMedia) {
// 旧版API
navigator.getUserMedia(constraints, success, error);
}
}
success(stream) {
// 兼容webkit核心浏览器
let CompatibleURL = window.URL || window.webkitURL;
// 将视频流设置为video元素的源
// video.src = CompatibleURL.createObjectURL(stream);
this.video.srcObject = stream;
this.video.play();
}
error(error) {
console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
}
run() {
if (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.mediaDevices.getUserMedia) {
// 调用用户媒体设备, 访问摄像头
this.getUserMedia(this.videoOption, this.success.bind(this), this.error);
}
else {
alert('不支持访问用户媒体');
}
}
get curVideo() {
return this.video;
}
}
import 'babel-polyfill';
import Graph from '../../src/executor/loader';
import IO from '../../src/feed/imageFeed';
import Logger from '../../tools/logger';
window.log = new Logger();
// 统计参数
window.badCases = [];
// import Utils from '../src/utils/utils';
// 获取map表
// import Map from '../test/data/map';
// import demoPic from './bbt1.jpg';
// import demoPic2 from './bbt2.jpg';
// import demoPic3 from './bbt3.jpg';
// import demoPic4 from './bbt4.jpg';
// import demoPic5 from './bbt5.jpg';
// 后处理测试用例
// let tempPic = [demoPic, demoPic2, demoPic3, demoPic4, demoPic5];
/**
* @file model demo 入口文件
* @author wangqun@baidu.com
*
*/
// 模型输出shape
const outputShapes = {
'608': {
from: [19, 19, 25, 1],
to: [19, 19, 5, 5]
},
'320': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'320fused': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
}
};
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
}
};
// 模型路径
const modelPath = {
'608': 'faceModel',
'320': 'facemodel320',
'320fused': 'facemodelfused'
};
const modelType = '320fused';
const path = modelPath[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
const {fw, fh} = feedShape[modelType];
// 第一遍执行比较慢 所以预热一下
async function preheat() {
const io = new IO();
let feed = io.process({
input: video,
params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404], // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差
}
});
const MODEL_URL = `/${path}/model.json`;
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const graphModel = new Graph();
log.start('加载模型');
model = await graphModel.loadGraphModel(MODEL_CONFIG, {
multipart: true,
dataType: 'binary',
binaryOption: {
fileCount: 1, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_0.dat';
}
},
feed
});
log.end('加载模型');
let inst = model.execute({
input: feed
});
};
async function run(input) {
// const input = document.getElementById('mobilenet');
log.start('总耗时');
const io = new IO();
log.start('预处理');
let feed = io.process({
input: input,
params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404], // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差
}
});
log.end('预处理');
if (!loaded) {
const MODEL_URL = `/${path}/model.json`;
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const graphModel = new Graph();
log.start('加载模型');
model = await graphModel.loadGraphModel(MODEL_CONFIG, {
multipart: true,
dataType: 'binary',
binaryOption: {
fileCount: 1, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_0.dat';
}
},
feed
});
log.end('加载模型');
}
log.start('运行耗时');
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
log.end('后处理-读取数据');
// console.dir(['result', result]);
log.start('后处理-形状调整');
const newData = [];
let newIndex = -1;
const [w, h, c, b] = outputShapes[modelType].from;
// c channel
for (let i = 0; i < c; i++) {
// height channel
for (let j = 0; j < h; j++) {
// width channel
for (let k = 0; k < w; k++) {
// position: (0, 0, 0, 0)
const index = j * (c * h) + k * c + i;
// const index = j * (i * k) + k * i + i;
newData[++newIndex] = result[index];
}
}
}
log.end('后处理-形状调整');
log.start('后处理-画框');
testRun(newData, input);
log.end('后处理-画框');
log.end('后处理');
log.end('总耗时');
};
var image = '';
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
let reader = new FileReader();
reader.onload = function (evt) {
let img = document.getElementById('image');
img.src = evt.target.result;
img.onload = function() {
log.during('每次执行的时间间隔');
run(img);
};
image = evt.target.result;
}
reader.readAsDataURL(file.files[0]);
};
// selectImage
document.getElementById("uploadImg").onchange = function () {
selectImage(this);
};
/* 后处理图片 by zhangmiao06 */
let preTestRun = (index) => {
let img = document.getElementById('image');
img.src = tempPic[index];
img.onload = function() {
testRun(testOutput.data[index], img);
};
};
let testRun = (data, img) => {
// console.log('ori', data);
const {from, to} = outputShapes[modelType];
// let shape = [1, 25, 19, 19];
let shape = [].concat(from).reverse();
// 1.从一维数组到1*25*19*19
let formatData = reshapeMany({
data: data,
reshapeShape: shape
});
// console.log('一维到多维', formatData);
// 2.从1*25*19*19 到 19*19*25*1
let formatData2 = transpose({
data: formatData,
shape: shape,
transposeShape: [2, 3, 1, 0]
});
// console.log('transpose', formatData2);
// 3.从19*19*25*1到19*19*5*5
let formatData3 = reshape({
data: formatData2,
shape: from,
reshapeShape: to
});
// console.log('reshape', formatData3);
// 4.运算
let finalData = handleFinal(formatData3, shape, img);
// console.log('final', finalData);
// 5.处理画布
// handleCanvas(finalData, img);
handleDiv(finalData, img);
};
// sigmoid
let sigmoid = (x) => {
if (x < -100) {
return 0.0;
}
return 1 / (1 + Math.exp(-x));
};
// transpose
let transpose = (data) => {
let shape = data.shape;
let transposeShape = data.transposeShape;
let formatData = data.data;
let formatData2 = [];
for(let n = 0; n < shape[transposeShape[0]]; n++) {
let nData = [];
for(let c = 0; c < shape[transposeShape[1]]; c++) {
let cData = [];
for(let row = 0; row < shape[transposeShape[2]]; row++) {
let rowData = [];
for(let col = 0; col < shape[transposeShape[3]]; col++) {
let tempArr = [n, c, row, col];
let newN = n;
let newC = c;
let newW = row;
let newH = col;
transposeShape.forEach((item, index)=> {
switch(item) {
case 0:
newN = tempArr[index];
break;
case 1:
newC = tempArr[index];
break;
case 2:
newW = tempArr[index];
break;
case 3:
newH = tempArr[index];
}
});
rowData.push(formatData[newN][newC][newW][newH]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData2.push(nData);
}
return formatData2;
};
// reshape
let reshape = (data) =>{
let formatData2 = data.data;
let shape = data.shape;
let reshapeShape = data.reshapeShape;
// 1.变成一维
let tempData = reshapeOne({
data: formatData2,
shape: shape
});
// 2.变成多维
let formatData3 = reshapeMany({
data: tempData,
reshapeShape: reshapeShape
});
return formatData3;
};
// 变成一维
let reshapeOne = (data) => {
let formatData2 = data.data;
let shape = data.shape;
let tempData = [];
for(let n = 0; n < shape[0]; n++) {
for(let c = 0; c < shape[1]; c++) {
for(let row = 0; row < shape[2]; row++) {
for(let col = 0; col < shape[3]; col++) {
tempData.push(formatData2[n][c][row][col]);
}
}
}
}
return tempData;
};
// 变成多维
let reshapeMany = (data) => {
let tempData = data.data;
let reshapeShape = data.reshapeShape;
let formatData3 = [];
for(let n = 0; n < reshapeShape[0]; n++) {
let nData = [];
for(let c = 0; c < reshapeShape[1]; c++) {
let cData = [];
for(let row = 0; row < reshapeShape[2]; row++) {
let rowData = [];
for(let col = 0; col < reshapeShape[3]; col++) {
let tempN = n * reshapeShape[1] * reshapeShape[2] * reshapeShape[3];
let tempC = c * reshapeShape[2] * reshapeShape[3];
let tempRow = row * reshapeShape[3];
rowData.push(tempData[tempN + tempC + tempRow + col]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData3.push(nData);
}
return formatData3;
};
let calSize = (img) => {
let w1 = img.width;
let h1 = img.height;
let wh1 = Math.max(w1, h1);
// let factor = 608.0 / wh1;
let factor = fw / wh1;
let width = Math.round(w1 * factor);
let height = Math.round(h1 * factor);
return [w1, h1, width, height];
};
// 处理运算
let handleFinal = (formatData3, shape, img) => {
let finalData = [];
let c = shape[2];
let [w1, h1, width, height] = calSize(img);
let factorX = Math.max(width, height) / width;
let factorY = Math.max(width, height) / height;
let maxProb = 0.0;
let anchors = [[1.603231, 2.094468], [6.041143, 7.080126], [2.882459, 3.518061], [4.266906, 5.178857], [9.041765, 10.66308]];
for(let i = 0; i < shape[2]; i++) {
for(let j = 0; j < shape[3]; j++) {
for(let k = 0; k < anchors.length; k++) {
let [a1, a2, a3, a4, prob] = formatData3[i][j][k];
prob = sigmoid(prob);
if (prob > maxProb && prob >= 0.5) {
let ctx = (j + sigmoid(a1)) / c * factorX;
let cty = (i + sigmoid(a2)) / c * factorY;
let col = Math.exp(a3) * anchors[k][0] / c * factorX;
let row = Math.exp(a4) * anchors[k][1] / c * factorY;
let x = (ctx - (col / 2));
let y = (cty - (row / 2));
finalData.push([x * w1, y * h1, col * w1, row * h1, prob]);
}
}
}
}
return finalData;
};
// 处理画布
let handleCanvas = (finalData, img) => {
let myCanvas = document.getElementById('myCanvas');
let [w1, h1, width, height] = calSize(img);
myCanvas.width = w1;
myCanvas.height = h1;
let ctx = myCanvas.getContext('2d');
ctx.drawImage(img, 0, 0, w1, h1);
finalData.forEach((demoArr,index) => {
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = demoArr;
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.moveTo(demoLeft, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop + demoHeight);
ctx.lineTo(demoLeft, demoTop + demoHeight);
ctx.closePath();
ctx.stroke();
});
};
let handleDiv = (finalData, img) => {
if (finalData.length < 1) {
return false;
}
let myCanvas = document.getElementById('myDiv');
let maxIndex = 0;
if (finalData.length > 1) {
for(let i = 1; i < finalData.length; i++) {
if (finalData[i].prob > finalData[maxIndex].prob) {
maxIndex = i;
}
}
}
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = finalData[maxIndex];
myCanvas.style.width = demoWidth;
myCanvas.style.height = demoHeight;
myCanvas.style.left = demoLeft;
myCanvas.style.top = demoTop;
};
// preTestRun(0);
// run(document.getElementById('pic'));
// import VConsole from 'vconsole';
import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle';
import IO from '../../src/feed/imageFeed';
// import Logger from '../../tools/logger';
// window.log = new Logger();
// // 统计参数
// window.badCases = [];
// 后处理测试用例
// let tempPic = [demoPic, demoPic2, demoPic3, demoPic4, demoPic5];
/**
* @file model demo 入口文件
* @author wangqun@baidu.com
*
*/
// 模型输出shape
const outputShapes = {
'608': {
from: [19, 19, 25, 1],
to: [19, 19, 5, 5]
},
'320': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'320fused': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'tinyYolo': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
}
};
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'tinyYolo': {
fw: 320,
fh: 320
}
};
// 模型路径
const modelPath = {
'tinyYolo': 'model/tinyYolo'
};
const modelType = 'tinyYolo';
const path = modelPath[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
const {fw, fh} = feedShape[modelType];
// 第一遍执行比较慢 所以预热一下
async function run(input) {
// const input = document.getElementById('mobilenet');
//log.start('总耗时');
const io = new IO();
// log.start('预处理');
let feed = io.process({
input: input,
params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404], // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差
}
});
// log.end('预处理');
if (!loaded) {
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: true,
dataType: 'binary',
options: {
fileCount: 1, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_0.dat';
}
}
}
});
model = await paddle.load();
}
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
// log.end('运行耗时');
// log.end('后处理-读取数据');
console.dir(['result', result]);
//log.start('后处理-形状调整');
const newData = [];
let newIndex = -1;
const [w, h, c, b] = outputShapes[modelType].from;
// c channel
for (let i = 0; i < c; i++) {
// height channel
for (let j = 0; j < h; j++) {
// width channel
for (let k = 0; k < w; k++) {
// position: (0, 0, 0, 0)
const index = j * (c * h) + k * c + i;
// const index = j * (i * k) + k * i + i;
newData[++newIndex] = result[index];
}
}
}
// log.end('后处理-形状调整');
// log.start('后处理-画框');
testRun(newData, input);
// log.end('后处理-画框');
// log.end('后处理');
// log.end('总耗时');
}
var image = '';
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
let reader = new FileReader();
reader.onload = function (evt) {
let img = document.getElementById('image');
img.src = evt.target.result;
img.onload = function() {
//log.during('每次执行的时间间隔');
run(img);
};
image = evt.target.result;
}
reader.readAsDataURL(file.files[0]);
}
// selectImage
document.getElementById("uploadImg").onchange = function () {
selectImage(this);
};
/* 后处理图片 by zhangmiao06 */
let preTestRun = (index) => {
let img = document.getElementById('image');
img.src = tempPic[index];
img.onload = function() {
testRun(testOutput.data[index], img);
};
};
let testRun = (data, img) => {
// console.log('ori', data);
const {from, to} = outputShapes[modelType];
// let shape = [1, 25, 19, 19];
let shape = [].concat(from).reverse();
// 1.从一维数组到1*25*19*19
let formatData = reshapeMany({
data: data,
reshapeShape: shape
});
// console.log('一维到多维', formatData);
// 2.从1*25*19*19 到 19*19*25*1
let formatData2 = transpose({
data: formatData,
shape: shape,
transposeShape: [2, 3, 1, 0]
});
// console.log('transpose', formatData2);
// 3.从19*19*25*1到19*19*5*5
let formatData3 = reshape({
data: formatData2,
shape: from,
reshapeShape: to
});
// console.log('reshape', formatData3);
// 4.运算
let finalData = handleFinal(formatData3, shape, img);
// console.log('final', finalData);
// 5.处理画布
// handleCanvas(finalData, img);
handleDiv(finalData, img);
};
// sigmoid
let sigmoid = (x) => {
if (x < -100) {
return 0.0;
}
return 1 / (1 + Math.exp(-x));
}
// transpose
let transpose = (data) => {
let shape = data.shape;
let transposeShape = data.transposeShape;
let formatData = data.data;
let formatData2 = [];
for(let n = 0; n < shape[transposeShape[0]]; n++) {
let nData = [];
for(let c = 0; c < shape[transposeShape[1]]; c++) {
let cData = [];
for(let row = 0; row < shape[transposeShape[2]]; row++) {
let rowData = [];
for(let col = 0; col < shape[transposeShape[3]]; col++) {
let tempArr = [n, c, row, col];
let newN = n;
let newC = c;
let newW = row;
let newH = col;
transposeShape.forEach((item, index)=> {
switch(item) {
case 0:
newN = tempArr[index];
break;
case 1:
newC = tempArr[index];
break;
case 2:
newW = tempArr[index];
break;
case 3:
newH = tempArr[index];
}
});
rowData.push(formatData[newN][newC][newW][newH]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData2.push(nData);
}
return formatData2;
};
// reshape
let reshape = (data) =>{
let formatData2 = data.data;
let shape = data.shape;
let reshapeShape = data.reshapeShape;
// 1.变成一维
let tempData = reshapeOne({
data: formatData2,
shape: shape
});
// 2.变成多维
let formatData3 = reshapeMany({
data: tempData,
reshapeShape: reshapeShape
});
return formatData3;
};
// 变成一维
let reshapeOne = (data) => {
let formatData2 = data.data;
let shape = data.shape;
let tempData = [];
for(let n = 0; n < shape[0]; n++) {
for(let c = 0; c < shape[1]; c++) {
for(let row = 0; row < shape[2]; row++) {
for(let col = 0; col < shape[3]; col++) {
tempData.push(formatData2[n][c][row][col]);
}
}
}
}
return tempData;
};
// 变成多维
let reshapeMany = (data) => {
let tempData = data.data;
let reshapeShape = data.reshapeShape;
let formatData3 = [];
for(let n = 0; n < reshapeShape[0]; n++) {
let nData = [];
for(let c = 0; c < reshapeShape[1]; c++) {
let cData = [];
for(let row = 0; row < reshapeShape[2]; row++) {
let rowData = [];
for(let col = 0; col < reshapeShape[3]; col++) {
let tempN = n * reshapeShape[1] * reshapeShape[2] * reshapeShape[3];
let tempC = c * reshapeShape[2] * reshapeShape[3];
let tempRow = row * reshapeShape[3];
rowData.push(tempData[tempN + tempC + tempRow + col]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData3.push(nData);
}
return formatData3;
};
let calSize = (img) => {
let w1 = img.width;
let h1 = img.height;
let wh1 = Math.max(w1, h1);
// let factor = 608.0 / wh1;
let factor = fw / wh1;
let width = Math.round(w1 * factor);
let height = Math.round(h1 * factor);
return [w1, h1, width, height];
};
// 处理运算
let handleFinal = (formatData3, shape, img) => {
let finalData = [];
let c = shape[2];
let [w1, h1, width, height] = calSize(img);
let factorX = Math.max(width, height) / width;
let factorY = Math.max(width, height) / height;
let maxProb = 0.0;
let anchors = [[1.603231, 2.094468], [6.041143, 7.080126], [2.882459, 3.518061], [4.266906, 5.178857], [9.041765, 10.66308]];
for(let i = 0; i < shape[2]; i++) {
for(let j = 0; j < shape[3]; j++) {
for(let k = 0; k < anchors.length; k++) {
let [a1, a2, a3, a4, prob] = formatData3[i][j][k];
prob = sigmoid(prob);
if (prob > maxProb && prob >= 0.5) {
let ctx = (j + sigmoid(a1)) / c * factorX;
let cty = (i + sigmoid(a2)) / c * factorY;
let col = Math.exp(a3) * anchors[k][0] / c * factorX;
let row = Math.exp(a4) * anchors[k][1] / c * factorY;
let x = (ctx - (col / 2));
let y = (cty - (row / 2));
finalData.push([x * w1, y * h1, col * w1, row * h1, prob]);
}
}
}
}
return finalData;
};
// 处理画布
let handleCanvas = (finalData, img) => {
let myCanvas = document.getElementById('myCanvas');
let [w1, h1, width, height] = calSize(img);
myCanvas.width = w1;
myCanvas.height = h1;
let ctx = myCanvas.getContext("2d");
ctx.drawImage(img, 0, 0, w1, h1);
finalData.forEach((demoArr,index) => {
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = demoArr;
ctx.beginPath();
ctx.strokeStyle="red";
ctx.moveTo(demoLeft, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop + demoHeight);
ctx.lineTo(demoLeft, demoTop + demoHeight);
ctx.closePath();
ctx.stroke();
});
};
let handleDiv = (finalData, img) => {
if (finalData.length < 1) {
return false;
}
let myCanvas = document.getElementById('myDiv');
let maxIndex = 0;
if (finalData.length > 1) {
for(let i = 1; i < finalData.length; i++) {
if (finalData[i].prob > finalData[maxIndex].prob) {
maxIndex = i;
}
}
}
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = finalData[maxIndex];
myCanvas.style.width = demoWidth;
myCanvas.style.height = demoHeight;
myCanvas.style.left = demoLeft;
myCanvas.style.top = demoTop;
};
// preTestRun(0);
// run(document.getElementById('pic'));
<!DOCYTPE html>
<html>
<head>
<meta charset="utf-8">
<title>paddleJS demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,initial-scale=1,viewport-fit=cover">
<style>
p {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
#uploadImg {
border: solid 1px gray;
width: 100%;
padding: 10px;
background-color: #cabfbf;
color: white;
font-size: 16px;
}
p.section-head {
font-variant: small-caps;
text-transform: uppercase;
letter-spacing: 0.17em;
line-height: 1.2em;
font-weight: 500;
margin-top: 2em;
margin-bottom: 1em;
border-left: 1px solid #EF6C00;
padding-left: 24px;
color: #818181;
}
.image-wrap {
position: relative;
}
#image {
width: 100%;
}
#myDiv {
position: absolute;
border: 1px solid red;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="pdjs-example-container">
<section class="title-area">
<h1>Paddle.js: Using a pretrained tinyYolo</h1>
</section>
<section>
<p class="section-head">Description</p>
<p>
Please upload a picture with face.
</p>
</section>
<section>
<p class="section-head">Model Output</p>
<div class="image-wrap">
<img id="mobilenet" />
</div>
<p>原图片</p>
<div class="image-wrap">
<img id="image" src=""/>
<div id="myDiv"></div>
</div>
<p>画布</p>
<canvas id="myCanvas"></canvas>
<br/>
<input type="file" id="uploadImg"/>
<div id="txt"></div>
</section>
</div>
</body>
<script src="index.es6"></script>
</html>
import 'babel-polyfill';
import Runner from '../src/executor/runner';
import Camera from '../src/executor/camera';
// 调试工具
// import vConsole from 'vconsole';
// const theConsole = new vConsole();
let startBtn = document.getElementById('start');
let stopBtn = document.getElementById('stop')
const runner = new Runner({
// 用哪个模型
modelName: 'separate' // '608' | '320' | '320fused' | 'separate'
});
startBtn.disabled = true;
runner.preheat()
.then(() =>{
startBtn.disabled = false
});
const domElement = document.getElementById('video');
const myCanvas = document.getElementById('myDiv');
const videoSelect = document.getElementById('videoSelect');
let camera = new Camera({
// 用来显示摄像头图像的dom
videoDom: domElement
});
camera.getDevices().then(devices => {
if (devices.length) {
camera.run(devices[0].deviceId);
devices.forEach((element, index) => {
let option = document.createElement('option');
option.value = element.deviceId;
option.text = (index + 1);
videoSelect.appendChild(option);
});
videoSelect.onchange = () => {
camera.run(videoSelect.value);
};
}
else {
camera.run();
}
});
const handleDiv = function (data) {
myCanvas.style.width = (data ? data[0] : 0) + 'px';
myCanvas.style.height = (data ? data[0] : 0) + 'px';
myCanvas.style.left = (data ? data[2] : 0) + 'px';
myCanvas.style.top = (data ? data[3] : 0) + 'px';
}
startBtn.addEventListener('click', function () {
startBtn.disabled = true;
runner.startStream(() => camera.curVideo, handleDiv);
});
stopBtn.addEventListener('click', function () {
startBtn.disabled = false;
runner.stopStream();
});
\ No newline at end of file
<!DOCYTPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>识别摄像头里的脸</title>
<style>
body {
margin: 0;
padding: 0;
}
#myDiv {
position: fixed;
border: 1px solid red;
box-sizing: border-box;
}
#video {
background: red;
}
</style>
</head>
<body>
<video id="video">
</video>
<p>
<button id="start">开始识别</button>
<button id="stop">结束</button>
</p>
<select id="videoSelect"></select>
<p id="tips">tips</p>
<div id="myDiv"></div>
<script src="./videoDemo.es6"></script>
</body>
</html>
\ No newline at end of file
/* eslint-disable */
import 'babel-polyfill';
import Paddle from '../../src/paddle/paddle';
import IO from '../../src/feed/imageFeed';
// import Logger from '../../tools/logger';
// window.log = new Logger();
// // 统计参数
// window.badCases = [];
// 后处理测试用例
// let tempPic = [demoPic, demoPic2, demoPic3, demoPic4, demoPic5];
/**
* @file model demo 入口文件
* @author wangqun@baidu.com
*
*/
// 模型输出shape
const outputShapes = {
'608': {
from: [19, 19, 25, 1],
to: [19, 19, 5, 5]
},
'320': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'320fused': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
},
'separate': {
from: [10, 10, 25, 1],
to: [10, 10, 5, 5]
}
};
// 模型feed数据
const feedShape = {
'608': {
fw: 608,
fh: 608
},
'320': {
fw: 320,
fh: 320
},
'320fused': {
fw: 320,
fh: 320
},
'separate': {
fw: 320,
fh: 320
}
};
// 模型路径
const modelPath = {
'separate': 'model/tinyYolo'
};
const modelType = 'separate';
const path = modelPath[modelType];
// 统计参数
let loaded = false;
let model = {};
window.statistic = [];
const {fw, fh} = feedShape[modelType];
// 第一遍执行比较慢 所以预热一下
async function run(input) {
// const input = document.getElementById('mobilenet');
//log.start('总耗时');
const io = new IO();
// log.start('预处理');
let feed = io.process({
input: input,
params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404], // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差
}
});
// log.end('预处理');
if (!loaded) {
const MODEL_CONFIG = {
dir: `/${path}/`, // 存放模型的文件夹
main: 'model.json', // 主文件
};
loaded = true;
const paddle = new Paddle({
urlConf: MODEL_CONFIG,
options: {
multipart: true,
dataType: 'binary',
options: {
fileCount: 1, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_0.dat';
}
},
feed
}
});
model = await paddle.load();
}
let inst = model.execute({
input: feed
});
// 其实这里应该有个fetch的执行调用或者fetch的输出
let result = await inst.read();
// log.end('运行耗时');
// log.end('后处理-读取数据');
console.dir(['result', result]);
//log.start('后处理-形状调整');
const newData = [];
let newIndex = -1;
const [w, h, c, b] = outputShapes[modelType].from;
// c channel
for (let i = 0; i < c; i++) {
// height channel
for (let j = 0; j < h; j++) {
// width channel
for (let k = 0; k < w; k++) {
// position: (0, 0, 0, 0)
const index = j * (c * h) + k * c + i;
// const index = j * (i * k) + k * i + i;
newData[++newIndex] = result[index];
}
}
}
// log.end('后处理-形状调整');
// log.start('后处理-画框');
testRun(newData, input);
// log.end('后处理-画框');
// log.end('后处理');
// log.end('总耗时');
}
var image = '';
function selectImage(file) {
if (!file.files || !file.files[0]) {
return;
}
let reader = new FileReader();
reader.onload = function (evt) {
let img = document.getElementById('image');
img.src = evt.target.result;
img.onload = function() {
//log.during('每次执行的时间间隔');
run(img);
};
image = evt.target.result;
}
reader.readAsDataURL(file.files[0]);
}
// selectImage
document.getElementById("uploadImg").onchange = function () {
selectImage(this);
};
/* 后处理图片 by zhangmiao06 */
let preTestRun = (index) => {
let img = document.getElementById('image');
img.src = tempPic[index];
img.onload = function() {
testRun(testOutput.data[index], img);
};
};
let testRun = (data, img) => {
// console.log('ori', data);
const {from, to} = outputShapes[modelType];
// let shape = [1, 25, 19, 19];
let shape = [].concat(from).reverse();
// 1.从一维数组到1*25*19*19
let formatData = reshapeMany({
data: data,
reshapeShape: shape
});
// console.log('一维到多维', formatData);
// 2.从1*25*19*19 到 19*19*25*1
let formatData2 = transpose({
data: formatData,
shape: shape,
transposeShape: [2, 3, 1, 0]
});
// console.log('transpose', formatData2);
// 3.从19*19*25*1到19*19*5*5
let formatData3 = reshape({
data: formatData2,
shape: from,
reshapeShape: to
});
// console.log('reshape', formatData3);
// 4.运算
let finalData = handleFinal(formatData3, shape, img);
// console.log('final', finalData);
// 5.处理画布
// handleCanvas(finalData, img);
handleDiv(finalData, img);
};
// sigmoid
let sigmoid = (x) => {
if (x < -100) {
return 0.0;
}
return 1 / (1 + Math.exp(-x));
}
// transpose
let transpose = (data) => {
let shape = data.shape;
let transposeShape = data.transposeShape;
let formatData = data.data;
let formatData2 = [];
for(let n = 0; n < shape[transposeShape[0]]; n++) {
let nData = [];
for(let c = 0; c < shape[transposeShape[1]]; c++) {
let cData = [];
for(let row = 0; row < shape[transposeShape[2]]; row++) {
let rowData = [];
for(let col = 0; col < shape[transposeShape[3]]; col++) {
let tempArr = [n, c, row, col];
let newN = n;
let newC = c;
let newW = row;
let newH = col;
transposeShape.forEach((item, index)=> {
switch(item) {
case 0:
newN = tempArr[index];
break;
case 1:
newC = tempArr[index];
break;
case 2:
newW = tempArr[index];
break;
case 3:
newH = tempArr[index];
}
});
rowData.push(formatData[newN][newC][newW][newH]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData2.push(nData);
}
return formatData2;
};
// reshape
let reshape = (data) =>{
let formatData2 = data.data;
let shape = data.shape;
let reshapeShape = data.reshapeShape;
// 1.变成一维
let tempData = reshapeOne({
data: formatData2,
shape: shape
});
// 2.变成多维
let formatData3 = reshapeMany({
data: tempData,
reshapeShape: reshapeShape
});
return formatData3;
};
// 变成一维
let reshapeOne = (data) => {
let formatData2 = data.data;
let shape = data.shape;
let tempData = [];
for(let n = 0; n < shape[0]; n++) {
for(let c = 0; c < shape[1]; c++) {
for(let row = 0; row < shape[2]; row++) {
for(let col = 0; col < shape[3]; col++) {
tempData.push(formatData2[n][c][row][col]);
}
}
}
}
return tempData;
};
// 变成多维
let reshapeMany = (data) => {
let tempData = data.data;
let reshapeShape = data.reshapeShape;
let formatData3 = [];
for(let n = 0; n < reshapeShape[0]; n++) {
let nData = [];
for(let c = 0; c < reshapeShape[1]; c++) {
let cData = [];
for(let row = 0; row < reshapeShape[2]; row++) {
let rowData = [];
for(let col = 0; col < reshapeShape[3]; col++) {
let tempN = n * reshapeShape[1] * reshapeShape[2] * reshapeShape[3];
let tempC = c * reshapeShape[2] * reshapeShape[3];
let tempRow = row * reshapeShape[3];
rowData.push(tempData[tempN + tempC + tempRow + col]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData3.push(nData);
}
return formatData3;
};
let calSize = (img) => {
let w1 = img.width;
let h1 = img.height;
let wh1 = Math.max(w1, h1);
// let factor = 608.0 / wh1;
let factor = fw / wh1;
let width = Math.round(w1 * factor);
let height = Math.round(h1 * factor);
return [w1, h1, width, height];
};
// 处理运算
let handleFinal = (formatData3, shape, img) => {
let finalData = [];
let c = shape[2];
let [w1, h1, width, height] = calSize(img);
let factorX = Math.max(width, height) / width;
let factorY = Math.max(width, height) / height;
let maxProb = 0.0;
let anchors = [[1.603231, 2.094468], [6.041143, 7.080126], [2.882459, 3.518061], [4.266906, 5.178857], [9.041765, 10.66308]];
for(let i = 0; i < shape[2]; i++) {
for(let j = 0; j < shape[3]; j++) {
for(let k = 0; k < anchors.length; k++) {
let [a1, a2, a3, a4, prob] = formatData3[i][j][k];
prob = sigmoid(prob);
if (prob > maxProb && prob >= 0.5) {
let ctx = (j + sigmoid(a1)) / c * factorX;
let cty = (i + sigmoid(a2)) / c * factorY;
let col = Math.exp(a3) * anchors[k][0] / c * factorX;
let row = Math.exp(a4) * anchors[k][1] / c * factorY;
let x = (ctx - (col / 2));
let y = (cty - (row / 2));
finalData.push([x * w1, y * h1, col * w1, row * h1, prob]);
}
}
}
}
return finalData;
};
// 处理画布
let handleCanvas = (finalData, img) => {
let myCanvas = document.getElementById('myCanvas');
let [w1, h1, width, height] = calSize(img);
myCanvas.width = w1;
myCanvas.height = h1;
let ctx = myCanvas.getContext("2d");
ctx.drawImage(img, 0, 0, w1, h1);
finalData.forEach((demoArr,index) => {
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = demoArr;
ctx.beginPath();
ctx.strokeStyle="red";
ctx.moveTo(demoLeft, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop + demoHeight);
ctx.lineTo(demoLeft, demoTop + demoHeight);
ctx.closePath();
ctx.stroke();
});
};
let handleDiv = (finalData, img) => {
if (finalData.length < 1) {
return false;
}
let myCanvas = document.getElementById('myDiv');
let maxIndex = 0;
if (finalData.length > 1) {
for(let i = 1; i < finalData.length; i++) {
if (finalData[i].prob > finalData[maxIndex].prob) {
maxIndex = i;
}
}
}
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = finalData[maxIndex];
myCanvas.style.width = demoWidth;
myCanvas.style.height = demoHeight;
myCanvas.style.left = demoLeft;
myCanvas.style.top = demoTop;
};
// preTestRun(0);
// run(document.getElementById('pic'));
/* eslint-enable */
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>paddle web demo</title>
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
<style>
.image-wrap {
position: relative;
}
#myDiv {
position: absolute;
border: 1px solid #f71111;
box-sizing: border-box;
}
</style>
</head>
<body>
<div class="image-wrap">
<img id="mobilenet">
</div>
<p>原图片</p>
<div class="image-wrap">
<img id="image" src="pic.png">
<div id="myDiv"></div>
</div>
<p>画布</p>
<canvas id="myCanvas"></canvas>
<input type="file" id="uploadImg">
<div id="txt"></div>
<script src="index.es6"></script>
</body>
</html>
{
"name": "paddle-web-demo",
"version": "1.0.0",
"description": "paddle",
"main": "index.js",
"scripts": {
"mnistdemo": "parcel ./examples/mnist/index.html",
"mobilenet": "parcel ./examples/mobileNet/index.html",
"tinyYolo": "parcel ./examples/tinyYolo/index.html",
"huangfan": "parcel ./examples/huangfan/index.html",
"yolo": "parcel ./examples/yolo/index.html",
"videoDemo": "parcel ./examples/videoDemo.html --port 8123 --https",
"unitTest": "parcel ./test/unitTest.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/preset-env": "^7.7.1",
"axios": "^0.17.1",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-polyfill": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-0": "^6.24.1",
"babel-runtime": "^6.26.0",
"parcel-bundler": "^1.10.3",
"webpack-cli": "^3.3.6"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"js-file-download": "^0.4.5",
"vconsole": "^3.3.2"
}
}
export PATH=$NODEJS_BIN_LATEST:$PATH
echo "node: $(node -v)"
echo "npm: v$(npm -v)"
npm install
npm run build
/**
* @file 视频流类
* @author zhangmiao06
*/
import $ from 'webpack-zepto';
export default class Camera {
constructor(option) {
this.option = option;
this.video = option.videoDom;
// 标志是否可以切换摄像头
this.haveDevice = false;
// 设置视频流宽度
if (option.width) {
this.video.width = option.width;
}
else if (option.height) {
this.video.height = option.height;
}
else {
this.video.width = window.innerWidth;
}
this.deviceInfos = [];
if(navigator.mediaDevices) {
this.haveDevice = true;
}
}
// 访问用户媒体设备的兼容方法
run(deviceId, callback) {
if (window.stream) {
window.stream.getTracks().forEach(function (track) {
track.stop();
});
}
let constraints = {
video: {}
};
const success = stream => {
this.success(stream, callback);
};
const error = this.error.bind(this);
if (this.deviceInfos.length) {
constraints.video.deviceId= {exact: deviceId || this.deviceInfos[0]};
}
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// 最新的标准API
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
}
else if (navigator.webkitGetUserMedia) {
// webkit核心浏览器
navigator.webkitGetUserMedia(constraints, success, error);
}
else if (navigator.mozGetUserMedia) {
// firfox浏览器
navigator.mozGetUserMedia(constraints, success, error);
}
else if (navigator.getUserMedia) {
// 旧版API
navigator.getUserMedia(constraints, success, error);
}
else {
console.log('您的浏览器不支持获取视频流~');
}
}
success(stream, callback) {
const domElement = this.video;
// make stream available to console
window.stream = stream;
// 旧的浏览器可能没有srcObject
const URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
if ('srcObject' in domElement) {
try {
domElement.srcObject = stream;
} catch (error) {
domElement.src = URL.createObjectURL(stream) || stream;
}
} else {
// 防止再新的浏览器里使用它,应为它已经不再支持了
domElement.src = URL.createObjectURL(stream) || stream;
}
domElement.addEventListener('loadeddata', () => {
// 设置视频流高度
if (this.option.height) {
domElement.width = $(domElement).width();
}
else {
domElement.height = $(domElement).height();
}
domElement.play();
callback && callback();
}, false);
}
error(error) {
alert(`访问用户媒体设备失败${error.name}, ${error.message}`);
}
// 处理摄像头列表
gotDevices(deviceInfos) {
const ua = navigator.userAgent;
const isIos = /iphone|ipod|ipad/ig.test(ua);
let delt = -1;
const range = deviceInfos.length;
let start = range - 1;
let end = - 1;
// ios机型camare顺序相反
if (isIos) {
delt = 1;
start = 0;
end = range;
}
for (let i = start; i !== end; i += delt) {
const deviceInfo = deviceInfos[i];
if (deviceInfo.kind === 'videoinput') {
this.deviceInfos.push(deviceInfos[i]);
}
}
}
get curVideo() {
return this.video;
}
getDevices() {
return new Promise((resolve, reject)=> {
if (this.haveDevice) {
if (this.deviceInfos.length) {
resolve(this.deviceInfos);
}
else {
navigator.mediaDevices.enumerateDevices()
.then(this.gotDevices.bind(this))
.then(()=> {
resolve(this.deviceInfos);
});
}
}
else {
resolve([]);
}
});
}
}
/* eslint-disable */
/**
* @file GraphExecutor,封装可执行单元
* @author wangqun@baidu.com
*/
// const fileDownload = require('js-file-download');
let start;
export default class GraphExecutor {
constructor(model) {
this.inputs = model.inputs;
this.outputs = model.outputs;
this.attrs = model.attrs || model['sub-attrs'];
this.type = model.type;
this.finish = false;
this.next = null;
this.opData = null;
this.id = +new Date() + model.type + Math.floor(Math.random() * 10 + 1) + model.idx;
}
get inputsName() {
if (this.type === 'feed') {
return this.inputs.X;
}
else if (this.type === 'batchnorm' || this.type === 'batch_norm') {
return this.inputs.X;
}
else if (this.type === 'conv2d') {
return this.inputs.Input;
}
else if (this.type === 'depthwise_conv2d') {
return this.inputs.Input;
}
else if (this.type === 'elementwise_add') {
return this.inputs.X;
}
else if (this.type === 'relu' || this.type === 'leaky_relu') {
return this.inputs.X;
}
else if (this.type === 'pool2d') {
return this.inputs.X;
}
else if (this.type === 'mul') {
return this.inputs.X;
}
else if (this.type === 'softmax') {
return this.inputs.X;
}
else if (this.type === 'scale') {
return this.inputs.X;
}
else if (this.type === 'fetch') {
return this.inputs.X;
}
return this.inputs.Input || this.inputs.X;
}
get outputsName() {
if (this.type === 'conv2d') {
return this.outputs.Output;
}
else if (this.type === 'depthwise_conv2d') {
return this.outputs.Output;
}
else if (this.type === 'batchnorm' || this.type === 'batch_norm') {
this.outputs.out = this.outputs.Y;
return this.outputs.Y;
}
else {
return this.outputs.Out || this.outputs.Output;
}
}
/**
* 将输入数据和具体op进行关联,触发执行具体每一个op
* @param runtime
* @param isRendered
*/
execute(runtime, isRendered) {
// console.log(inputs, outputs);
if (this.type !== 'feed') {
// let time = +Date.now();
// log.start(this.opData.iLayer + '-' + this.type);
console.log(this.type, this.opData);
runtime.run(this.type, this.opData, isRendered);
// log.end(this.opData.iLayer + '-' + this.type);
// if (runtime.gpu.frameBufferIsComplete().isComplete) {
// var result = runtime.read();
// let res = Array.prototype.slice.call(result);
// fileDownload(res, "result.csv");
// }
// let length = statistic.length;
// statistic[length - 1].type = this.type;
// statistic[length - 1].runTime = +Date.now() - time;
// if (this.type === 'scale') {
// console.log('时间是:' + (+Date.now() - start));
// }
} else {
start = +Date.now();
}
}
}
/* eslint-enable */
/* eslint-disable */
/* 后处理图片 by zhangmiao06 */
// let preTestRun = index => {
// let img = document.getElementById('image');
// img.src = tempPic[index];
// img.onload = function () {
// testRun(testOutput.data[index], img);
// };
// };
import models from '../utils/models';
const isSimilar = (r1, r2, threshold = 5) => {
return Math.max(Math.abs(r1[0] - r2[0]), Math.abs(r1[1] - r2[1])) < threshold;
// return Math.abs((r1[0] + r1[1] + r1[2] + r1[3]) - (r2[0] + r2[1] + r2[2] + r2[3])) < threshold;
}
// sigmoid
let sigmoid = (x) => {
if (x < -100) {
return 0.0;
}
return 1 / (1 + Math.exp(-x));
};
// transpose
let transpose = (data) => {
let shape = data.shape;
let transposeShape = data.transposeShape;
let formatData = data.data;
let formatData2 = [];
for (let n = 0; n < shape[transposeShape[0]]; n++) {
let nData = [];
for (let c = 0; c < shape[transposeShape[1]]; c++) {
let cData = [];
for (let row = 0; row < shape[transposeShape[2]]; row++) {
let rowData = [];
for (let col = 0; col < shape[transposeShape[3]]; col++) {
let tempArr = [n, c, row, col];
let newN = n;
let newC = c;
let newW = row;
let newH = col;
transposeShape.forEach((item, index) => {
switch (item) {
case 0:
newN = tempArr[index];
break;
case 1:
newC = tempArr[index];
break;
case 2:
newW = tempArr[index];
break;
case 3:
newH = tempArr[index];
}
});
rowData.push(formatData[newN][newC][newW][newH]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData2.push(nData);
}
return formatData2;
};
// reshape
const reshape = (data) => {
let formatData2 = data.data;
let shape = data.shape;
let reshapeShape = data.reshapeShape;
// 1.变成一维
let tempData = reshapeOne({
data: formatData2,
shape: shape
});
// 2.变成多维
let formatData3 = reshapeMany({
data: tempData,
reshapeShape: reshapeShape
});
return formatData3;
};
// 变成一维
const reshapeOne = (data) => {
let formatData2 = data.data;
let shape = data.shape;
let tempData = [];
for (let n = 0; n < shape[0]; n++) {
for (let c = 0; c < shape[1]; c++) {
for (let row = 0; row < shape[2]; row++) {
for (let col = 0; col < shape[3]; col++) {
tempData.push(formatData2[n][c][row][col]);
}
}
}
}
return tempData;
};
// 变成多维
const reshapeMany = data => {
let tempData = data.data;
let reshapeShape = data.reshapeShape;
let formatData3 = [];
for (let n = 0; n < reshapeShape[0]; n++) {
let nData = [];
for (let c = 0; c < reshapeShape[1]; c++) {
let cData = [];
for (let row = 0; row < reshapeShape[2]; row++) {
let rowData = [];
for (let col = 0; col < reshapeShape[3]; col++) {
let tempN = n * reshapeShape[1] * reshapeShape[2] * reshapeShape[3];
let tempC = c * reshapeShape[2] * reshapeShape[3];
let tempRow = row * reshapeShape[3];
rowData.push(tempData[tempN + tempC + tempRow + col]);
}
cData.push(rowData);
}
nData.push(cData);
}
formatData3.push(nData);
}
return formatData3;
};
export default class PostProcess {
constructor(options) {
this.modelConfig = models[options.modelName];
this.count = 0;
this.lastRect = [0, 0, 0, 0]
}
run(data, img, callback, canavs) {
let {from, to} = this.modelConfig.outputShapes;
let shape = [].concat(from).reverse();
// 1.从一维数组到1*25*19*19
let formatData = reshapeMany({
data: data,
reshapeShape: shape
});
// console.log('一维到多维', formatData);
// 2.从1*25*19*19 到 19*19*25*1
let formatData2 = transpose({
data: formatData,
shape: shape,
transposeShape: [2, 3, 1, 0]
});
// console.log('transpose', formatData2);
// 3.从19*19*25*1到19*19*5*5
let formatData3 = reshape({
data: formatData2,
// shape: [19, 19, 25, 1],
// reshapeShape: [19, 19, 5, 5]
shape: from,
reshapeShape: to
});
// console.log('reshape', formatData3);
// 4.运算
let finalData = this.handleFinal(formatData3, shape, img);
// console.log('final', finalData);
// 5.处理画布
// finalData.length && handleCanvas(finalData, img);
this.handleDiv(finalData, img, callback, canavs);
}
calSize(img) {
let w1 = img.width;
let h1 = img.height;
let wh1 = Math.max(w1, h1);
let factor = this.modelConfig.feedShape.fw / wh1;
// let factor = 608.0 / wh1;
let width = Math.round(w1 * factor);
let height = Math.round(h1 * factor);
return [w1, h1, width, height];
}
// 处理运算
handleFinal(formatData3, shape, img) {
let finalData = [];
let c = shape[2];
let [w1, h1, width, height] = this.calSize(img);
let factorX = Math.max(width, height) / width;
let factorY = Math.max(width, height) / height;
let maxProb = 0.0;
let anchors = [[1.603231, 2.094468], [6.041143, 7.080126], [2.882459, 3.518061], [4.266906, 5.178857], [9.041765, 10.66308]];
for (let i = 0; i < shape[2]; i++) {
for (let j = 0; j < shape[3]; j++) {
for (let k = 0; k < anchors.length; k++) {
let [a1, a2, a3, a4, prob] = formatData3[i][j][k];
prob = sigmoid(prob);
if (prob > maxProb && prob >= 0.5) {
let ctx = (j + sigmoid(a1)) / c * factorX;
let cty = (i + sigmoid(a2)) / c * factorY;
let col = Math.exp(a3) * anchors[k][0] / c * factorX;
let row = Math.exp(a4) * anchors[k][1] / c * factorY;
let x = (ctx - (col / 2));
let y = (cty - (row / 2));
finalData.push([x * w1, y * h1, col * w1, row * h1, prob]);
}
}
}
}
return finalData;
}
handleDiv(finalData, img, callback, canavs) {
if (finalData.length < 1) {
callback();
return false;
}
let maxIndex = 0;
if (finalData.length > 1) {
for (let i = 1; i < finalData.length; i++) {
if (finalData[i].prob > finalData[maxIndex].prob) {
maxIndex = i;
}
}
}
let [demoLeft, demoTop, demoWidth, demoHeight] = finalData[maxIndex];
if (!isSimilar(this.lastRect, [demoLeft, demoTop, demoWidth, demoHeight])) {
callback([demoWidth, demoHeight,demoLeft, demoTop], canavs);
};
this.lastRect = [demoLeft, demoTop, demoWidth, demoHeight];
}
// 处理画布
handleCanvas(finalData, img) {
let myCanvas = document.getElementById('myCanvas');
let [w1, h1, width, height] = calSize(img);
myCanvas.width = w1;
myCanvas.height = h1;
let ctx = myCanvas.getContext('2d');
// ctx.drawImage(img, 0, 0, w1, h1);
// finalData.forEach((demoArr, index) => {
// let [demoLeft, demoTop, demoWidth, demoHeight, prob] = demoArr;
let [demoLeft, demoTop, demoWidth, demoHeight, prob] = finalData[0];
ctx.beginPath();
ctx.lineWidth = 4;
ctx.strokeStyle = 'red';
ctx.moveTo(demoLeft, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop);
ctx.lineTo(demoLeft + demoWidth, demoTop + demoHeight);
ctx.lineTo(demoLeft, demoTop + demoHeight);
ctx.closePath();
ctx.stroke();
// });
}
}
/**
* @file Runner 整个流程封装一下
* @author hantian(hantianjiao@baidu.com)
* 使用方法:
* const runner = new Runner({
* modelName: 'separate' // '608' | '320' | '320fused' | 'separate'
* });
* runner.preheat().then(r => {
* r.run(document.getElementById('test'));
* });
*/
import IO from '../feed/ImageFeed';
import DataFeed from '../feed/dataFeed';
import Graph from './loader';
import PostProcess from './postProcess';
import models from '../utils/models';
import Logger from '../../tools/logger';
window.log = new Logger();
export default class Runner {
// 加载模型&预热
constructor(options) {
this.modelConfig = models[options.modelName];
this.flags = {
isRunning: false,
isPreheating: false,
runVideoPaused: false
};
this.buffer = new Float32Array();
this.io = new IO();
this.postProcess = new PostProcess(options);
}
// 预热 用用空数据跑一遍
async preheat() {
this.flags.isPreheating = true;
let {fh, fw} = this.modelConfig.feedShape;
let path = this.modelConfig.modelPath;
let feed = [{
data: new Float32Array(3 * fh * fw),
name: 'image',
shape: [1, 3, fh, fw]
}];
const MODEL_URL = `/${path}/model.json`;
let dir = `https://mms-graph.cdn.bcebos.com/activity/facegame/paddle/${path}/`;
if (location.href.indexOf('test=1') > -1) {
dir = `/src/view/common/lib/paddle/${path}/`;
}
const MODEL_CONFIG = {
dir: dir,
main: 'model.json' // 主文件
};
const graphModel = new Graph();
this.model = await graphModel.loadGraphModel(MODEL_CONFIG, {
multipart: true,
dataType: 'binary',
binaryOption: {
fileCount: 1, // 切成了多少文件
getFileName(i) { // 获取第i个文件的名称
return 'chunk_0.dat';
}
},
feed
});
this.model.execute({
input: feed
});
this.flags.isPreheating = false;
return this;
}
// 跑一遍
async run(input, callback) {
this.flags.isRunning = true;
let {fh, fw} = this.modelConfig.feedShape;
let path = this.modelConfig.modelPath;
if (!this.model) {
console.warn('It\'s better to preheat the model before running.');
await this.preheat();
}
// log.start('总耗时'); // eslint-disable-line
// log.start('预处理'); // eslint-disable-line
let feed;
if (typeof input === 'string') {
const dfIO = new DataFeed();
feed = await dfIO.process({
input: `/${path}/${input}`,
shape: [1, 3, fh, fw]
});
}
else {
feed = this.io.process({
input: input,
params: {
gapFillWith: '#000', // 缩放后用什么填充不足方形部分
targetSize: {
height: fw,
width: fh
},
targetShape: [1, 3, fh, fw], // 目标形状 为了兼容之前的逻辑所以改个名
// shape: [3, 608, 608], // 预设tensor形状
mean: [117.001, 114.697, 97.404] // 预设期望
// std: [0.229, 0.224, 0.225] // 预设方差
}
});
}
// log.end('预处理'); // eslint-disable-line
// log.start('运行耗时'); // eslint-disable-line
let inst = this.model.execute({
input: feed
});
let result = await inst.read();
// log.end('后处理-读取数据'); // eslint-disable-line
const newData = [];
let newIndex = -1;
const [w, h, c, b] = this.modelConfig.outputShapes.from;
// c channel
for (let i = 0; i < c; i++) {
// height channel
for (let j = 0; j < h; j++) {
// width channel
for (let k = 0; k < w; k++) {
// position: (0, 0, 0, 0)
const index = j * (c * h) + k * c + i;
// const index = j * (i * k) + k * i + i;
newData[++newIndex] = result[index];
}
}
}
this.postProcess.run(newData, input, callback, feed[0].canvas);
// log.end('后处理'); // eslint-disable-line
this.flags.isRunning = false;
// log.end('总耗时'); // eslint-disable-line
}
// 传入获取图片的function
async runStream(getMedia, callback) {
await this.run(getMedia, callback);
if (!this.flags.runVideoPaused) {
setTimeout(async () => {
await this.runStream(getMedia, callback);
}, 0);
}
}
stopStream() {
this.flags.runVideoPaused = true;
}
startStream(getMedia, callback) {
this.flags.runVideoPaused = false;
this.runStream(getMedia, callback);
}
}
[中文版](./README_cn.md)
# PaddleJS Operators Support Table
Operators represent the operators corresponding to each layer of the neural network. Refer to the specific algorithm implementation, the table shows the support of Baidu artificial intelligence operators. Padderjs currently supports GPU operation calculation version.
See Compatibility for a list of the supported platforms.
Please refer to compatibility for the list supported by paddle.js. This file will change as the number of operators increases and the support situation changes.
Baidu paddlejs uses the ready-made JavaScript model or transforms the paddle model to run in the browser.
## Demonstration
| Operator | Gpu Backend | desc |
| ------------- | ------------- | ------------- |
| conv2d_transpose | webGL1、 webGL2 | |
| conv2d | webGL1、 webGL2 | |
| conv2d_depthwise | webGL1、 webGL2 | |
| conv2d_elementwise_add | webGL1、 webGL2 | |
| conv2d_elementwise_add_winograd | webGL1、 webGL2 | |
| dynamic | webGL1、 webGL2 | |
| scale | webGL1、 webGL2 | |
| pool2d | webGL1、 webGL2 | |
| pool2d_max | webGL1、 webGL2 | |
| pool2d_winograd | webGL1、 webGL2 | |
| elementwise_add | webGL1、 webGL2 | |
| mul | webGL1、 webGL2 | |
| relu | webGL1、 webGL2 | |
| relu6 | webGL1、 webGL2 | |
| softmax | webGL1、 webGL2 | |
| batchnorm | webGL1、 webGL2 | |
| reshape | webGL1、 webGL2 | |
| transpose | webGL1、 webGL2 | |
## Browser coverage
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
# PaddleJS Operators 支持表
Operators表示神经网络每层对应的算子,参考具体的算法实现,表格显示了百度人工智能算子支持情况,PadderJS目前支持GPU操作计算版本。
受paddle.js支持的列表,请参阅兼容性,此文件会随着Operator数量增加和支持情况做相应的变更。
## 演示
| Operator | Gpu Backend | desc |
| ------------- | ------------- | ------------- |
| conv2d_transpose | webGL1、 webGL2 | |
| conv2d | webGL1、 webGL2 | |
| conv2d_depthwise | webGL1、 webGL2 | |
| conv2d_elementwise_add | webGL1、 webGL2 | |
| conv2d_elementwise_add_winograd | webGL1、 webGL2 | |
| dynamic | webGL1、 webGL2 | |
| scale | webGL1、 webGL2 | |
| pool2d | webGL1、 webGL2 | |
| pool2d_max | webGL1、 webGL2 | |
| pool2d_winograd | webGL1、 webGL2 | |
| elementwise_add | webGL1、 webGL2 | |
| mul | webGL1、 webGL2 | |
| relu | webGL1、 webGL2 | |
| relu6 | webGL1、 webGL2 | |
| softmax | webGL1、 webGL2 | |
| batchnorm | webGL1、 webGL2 | |
| reshape | webGL1、 webGL2 | |
| transpose | webGL1、 webGL2 | |
## 浏览器覆盖面
* PC: Chrome
* Mac: Chrome
* Android: Baidu App and QQ Browser
import ops from './ops';
/**
* @file 工厂类,生成fragment shader
* @author wangqun
*/
export default class Factory {
constructor(opts) {
this.defaultOpts = Object.assign({}, opts);
this.webglVersion = 2;
this.texture2d = 'texture';
}
setWebglVersion(vs = 0) {
this.webglVersion = vs;
if (vs === 1) {
this.texture2d = 'texture2D';
}
}
buildShader(opName, data) {
let result = '';
result = this.buildPrefix(opName);
result += this.buildCommon(opName);
result += this.buildOp(opName);
data.texture2d = this.texture2d;
result = this.populateData(result, data);
return result;
}
buildPrefix(opName) {
if (this.webglVersion === 1) {
return ops.common.prefix;
}
return ops.common.prefix2;
}
buildCommon(opName) {
return ops.common.params + ops.common.func;
}
buildOp(opName) {
let code = ops.ops[opName].params;
// 依赖的方法
let atoms = ops.atoms;
let confs = ops.ops[opName].confs;
let dep = confs.dep || [];
dep.map(item => {
let func = item.func;
let data = item.conf;
let snippet = atoms[func];
code += this.populateData(snippet, data);
});
// suffix
code += this.buildSuffix(opName);
// main方法
code += ops.ops[opName].func;
return code;
}
buildSuffix(opName) {
return ops.common.suffix;
}
populateData(result, data) {
let code = result;
for (let key in data) {
code = code.replace(new RegExp(key.toUpperCase(), 'g'),
((typeof data[key]) === 'undefined') ? 1 : data[key]);
}
return code;
}
getOpConfs() {
const opsConfs = {};
for (let key in ops.ops) {
if (ops.ops.hasOwnProperty(key)) {
opsConfs[key] = ops.ops[key].confs.input;
}
}
return opsConfs;
}
}
/* eslint-disable */
import common_params from '../../shader/atom/common_params';
import common_func from '../../shader/atom/common_func';
import prefix from '../../shader/atom/prefix';
import prefix2 from '../../shader/atom/prefix2';
import suffix from '../../shader/atom/suffix';
import ivec56 from '../../shader/atom/type_ivec56';
import conv2d_params from '../../shader/conv2d/params';
import conv2d_func from '../../shader/conv2d/main';
import conv2d_conf from '../../shader/conv2d/conf';
import conv2d_depthwise_params from '../../shader/conv2d_depthwise/params';
import conv2d_depthwise_func from '../../shader/conv2d_depthwise/main';
import conv2d_depthwise_conf from '../../shader/conv2d_depthwise/conf';
import dynamic_params from '../../shader/dynamic/params';
import dynamic_func from '../../shader/dynamic/main';
import dynamic_conf from '../../shader/dynamic/conf';
import pool2d_params from '../../shader/pool2d/params';
import pool2d_func from '../../shader/pool2d/main';
import pool2d_conf from '../../shader/pool2d/conf';
import pool2d_max_params from '../../shader/pool2d_max/params';
import pool2d_max_func from '../../shader/pool2d_max/main';
import pool2d_max_conf from '../../shader/pool2d_max/conf';
import pool2d_winograd_params from '../../shader/pool2d_winograd/params';
import pool2d_winograd_func from '../../shader/pool2d_winograd/main';
import pool2d_winograd_conf from '../../shader/pool2d_winograd/conf';
import elementwise_add_params from '../../shader/elementwise_add/params';
import elementwise_add_func from '../../shader/elementwise_add/main';
import elementwise_add_conf from '../../shader/elementwise_add/conf';
import mul_params from '../../shader/mul/params';
import mul_func from '../../shader/mul/main';
import mul_conf from '../../shader/mul/conf';
import softmax_params from '../../shader/softmax/params';
import softmax_func from '../../shader/softmax/main';
import softmax_conf from '../../shader/softmax/conf';
import batchnorm_params from '../../shader/batchnorm/params';
import batchnorm_func from '../../shader/batchnorm/main';
import batchnorm_conf from '../../shader/batchnorm/conf';
import conv2d_elementwise_add_params from '../../shader/conv2d_elementwise_add/params';
import conv2d_elementwise_add_func from '../../shader/conv2d_elementwise_add/main';
import conv2d_elementwise_add_conf from '../../shader/conv2d_elementwise_add/conf';
import conv2d_elementwise_add_winograd_params from '../../shader/conv2d_elementwise_add_winograd/params';
import conv2d_elementwise_add_winograd_func from '../../shader/conv2d_elementwise_add_winograd/main';
import conv2d_elementwise_add_winograd_conf from '../../shader/conv2d_elementwise_add_winograd/conf';
import getArrayIndexFromTensorPos from '../../shader/atom/getArrayIndexFromTensorPos';
import getArrayIndexFromTexturePos from '../../shader/atom/getArrayIndexFromTexturePos';
import getTensorPosFromArrayIndex from '../../shader/atom/getTensorPosFromArrayIndex';
import getTexturePosFromArrayIndex from '../../shader/atom/getTexturePosFromArrayIndex';
import getValueFromTexturePos from '../../shader/atom/getValueFromTexturePos';
import getValueFromTensorPos from '../../shader/atom/getValueFromTensorPos';
import getValueFromTensorPosPacked from '../../shader/atom/getValueFromTensorPosPacked';
import moveTexture2PosToReal from '../../shader/atom/moveTexture2PosToReal';
import getPixelsFromTexturePos from '../../shader/atom/getPixelsFromTexturePos';
import getRangePowSumFromArrayIndex from '../../shader/atom/getRangePowSumFromArrayIndex';
import getRangeSumFromArrayIndex from '../../shader/atom/getRangeSumFromArrayIndex';
import sigmoid from '../../shader/atom/sigmoid';
import prelu from '../../shader/atom/prelu';
import scale from '../../shader/atom/scale';
import softmax from '../../shader/atom/softmax';
/**
* @file op文件
* @author yangmingming
*/
export default {
common: {
params: common_params,
func: common_func,
prefix,
prefix2,
suffix,
ivec56
},
ops: {
conv2d: {
params: conv2d_params,
func: conv2d_func,
confs: conv2d_conf
},
conv2d_depthwise: {
params: conv2d_depthwise_params,
func: conv2d_depthwise_func,
confs: conv2d_depthwise_conf
},
conv2d_elementwise_add: {
params: conv2d_elementwise_add_params,
func: conv2d_elementwise_add_func,
confs: conv2d_elementwise_add_conf
},
conv2d_elementwise_add_winograd: {
params: conv2d_elementwise_add_winograd_params,
func: conv2d_elementwise_add_winograd_func,
confs: conv2d_elementwise_add_winograd_conf
},
dynamic: {
params: dynamic_params,
func: dynamic_func,
confs: dynamic_conf
},
pool2d: {
params: pool2d_params,
func: pool2d_func,
confs: pool2d_conf
},
pool2d_max: {
params: pool2d_max_params,
func: pool2d_max_func,
confs: pool2d_max_conf
},
pool2d_winograd: {
params: pool2d_winograd_params,
func: pool2d_winograd_func,
confs: pool2d_winograd_conf
},
elementwise_add: {
params: elementwise_add_params,
func: elementwise_add_func,
confs: elementwise_add_conf
},
mul: {
params: mul_params,
func: mul_func,
confs: mul_conf
},
relu: {
params: dynamic_params,
func: dynamic_func,
confs: dynamic_conf
},
relu6: {
params: dynamic_params,
func: dynamic_func,
confs: dynamic_conf
},
scale: {
params: dynamic_params,
func: dynamic_func,
confs: dynamic_conf
},
softmax: {
params: softmax_params,
func: softmax_func,
confs: softmax_conf
},
batchnorm: {
params: batchnorm_params,
func: batchnorm_func,
confs: batchnorm_conf
}
},
atoms: {
getArrayIndexFromTensorPos,
getArrayIndexFromTexturePos,
getTensorPosFromArrayIndex,
getTexturePosFromArrayIndex,
getValueFromTexturePos,
getValueFromTensorPos,
getValueFromTensorPosPacked,
moveTexture2PosToReal,
getPixelsFromTexturePos,
getRangeSumFromArrayIndex,
getRangePowSumFromArrayIndex,
sigmoid,
prelu,
scale,
softmax
}
};
/* eslint-disable */
/**
* @file image,feed 获取图像相关输入
* @author wangqun@baidu.com
*/
export default class imageFeed {
constructor() {
this.fromPixels2DContext = document.createElement('canvas').getContext('2d');
this.fromPixels2DContext2 = document.createElement('canvas').getContext('2d');
this.defaultWidth = 224;
this.defaultHeight = 224;
this.minPixels = 225;
this.pixels = '';
this.defaultParams = {
gapFillWith: '#000',
std: [1, 1, 1]
};
};
/**
* 处理图像方法
* @param inputs
*/
process(inputs) {
const input = inputs.input;
const mode = inputs.mode;
const channel = inputs.channel;
const rotate = inputs.rotate;
const params = {
...this.defaultParams,
...inputs.params
};
let output = [];
if (!this.result) {
const [b, c, h, w] = params.targetShape;
// 计算确定targetShape所需Float32Array占用空间
this.result = new Float32Array(h * w * c);
}
output = this.fromPixels(input, params);
return output;
};
/**
* crop图像&重新设定图片tensor形状
* @param shape
*/
reshape(imageData, opt, scaleSize) {
const {sw, sh} = scaleSize;
const {width, height} = opt;
const hPadding = Math.ceil((sw - width) / 2);
const vPadding = Math.ceil((sh - height) / 2);
let data = imageData.data;
// channel RGB
let red = [];
let green = [];
let blue = [];
// 平均数
let mean = opt.mean;
// 标准差
let std = opt.std;
// 考虑channel因素获取数据
for (let i = 0; i < data.length; i += 4) {
let index = i / 4;
let vIndex = Math.floor(index / sw);
let hIndex = index - (vIndex * sw) - 1;
if (hIndex >= hPadding && hIndex < (hPadding + width) &&
vIndex >= vPadding && vIndex < (vPadding + height)) {
red.push(((data[i] / 255) - mean[0]) / std[0]); // red
green.push(((data[i + 1] / 255) - mean[1]) / std[1]); // green
blue.push(((data[i + 2] / 255) - mean[2]) / std[2]); // blue
}
}
// 转成 GPU 加速 NCHW 格式
let tmp = green.concat(blue);
return red.concat(tmp);
};
/**
* 全部转rgb * H * W
* @param shape
*/
allReshapeToRGB(imageData, opt, scaleSize) {
const {sw, sh} = scaleSize;
const [b, c, h, w] = opt.targetShape;
let data = imageData.data || imageData;
let mean = opt.mean;
let dataLength = data.length;
// let result = new Float32Array(dataLength * 3);
let result = this.result;
// let offsetR = 0;
// let offsetG = dataLength / 4;
// let offsetB = dataLength / 2;
let offset = 0;
let size = h * w;
// h w c
for (let i = 0; i < h; ++i) {
let iw = i * w;
for (let j = 0; j < w; ++j) {
let iwj = iw + j;
for (let k = 0; k < c; ++k) {
let a = iwj * 4 + k;
result[offset++] = (data[a] - mean[k]) / 256;
}
}
}
return result;
};
/**
* 根据scale缩放图像
* @param image
* @param params
* @return {Object} 缩放后的尺寸
*/
reSize(image, params) {
// 原始图片宽高
const width = this.pixelWidth;
const height = this.pixelHeight;
// 缩放后的宽高
let sw = width;
let sh = height;
// 最小边缩放到scale
if (width < height) {
sw = params.scale;
sh = Math.round(sw * height / width);
} else {
sh = params.scale;
sw = Math.round(sh * width / height);
}
this.fromPixels2DContext.canvas.width = sw;
this.fromPixels2DContext.canvas.height = sh;
this.fromPixels2DContext.drawImage(
image, 0, 0, sw, sh);
this.setInputCanvas(image);
return {sw, sh};
};
/**
* 缩放成目标尺寸并居中
*/
fitToTargetSize(image, params, center) {
// 目标尺寸
const targetWidth = params.targetSize.width;
const targetHeight = params.targetSize.height;
this.fromPixels2DContext.canvas.width = targetWidth;
this.fromPixels2DContext.canvas.height = targetHeight;
this.fromPixels2DContext.fillStyle = params.gapFillWith;
this.fromPixels2DContext.fillRect(0, 0, targetHeight, targetWidth);
// 缩放后的宽高
let sw = targetWidth;
let sh = targetHeight;
let x = 0;
let y = 0;
// target的长宽比大些 就把原图的高变成target那么高
if (targetWidth / targetHeight * this.pixelHeight / this.pixelWidth >= 1) {
sw = Math.round(sh * this.pixelWidth / this.pixelHeight);
x = Math.floor((targetWidth - sw) / 2);
}
// target的长宽比小些 就把原图的宽变成target那么宽
else {
sh = Math.round(sw * this.pixelHeight / this.pixelWidth);
y = Math.floor((targetHeight - sh) / 2);
}
// console.log(x, y, sw, sh);
if (center) {
this.fromPixels2DContext.drawImage(
image, x, y, sw, sh);
}
else {
this.fromPixels2DContext.drawImage(
image, 0, 0, sw, sh);
// currentPic = this.fromPixels2DContext.canvas.toDataURL();
}
this.setInputCanvas(image);
// window.currentPic = this.fromPixels2DContext.canvas;// test only, demele me
// document.getElementById('p-c').appendChild(this.fromPixels2DContext.canvas);// test only, demele me
return {sw: targetWidth, sh: targetHeight};
}
/**
* 设置原始video画布
* @param image 原始video
*/
setInputCanvas(image) {
// 原始图片宽高
const width = this.pixelWidth;
const height = this.pixelHeight;
// 画布设置
this.fromPixels2DContext2.canvas.width = width;
this.fromPixels2DContext2.canvas.height = height;
this.fromPixels2DContext2.drawImage(image, 0, 0, width, height);
}
/**
* 获取图像内容
* @param pixels
* @returns {Uint8ClampedArray}
*/
getImageData(pixels, scaleSize) {
const {sw, sh} = scaleSize;
// 复制画布上指定矩形的像素数据
let vals = this.fromPixels2DContext
.getImageData(0, 0, sw, sh);
// crop图像
// const width = pixels.width;
// const height = pixels.height;
return vals;
};
/**
* 计算灰度图
* @param imageData
* @returns {*}
*/
grayscale (imageData) {
let data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// 3 channel 灰度处理无空间压缩
let avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = avg; // red
data[i + 1] = avg; // green
data[i + 2] = avg; // blue
}
return data;
};
fromPixels(pixels, opt) {
let data;
// 原始video画布数据
let data2;
let scaleSize;
if (pixels instanceof HTMLImageElement || pixels instanceof HTMLVideoElement) {
this.pixelWidth = pixels.naturalWidth || pixels.width;
this.pixelHeight = pixels.naturalHeight || pixels.height;
if (opt.scale) { // 兼容以前的,如果有scale就是短边缩放到scale模式
scaleSize = this.reSize(pixels, opt);
data = this.getImageData(opt, scaleSize);
data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight);
}
else if (opt.targetSize) { // 如果有targetSize,就是装在目标宽高里的模式
scaleSize = this.fitToTargetSize(pixels, opt);
data = this.getImageData(opt, scaleSize);
data2 = this.fromPixels2DContext2.getImageData(0, 0, this.pixelWidth, this.pixelHeight);
}
}
if (opt.gray) {
data = grayscale(data);
}
if (opt.reShape) {
data = this.reshape(data, opt, scaleSize);
}
if (opt.targetShape) {
data = this.allReshapeToRGB(data, opt, scaleSize);
}
return [{data: data, shape: opt.shape || opt.targetShape, name: 'image', canvas: data2}];
}
}
/* eslint-enable */
[中文版](./README_cn.md)
# PaddleJS FEED
Baidu paddlejs provides an input processing module implemented by JavaScript to help developers quickly achieve the input data format required by paddle.
\ No newline at end of file
# PaddleJS 输入前处理
百度PaddleJS提供使用 JavaScript 实现的输入处理模块,帮助开发者快速实现输入数据达到 Paddle 要求的输入数据格式。
/**
* @file 直接数据输入
* @author hantianjiao@baidu.com
*/
export default class dataFeed {
toFloat32Array(data) {
for (let i = 0; i < data.length; i++) {
this.f32Arr[i] = data[i];
}
}
getLengthFromShape(shape) {
return shape.reduce((a, b) => a * b);
}
loadData() {
return fetch(this.dataPath).then(res => res.json());
}
getOutput() {
return this.loadData().then(data => {
this.toFloat32Array(data);
return [{
data: this.f32Arr,
shape: this.shape,
name: 'x'
}];
});
}
async process(input) {
this.len = this.getLengthFromShape(input.shape);
if (!this.f32Arr || this.len > this.f32Arr.length) {
this.f32Arr = new Float32Array(this.len);
}
this.shape = input.shape;
this.dataPath = input.input;
let output = await this.getOutput();
return output;
}
}
\ No newline at end of file
/* eslint-disable */
/**
* @file io,loader相关输入输出
* @author wangqun@baidu.com
*/
export default class io {
constructor() {
this.fromPixels2DContext = document.createElement('canvas').getContext('2d');
};
fromPixels(pixels, opt) {
pixels = pixels.input;
const shape = opt[0].shape;
const numChannels = opt[0].shape[0];
if (pixels == null) {
throw new Error(
'pixels passed to tf.browser.fromPixels() can not be null');
}
let vals;
// tslint:disable-next-line:no-any
// tslint:disable-next-line:no-any
if (pixels.getContext != null) {
// tslint:disable-next-line:no-any
vals = pixels
.getContext('2d')
.getImageData(0, 0, pixels.width, pixels.height)
.data;
} else if (pixels instanceof ImageData) {
vals = pixels.data;
} else if (
pixels instanceof HTMLImageElement ||
pixels instanceof HTMLVideoElement) {
if (this.fromPixels2DContext == null) {
throw new Error(
'Can\'t read pixels from HTMLImageElement outside ' +
'the browser.');
}
this.fromPixels2DContext.canvas.width = pixels.width;
this.fromPixels2DContext.canvas.height = pixels.height;
this.fromPixels2DContext.drawImage(
pixels, 0, 0, pixels.width, pixels.height);
vals = this.fromPixels2DContext
.getImageData(0, 0, pixels.width, pixels.height)
.data;
} else {
}
let values;
if (numChannels === 4) {
values = new Array(vals);
} else {
const numPixels = (shape[1] || pixels.width) * (shape[2] ||pixels.height);
// console.log(numPixels, numPixels * numChannels);
values = new Array(numPixels * numChannels);
for (let i = 0; i < numPixels; i++) {
for (let channel = 0; channel < numChannels; ++channel) {
values[i * numChannels + channel] = vals[i * 4 + channel];
}
}
}
// console.log(pixels.height, pixels.width, numChannels, values);
// const outShape: [number, number, number] =
// [pixels.height, pixels.width, numChannels];
values = [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
7.0,
0.0,
0.0,
0.0,
0.0,
0.0,
6.0,
7.0,
0.0,
0.0,
0.0,
0.0,
3.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
3.0,
0.0,
0.0,
14.0,
16.0,
8.0,
1.0,
0.0,
0.0,
0.0,
14.0,
1.0,
0.0,
0.0,
14.0,
4.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
5.0,
13.0,
0.0,
0.0,
0.0,
9.0,
0.0,
27.0,
0.0,
0.0,
0.0,
5.0,
0.0,
0.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
4.0,
0.0,
0.0,
5.0,
11.0,
5.0,
4.0,
8.0,
0.0,
0.0,
15.0,
7.0,
0.0,
2.0,
7.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
11.0,
2.0,
0.0,
0.0,
0.0,
0.0,
4.0,
11.0,
3.0,
0.0,
2.0,
0.0,
5.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
0.0,
0.0,
10.0,
6.0,
0.0,
0.0,
0.0,
0.0,
4.0,
9.0,
0.0,
0.0,
2.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
8.0,
0.0,
8.0,
11.0,
0.0,
4.0,
113.0,
202.0,
249.0,
255.0,
255.0,
135.0,
44.0,
0.0,
7.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
0.0,
2.0,
0.0,
33.0,
188.0,
230.0,
101.0,
52.0,
6.0,
106.0,
162.0,
183.0,
11.0,
0.0,
4.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
9.0,
0.0,
4.0,
58.0,
230.0,
189.0,
31.0,
0.0,
3.0,
0.0,
14.0,
0.0,
204.0,
17.0,
7.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
20.0,
24.0,
231.0,
181.0,
0.0,
0.0,
5.0,
4.0,
2.0,
0.0,
119.0,
228.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
173.0,
232.0,
32.0,
4.0,
10.0,
0.0,
0.0,
7.0,
79.0,
230.0,
108.0,
18.0,
0.0,
10.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
100.0,
246.0,
47.0,
0.0,
5.0,
0.0,
1.0,
8.0,
63.0,
216.0,
109.0,
0.0,
0.0,
6.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
8.0,
122.0,
210.0,
0.0,
31.0,
0.0,
8.0,
28.0,
109.0,
235.0,
182.0,
0.0,
13.0,
0.0,
22.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
128.0,
233.0,
0.0,
6.0,
66.0,
126.0,
180.0,
191.0,
220.0,
27.0,
0.0,
0.0,
11.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
78.0,
246.0,
233.0,
220.0,
255.0,
199.0,
59.0,
235.0,
68.0,
12.0,
0.0,
1.0,
2.0,
1.0,
10.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
0.0,
80.0,
120.0,
139.0,
62.0,
0.0,
155.0,
211.0,
5.0,
10.0,
0.0,
0.0,
0.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
5.0,
2.0,
0.0,
0.0,
90.0,
255.0,
70.0,
0.0,
0.0,
0.0,
9.0,
0.0,
0.0,
9.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
17.0,
5.0,
0.0,
11.0,
47.0,
227.0,
159.0,
0.0,
0.0,
8.0,
0.0,
0.0,
2.0,
6.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
5.0,
0.0,
0.0,
0.0,
4.0,
213.0,
207.0,
19.0,
0.0,
0.0,
3.0,
12.0,
0.0,
2.0,
4.0,
2.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
16.0,
7.0,
91.0,
253.0,
50.0,
0.0,
0.0,
4.0,
0.0,
2.0,
0.0,
1.0,
2.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
5.0,
0.0,
45.0,
252.0,
131.0,
0.0,
8.0,
0.0,
7.0,
0.0,
15.0,
5.0,
0.0,
0.0,
2.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
8.0,
11.0,
207.0,
205.0,
30.0,
2.0,
0.0,
0.0,
22.0,
0.0,
0.0,
4.0,
9.0,
11.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
14.0,
155.0,
255.0,
28.0,
0.0,
0.0,
6.0,
4.0,
0.0,
5.0,
150.0,
210.0,
91.0,
17.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
14.0,
40.0,
250.0,
91.0,
0.0,
0.0,
7.0,
0.0,
0.0,
24.0,
0.0,
10.0,
130.0,
183.0,
147.0,
11.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
207.0,
146.0,
4.0,
0.0,
4.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
25.0,
237.0,
29.0,
0.0,
12.0,
0.0,
0.0,
14.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
13.0,
0.0,
15.0,
7.0,
0.0,
9.0,
2.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
4.0,
0.0,
4.0,
3.0,
4.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
];
return [{data: values, shape: shape, name: 'pixel'}];
}
}
/* eslint-enable */
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/* eslint-disable */
/**
* @file 公共参数
* @author yangmingming
*/
export default `
// dynamic的input数据
const float multi_value = float(MULTI_VALUE);
const float bias_value = float(BIAS_VALUE);
// 输出数据
const int width_shape_out = WIDTH_SHAPE_OUT;
const int height_shape_out = HEIGHT_SHAPE_OUT;
const int width_texture_out = WIDTH_TEXTURE_OUT;
const int height_texture_out = HEIGHT_TEXTURE_OUT;
const int channel_out = CHANNEL_OUT;
const int offset_y_out = OFFSET_Y_OUT;
`;
此差异已折叠。
此差异已折叠。
此差异已折叠。
/* eslint-disable */
/**
* @file 公共方法
* @author yangmingming
* desc 根据当前材质坐标位置获取值
*/
// 获取材质中的像素
export default `
#define getPixelsFromTexturePos_TEXTURE_NAME(pos) TEXTURE2D(TEXTURE_NAME, pos)
`;
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册