Внешние программы

Программа MeterVision достигает максимальной эффективности в сочетание с другими программами, которые способны обрабатывать результаты распознавания машинного зрения. Например, такой программой может быть METLAB или программа пользователя

Для этих целей предусмотрены возможности отправлять результаты распознавания из данной программы во внешние двумя способами (файлы в output и сервер socket; включение режимов — в Результаты распознавания).

Также из внешних программ можно управлять некоторыми функциями программы MeterVision двумя способами:

  1. Через текстовый файл input/command.txt в Каталог программы.

  2. По socket (если включено «Передавать результаты по socket» в Настройки) — тем же синтаксисом команд, каждая команда на отдельной строке; сервер отвечает OK / ERROR: ... (или результатами на команду get).

В файл или по socket можно передать сразу несколько команд: каждая команда на отдельной строке. Порядок выполнения — от первой строки к последней.

Возможны следующие команды:

  1. Закрыть программу MeterVision

exit
  1. Сохранить Скриншот

  • В папку по умолчанию (output/screenshots/ в Каталог программы) с названием файла по умолчанию (дата и время создания)

screenshot
  • В папку по умолчанию с другим названием

screenshot my_name.png
  • В указанную папку с другим названием

screenshot path/to/my/dir/my_name.png
  1. Открыть файл настроек зон

open path/to/my/dir/settings.mv
  1. Зафиксировать фон (только для стрелочных методов)

fix_background n

Где n - номер целевой зоны

  1. Снять фиксацию фона (только для стрелочных методов)

unfix_background n

Где n - номер целевой зоны

  1. Зафиксировать центр (только для стрелочных методов)

fix_center n

Где n - номер целевой зоны

  1. Снять фиксацию центра (только для стрелочных методов)

unfix_center n

Где n - номер целевой зоны

  1. Забыть статистику зоны (только для стрелочных методов)

forget_stats n

Где n - номер целевой зоны

  1. Забыть фон (только для стрелочных методов)

forget_background n

Где n - номер целевой зоны

  1. Переключиться на другую шкалу (только для стрелочных методов)

scale n m

Где n - номер целевой зоны, m - номер шкалы, на которую нужно переключиться

  1. Переключить режим отображения результата (только для стрелочных методов)

  • Результат — показания по шкале

result_mode n scale
  • Результат — угол наклона стрелки (в градусах)

result_mode n angle

Где n - номер целевой зоны

Пример файла input/command.txt

screenshot my_name.png
unfix_background 1
fix_center 1
scale 1 3
result_mode 1 angle

Передача команд и результатов по socket

При включённом режиме socket (см. Результаты распознавания) внешняя программа подключается к host/port из input/socket_config.txt и отправляет текстовые строки с переводом строки в конце.

Разделитель команд и ответов — перевод строки. За одно подключение можно отправить несколько команд; на каждую команду сервер отвечает одной строкой (для get — строка с результатами вида {1: '24.10', 2: 'AC'}, для остальных — OK или ERROR: ...).

  • get или results — получить текущие результаты распознавания (один ответ на запрос; на одном соединении команду можно повторять сколько угодно раз).

  • Любая команда из списка выше — выполнить действие; ответ OK или ERROR: ....

Пример последовательности команд:

get
fix_center 1
scale 1 2

Пример получения результатов (файл examples/socket_results_example.py). На одном соединении можно многократно вызывать get_results():

import socket
import time


class MeterVisionClient:
    def __init__(self, host='localhost', port=65432):
        self.host = host
        self.port = port
        self.sock = None
        self._buffer = ''

    def connect(self):
        """Подключиться к серверу MeterVision."""
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((self.host, self.port))
        self._buffer = ''
        print(f"Подключено к серверу {self.host}:{self.port}")

    def get_results(self):
        """
        Запросить текущие результаты. Можно вызывать многократно
        на одном соединении. Возвращает строку вида "{1: '24.10', 2: 'AC'}".
        """
        if self.sock is None:
            raise RuntimeError('Сначала вызовите connect()')

        self.sock.sendall(b'get\n')
        while '\n' not in self._buffer:
            chunk = self.sock.recv(4096)
            if not chunk:
                raise ConnectionError('Сервер закрыл соединение')
            self._buffer += chunk.decode('utf-8')
        line, self._buffer = self._buffer.split('\n', 1)
        return line

    def close(self):
        """Закрыть соединение."""
        if self.sock is not None:
            self.sock.close()
            self.sock = None
            print('Соединение закрыто')


if __name__ == "__main__":
    client = MeterVisionClient()
    try:
        client.connect()
        for i in range(5):
            results = client.get_results()
            print(f"[{i + 1}] Получено:", results)
            time.sleep(1)
    except ConnectionRefusedError as e:
        print(e)
    except KeyboardInterrupt:
        print('Соединение прервано')
    finally:
        client.close()

Пример отправки команд (файл examples/socket_commands_example.py):

import socket


def send_commands(commands, host='localhost', port=65432):
    """
    Отправляет список команд и печатает ответы сервера.

    Args:
        commands: список строк-команд без завершающего \\n
        host, port: адрес сервера MeterVision
    """
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    try:
        client_socket.connect((host, port))
        print(f"Подключено к серверу {host}:{port}")
    except ConnectionRefusedError as e:
        print(e)
        return

    try:
        payload = ''.join(cmd.strip() + '\n' for cmd in commands if cmd.strip())
        client_socket.sendall(payload.encode('utf-8'))

        buffer = ''
        replies_expected = sum(1 for cmd in commands if cmd.strip())
        replies_got = 0

        while replies_got < replies_expected:
            data = client_socket.recv(4096)
            if not data:
                break
            buffer += data.decode('utf-8')
            while '\n' in buffer:
                line, buffer = buffer.split('\n', 1)
                print("Ответ:", line)
                replies_got += 1
                if replies_got >= replies_expected:
                    break

    except KeyboardInterrupt:
        print('Соединение прервано')

    finally:
        client_socket.close()


if __name__ == "__main__":
    # Пример: запросить результаты и выполнить команды для стрелочной зоны
    send_commands([
        'get',
        'fix_center 1',
        'result_mode 1 scale',
    ])

Примечание

Эти примеры также находятся в examples/socket_results_example.py и examples/socket_commands_example.py относительно директории установки программы.