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 пока не позволит нам создать приложение, так как нам нужно выбрать план:
Давайте выберем план, чтобы мы могли добиться успеха. Для нашей демонстрации бесплатный план должен быть более чем подходящим. Мы можем обновить позже, если это необходимо:
Теперь нам разрешено создавать приложение, для этого мы можем либо щелкнуть левой кнопкой мыши по пункту меню «Приложения», либо по ссылке «создать приложение»:
Нажмите кнопку «Создать новое приложение»:
Мы даем нашему новому приложению имя (например, «Image Recognizer»), оставляем модель по умолчанию как есть и устанавливаем наш язык (мы сохранили его на английском, вы можете предпочесть другой язык!). Чтобы закончить, нажмите «Создать приложение»:
Наши новые данные приложения должны появиться. Два наиболее важных фрагмента, которые мы хотим скопировать в безопасное место, — это «Идентификатор клиента» и «Секрет клиента» — они понадобятся нам для доступа к 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 .