wasm 前端抠图 性能对比

原文链接: wasm 前端抠图 性能对比

上一篇: wasm cpp 传值

下一篇: vscode 使用 clang 格式化 c++代码

inline 的对比好像不明显

up-e788f917ea690f17701f869364cdd5195e5.pngup-9af1ba574ba78592d4aff2f3fcc0cf788ee.png

手动加了inline后, 感觉O3的优化应该是已经做了这些处理了

up-890ce29e1954877d0b2b18af93429a50f21.pngup-63ea57d8a2794eb489974eaaa919c7f044d.png

_________________________________________________________________'';;

目前看来对于计算密集型任务, wasm也就那样了, 相比与开发难度(c++/c) 以及移动端的支持来讲, 不是很推荐使用....尤其是需要兼容什么安卓4, ios9之类的, 想都不想js一把梭

如果是纯桌面端, 且能够把控设备和浏览器的话, 还是可以试试的

大概也能提高30%左右.............

不过目前打包后的js文件, 如果使用webpack的import语法引入, 会报fs找不到的问题, 需要使用script标签引入

后面有时间看看怎么能用import 引入

up-8186c60dc2b6200066ee1f68c2ae74c5580.png

up-e93275e0bb7b3765c5b4eef11543ba20a99.png

几次试下来基本上数据波动不大

up-73bb3950652ba5b7f38acbd6273548bf42b.png

index.vue

<template>
  <div class="wrap">
    <img
      @click="clickInput"
      class="box"
      ref="inputRef"
      :src="imageUrl"
      alt=""
    />
    <canvas :style="canvasStyleRef" ref="canvasRef" class="box"></canvas>
    <img :style="canvasStyleRef" ref="outputRef" class="box" src="" alt="" />
  </div>
</template>

<script>
import { ref, onMounted } from "vue";
import { delColor } from "./util";
export default {
    props:['imageUrl'],
  setup(props) {
    console.log("props", props);
    const imageUrl = ref(props.imageUrl);
    const canvasRef = ref(null);
    const outputRef = ref(null);
    const inputRef = ref(null);
    const canvasStyleRef = ref("");
    // 将图片绘制到canvas中
    const input = () => {
      if (!inputRef.value || !canvasRef.value) return;
      console.log("input");
      canvasRef.value
        .getContext("2d")
        .drawImage(
          inputRef.value,
          0,
          0,
          inputRef.value.width,
          inputRef.value.height
        );
    };

    // 将canvas中的内容画到图片中
    const output = () => {
      if (!outputRef.value || !canvasRef.value) return;
      console.log("output");
      const url = canvasRef.value.toDataURL("image/png", 1);
      outputRef.value.src = url;
    };

    onMounted(() => {
      inputRef.value.onload = () => {
        // const { width, height } = inputRef.value.getBoundingClientRect();
        canvasRef.value.width = inputRef.value.width;
        canvasRef.value.height = inputRef.value.height;
        // canvasRef.value.height =  width;
        // canvasRef.value.height =  height;
        input();
        output();
        console.log(inputRef.value.width);
        canvasStyleRef.value = `width:${canvasRef.width}px;height:${canvasRef.height}px`;
      };
    });

    const clickInput = (e) => {
      console.log(e);
      const x = e.offsetX;
      const y = e.offsetY;
      const color = canvasRef.value.getContext("2d").getImageData(x, y, 1, 1)
        .data;
      delColor(canvasRef.value, x, y, color);
      output();
    };
    return {
      clickInput,
      canvasRef,
      canvasStyleRef,
      inputRef,
      outputRef,
      imageUrl,
    };
  },
};
</script>

<style lang="less">
.wrap {
  display: flex;
  align-items: center;
  justify-content: space-around;
  width: 100%;
  height: 100%;

  .box {
    //   width: 100%;
    // width: 25%;
    // height: auto;
  }
}
</style>

uitl.js

