---
# System prepended metadata

title: 利用MQTT與Tesseract OCR技術實現即時設備數據監控與通知
tags: [Python, Node-RED, MQTT]

---

---
disqus: ahb0222
GA : G-VF9ZT413CG
---

> [color=#40f1ef][name=LHB阿好伯, 2021/07/16][:earth_africa:](https://www.facebook.com/LHB0222/)


[TOC]


Python結合MQTT與Tesseract OCR技術
可以實現設備主機數值截圖的傳輸與數字辨識
透過這項技術，您可以將設備的數據截圖傳送至Node-RED進行處理
並利用本地化的Tesseract OCR進行數字辨識
(取代之前我使用的[OCR.space服務](https://ocr.space/OCRAPI))
可以避免又遇到伺服器出現問題或免費使用的次數限制
![image](https://hackmd.io/_uploads/Sk9SdjFU0.png)
![image](https://hackmd.io/_uploads/HkZuYjF8A.png)

利用node-red設定當設備的強度變化低於設定值時
系統會自動發送Line通知
同時還可以繪製趨勢圖以觀察數據變化。
解決了許多設備軟體缺乏通知功能的問題
避免了人員無法隨時關注或及時發現遠端設備狀態的困境
![image](https://hackmd.io/_uploads/ryQBcotLC.png)

以下是程式的實現步驟和主要功能：

連接MQTT Broker：設定連接和斷開連接的處理函數，確保穩定連線。
接收影像訊息：訂閱特定主題以接收影像訊息，並將接收到的影像數據解碼保存為圖片檔案。
影像處理：檢查影像最上面三行的平均亮度，判斷是否需要進行黑白反轉，以便於OCR辨識
(使用過程中發現Tesseract OCR辨識白底黑字比較正常)
傳送辨識結果：將辨識出的數字結果發布到對應的MQTT主題，以便進一步處理。

```python=
# sudo apt install tesseract-ocr
# sudo apt install libtesseract-dev
import base64
import cv2
import pytesseract
from PIL import Image, ImageOps
import io
from paho.mqtt import client as mqtt_client
import random
from datetime import datetime
import logging
import numpy as np

# 設置 logging 配置
logging.basicConfig(filename='mqtt_ocr.log', level=logging.INFO, format='%(asctime)s %(message)s')

# MQTT 配置
broker = 'broker.emqx.io'
port = 1883
topic = "MQTTin/image-topic/#"  #MQTT訂閱的路徑
client_id = f'subscribe-{random.randint(0, 100)}'
ocr_topic_base = "MQTTout/ocr-topic/"  #OCR結果發佈的路徑
is_connected = False

def log_with_timestamp(message):
    timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    logging.info(f"{message}")

def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        global is_connected
        if rc == 0:
            is_connected = True
            log_with_timestamp("Connected to MQTT Broker!")
            client.subscribe(topic)
        else:
            log_with_timestamp(f"Failed to connect, return code {rc}")

    def on_disconnect(client, userdata, rc):
        global is_connected
        is_connected = False
        log_with_timestamp(f"Disconnected from MQTT Broker, return code {rc}")
        if rc != 0:
            log_with_timestamp("Unexpected disconnection.")

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.connect(broker, port)
    return client

def on_message(client, userdata, msg):
    log_with_timestamp(f"Received message on topic {msg.topic}")
    
    # 解碼並保存影像
    try:
        img_data = base64.b64decode(msg.payload)
        image = Image.open(io.BytesIO(img_data))
        image.save("received_image.png")
    except Exception as e:
        log_with_timestamp(f"Error decoding image: {e}")
        return
    
    # 讀取影像並判斷最上面三行像素的平均亮度
    try:
        image = Image.open("received_image.png").convert("L")
        image_np = np.array(image)
        top_three_rows = image_np[:3, :]  # 取得最上面三行
        mean_brightness = np.mean(top_three_rows)
        log_with_timestamp(f"Mean brightness of top three rows: {mean_brightness}")
        
        # 如果背景為黑色，則進行黑白反轉
        if mean_brightness < 128:
            inverted_image = ImageOps.invert(image)
            inverted_image.save("processed_image.png")
        else:
            image.save("processed_image.png")
    except Exception as e:
        log_with_timestamp(f"Error processing image: {e}")
        return
    
    # 讀取處理後的影像
    image = cv2.imread("processed_image.png")
    if image is None:
        log_with_timestamp("Error reading image")
        return
    
    # 進行 OCR 辨識
    try:
        # 設定只辨識數字和小數點
        config = '--psm 7 -c tessedit_char_whitelist=0123456789.'
        text = pytesseract.image_to_string(image, config=config)
    except Exception as e:
        log_with_timestamp(f"Error during OCR: {e}")
        return
    
    # 生成回傳的主題
    ocr_topic = ocr_topic_base + msg.topic.split('/')[-1]
    
    # 發布 OCR 結果
    client.publish(ocr_topic, text)
    log_with_timestamp(f"Published OCR result to {ocr_topic}: {text}")

def run():
    client = connect_mqtt()
    client.on_message = on_message
    while True:
        if not is_connected:
            client.reconnect()
        client.loop_forever()

if __name__ == '__main__':
    run()

```


🌟全文可以至下方連結觀看或是補充


全文分享至

https://www.facebook.com/LHB0222/

https://www.instagram.com/ahb0222/

有疑問想討論的都歡迎於下方留言

喜歡的幫我分享給所有的朋友 \o/

有所錯誤歡迎指教

# [:page_with_curl: 全部文章列表](https://hackmd.io/@LHB-0222/AllWritings)



![](https://i.imgur.com/nHEcVmm.jpg)


