#26 2020-04-21 22:26:41

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

Приехал экранчик на ST7789, почти как у вас исходный вариант был. Вы библиотеку Adafruit_ST7735.h использовали? Не осталось бекапа с маленьким экраном подсмотреть?
У Вас экранчик с выведеным пином CS был? У меня - без, я так понимаю он на шине параллельно с SD карточкой сидит и тогда что-то одно получится использовать или подпаиваться надо.

Редактировался executer (2020-04-22 10:17:53)

#27 2020-04-22 19:59:45

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

executer пишет:

Приехал экранчик на ST7789, почти как у вас исходный вариант был. Вы библиотеку Adafruit_ST7735.h использовали? Не осталось бекапа с маленьким экраном подсмотреть?
У Вас экранчик с выведеным пином CS был? У меня - без, я так понимаю он на шине параллельно с SD карточкой сидит и тогда что-то одно получится использовать или подпаиваться надо.

У меня был экран ST7735. Я использовал две библиотеки Adafruit_ST7735.h и UTFT.h
Бакапы этих двух библиотек скинул на Google Disk
https://drive.google.com/open?id=1NJuxV … 2Apie_qK7C
Может поможет, но у библиотек разные команды и сами бекапы старые.
Библиотека UTFT более универсальная - подходит для разных дисплеев, на "тяжелая" и мне больше понравилась Adafruit, т.к. она как бы встроена в IDE.

Если судить из этого описания http://arduino.ua/prod466-1-8-128h160-t … reen-modyl то наверное можно и без него.
Я SD карточкой не пользовался, тем более, что карта есть и на плате процессора.

Попробовал записывать данные в GoogleSheets - что-то работает на ESP8266, а что-то на ESP32, но нужно разбираться слета не вышло.

#28 2020-04-22 20:57:37

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

Благодарю.
Меня смущало большое количество SPI хостов на ESP32, почему-то решил что для экрана отдельный хост используется, а как указать какой именно бибилиотеке - не понятно, короче перемудрил).

По GoogleSheets можете подсмотреть у меня в предыдущем проекте https://github.com/executer-uno/ESP32_DustTracker - запись пары сотни символов раз в 30 секунд - работает отлично на ESP32. Лимит - миллион ячеек на книгу, кажется. Делал по мануалам от автора библиотеки  https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect, ну только запись в книгу использовал, без календаря и вычитки параметров.

#29 2020-04-25 19:58:19

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

executer пишет:

По GoogleSheets можете подсмотреть у меня в предыдущем проекте https://github.com/executer-uno/ESP32_DustTracker - запись пары сотни символов раз в 30 секунд - работает отлично на ESP32. Лимит - миллион ячеек на книгу, кажется. Делал по мануалам от автора библиотеки  https://github.com/electronicsguy/ESP8266/tree/master/HTTPSRedirect, ну только запись в книгу использовал, без календаря и вычитки параметров.

Спасибо за ссылку на Ваш предыдущий проект, но как в описании Вы написали
"HTTPS Redirect библиотека Таблицы Google использовал этот протокол для загрузки данных. Самая сложная библиотека как по мне)"

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

//запись данных счетчика в таблицу
//https://github.com/mrmdudek/ESP32-send-data-to-google-sheet
//https://github.com/ExploreLab/IoT_ggSpreadSheet 
//https://voltiq.ru/post-data-to-google-sheets-with-esp8266/ - скрипт за основу брал этот
//https://developers.google.com/apps-script/reference/spreadsheet/sheet


#include <WiFiClientSecure.h>
WiFiClientSecure client;
char *server_sheet = "script.google.com";  // Server URL
char *GScriptId = "****************"; //ID 
const int httpsPort = 443;

