/* eslint-disable */ /** * @file image,feed 获取图像相关输入 * @author wangqun@baidu.com */ export default class imageFeed { constructor() { this.fromPixels2DContext = 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; this.result = new Float32Array(h * w * 3); } 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; let red = []; let green = []; let blue = []; let mean = opt.mean; let std = opt.std; for (let i = 0; i < data.length; i += 4) { // img_mean 0.485, 0.456, 0.406 //img_std 0.229, 0.224, 0.225 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 } } 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; 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); 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(); } // 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}; } /** * 获取图像内容 * @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) { 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; 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); } else if (opt.targetSize) { // 如果有targetSize,就是装在目标宽高里的模式 scaleSize = this.fitToTargetSize(pixels, opt); data = this.getImageData(opt, scaleSize); } } if (opt.gray) { data = grayscale(data); } if (opt.shape) { 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'}]; } } /* eslint-enable */