function fillWasm(data, x, y, w, h) {
  const size = data.length;
  const ccall = Module.ccall;
  const numBytes = size * Uint8Array.BYTES_PER_ELEMENT;
  const ptr = Module._malloc(numBytes);
  const heapBytes = new Uint8Array(Module.HEAP8.buffer, ptr, numBytes);
  const imageDataBuffer = Uint8Array.from(data);
  heapBytes.set(new Uint8Array(imageDataBuffer));
  const st = +new Date();
  ccall(
    "fillWasm",
    "null",
    ["Uint8Array", "number", "number", "number", "number"],
    [heapBytes.byteOffset, x, y, w, h]
  );
  console.log("time wasm:", +new Date() - st);
  const resultArray = new Uint8Array(Module.HEAP8.buffer, ptr, size);
  const result = new Uint8ClampedArray(resultArray);
  return result
}
// console.log(wasmModule)
export const delColor = (canvas, x, y) => {
  const w = canvas.width;
  const h = canvas.height;
  const ctx = canvas.getContext("2d");
  const { data, width, height } = ctx.getImageData(0, 0, w, h);
  const newData = fillWasm(data, x, y, width, height);
  const b2 = new ImageData(newData, width, height);
  ctx.putImageData(b2, 0, 0);
};

fillWasm.cpp

#include <stdlib.h>
#include <emscripten.h>
#include <iostream>
#include <stack>
#include <map>

using namespace std;

void setColor(uint8_t *data, int x, int y, int w, uint8_t *c)
{
    for (int i = 0; i < 4; i++)
    {
        data[(y * w + x) * 4 + i] = c[i];
    }
}

uint8_t *getColor(uint8_t *data, int x, int y, int w)
{
    return data + (y * w + x) * 4;
}

bool compare(uint8_t *c1, uint8_t *c2)
{
    int d = abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2]);
    return d < 100;
}

extern "C"
{
    void fillWasm(uint8_t *data, int x, int y, int w, int h);
}

bool canVisit(map<int, bool> &v, int x, int y, int w, int h)
{
    if (x < 0 || y < 0 || x >= w || y >= h)
        return 0;
    return !v[(x << 16) + y];
}

void setVisit(map<int, bool> &v, int x, int y, bool value)
{
    v[(x << 16) + y] = value;
}

void fillWasm(uint8_t *data, int x, int y, int w, int h)
{
    int byteSize = w * h * 4;
    uint8_t *dataMock = new uint8_t[byteSize];
    memcpy(dataMock, data, byteSize);

    uint8_t *sourceColor = getColor(dataMock, x, y, w);
    uint8_t fillColor[] = {98, 237, 240, 255};
    uint8_t redColor[] = {255, 0, 0, 255};

    map<int, bool> v;
    int directionSize = 4;
    int direction[4][2] = {
        {0, 1},
        {0, -1},
        {1, 0},
        {-1, 0},
    };

    stack<int *> st;
    int init[3] = {x, y, 0};
    st.push(init);

    int count = 0;
    while (st.size())
    {
        count++;
        int *top = st.top();
        int tx = top[0];
        int ty = top[1];
        int td = top[2];
        setColor(data, tx, ty, w, fillColor);
        setVisit(v, tx, ty, 1);

        if (td == directionSize)
        {

            st.pop();
            continue;
        }

        int dx = direction[td][0];
        int dy = direction[td][1];
        int nx = tx + dx;
        int ny = ty + dy;
        top[2]++;
        if (
            canVisit(v, nx, ny, w, h) &&
            compare(sourceColor, getColor(dataMock, nx, ny, w)))
        {
            int *ptr = new int[3];
            ptr[0] = nx;
            ptr[1] = ny;
            ptr[2] = 0;
            st.push(ptr);
            setVisit(v, tx, ty, 1);
        }
        else if (
            nx >= 0 &&
            ny >= 0 &&
            nx < w &&
            ny < h &&
            !compare(sourceColor, getColor(dataMock, nx, ny, w)))
        {
            setColor(dataMock, nx, ny, w, redColor);
        }
    }
    cout << "count:" << count << endl;
}

int main(int argc, char **argv)
{
    return 0;
}
/*

emcc -O3 -s   \
    -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap","ccall"]' \
    -s EXPORTED_FUNCTIONS='["_main","_fillWasm"]' \
    -s ALLOW_MEMORY_GROWTH \
     fillWasm.cpp

*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值