Статьи

Как сделать ваше веб-приложение умнее с помощью распознавания изображений

Clarifai — это API, который обеспечивает невероятно простое в использовании распознавание изображений и видео и очень интересное для реализации. В этой статье мы рассмотрим перетаскивание изображений со всего Интернета в простое веб-приложение, которое будет читать их и сообщать нам, что они считают.

В этой демонстрации мы будем использовать Node.js для сервера и относительно простой интерфейс, который использует JQuery для запросов AJAX. Если вы не сильны в Node.js, это будет нормально, если вы находитесь на уровне, на котором вы можете node app.js запускать npm install чтобы node app.js модули и node app.js в командной строке для node app.js вашего веб-приложения. Вам не нужно будет слишком много настраивать в нем, и вы можете изучить одну или две вещи в конце, запустив существующий код!

Код

Весь пример кода для этой демонстрации доступен на GitHub .

Начиная

Чтобы начать, перейдите на домашнюю страницу Clarifai и нажмите кнопку «Зарегистрироваться сейчас» в правом верхнем углу:

Домашняя страница Clarifai

Зарегистрируйтесь, указав свой адрес электронной почты и данные:

Страница регистрации Clarifai

Мы хотим создать новое приложение, поэтому мы отправляемся на экран приложения, щелкая пункт меню «Приложения» слева.

Создание нового приложения в Clarifai

Clarifai пока не позволит нам создать приложение, так как нам нужно выбрать план:

Поиск кнопки выбора плана

Давайте выберем план, чтобы мы могли добиться успеха. Для нашей демонстрации бесплатный план должен быть более чем подходящим. Мы можем обновить позже, если это необходимо:

Выбор плана Clarifai

Теперь нам разрешено создавать приложение, для этого мы можем либо щелкнуть левой кнопкой мыши по пункту меню «Приложения», либо по ссылке «создать приложение»:

Навигация назад для создания приложения

Нажмите кнопку «Создать новое приложение»:

Кнопка «Создать новое приложение»

Мы даем нашему новому приложению имя (например, «Image Recognizer»), оставляем модель по умолчанию как есть и устанавливаем наш язык (мы сохранили его на английском, вы можете предпочесть другой язык!). Чтобы закончить, нажмите «Создать приложение»:

Создание приложения Clarifai

Наши новые данные приложения должны появиться. Два наиболее важных фрагмента, которые мы хотим скопировать в безопасное место, — это «Идентификатор клиента» и «Секрет клиента» — они понадобятся нам для доступа к Clarifai на нашем сервере, который мы настроим дальше.

Поиск ваших ключей Clarifai

Настройка нашего сервера Node.js

У Clarifai есть клиент Node.js, который мы можем использовать для взаимодействия со своим сервисом, доступным на GitHub . Загрузите репо на свой компьютер. В частности, нам нужен файл clarifai_node.js .

Создайте каталог для вашего Node-сервера и добавьте файл JavaScript `clarifai_node.js` в корневой каталог.