//---------------------------------------------------- GG_ScriptSheet
void GG_ScriptSheet(float m3_sheet, float minutes_sheet){
  String Data = String("&m3=")+(int)m3_sheet+String("&minutes=") + (int)minutes_sheet; 
  String url32 = String("/macros/s/") + GScriptId + "/exec?"+Data;
  Serial.print("Client.Connecting...");
//  Serial.println(url32);
  if (client.connect(server_sheet, httpsPort)) {
    client.println("GET " + String(url32) + " HTTP/1.1"); //HTTP/1.0 OK sent LINEnotify and GoogleSheet
    client.println("Host: " + String(server_sheet));
    client.println("User-Agent: ESP32_counter");
    client.println("Connection: close\r\n\r\n");
//    Serial.println("Response...OK !!!");  
  }
  else Serial.println("Connection failed!");  
/*  
  while (client.connected()) 
  {
      String line = client.readStringUntil('\n');
      if (line == "\r") 
      {
//        Serial.println("headers received");
        break;
      }
    }
    // if there are incoming bytes available
    // from the server, read them and print them:
    while (client.available()) 
    {
      char c = client.read();
//      Serial.write(c);
  }
*/
  client.stop();
}
//---------------------------------------------------- GG_ScriptSheet

Поставил на прогон - работает.
Таблица состоит из двух листов на первом - последнее время записи, число строк и последнее значение счетчика.
На вторую страницу записываются сами данные виде ID | DataTime | m3*100 | minutes
За трое суток, при неработающем отоплении, у меня в кольцевом буфере сохранилось около 150 значений. Потребление при использовании горячей воды (как правило не более 0,01 м3/мин).

Редактировался NickVectra (2020-04-30 07:04:45)

#30 2020-04-30 00:47:08

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

Шикарно, я думал там сплошная магия в библиотеке ) Гуглотаблицы кажется идеальное хранилище таких данных.

Тем временем промучился неделю с тем чтобы обойтись без экрана и без MMC карточки, голой ESP-CAM. Т.е. чтобы весь интерфейс в браузере был.
Самая сложная часть побеждена - https://github.com/executer-uno/ESP32_CAM_WEB_Photo
Показывает в браузер фоточки из буффера. Проблема была в том что целиком изображение не влазило в буффер web-сервера (использовал ESPAsyncWebServer и поэтому путем проб и ошибок пришлось дойти до chunked запросов, они оказались за пределами моих знаний в С), наконец все поборол и BMP картинка доступна в браузере.

Теперь буду прикручивать обработку картинки из Вашего проекта.

#31 2020-04-30 07:04:04

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

executer пишет:

Шикарно, я думал там сплошная магия в библиотеке ) Гуглотаблицы кажется идеальное хранилище таких данных.

А я пока немного застрял на сбросе картинки на Google Disk по запросу на основе этого примера https://github.com/executer-uno/esp32cam-gdrive.

Изображение взял такое же как и у меня 320х240 PIXFORMAT_GRAYSCALE. После получения от камеры преобразовываю в JPEG (frame2jpg()).

Это работает, а вот после добавления "рабочего" куска в общий проект нет ответа от сервера Google после отправки туда картинки. 

Фактически срабатывает этот кусочек кода

