www.machinelearningmastery.ru

Машинное обучение, нейронные сети, искусственный интеллект
Header decor

Home

Обнаружение объекта изображения с помощью Tensorflow-js 🤔

Дата публикации Aug 27, 2019

Это четвертый пост серии обработки изображений от нуля до единицы.

Вот список других постов

  1. Обработка изображений - OpenCV и Node.js (часть 3)
  2. Обработка изображений - Создание пользовательских фильтров - React.js - Часть 2
  3. Обработка изображений с использованием Cloundinary (часть 1)

В этом посте мы создадим систему обнаружения объектов изображений с Tensorflow-js с предварительно обученной моделью.

Начнем с того, что существует множество способов развертывания TensorFlow на веб-странице, одним из которых является включение ml5js. Посетитьhttps://ml5js.org/, Это оболочка вокруг тензорного потока tf.js и библиотеки p5.js, используемой для выполнения операций в элементе Html.

Но мы хотели бы сохранить власть на серверной части, чтобы я мог попытаться запустить эти модели поверх серверной части с бэкэнд-процессами API и так далее.

Поэтому в первой половине поста мы создадим пользовательский интерфейс с использованием React.js и Material-UI, а во второй половине мы создадим API в Node.js для поддержки пользовательского интерфейса.

Давайте начнем с создания примера проекта React. 🚀

ПЕРЕДНЯЯ ЧАСТЬ: -

Если вы ознакомились с моей предыдущей статьей, реактивный проект будет довольно легко построить.

  1. Откройте терминал и сделайте
create-react-app image_classification_react_ui

Это создаст реактивный проект для работы с.

2. Давайте установим требуемую зависимость

npm install @material-ui/core
npm install — save isomorphic-fetch es6-promise

Примечание: isomorphic-fetch требуется для вызова конечной точки API обнаружения объекта из кода React.

3. Откройте проект в вашем любимом редакторе и давайте создадим 2 папки

  1. контейнер- Это будет содержать файл -ImageOps.jsx, которые имеют весь код пользовательского интерфейса.
  2. Utils- Это будет содержать файлApi.js, который используется для вызова конечной точки обнаружения объекта.
└── src
├── containers
├── ImageOps.jsx
├── utils
├── Api.js

Давайте посмотрим наImageOps.jsxкод и понять это.

import React from 'react';

import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';

import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import { red } from '@material-ui/core/colors';

import {api} from '../utils/Api';

import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
import CircularProgress from '@material-ui/core/CircularProgress';


export default class ImageOps extends React.Component {

constructor(props) {
super(props);

this.state = {
image_object: null,
image_object_details: {},
active_type: null
}
}

updateImageObject(e) {
const file = e.target.files[0];
const reader = new FileReader();

reader.readAsDataURL(file);
reader.onload = () => {
this.setState({image_object: reader.result, image_object_details: {}, active_type: null});
};

}

processImageObject(type) {

this.setState({active_type: type}, () => {

if(!this.state.image_object_details[this.state.active_type]) {
api("detect_image_objects", {
type,
data: this.state.image_object
}).then((response) => {

const filtered_data = response;
const image_details = this.state.image_object_details;

image_details[filtered_data.type] = filtered_data.data;

this.setState({image_object_details: image_details });
});
}
});
}

render() {
return (
<Container maxWidth="md">
<Grid container spacing={2}>
<Grid item xs={12}>
<CardContent>
<Typography variant="h4" color="textPrimary" component="h4">
Object Detection Tensorflow
</Typography>
</CardContent>
</Grid>
<Grid item xs={12}>
{this.state.image_object &&
<img src={this.state.image_object} alt="" height="500px"/>
}
</Grid>
<Grid item xs={12}>
<Card>
<CardContent>
<Button variant="contained"
component='label' // <-- Just add me!
>
Upload Image
<input accept="image/jpeg" onChange={(e) => this.updateImageObject(e)} type="file" style={{ display: 'none' }} />
</Button>
</CardContent>
</Card>
</Grid>
<Grid item xs={3}>
<Grid container justify="center" spacing={3}>
<Grid item >
{this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
Get objects with ImageNet
</Button>}
</Grid>
<Grid item>
{this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
Get objects with Coco SSD
</Button>}
</Grid>
</Grid>
</Grid>
<Grid item xs={9}>
<Grid container justify="center">
{this.state.active_type && this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<Card>
<CardContent>
<Typography variant="h4" color="textPrimary" component="h4">
{this.state.active_type.toUpperCase()}
</Typography>
<ImageDetails type={this.state.active_type} data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
</CardContent>
</Card>
</Grid>
}
{this.state.active_type && !this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<CircularProgress
color="secondary"
/>
</Grid>
}
</Grid>
</Grid>
</Grid>
</Container>
)
}
}