Наши серверные функции Node.js будут находиться в файле JavaScript с именем app.js Здесь мы будем управлять нашими запросами на распознавание изображений с помощью Clarifai. app.js имеет следующий JavaScript:

 var Clarifai = require("./clarifai_node.js"), express = require("express"), app = express(), server = require("http").Server(app), bodyParser = require("body-parser"), port = process.env.PORT || 5000; app.use(bodyParser.json()); Clarifai.initAPI("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET"); function identifyClarifaiError(err) { // Default error function from Clarifai we won't go into but you can find it in the GitHub download of this code! } app.post("/examineImage", function(req, resp) { var imageURL = req.body.imageRequested; console.log("Response was ", imageURL); Clarifai.tagURL(imageURL, "Image from browser", commonResultHandler); function commonResultHandler(err, res) { if (err != null) { identifyClarifaiError(err); } else { if (typeof res["status_code"] === "string" && (res["status_code"] === "OK" || res["status_code"] === "PARTIAL_ERROR")) { if (res["results"][0]["status_code"] === "OK") { var tags = res["results"][0].result["tag"]["classes"]; console.log("Tags found were: ", tags); resp.send(tags); } else { console.log("We had an error... Details: " + " docid=" + res.results[0].docid + " local_id=" + res.results[0].local_id + " status_code="+res.results[0].status_code + " error = " + res.results[0]["result"]["error"]); resp.send("Error: " + res.results[0]["result"]["error"]); } } } } }); app.get("/", function(request, response) { response.sendFile(__dirname + "/public/index.html"); }); app.get(/^(.+)$/, function(req, res) { res.sendFile(__dirname + "/public/" + req.params[0]); }); app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send("Something broke!"); }); server.listen(port, function() { console.log("Listening on " + port); }); 

Большая часть кода — это базовые функциональные возможности Node Express Server, которые мы не рассмотрим в этой статье. Если вы не уверены, что эти части имеют в виду, вы можете оставить их как есть и просто наслаждаться работающим сервером Node.

Биты, которые относятся конкретно к Clarifai, начинаются с нашей строки кода, которая включает в себя наш файл clarifai_node.js :

 var Clarifai = require("./clarifai_node.js"), 

Следующая строка, которая использует Clarifai, начинает инициализацию API. Это дает нам доступ к API, используя идентификатор клиента и секрет клиента, которые мы ранее скопировали в безопасное место. Вставьте их в соответствующие места:

 Clarifai.initAPI("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET"); 

Затем у нас есть POST-запрос, который Node-сервер будет искать и отвечать на него. Этот запрос предполагает получение веб-URL для изображения в нашем теле POST с именем imageRequested при доступе через /examineImage . Он записывает любой найденный URL в нашу консоль:

 app.post("/examineImage", function(req, resp) { var imageURL = req.body.imageRequested; console.log("Response was ", imageURL); 

Затем мы запускаем функцию из клиента клиента Clarifai Node с именем tagURL() . Эта функция принимает три параметра: URL-адрес изображения, которое мы хотим, чтобы Clarifai изучил, имя, которое мы даем изображению (вы можете изменить это имя и адаптировать его к URL-адресу, если хотите, но для простоты мы сохранили его как общий имя для всех) и функцию обратного вызова после ее запуска:

 Clarifai.tagURL(imageURL, "Image from browser", commonResultHandler); 

В рамках commonResultHandler() мы реагируем на то, что Clarifai возвращает нам. Если он возвращает ошибку, мы передаем ее в функцию identifyClarifaiError() которую мы можем оставить как есть (вы можете найти эту функцию в загрузке GitHub выше). Он содержит серию проверок кодов состояния, полученных от Clarifai. Для наших целей в этой базовой демонстрации мы не будем описывать все, что она делает, поскольку вам не нужно ее настраивать.

 function commonResultHandler(err, res) { if (err != null) { identifyClarifaiError(err); } // Continues further 

Если у нас нет явной ошибки, мы дважды проверяем, что возвращенные данные Clarifai также не содержат статусы ошибок в своем res["status_code"] :

 else { if (typeof res["status_code"] === "string" && (res["status_code"] === "OK" || res["status_code"] === "PARTIAL_ERROR")) { 

Clarifai возвращает массив результатов в res["results"] — по одному для каждого заданного изображения. Поскольку мы предоставляем только одно изображение, нам нужно получить только первый элемент в этом массиве. У каждого элемента будет объект данных JSON, который он имеет для этого изображения. Возвращенный JSON выглядит так:

 { "docid": 6770681588539017000, "url": "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQSoU65AMIOpJ2rwtvdJyuSExIjcwQfuIup8sm6tesdWwtCEajzVw", "status_code": "OK", "status_msg": "OK", "local_id": "Image from browser", "result": { "tag": { "concept_ids": [ "ai_l8TKp2h5", "ai_VPmHr5bm" ], "classes": [ "people", "adult" ], "probs": [ 0.9833399057388306, 0.9695020318031311 ] } }, "docid_str": "c009c46cf0c7b68b5df64b083c2547b4" } 

Наиболее важные биты, которые мы можем использовать, находятся внутри объекта result . Он содержит три массива, один из которых перечисляет идентификаторы концепта Clarifai для найденных элементов, один — «классы» для них (понятные человеку имена для каждого концепта), а другой — вероятность каждого из них правильна. Их порядок совпадает с тегом каждого объекта, поэтому в приведенном выше примере идентификатор концепции "ai_l8TKp2h5" известен как "people" и Clarifai примерно на 0.9833399057388306 процентов уверены, что на этом изображении есть люди.

Используя эти данные, мы можем перечислить эти классы, чтобы показать, что обнаружил Clarifai. В приведенном ниже коде мы проверяем код состояния в этом результате "OK" а затем отправляем массив тегов в ответ на запрос AJAX внешнего интерфейса.

 if (res["results"][0]["status_code"] === "OK") { var tags = res["results"][0].result["tag"]["classes"]; console.log("Tags found were: ", tags); resp.send(tags); } 

В противном случае, если код состояния не "OK" , мы регистрируем детали ошибки и отправляем ее обратно в наше веб-приложение:

 else { console.log("We had an error... Details: " + " docid=" + res.results[0].docid + " local_id=" + res.results[0].local_id + " status_code="+res.results[0].status_code + " error = " + res.results[0]["result"]["error"]); resp.send("Error: " + res.results[0]["result"]["error"]); } 

Наш интерфейс JavaScript

Многое из переднего конца может быть сделано, как вы хотите. В нашем примере внешний интерфейс будет относительно простым, который позволяет перетаскивать изображение в приложение из других источников в Интернете. Мы читаем URL-адрес, отправляем его на наш Node-сервер выше, а затем ожидаем список отображаемых тегов.

Наш полный интерфейсный файл JavaScript выглядит так:

 var baseUrl = window.location.origin, dropArea = document.getElementById("dropArea"); dropArea.addEventListener("drop", imageDropped, false); function imageDropped(evt) { evt.stopPropagation(); evt.preventDefault(); var imageHTML = evt.dataTransfer.getData("text/html"), dataParent = $("<div>").append(imageHTML), imageRequested = $(dataParent).find("img").attr("src"), $imageFound = $("#imageFound"); console.log(imageRequested); $imageFound.attr("src", imageRequested); $.ajax({ type: "POST", url: baseUrl + "/examineImage", contentType: "application/json; charset=utf-8", dataType: "json", data: JSON.stringify({"imageRequested": imageRequested}), success: function(data) { console.log(data); var tags = ""; for (var i = 0; i The initial line of code reads in the URL we've got in the browser bar, as this is also the URL for our server: [code language="js"] var baseUrl = window.location.origin, 

Затем мы #dropArea JavaScript следить за элементом #dropArea и добавляем прослушиватель событий, который будет запускать imageDropped() если мы что-то imageDropped() на него:

 dropArea = document.getElementById("dropArea"); dropArea.addEventListener("drop", imageDropped, false); 

imageDropped() начинается с предотвращения обычного поведения, которое происходит, когда файл перетаскивается в браузер (он обычно загружает этот файл в окно браузера, в которое вы перетаскивали его):

 function imageDropped(evt) { evt.stopPropagation(); evt.preventDefault(); 

Как только мы убедились, что обычная функциональность перетаскивания браузером была исключена, мы получаем HTML из пропущенных данных события. Данные обычно должны включать <img> , но иногда есть другие теги, которые идут вместе с ним, такие как <meta> и другие теги <div> . Чтобы убедиться, что у нас всегда есть родительский элемент для просмотра, мы добавляем любые данные, которые у нас есть, в <div> . Затем мы находим внутри него <img> , читаем его атрибут src и помещаем это значение в переменную с именем imageRequested :

 var imageHTML = evt.dataTransfer.getData("text/html"), dataParent = $("<div>").append(imageHTML), imageRequested = $(dataParent).find("img").attr("src") 

В нашем HTML есть тег <img> с идентификатором #imageFound в который мы затем #imageFound перетаскиваемое изображение, чтобы мы могли визуально увидеть изображение под нашими результатами. Мы также записываем URL изображения для отладки (вы можете удалить console.log если хотите):

 $imageFound = $("#imageFound"); console.log(imageRequested); $imageFound.attr("src", imageRequested); 

С нашим недавно полученным URL-адресом изображения, который мы imageRequested и сохранили в imageRequested , мы отправляем его на адрес нашего сервера Node /examineImage в объекте JSON в формате {"imageRequested": "http://www.somewebsite.com/yourimage.jpg"} При успешном извлечении тегов (Clarifai называет их классами), мы превращаем их в строку, разделенную запятыми, и #dropArea эту строку в наш HTML-элемент #dropArea . Если есть ошибка, мы регистрируем, что ошибка произошла.

 $.ajax({ type: "POST", url: baseUrl + "/examineImage", contentType: "application/json; charset=utf-8", dataType: "json", data: JSON.stringify({"imageRequested": imageRequested}), success: function(data) { console.log(data); var tags = ""; for (var i = 0; i I won't cover the HTML in detail as it isn't too exciting and could definitely be optimized! It looks like so: [code language="html"] <!doctype html> <html> <head> <title>Image recognition tester</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script src="//code.jquery.com/jquery-1.12.0.min.js"></script> <link href="https://fonts.googleapis.com/css?family=Lora" rel="stylesheet" type="text/css"/> <style type="text/css"> #dropArea { border: 1px solid #fff; bottom: 10%; color: #fff; display: flex; justify-content: center; flex-direction: column; font-family: "Lora", Arial, sans-serif; font-size: 30px; left: 10%; position: absolute; right: 10%; text-align: center; text-shadow: 0 0 10px rgba(0,0,0,0.5); top: 10%; } #imageFound { background-size: 100% cover; background: none 0 0 no-repeat #000; height: 100%; left: 0; position: absolute; top: 0; width: 100%; } </style> </head> <body> <img src="" id="imageFound" /> <div id="dropArea" ondragover="return false;">Drop your image from the web into here!</div> <script src="./main.js"></script> </body> </html> 

В бою

Если мы запускаем наш сервер Node локально, мы можем получить к нему доступ через localhost:5000 , поэтому запустите сервер с помощью node app.js и перейдите на страницу в своем веб-браузере.

Наше веб-приложение в действии до загрузки изображения

Посетите другой веб-сайт в отдельном окне и перетащите изображение из этого окна в следующее:

Перетаскивание изображения

Когда он распознает и идентифицирует изображение, он сообщает нам список тегов в порядке от наиболее вероятного к наименее вероятному, который, по его мнению, содержит изображение:

Наше изображение распознается и помечается

Вывод

Clarifai имеет большой потенциал с его возможностями распознавания изображений. API этого сервиса может быть добавлен в ряд приложений ИИ, чтобы дать нашему ИИ немного визуального понимания окружающего мира. Например, мы могли бы добавить эту функцию в личный помощник в стиле Siri, например, в статьи о том, как создать свой собственный AI Assistant с помощью Api.ai и настроить Api.ai Assistant с помощью Intent и Context . Вы можете добавить его в Nodebot или любое другое веб-приложение. Служба Clarifai также может распознавать видео, что открывает совершенно новый уровень потенциала!

Где вы планируете использовать распознавание изображений Clarifai? Я хотел бы услышать о том, где этот API используется! Дайте мне знать в комментариях ниже или свяжитесь со мной в Твиттере по адресу @thatpatrickguy .