Serial.println("Waiting for response.");
    long int StartTime=millis();
    while (!client.available()) {
      Serial.print(".");
      delay(100);
      if ((StartTime+waitingTime) < millis()) {
        Serial.println();
        Serial.println("No response.");
        //If you have no response, maybe need a greater value of waitingTime
        break;
      }

waitingTime - 30 секунд, хотя, когда работает полный цикл (считывание, кодировка и  отправка) занимает не более 5 секунд, т.е. не в этом дело  sad.

Так и не смог за несколько дней добиться стабильной работы записи изображения на  Google Disk, поэтому переделал сегодня (1 мая) сохранение не на Google Disk, а на DropBox на основе https://github.com/duthienkt/ESP32DropboxCam

Этот код работает нормально

//https://github.com/duthienkt/ESP32DropboxCam
//http://developer.alexanderklimov.ru/android/dropbox.php

#include "dropbox.h"

// Это ключ приложения, каждое приложение будет иметь свой собственный ключ
#define DROPBOX_ACESS_KEY "*************************"

DropboxMan dropboxMan;

void capture_DropBox(){

  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;

  fb = NULL;
  fb = esp_camera_fb_get();
  if (!fb) {
    Serial.println("Camera capture failed");
    return;
  }

  if (fb->format != PIXFORMAT_JPEG) {
    bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
    if (!jpeg_converted) {
      esp_camera_fb_return(fb);
      fb = NULL;
      Serial.println("JPEG compression failed");
      return;
    }
  }
  else {
    _jpg_buf_len = fb->len;
    _jpg_buf = fb->buf;
  }

  String path = "/picture/";
  // Если есть возможность получить время из интернета, используйте его для названия, если нет то время запуска
  struct tm timeinfo;
  if (!getLocalTime(&timeinfo)) {
    path += String(millis());
  }
  else {
    char buf[50];
    sprintf(buf, "%4d%02d%02d_%02d%02d%02d\0", timeinfo.tm_year + 1900, timeinfo.tm_mon + 1, timeinfo.tm_mday,
            timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
    path += buf;
    //        Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
  }
  path += ".jpg";

  dropboxMan.bufferUpload(_jpg_buf, _jpg_buf_len, path, 1); // save to DropBox
  esp_camera_fb_return(fb);
}

Редактировался NickVectra (2020-05-01 19:38:05)

#32 2020-05-02 07:29:57

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

Изображение, которое "видит" камера, сохраненное в DropBox сегодня утром в 7:13
e67be9c8b9a8bb347d789a5e3ceda96d.jpg
Экран дисплея
76674f725e5da0860e3eea6b7aa442a7.jpg

#33 2020-05-07 12:23:06

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

NickVectra, добрый день. Перечитал первый пост с описанием, я правильно понял что окно с индикатором счетчика ищется по всему кадру? Единственное требование - оно должно быть более-менее горизонтально расположено на кадре?
Я пока думаю что для понимания шагов обработки и промежуточных результатов нужно сделать подмену TFT библиотеки - заглушку чтобы она генерировала TFT вывод в jpeg картинки для браузера, чтобы в исходном проекте графический вывод не менять сильно.

#34 2020-05-07 13:17:42

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

executer пишет:

я правильно понял что окно с индикатором счетчика ищется по всему кадру?

На первых этапах при разработке так и было. Потом я ограничил поиск в процедуре find_digits_y
//поиск положения цифр по высоте Y
#define  Y_FIRST_LOOK 10  //ограничим начало поиска 10 пикселями в строке
#define  Y_LAST_LOOK 100 //ограничим конец поиска 100 пикселями в строке

но тестовый счетчик был первоначально "затемнен" черной бумагой (см. фото 2 первого сообщения) и сторонних засветов, которые могли быть восприняты как шкала не было.

Когда стал применять программные "шторки"
#define old_level_Y_up 22 //Положение шторки сверху Y_up
#define old_level_Y_down 48 //Положение шторки снизу X_down

то изображение выше и ниже шторок в программе зачерняется и затемнение счетчика потеряло смысл.

Сейчас, когда эта часть отработана и нет перемещения счетчика, то поиск положения шкалы по оси Y фактически не имеет значения, т.к. шкала уже находится в нужном месте сразу, а я могу подстроить окно из приложения, изменив значение "V2 - смещение по оси Y при суммировании кадров и отображении на дисплее" .
Кроме того идет постоянная автоматическая подстройка положения цифр, о которой я писал выше.

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

executer пишет:

Единственное требование - оно должно быть более-менее горизонтально расположено на кадре?

Это требование вызвано тем, что у меня нет процедуры вращения изображения.

executer пишет:

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

Мне как-то было проще делать это вначале физически - подклеивая изоленту и картонки smile , а затем выводить изображение именно на индикатор.
Были случаи, когда изображение "терялось" из-за значительного перемещения счетчика и камеры поэтому и ввел режим вывода полного изображения на индикатор в градациях серого (фото 5 первое сообщение).
Я запускал программу без подключенного физически индикатора TFT и ошибок не выдавало.

Редактировался NickVectra (2020-05-07 13:22:11)

#35 2020-05-11 17:30:46

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

Так как у меня в поле зрения будут два счетчика воды то для получения достаточного разрешения переключил камеру на максимальный формат 1600*1200 в JPEG с качеством = 5. Довольно неплохое изображение делает. Так как такой кадр ни в какую память не влезет в распакованном виде - помогла библиотека из списка ардуиновского репозитария "JPEGDecoder". В ней можно получить доступ к каждому запакованному кусочку JPEG и обработать необходимые. Нужный диапазон в итоге сохраняю в буфер с накоплением нескольких кадров, для получения некоего подобия HDR изображения. К сожалению JPEG выдает меньше чем 8 бит на канал, поэтому для получения итогового качества как у GRAYSCALE формата нужно делать несколько снимков для усреднения. У меня уходит 17 секунд на 5 кадров + 1 кадр превью с высоким сжатием.

Дальше этапы обработки отрисовываются в буфере, который потом жмется в JPEG и доступен в браузере:
скриншот
Следующий шаг - собственно распознавание текста )

Редактировался executer (2020-05-11 17:32:17)

#36 2020-05-11 18:11:09

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

Большая работа - выходные проходят не зря.

На картинке там где нули засветы они могут немного затруднять распознавание. Это видно и на найденной ширине цифр - она разная.

Как у Вас выполнена подсветка?
Вы линзу ставили?

Редактировался NickVectra (2020-05-11 18:11:49)

#37 2020-05-11 18:29:53

executer
Участник
Зарегистрирован: 2020-04-19
Сообщений: 8

Re: Очередная система считывания данных счетчика

Да уж, погрузился основательно, но удачно все нужные библиотеки и примеры нашлись и особо косяков никаких не вылезло. Повезло.
Камера ESP_CAM32 как есть, без доработок. Подсветка встроенным светодиодом родным. Там где у меня стоят счетчики - других источников света нет, условия стабильные - темнота ). Тестовый стенд - ч.б. распечатка фотки с телефона перед камерой (телефон со вспышкой фотографировал). Не слишком натуралистично, но пока с такими условиями разберусь что к чему, а там буду думать как дальше тестировать. Фото с камеры в тестовых условиях
camera view