class ImageDetails extends React.Component {

render() {

console.log(this.props.data);

return (
<Grid item xs={12}>
<Paper>
<Table>
<TableHead>
<TableRow>
<TableCell>Objects</TableCell>
<TableCell align="right">Probability</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.props.data.map((row) => {
if (this.props.type === "imagenet") {
return (
<TableRow key={row.className}>
<TableCell component="th" scope="row">
{row.className}
</TableCell>
<TableCell align="right">{row.probability.toFixed(2)}</TableCell>
</TableRow>
)
} else if(this.props.type === "coco-ssd") {
return (
<TableRow key={row.className}>
<TableCell component="th" scope="row">
{row.class}
</TableCell>
<TableCell align="right">{row.score.toFixed(2)}</TableCell>
</TableRow>
)
}
})
}
</TableBody>
</Table>
</Paper>

</Grid>
)
}
}

}

Примечание: вот ссылка на репозиторий Github выше -https://github.com/overflowjs-com/image_object_detction_react_ui, Если вы находите понимание выше сложности, то я настоятельно рекомендую прочитать нашу часть 2 и часть 1.

При рендеринге мы создали сетку из трех строк, чтобы строка, содержащая заголовок

Во-вторых, содержащий изображение для отображения

<Grid item xs={12}>
{this.state.image_object &&
<img src={this.state.image_object} alt="" height="500px"/>}
</Grid>

Здесь мы показываем изображение, если изображение было загружено или объект изображения доступен в состоянии

Следующая сетка содержит кнопку для загрузки файла и обновления загруженного файла до текущего состояния.

<Grid item xs={12}>
<Card>
<CardContent>
<Button variant="contained"
component='label' // <-- Just add me!
>
Upload Image
<input accept="image/jpeg" onChange={(e) => this.updateImageObject(e)} type="file" style={{ display: 'none' }} />
</Button>
</CardContent>
</Card>
</Grid>

На кнопке для загрузки изображения при изменении события мы вызвали функциюupdateImageобновить выбранное в данный момент изображение по состоянию.

updateImageObject(e) {
const file = e.target.files[0];
const reader = new FileReader();

reader.readAsDataURL(file);
reader.onload = () => {
this.setState({image_object: reader.result, image_object_details: {}, active_type: null
});
};
}

В приведенном выше коде мы читаем текущий объект файла из загрузчика файлов и загружаем его данные в текущем состоянии. Когда новое изображение загружается, мы сбрасываем image_object_details и active_type, чтобы новые операции можно было применить к загруженному изображению

Ниже приведена следующая таблица, содержащая код для двух кнопок для каждой модели.

<Grid item xs={3}>
<Grid container justify="center" spacing={3}>
<Grid item >
{this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
Get objects with ImageNet
</Button>}
</Grid>
<Grid item>
{this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
Get objects with Coco SSD
</Button>}
</Grid>
</Grid>
</Grid>
<Grid item xs={9}>
<Grid container justify="center">
{this.state.active_type && this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<Card>
<CardContent>
<Typography variant="h4" color="textPrimary" component="h4">
{this.state.active_type.toUpperCase()}
</Typography>
<ImageDetails data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
</CardContent>
</Card>
</Grid>
}
{this.state.active_type && !this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<CircularProgress
color="secondary"
/>
</Grid>
}
</Grid>
</Grid>

Здесь мы делим Grid на две части: 3 столбца и 9 столбцов из 12 родительских столбцов.

Первая Сетка с 3 столбцами содержит две Сетки, имеющие две кнопки

