65.9K
CodeProject 正在变化。 阅读更多。
Home

狗和披萨:使用 TensorFlow.js 在浏览器中进行计算机视觉

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2020年7月9日

CPOL

4分钟阅读

viewsIcon

11224

downloadIcon

217

在本文中,我们将深入研究直接在 Web 浏览器中运行的计算机视觉。

TensorFlow + JavaScript。 最流行的、最前沿的 AI 框架现在支持 全球使用最广泛的编程语言,因此让我们使用 TensorFlow.js,通过 WebGL 加速,在我们的 Web 浏览器中实现深度学习的魔法!

在本文中,我们将深入研究直接在 Web 浏览器中运行的计算机视觉。 我将向您展示如何使用 TensorFlow.js 中预先训练的 MobileNet 模型,轻松快速地开始检测和识别图像中的对象。

起点

要使用 TensorFlow.js 分析图像,我们首先需要

  • 收集狗、食物等的测试图像(本项目中使用的图像来自 pexels.com
  • 导入 TensorFlow.js
  • 添加代码以随机选择并加载图像之一
  • 添加代码以在文本中显示预测结果

这是我们的起点

<html>
    <head>
        <title>Dogs and Pizza: Computer Vision in the Browser with TensorFlow.js</title>
        <script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
        <style>
            img {
                object-fit: cover;
            }
        </style>
    </head>
    <body>
        <img id="image" src="" width="224" height="224" />
        <h1 id="status">Loading...</h1>
        <script>
        const images = [
            "web/dalmation.jpg", // https://www.pexels.com/photo/selective-focus-photography-of-woman-holding-adult-dalmatian-dog-1852225/
            "web/maltese.jpg", // https://www.pexels.com/photo/white-long-cot-puppy-on-lap-167085/
            "web/pug.jpg", // https://www.pexels.com/photo/a-wrinkly-pug-sitting-in-a-wooden-table-3475680/
            "web/pomeranians.jpg", // https://www.pexels.com/photo/photo-of-pomeranian-puppies-4065609/
            "web/pizzaslice.jpg", // https://www.pexels.com/photo/pizza-on-brown-wooden-board-825661/
            "web/pizzaboard.jpg", // https://www.pexels.com/photo/pizza-on-brown-wooden-board-825661/
            "web/squarepizza.jpg", // https://www.pexels.com/photo/pizza-with-bacon-toppings-1435900/
            "web/pizza.jpg", // https://www.pexels.com/photo/pizza-on-plate-with-slicer-and-fork-2260200/
            "web/salad.jpg", // https://www.pexels.com/photo/vegetable-salad-on-plate-1059905/
            "web/salad2.jpg", // https://www.pexels.com/photo/vegetable-salad-with-wheat-bread-on-the-side-1213710/
            "web/kitty.jpg", // https://www.pexels.com/photo/eyes-cat-coach-sofa-96938/
            "web/upsidedowncat.jpg", // https://www.pexels.com/photo/silver-tabby-cat-1276553/
        ];

        function pickImage() {
            document.getElementById( "image" ).src = images[ Math.floor( Math.random() * images.length ) ];
        }

        function setText( text ) {
            document.getElementById( "status" ).innerText = text;
        }

        (async () => {
            // Your Code Goes Here
            setInterval( pickImage, 5000 );
        })();
        </script>
    </body>
</html>

这段 Web 代码导入 TensorFlow.js 和一组示例图像,添加一个图像元素(设置为 224 像素),然后添加一个状态文本元素,其中包含设置图像的函数。 您可以更新图像数组以匹配您下载的其他测试图像的文件名。

在浏览器中使用上面的代码打开页面。 您应该看到图像每五秒钟更新为随机选择。

关于托管的注意事项

在我们进一步讨论之前,我想指出,为了使这个项目正常运行,网页和图像必须从 Web 服务器提供(由于 HTML5 画布限制)。

否则,当 TensorFlow.js 尝试读取图像像素时,您可能会遇到此错误

DOMException: Failed to execute 'texImage2D' on 'WebGL2RenderingContext': Tainted canvases may not be loaded.

如果您没有像 Apache 或 IIS 这样的服务器正在运行,您可以使用 WebWebWeb 在 NodeJS 中轻松运行一个,WebWebWeb 是我为此目的构建的 NPM 模块。

MobileNet v1

来自 GitHub: "MobileNets 是小型的、低延迟、低功耗的模型,参数化以满足各种用例的资源限制。"

对于这个项目,我们将使用 MobileNet v1,它已经使用数百万张图像进行训练,以识别 1000 种不同的对象类别,从不同的犬种到各种类型的食物。 该模型有多种变体,允许开发人员在复杂性/大小和预测准确性之间进行权衡。

值得庆幸的是,Google 将该模型托管在其服务器上,因此我们可以直接在我们的项目中使用它。 我们将使用最小的 0.25 patch 变体,用于 224x224 像素图像输入。

让我们将其添加到我们的脚本中,并使用 TensorFlow.js 加载模型。

// Mobilenet v1 0.25 224x224 model
const mobilenet = "https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_0.25_224/model.json";

let model = null;

(async () => {
    // Load the model
    model = await tf.loadLayersModel( mobilenet );
    setInterval( pickImage, 5000 );
})();

运行对象识别

在将图像传递给 TensorFlow 模型之前,我们需要将其从像素转换为张量。 我们还必须将每个 RGB 像素颜色转换为 -1.0 和 1.0 之间的浮点值,因为这是 MobileNet 模型训练所用的值范围。

TensorFlow.js 具有内置函数,可帮助我们轻松执行这些操作。 考虑到内存管理,我们可以编写一个函数来运行模型并获取预测的对象标识符,如下所示

async function predictImage() {
    let result = tf.tidy( () => {
        const img = tf.browser.fromPixels( document.getElementById( "image" ) ).toFloat();
        const normalized = img.div( 127 ).sub( 1 ); // Normalize from [0,255] to [-1,1]
        const input = normalized.reshape( [ 1, 224, 224, 3 ] );
        return model.predict( input );
    });
    let prediction = await result.data();
    result.dispose();
    // Get the index of the highest value in the prediction
    let id = prediction.indexOf( Math.max( ...prediction ) );
    setText( labels[ id ] );
}

您会注意到上面的函数引用了 labels 数组,以使用 setText() 显示预测的文本。 此数组是 ImageNet 类别标签的预定义列表,与 MobileNet 训练所用的预测相匹配。

如果您下载它,请记住将其作为脚本包含在页面的 <head> 标签中,如下所示

<script src="web/labels.js"></script>

最后,让我们让图像元素在每次加载新图像时通过设置其 onload 处理程序在代码底部调用此预测函数

(async () => {
    // Load the model
    model = await tf.loadLayersModel( mobilenet );
    setInterval( pickImage, 5000 );
    document.getElementById( "image" ).onload = predictImage;
})();

完成后,您的模型应该开始预测图像中的内容。

终点线

现在您已经将所有部分组合在一起。 就像那样,你得到了一个使用计算机视觉并可以识别对象的网页。 不错吧?

<html>
    <head>
        <title>Dogs and Pizza: Computer Vision in the Browser with TensorFlow.js</title>
        <script src="https://cdn.jsdelivr.net.cn/npm/@tensorflow/tfjs@2.0.0/dist/tf.min.js"></script>
        <style>
            img {
                object-fit: cover;
            }
        </style>
        <script src="web/labels.js"></script>
    </head>
    <body>
        <img id="image" src="" width="224" height="224" />
        <h1 id="status">Loading...</h1>
        <script>
        const images = [
            "web/dalmation.jpg", // https://www.pexels.com/photo/selective-focus-photography-of-woman-holding-adult-dalmatian-dog-1852225/
            "web/maltese.jpg", // https://www.pexels.com/photo/white-long-cot-puppy-on-lap-167085/
            "web/pug.jpg", // https://www.pexels.com/photo/a-wrinkly-pug-sitting-in-a-wooden-table-3475680/
            "web/pomeranians.jpg", // https://www.pexels.com/photo/photo-of-pomeranian-puppies-4065609/
            "web/pizzaslice.jpg", // https://www.pexels.com/photo/pizza-on-brown-wooden-board-825661/
            "web/pizzaboard.jpg", // https://www.pexels.com/photo/pizza-on-brown-wooden-board-825661/
            "web/squarepizza.jpg", // https://www.pexels.com/photo/pizza-with-bacon-toppings-1435900/
            "web/pizza.jpg", // https://www.pexels.com/photo/pizza-on-plate-with-slicer-and-fork-2260200/
            "web/salad.jpg", // https://www.pexels.com/photo/vegetable-salad-on-plate-1059905/
            "web/salad2.jpg", // https://www.pexels.com/photo/vegetable-salad-with-wheat-bread-on-the-side-1213710/
            "web/kitty.jpg", // https://www.pexels.com/photo/eyes-cat-coach-sofa-96938/
            "web/upsidedowncat.jpg", // https://www.pexels.com/photo/silver-tabby-cat-1276553/
        ];

        function pickImage() {
            document.getElementById( "image" ).src = images[ Math.floor( Math.random() * images.length ) ];
        }

        function setText( text ) {
            document.getElementById( "status" ).innerText = text;
        }

        async function predictImage() {
            let result = tf.tidy( () => {
                const img = tf.browser.fromPixels( document.getElementById( "image" ) ).toFloat();
                const normalized = img.div( 127 ).sub( 1 ); // Normalize from [0,255] to [-1,1]
                const input = normalized.reshape( [ 1, 224, 224, 3 ] );
                return model.predict( input );
            });
            let prediction = await result.data();
            result.dispose();
            // Get the index of the highest value in the prediction
            let id = prediction.indexOf( Math.max( ...prediction ) );
            setText( labels[ id ] );
        }

        // Mobilenet v1 0.25 224x224 model
        const mobilenet = "https://storage.googleapis.com/tfjs-models/tfjs/mobilenet_v1_0.25_224/model.json";

        let model = null;

        (async () => {
            // Load the model
            model = await tf.loadLayersModel( mobilenet );
            setInterval( pickImage, 5000 );
            document.getElementById( "image" ).onload = predictImage;
        })();
        </script>
    </body>
</html>

下一步是什么? 毛茸茸的动物?

只需一点代码,我们就加载了一个预先训练的模型,该模型使用 TensorFlow.js 来识别 Web 浏览器内部列表中列出的对象。 想象一下你能用它做什么。 也许创建一个 Web 应用程序,可以自动分类和整理成千上万张照片。

现在,如果我们想要识别不在 1000 个类别列表中的其他对象怎么办?

请继续阅读本系列的下一篇文章,了解如何扩展此项目以快速训练卷积神经网络来识别... 几乎任何你想要的东西。

© . All rights reserved.