#38 2020-05-25 20:08:46

NickVectra
Участник
Зарегистрирован: 2020-01-09
Сообщений: 26

Re: Очередная система считывания данных счетчика

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

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

Batu пишет:

Думаю здесь вполне можно реализовать распознавание с помощью нейронной сети. Задача обсосаная и решений полно. На одном шрифте обучение должно быть простым.

На основании этого примера https://github.com/surya-veer/RealTime-DigitRecognition на Python OpenCV (настольный компьютер) получается довольно быстро (на мое обучение Python и первые наброски программы ушло неполных 2 дня).

Изображение, которое можно получить практически от любого источника (файл, Web камера, USB камера), преобразуется в градации серого и после фильтра переводится в черно-белое. Найденные контуры позволяют определить положение цифр шкалы, которые вырезаются из общего изображения.

В начале (май - середина июня 2020) распознавание цифр проводилось уже обученной нейронной сетью, предназначенной для рукописных цифрах. Однако анализ показал, что некоторые цифры распознавались не точно.

Поэтому была построена и обучена новая нейронная сеть на изображениях цифр реальной шкалы. Для увеличения ряда обучающей последовательности был использован ImageDataGenerator, который каждую цифру смещал по осям и производил вращение в произвольном порядке. Всего было создано 10000 изображений.
Нейронная сеть обучалась 8 эпох.

Не думаю, что все это можно реализовать на ESP32 Tensofflow lite, хотя заманчиво.
Основные идеи программы приведены ниже.

#!/usr/bin/env python3

import os
from datetime import datetime, timedelta

import numpy as np
import openpyxl
from PIL import Image
import cv2
import sys
import imutils
from keras.models import load_model
import glob
import time

from collections import Counter
import urllib

# поиск и выделенее цифр шкалы