<Grid container justify="center" spacing={3}>
<Grid item >
{this.state.image_object && <Button onClick={() => this.processImageObject("imagenet")}variant="contained" color="primary">
Get objects with ImageNet
</Button>}
</Grid>
<Grid item>
{this.state.image_object && <Button onClick={() => this.processImageObject("coco-ssd")}variant="contained" color="secondary">
Get objects with Coco SSD
</Button>}
</Grid>
</Grid>

Мы анализируем обнаружение изображения с помощьюМодели SSD ImageNet и Cocoи сравните результаты.

Каждая кнопка имеет событие действия onClick и вызывает функциюprocessImageObject()который принимает имя модели в качестве параметра.

processImageObject(type) {this.setState({active_type: type}, () => {
api("detect_image_objects", {
type,
data: this.state.image_object
}).then((response) => {

const filtered_data = response;
const image_details = this.state.image_object_details;image_details[filtered_data.type] = filtered_data.data;this.setState({image_object_details: image_details });
});
});
}

Мы устанавливаем государственный объектaction_typeс выбранным в данный момент модальным.

Функция объекта Process image берет текущее изображение из состояния и отправляет его в функцию API, которую я покажу вам дальше, и API будет вызванdetect_image_objectsи в ответ мы обработаем и покажем в интерфейсе.

Будет получен ответ от API, который будет установлен на этапеimage_object_details,

Мы устанавливаем каждый ответ API в зависимости от типа модели.(Imagenet / коко-SSD)

Эти кнопки будут видны только тогда, когдаimage_objectприсутствует в гос.

{
this.state.image_object &&
<Button onClick={() => this.processImageObject()} variant="contained" color="primary">Process Image
</Button>
}

Ниже еще одна сетка, которую мы создали:

<Grid item xs={9}>
<Grid container justify="center">
{this.state.active_type && this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<Card>
<CardContent>
<Typography variant="h4" color="textPrimary" component="h4">
{this.state.active_type.toUpperCase()}
</Typography>
<ImageDetails type={this.state.active_type} data = {this.state.image_object_details[this.state.active_type]}></ImageDetails>
</CardContent>
</Card>
</Grid>
}
{this.state.active_type && !this.state.image_object_details[this.state.active_type] &&
<Grid item xs={12}>
<CircularProgress
color="secondary"
/>
</Grid>
}
</Grid>
</Grid>

Здесь мы проверили, является ли текущийaction_typeмодальный выбран или нет, тогда, если API обработал детали, он показывает детали объекта. Для этого мы создали компонентImageDetails,

Давайте посмотрим наImageDetailsкод компонента, который легко понять.

class ImageDetails extends React.Component {

render() {

console.log(this.props.data);

return (
<Grid item xs={12}>
<Paper>
<Table>
<TableHead>
<TableRow>
<TableCell>Objects</TableCell>
<TableCell align="right">Probability</TableCell>
</TableRow>
</TableHead>
<TableBody>
{this.props.data.map((row) => {
if (this.props.type === "imagenet") {
return (
<TableRow key={row.className}>
<TableCell component="th" scope="row">
{row.className}
</TableCell>
<TableCell align="right">{row.probability.toFixed(2)}</TableCell>
</TableRow>
)
} else if(this.props.type === "coco-ssd") {
return (
<TableRow key={row.className}>
<TableCell component="th" scope="row">
{row.class}
</TableCell>
<TableCell align="right">{row.score.toFixed(2)}</TableCell>
</TableRow>
)
}
})
}
</TableBody>
</Table>
</Paper>

</Grid>
)
}
}

Этот компонент будет отображать детали, полученные из модального имени объекта и их вероятность. В зависимости от типа модальной зоны, с которой мы работаем, мы можем отобразить два разных вывода, которые обрабатываются в этом классе.

4. Последний шаг - написать обертку API.js для вызова на стороне сервера.

import fetch from  'isomorphic-fetch';

const BASE_API_URL = "http://localhost:4000/api/"

export function api(api_end_point, data) {

return fetch(BASE_API_URL+api_end_point,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body:JSON.stringify(data)
}).then((response) => {
return response.json();
});
}

В этом примере кода мы предоставляем API-оболочку для функции извлечения, которая будет принимать конечную точку API и данные, и будет создавать полный URL-адрес и ответ, отправленный API.

Окончательный интерфейс будет выглядеть так

ЗАДНЯЯ ЧАСТЬ: -

