Как создать инструмент быстрой маркировки изображений для обучения нейронной сети?
вступление
Допустим, вы хотите обучить нейронную сеть распознавать определенные типы объектов на вашем изображении (например, это могут быть автомобили, пешеходы и дорожные знаки).
Для этого вам нужно будет пометить окружающий прямоугольник каждого интересующего объекта на каждом изображении вашего тренировочного набора.
Здесь пригодится простое веб-приложение в Dash.
Что такое Даш?
Dash по сюжету — очень простой и эффективный способ создания интерактивных аналитических приложений.
Тире Холст это модуль для аннотирования изображений и обработки изображений с использованием Dash. Это то, что мы будем использовать для обозначения объектов внутри изображения.
Монтаж
Во-первых, вам нужно установить Dash Canvas:
$ pip install dash-canvas
Создание приложения
После того, как вы настроили процесс установки, пришло время попробовать создать приложение. Я расскажу более подробно о каждом разделе, но если вы хотите продолжить изучение, я настоятельно рекомендую пройти руководство тур, который фактически начинается со второй главы, как только вы установите Dash.
Импорт
Вот различные импорты, которые нам понадобятся для работы нашего приложения.
import dash
import dash_canvas
import dash_table
import pandas as pd
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash_canvas.utils import parse_jsonstring_rectangle
Это в значительной степени говорит само за себя, но стоит упомянуть два момента:
- Ввод, вывод и состояние на самом деле являются основными компонентами, которые вы будете использовать в обратных вызовах вашего приложения. В нем соответственно указывается:
- часть (части) вашего приложения, которая вызовет обратный вызов (ввод),
- часть (части) вашего приложения, с которыми следует обращаться для обратного вызова (состояние),
- часть вашего приложения, на которую повлияет обратный вызов (выход).
- parse_jsonstring_rectangle — это особый метод из dash_canvas.utils, который преобразует json (выделенную область) в координаты.
Некоторые параметры
Во-первых, давайте введем некоторые параметры:
filename = '
app = dash.Dash(__name__)
app.config.suppress_callback_exceptions = True
list_columns = ['width', 'height', 'left', 'top', 'animal']
list_animals = ['penguin', 'iguana', 'turtle', 'pelican']
columns = [{'name': i, "id": i} for i in list_columns]
columns[-1]['presentation'] = 'dropdown'
animals = [{'label': i, 'value': i} for i in list_animals]
Имя файла может быть URL-адресом изображения, которое будет помечено (здесь это фотография, которую я сделал на Галапагосских островах). Вы определяете приложение как компонент Dash, присваиваете имена своим столбцам базы данных (для ящиков), возможностям меток (list_animals) и указываете список словарей как для столбцов, так и для типов объектов, которые вы хотите пометить. Обратите внимание, что мы добавляем ключ, значение «представление»: «раскрывающийся список» для последнего столбца. Это действительно позволит нам указать, какой объект (здесь животное) мы помечаем для соответствующих координат коробки.
Макет приложения
Теперь пришло время указать теги html для сборки приложения:
app.layout = html.Div([
html.Div([
html.H3('Label images with bounding boxes'),
dash_canvas.DashCanvas(
id='canvas',
width=500,
tool="rectangle",
lineWidth=2,
lineColor="rgba(0, 255, 0, 0.5)",
filename=filename,
hide_buttons=['pencil', 'line'],
goButtonTitle="Label"
),
]),
html.Div([
dash_table.DataTable(
id='table',
columns=columns,
editable=True,
dropdown={
'animal': {
'options': animals
}
}
),
])
])
- DashCanvas содержит изображение:
- идентификатор контейнера (используется позже в функциях обратного вызова)
- ширина окна
- инструмент выделения
- Ширина линии
- цвет (и прозрачность) линии
- путь к файлу
- кнопки, которые нужно скрыть
- кнопка для маркировки
- DataTable содержит таблицу:
- идентификатор контейнера (используется позже в функциях обратного вызова)
- столбцы
- редактируемый вариант (для животного)
- параметры раскрывающегося списка (для ярлыка)
Обратные вызовы
Конечно, если вы хотите, чтобы ваше приложение было отзывчивым, вам нужно написать несколько обратных вызовов:
@app.callback(Output('table', 'data'), [Input('canvas', 'json_data')])
def show_string(json_data):
box_coordinates = parse_jsonstring_rectangle(json_data)
df = pd.DataFrame(box_coordinates, columns=list_columns[:-1])
df['animal'] = 'penguin'
return df.to_dict('records')
Обратный вызов — это декоратор @ (обертка, если хотите), который вызывается, когда что-то изменяется на входе. Затем он выполняет функцию со значениями, собранными из разных входных данных и, возможно, из разных состояний. Затем он возвращает значение на вход.
Не волнуйтесь, если вы не поняли последний абзац, просмотр этого примера должен прояснить ситуацию.
Когда свойство «json_data» «холста» изменяется (т. е. когда вокруг объекта нарисована рамка выбора), вызывается функция show_string(json_data), она в основном переводит json выбора в словарь записей (1 на объект), установив животное по умолчанию на «пингвин».
Запустим код!!!
Вам просто нужно добавить строку кода
if __name__ == '__main__':
app.run_server(debug=True)
и вы можете идти.
Запустив скрипт, вы получите IP-адрес, по которому откроется страница в вашем браузере. Затем вы можете нарисовать прямоугольники вокруг животных, а затем нажать кнопку «Метка», чтобы получить координаты всех ящиков. Затем вы можете выбрать животное для каждой коробки.
Наслаждаться!
Полный код
import dash
import dash_canvas
import dash_table
import pandas as pd
import dash_html_components as html
from dash.dependencies import Input, Output, State
from dash_canvas.utils import parse_jsonstring_rectangle
filename = '
app = dash.Dash(__name__)
app.config.suppress_callback_exceptions = True
list_columns = ['width', 'height', 'left', 'top', 'animal']
list_animals = ['penguin', 'iguana', 'turtle', 'pelican']
columns = [{'name': i, "id": i} for i in list_columns]
columns[-1]['presentation'] = 'dropdown'
animals = [{'label': i, 'value': i} for i in list_animals]
app.layout = html.Div([
html.Div([
html.H3('Label images with bounding boxes'),
dash_canvas.DashCanvas(
id='canvas',
width=500,
tool='rectangle',
lineWidth=2,
lineColor='rgba(0, 255, 0, 0.5)',
filename=filename,
hide_buttons=['pencil', 'line'],
goButtonTitle='Label'
),
]),
html.Div([
dash_table.DataTable(
id='table',
columns=columns,
editable=True,
dropdown={
'animal': {
'options': animals
}
}
),
])
])
@app.callback(Output('table', 'data'), [Input('canvas', 'json_data')])
def show_string(json_data):
box_coordinates = parse_jsonstring_rectangle(json_data)
df = pd.DataFrame(box_coordinates, columns=list_columns[:-1])
df['animal'] = 'penguin'
return df.to_dict('records')
if __name__ == '__main__':
app.run_server(debug=True)
Заключительные мысли и следующие шаги
Я сознательно выбрал «простую» версию кода, которой очень легко следовать, но более надежная версия не должна содержать в коде имени метки, все можно передать через argparse или файл yaml. Я призываю вас написать эту часть в качестве упражнения. Таким образом, ваш код будет переносим во множество ситуаций.
Я рекомендую вам добавить поле ввода для загрузки файла, который вы хотите пометить (см. Основные компоненты Dashтакже известный как dcc) и экспортировать координаты ящиков в файл для будущего обучения вашей сети.
Наслаждайтесь маркировкой!