def letters_extract(image_pic, image_size_W, image_size_H):
    add_x_y = 10
    min_contourArea = 2000  # минимальне площадь контура, которая отбрасывается
    min_h = 150  # минимлаьная высоты цифры
    max_h = 210  # максимальная высота цифры
    min_w = 60  # миниалная ширина цифры

    # преобразовать в градации серого
    gray = cv2.cvtColor(image_pic, cv2.COLOR_BGR2GRAY)
    # cv2.imshow("gray", gray)

    W = image_pic.shape[1]
    H = image_pic.shape[0]

    # Apply bilateral filter with d = 15,
    # sigmaColor = sigmaSpace = 75.
    gray = cv2.bilateralFilter(gray, 4, 75, 75)

    # cv2.imshow("gray1", gray)
    # поиск значения уровня бинаризации
    ret, thresh = cv2.threshold(
        gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    # cv2.imshow("thresh", thresh)
    # бинаризация изображения
    _, binary = cv2.threshold(gray, ret + 5, 255, cv2.THRESH_BINARY_INV)
    cv2.imshow("binary", binary)

    img_erode = binary.copy()
    # выделенее контуров
    contours, hierarchy = cv2.findContours(
        img_erode, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)

    output = image_pic.copy()
    letters = []
    for idx, contour in enumerate(contours):  # индекс и элемент
        (x, y, w, h) = cv2.boundingRect(contour)
        # если площадь меньше отбрасываем
        if cv2.contourArea(contour) < min_contourArea:
            continue
        # строим рамку вокруг контура
        cv2.rectangle(output, (x, y), (x + w, y + h), (255, 0, 255), 1)
        # подписываем высоту, ширину и площадь контура
        cv2.putText(output, str(h)+" "+str(w)+" " + str(cv2.contourArea(contour)), (x+30, y+40), cv2.FONT_HERSHEY_SIMPLEX,
                    0.4, (255, 0, 255), 1, cv2.LINE_AA)

        # отбираем по высоте
        if h < min_h or h > max_h:
            continue

        if hierarchy[0][idx][3] > -1:
            # расширим размер области для вырезания цифры
            if (w < min_w):
                x -= (min_w - w) // 2
                w = min_w

            x -= add_x_y
            y -= add_x_y
            # подписываем высоту и ширину контура
            cv2.putText(output, str(h)+" "+str(w)+" "+str(cv2.contourArea(contour)), (x, y), cv2.FONT_HERSHEY_SIMPLEX,
                        0.5, (0, 255, 0), 1, cv2.LINE_AA)
            w += 2 * add_x_y
            h += 2 * add_x_y
            # строим расширенную рамку вокруг контуров
            cv2.rectangle(output, (x, y), (x + w, y + h), (0, 255, 255), 1)

            # вырезаем область контура - считем это цифой
            letter_crop = gray[y:y + h, x:x + w]
            # cv2.putText(output, str(idx), (x, y), cv2.FONT_HERSHEY_SIMPLEX,
            #             1, (0, 255, 0), 1, cv2.LINE_AA)

            # print(str(len(letters)), letter_crop.shape, idx)
            # изменяем размер
            letter_crop = cv2.resize(letter_crop, (image_size_W, image_size_H))
            letters.append((x, y, h, letter_crop))

    # сортируем значения по X-координате
    letters.sort(key=lambda a: (a[0], a[2]), reverse=False)

    return letters, output


if __name__ == "__main__":
    print("Start loading model...")
    model_32_16 = load_model('my_model.h5')
    print("Model loaded")

    old_time = int(time.time())
    # файл сохранения значений
    WORKBOOK_NAME = 'Counter.xlsx'
    ONE_HOUR = timedelta(hours=1)
    old_shot_hour = datetime.now().hour

    if os.path.isfile(WORKBOOK_NAME):
        wb = openpyxl.load_workbook(WORKBOOK_NAME)
    else:
        wb = openpyxl.Workbook()
    ws = wb.active
    # параметры изображения для распознавания
    image_size_H = 32
    image_size_W = 16
    num_channels = 1

    old_count = 0
    counter_volue = []
    counter_res = 0

    d = 0
    while (1):
        # видео берем от телефона с программой IP WebCam
        cap = cv2.VideoCapture("rtsp://10.0.1.251:8080/h264_ulaw.sdp")
        ret, start_pic = cap.read()
        if ret is not True:
            continue
        # вырезаем область шкалы с запасом
        image_pic = start_pic[100:700, 0:1920]
        H = image_pic.shape[0]
        W = image_pic.shape[1]
        # понизим яркость в районе красных цифр
        image_pic[0:H, W-230:W] = cv2.add(
            image_pic[0:H, W - 230:W], np.array([-40.0]))
        # повысим яркость в районе первой цифры
        image_pic[0:H, 90:300] = cv2.add(
            image_pic[0:H, 90:300], np.array([30.0]))

        # надем все цифры шкалы
        letters, output = letters_extract(
            image_pic, image_size_W, image_size_H)
        i = 0
        count_metter = 0
        while i < len(letters):
            # обработаем найденные цыфры
            pic = letters[i][3]
            pic_data = np.reshape(
                pic, (1, image_size_H, image_size_W, num_channels))
            # опознать цифру
            predictions = model_32_16.predict(pic_data)
            dig = np.argmax(predictions)

            ver = predictions[0][dig]
            y_dig = letters[i][1]
            # если цифры находятся на одной оси Х - то выберем максимальную по высоте
            if i < len(letters) - 1:
                if abs(letters[i][0] - letters[i + 1][0]) < 50:  # x
                    print("цифра {} на одной оси x = {} {}".format(
                        i, letters[i][0], letters[i + 1][0]))
                    if letters[i][2] < letters[i + 1][2]:  # h
                        pic = letters[i + 1][3]
                        pic_data = np.reshape(
                            pic, (1, image_size_H, image_size_W, num_channels))
                        predictions = model_32_16.predict(pic_data)
                        dig = np.argmax(predictions)
                        ver = predictions[0][dig]
                        print("next -------- ", end=" ")
                        print(i, (dig, ver),
                              (letters[i + 1][0], letters[i + 1][2]))
                        y_dig = letters[i + 1][1]

                    else:
                        print("old -------- ", end=" ")
                        print(i, (dig, ver), (letters[i][0], letters[i][2]))

                    i += 1

            # преобразуем значения в число
            count_metter = count_metter * 10 + dig
            # вывод значений опознанных цифр
            cv2.putText(output, str(dig), (letters[i][0]+35, y_dig-20), cv2.FONT_HERSHEY_SIMPLEX,
                        1, (255, 255, 0), 1, cv2.LINE_AA)

            i += 1

        now_time = int(time.time())
        now_date = datetime.now()
        # сохранение показаний в таблице каждый час
        if (now_date.minute == 0) and (now_date.hour != old_shot_hour):
            cv2.imwrite(now_date.strftime("%Y%m%d-%H%M%S.jpg"), start_pic)
            delta = counter_res - old_count
            time_delta = timedelta(seconds=(now_time-old_time))
            ws.append([now_date, old_count, time_delta, delta])
            wb.save(WORKBOOK_NAME)
            old_shot_hour = now_date.hour
        # сохранение показаний в таблице при изменении
        if (now_time - old_time) >= 60:
            if (len(letters) == 7):
                counter_volue.append(count_metter)
                # накопленее значений для усреднения 17 раз
                if len(counter_volue) == 17:
                    c = Counter(counter_volue)
                    counter_res = c.most_common(1)[0][0]
                    counter_res_n = c.most_common(1)[0][1]
                    print("c = {} counter_res = {} counter_res_n = {}".format(
                        c, counter_res, counter_res_n))
                    counter_volue = []

                    if old_count != counter_res:
                        delta = counter_res - old_count
                        time_delta = timedelta(seconds=(now_time-old_time))
                        ws.append([now_date, counter_res, time_delta, delta])
                        ws.column_dimensions['A'].width = 20
                        wb.save(WORKBOOK_NAME)
                        old_time = now_time
                        old_count = counter_res
            else:
                print("recognized " + str(len(letters)), end=" digits ")
            print("data_time = {} counter_res = {} count_metter = {} old_count = {}".format(
                datetime.now(), counter_res, count_metter, old_count))

        # print("-------")
        cv2.imshow("finish", output)
        k = cv2.waitKey(5) & 0xFF
        if k == 27:
            print("CLOSING WEBCAM")
            break

    cap.release()
    cv2.destroyAllWindows()

Эксплуатация программы в течении месяца (середина июня - июль 2020) показала ее полную работоспособность. Может нужно будет перевести потом на Raspberry Pi

Редактировался NickVectra (Вчера 10:54:15)

Быстрое сообщение

Введите сообщение и нажмите Отправить

Подвал раздела