Теперь, когда у нас есть наш пользовательский интерфейс, давайте начнем с создания конечной точки API с использованием tenorflow.js, которая будет выглядеть следующим образом

http://localhost:4000/api/detect_image_objects
  1. Первый шаг - выбрать шаблон, который использует express.js и предоставляет возможность просто написать маршрут и логику обнаружения объекта. Мы используемhttps://github.com/developit/express-es6-rest-apiдля этого урока. Давайте клонируем это
git clone https://github.com/developit/express-es6-rest-api image_detection_tensorflow_api

2. Теперь установите все зависимости, запустив

cd image_detection_tensorflow_api
npm install

3 Перейти кconfig.jsonв корне проекта и редактироватьportдо 4000 иbodylimitдо 10000кб.

Примечание: мы будем использовать предварительно обученные моделиimagenet and coco-ssd.Поиск нескольких объектов на изображении - это утомительная работа, хотя сеть изображений известна тем, что обнаруживает один объект по изображениям (животные / другие объекты), но тем не менее, оба этих модала основаны на очень разнообразных наборах данных. Так что, если вы не правильно поняли объект, не волнуйтесь ».

4. Чтобы начать с TensorFlow, нам нужно обновить версию узла, если вы используете старую. После того как вы освоитесь с версией узла, давайте запустим приведенную ниже команду для установкиhttps://github.com/tensorflow/tfjs-models

npm install @tensorflow/tfjs-node

Примечание: вы можете установитьtfjs-узелсогласно вашей системе Linux / Windows / Mac с использованием -https://www.npmjs.com/package/@tensorflow/tfjs-node

5. Теперь давайте установим обе модели, которые будем использовать, поэтому запустим

npm install @tensorflow-models/mobilenet — save
npm install @tensorflow-models/coco-ssd — save

6. Нам нужно установить ниже модуль тоже, как требуется зависимость

npm install base64-to-uint8array — save

7. Теперь перейдите кindex.jsподsrc > apiпапку и создать новую конечную точку

api.post('/detect_image_objects', async (req, res) => {
const data = req.body.data;
const type = req.body.type; const objectDetect = new ObjectDetectors(data, type);
const results = await objectDetect.process(); res.json(results);
});

Здесь мы звонимObjectDetectorsclass и передавая два аргумента, полученных из пользовательского интерфейса, один - это кодированное в base64 изображение, а другой - тип модели

8. Теперь давайте создадимObjectDetectorsучебный класс. Перейти кsrc > apiпапка и создатьobject_detectorпапки. внутриobject_detectorмы создадим новый файлObjectDetectors.js

const tf = require('@tensorflow/tfjs-node');

const cocossd = require('@tensorflow-models/coco-ssd');
const mobilenet = require('@tensorflow-models/mobilenet');

import toUint8Array from 'base64-to-uint8array';


export default class ObjectDetectors {

constructor(image, type) {

this.inputImage = image;
this.type = type;
}

async loadCocoSsdModal() {
const modal = await cocossd.load({
base: 'mobilenet_v2'
})
return modal;
}

async loadMobileNetModal() {
const modal = await mobilenet.load({
version: 1,
alpha: 0.25 | .50 | .75 | 1.0,
})
return modal;
}

getTensor3dObject(numOfChannels) {

const imageData = this.inputImage.replace('data:image/jpeg;base64','')
.replace('data:image/png;base64','');

const imageArray = toUint8Array(imageData);

const tensor3d = tf.node.decodeJpeg( imageArray, numOfChannels );

return tensor3d;
}

async process() {

let predictions = null;
const tensor3D = this.getTensor3dObject(3);

if(this.type === "imagenet") {

const model = await this.loadMobileNetModal();
predictions = await model.classify(tensor3D);

} else {

const model = await this.loadCocoSsdModal();
predictions = await model.detect(tensor3D);
}

tensor3D.dispose();

return {data: predictions, type: this.type};
}
}

У нас есть конструктор, который принимает два параметра, один из которых - это кодированное изображение base64 и тип изображения.

processфункция называется которая вызываетgetTensor3dObject(3).

Примечание. Здесь 3 - это количество каналов, так как в пользовательском интерфейсе мы ограничиваем тип изображения jpeg, который сейчас является 3-канальным изображением. Мы не обрабатываем 4-канальные изображения, которые вы можете легко создать, так как вы можете отправить тип изображения в API и при необходимости изменить заданные функции.

getTensor3dObject(numOfChannels) {
const imageData = this.inputImage.replace('data:image/jpeg;base64','')
.replace('data:image/png;base64','');const imageArray = toUint8Array(imageData);const tensor3d = tf.node.decodeJpeg( imageArray, numOfChannels );return tensor3d;
}

В этой функции мы удаляем теги из изображения base64, преобразуем его в массив изображений и создаем тензор 3d.

Наши предварительно обученные модели потребляют либо объект tenor3d, либо<img>HTML-тег или HTML-видео-тег, но, поскольку мы делаем это из API Node.js, у нас есть изображение base64, которое преобразуется в объект тензор3d.

Радостно tenorflow.js предоставляет функцию для негоdecodeJpeg,

Есть и другие функции, которые также предоставляет TensorFlow для той же работы, которую вы можете увидеть более подробно -https://js.tensorflow.org/api_node/1.2.7/#node.decodeJpeg

В настоящее времяdecodeJpegпреобразует нашArrayBufferизображения 3 каналов к объекту tesnor3d.

if(this.type === "imagenet") {
const model = await this.loadMobileNetModal();
predictions = await model.classify(tensor3D);} else {
const model = await this.loadCocoSsdModal();
predictions = await model.detect(tensor3D);
}

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

Теперь ниже приведены результаты, которые я получил до сих пор

IMAGENET МОДЕЛЬ ВЫХОДА

Выход изimagenetэто обеспечивает название объекта и его вероятность, что три объекта идентифицированы сimagenet.

COCO-SSD МОДЕЛЬ ВЫХОД-

Если вы читаете больше о coco-ssd, то cam идентифицирует несколько объектов, даже если они похожи. Вместе с прямоугольными координатами, на которые опирается их объект.

Узнайте больше здесь -https://github.com/tensorflow/tfjs-models/tree/master/coco-ssd

Здесь вы можете видеть, что он идентифицировал 6 человек с их позициями в виде прямоугольника. Теперь вы можете использовать эти координаты для любых целей, так как они сообщают вам имя объекта и местоположение объекта.

Вы можете использовать любую библиотеку изображений, чтобы нарисовать эти прямоугольники, чтобы создать несколько интересных приложений с эффектами изображения вокруг этих деталей.

Вы можете попробовать мое руководство по Cloudniary и OpenCV на React.js, Nodejs из предыдущих статей пытаются использовать эти знания для создания классных вещей.

Счастливое кодирование ❤️

Пожалуйста примите к сведениювведите свой адрес электронной почты здесьесли вы хотите быть добавлены в мой список адресов электронной почты иследуй за мнойсреднийчитать больше статьи на JavaScript и наGitHubчтобы увидеть мой сумасшедший код, Если что-то не понятно или вы хотите что-то указать, пожалуйста, прокомментируйте ниже.

Вам также могут понравиться мои другие статьи

  1. Контекст выполнения Javascript и Подъем
  2. Javascript - Generator-Yield / Next & Async-Await 🤔
  3. Понимание Javascript «это» ключевое слово (контекст),
  4. Структура данных Javascript с картой, уменьшением, фильтром
  5. Javascript - Curry VS Частичное применение
  6. Javascript ES6 - итераторы и итераторы
  7. Тест производительности Javascript - для vs для каждого vs (отобразить, уменьшить, отфильтровать, найти).
  8. Javascript - Прокси
  9. Javascript - Области применения
  10. Обнаружение объекта изображения с помощью Tensorflow-js 🤔
  11. Структура приложения Nodejs - для построения масштабируемой архитектуры.
  12. Node.js 10.0.0, Чего ожидать от Backend-разработчика / энтузиаста безопасности?
  13. Обработка изображений - Создание пользовательских фильтров изображений в React.js
  14. Google Индия Интервью Вопросы

Если вам понравилась статья, пожалуйста, порадуйте себя. Совет - вы можете хлопать 50 раз! Кроме того, рекомендовать и делиться, чтобы помочь другим найти его!

Оригинальная статья

Footer decor

© www.machinelearningmastery.ru | Ссылки на оригиналы и авторов сохранены. | map