JPEG で画像を取得する (Python)

 

本ページは i-PRO株式会社 の有志メンバーにより記載されたものです。
本ページの情報は ライセンス に記載の条件で提供されます。

 

 

 

本ページでは、i-PRO カメラとPCを JPEG により接続してPC画面へ表示するプログラムを Python で作成する例を紹介します。とても短いプログラムで i-PRO カメラの映像を見ることができます。動作確認は i-PRO mini (WV-S7130)、モジュールカメラ(AIスターターキット)を使って行いましたが、ほとんどの i-PRO カメラでそのまま利用できるはずです。ぜひお試しください。

 

[動画] JPEG でカメラと接続して映像表示した様子

 


 

"i-PRO mini" 紹介:

i-PRO mini 画像

 

"モジュールカメラ" 紹介:

AI スターターキット 画像(1) AI スターターキット 画像(2)

 

カメラ初期設定についてはカメラ毎の取扱説明書をご確認ください。

カメラのIPアドレスを確認・設定できる下記ツールを事前に入手しておくと便利です。

 


 

1. JPEG 表記仕様

[概要]

JPEG(1shot要求)で接続するための表記を以下に記載します。

「ネットワークカメラCGIコマンドインターフェース仕様書 統合版」[1] で下記に記載されている情報です。

 

http://<カメラのIPアドレス>/cgi-bin/camera?resolution={resolution}

 

(具体例)

http://192.168.0.10/cgi-bin/camera?resolution=1920

 

補足説明:

 

 

2. i-PRO カメラと JPEG 接続して映像を表示してみる

[概要]

とりあえず映像を取得してPC画面に表示するまでをやってみます。

 

[評価環境1]

言語 : Python, 3.10.4
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

[評価環境2]

言語 : Python, 3.8.10
OS : Ubuntu(WSL), 20.04

 

 

[プログラム]

プログラムを終了する方法を実装していません。コンソール上で [ctrl]+[c] して終了してください。

 

[プログラムソース "connect_with_jpeg_1.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG(1 shot).
    JPEG(1 shot) で i-PRO カメラと接続してみる

[Details]
    Let's try first.
    まずはやってみる

[Library install]
    cv2:        pip install opencv-python
    numpy:      pip install numpy
    requests:   pip install requests
'''

import requests
from requests.auth import HTTPDigestAuth
import numpy as np
import cv2

user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution

# URL
url = f"http://{host}/cgi-bin/camera?resolution={resolution}"

while True:
    try:
        # Request and receive image from camera.
        rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw))

        # Convert from binary to ndarray.
        img_buf= np.frombuffer(rs.content, dtype=np.uint8)

        # Convert from ndarray to OpenCV image.
        img1 = cv2.imdecode(img_buf, cv2.IMREAD_UNCHANGED)

        # Please modify the value to fit your PC screen size.
        img2 = cv2.resize(img1, (1280, 720))

        # Display video.
        cv2.imshow(winname, img2)
        cv2.waitKey(1)      # necessary to display the video by imshow ()

    except KeyboardInterrupt:
        # Press '[ctrl] + [c]' on the console to exit the program.
        print("KeyboardInterrupt")
        break
    
cv2.destroyAllWindows()

 

上記プログラムを動かしてみます。

Windows ではこんな感じで実行します。

$ python connect_with_jpeg_1.py

 

Linux はこんな感じで実行します。

$ python3 connect_with_jpeg_1.py

 

Windows環境で複数の Python バージョンをインストールしている場合、下図のような感じで実行バージョンを指定することもできます。
こちらはバージョン 3.10 の Python で実行する例です。

$ py -3.10 connect_with_jpeg_1.py

 

上記プログラムを動かした様子を動画で示します。

こんなに簡単なプログラムでちゃんと映像表示を実現することができました。

5fps(毎秒5コマ)ぐらいの表示でしょうか。JPEGなので妥当な結果だと思います。

[動画] JPEG でカメラと接続して映像表示した様子

 

 

3.プログラムを改善する

[概要]

前章で作成したプログラムはとても簡単に作成できましたが、いろいろと課題がありました。
とりあえず下記3つの課題を解決してみます。

 

課題1
プログラムを起動するたびにウィンドウ位置が変わる。場合によっては画面外へ表示する場合もあって不便。
適当に画面内に収まる場所に表示してほしい。
⇨ 指定する場所にウィンドウを表示するようにします。

 

課題2
プログラムを終了するのが大変。
ウィンドウ右上の[x]を押すとウィンドウがいったん消えるが、すぐに再表示されて終われない。
⇨ ウィンドウ右上の[x]ボタンでプログラムを終了できるようにします。

 

課題3
同様に、任意のキー入力でプログラムを終了できるとうれしい。
⇨ "q" キー押下でプログラムを終了できるようにします。

 

 

 

[評価環境1]

言語 : Python, 3.10.4
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

[評価環境2]

言語 : Python, 3.8.10
OS : Ubuntu(WSL), 20.04

 

 

[プログラム]

[プログラムソース "connect_with_jpeg_2.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG(1 shot).
    JPEG(1 shot) で i-PRO カメラと接続してみる

[Details]
    Let's improve the three issues of "connect_with_jpeg_1.py".
    "connect_with_jpeg_1.py" で確認した3つの課題を改善してみます。

    [Issues 1]
    Specifies the position where the window is displayed.
    ウィンドウを指定する場所に表示するようにします。
    [Issues 2]
    Modify the program so that you can exit the program by clicking the [x] button.
    ウィンドウ右上の[x]ボタンでプログラムを終了できるようにします。
    [Issues 3]
    Modify the program so that you can exit the program by pressing the [q] key.
    "q" キー押下でプログラムを終了できるようにします。

[Library install]
    cv2:        pip install opencv-python
    numpy:      pip install numpy
    requests:   pip install requests
'''

import requests
from requests.auth import HTTPDigestAuth
import numpy as np
import cv2

user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution

# URL
url = f"http://{host}/cgi-bin/camera?resolution={resolution}"

#
initialized = False

# Exception 定義
BackendError = type('BackendError', (Exception,), {})

def IsWindowVisible(winname):
    '''
    [Abstract]
        Check if the target window exists.
        対象ウィンドウが存在するかを確認する。
    [Param]
        winname :       Window title
    [Return]
        True :          exist
                        存在する
        False :         not exist
                        存在しない
    [Exception]
        BackendError :
    '''
    try:
        ret = cv2.getWindowProperty(winname, cv2.WND_PROP_VISIBLE)
        if ret == -1:
            raise BackendError('Use Qt as backend to check whether window is visible or not.')

        return bool(ret)

    except cv2.error:
        return False


while True:
    try:
        # Request and receive image from camera.
        rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw))

        # Convert from binary to ndarray.
        img_buf= np.frombuffer(rs.content, dtype=np.uint8)

        # Convert from ndarray to OpenCV image.
        img1 = cv2.imdecode(img_buf, cv2.IMREAD_UNCHANGED)

        # Please modify the value to fit your PC screen size.
        img2 = cv2.resize(img1, (1280, 720))

        # Display video.
        cv2.imshow(winname, img2)

        if initialized==False:
            # Specify window position only once at startup.
            cv2.moveWindow(winname, 100, 100)
            initialized = True
            
        # Press the "q" key to finish.
        k = cv2.waitKey(1) & 0xff   # necessary to display the video by imshow ()
        if k == ord("q"):
            break

        # Exit the program if there is no specified window.
        if not IsWindowVisible(winname):
            break

    except KeyboardInterrupt:
        # Press '[ctrl] + [c]' on the console to exit the program.
        print("KeyboardInterrupt")
        break

cv2.destroyAllWindows()

 

 

 

4. OpenCV で顔検知を加えてみる

[概要]

OpenCV を使って顔検知を行って、見つけた顔部分に赤枠を描画してみます。 

 

下記 URL からファイル "haarcascade_frontalface_alt2.xml" を入手してプログラムと同じ場所に保存する必要があります。

https://github.com/opencv/opencv/tree/master/data/haarcascades

xml ファイル取得方法は こちら を参照ください

 

[評価環境1]

言語 : Python, 3.10.4
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

[評価環境2]

言語 : Python, 3.8.10
OS : Ubuntu(WSL), 20.04

 

 

[プログラム]

[プログラムソース "connect_with_jpeg_3.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG(1 shot).
    JPEG(1 shot) で i-PRO カメラと接続してみる

[Details]
    Let's add face detection using OpenCV.
    OpenCV を使って顔検知を追加してみます

[Library install]
    cv2:        pip install opencv-python
    numpy:      pip install numpy
    requests:   pip install requests

[OpenCV]
    Get the file "haarcascade_frontalface_alt2.xml" from the URL below.
    下記URLからファイル "haarcascade_frontalface_alt2.xml" を入手するしてください。
    https://github.com/opencv/opencv/tree/master/data/haarcascades
'''

import requests
from requests.auth import HTTPDigestAuth
import numpy as np
import cv2


user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution

# URL
url = f"http://{host}/cgi-bin/camera?resolution={resolution}"

# haarcascade file for opencv cascade classification.
cascade_file = "haarcascade_frontalface_alt2.xml"       # face
#cascade_file = "haarcascade_eye.xml"                   # eye ?
#cascade_file = "haarcascade_eye_tree_eyeglasses.xml"   # eye ?
cascade = cv2.CascadeClassifier(cascade_file)

#
initialized = False

# Exception definition.
BackendError = type('BackendError', (Exception,), {})

def IsWindowVisible(winname):
    '''
    [Abstract]
        Check if the target window exists.
        対象ウィンドウが存在するかを確認する。
    [Param]
        winname :       Window title
    [Return]
        True :          exist
                        存在する
        False :         not exist
                        存在しない
    [Exception]
        BackendError :
    '''
    try:
        ret = cv2.getWindowProperty(winname, cv2.WND_PROP_VISIBLE)
        if ret == -1:
            raise BackendError('Use Qt as backend to check whether window is visible or not.')

        return bool(ret)

    except cv2.error:
        return False


if __name__ == '__main__':
    '''
    [Abstract]
        main function
    '''
    while True:
        try:
            # Request and receive image from camera.
            rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw))

            # Convert from binary to ndarray.
            img_buf= np.frombuffer(rs.content, dtype=np.uint8)

            # Convert from ndarray to OpenCV image.
            img1 = cv2.imdecode(img_buf, cv2.IMREAD_UNCHANGED)

            # Convert to grayscale image for face detection.
            img_gray = cv2.imdecode(img_buf, cv2.IMREAD_GRAYSCALE)

            # Detect faces from image.
            face_list = cascade.detectMultiScale(img_gray, minSize=(100, 100))

            # Draw red frames for the number of detected faces.
            if len(face_list) != 0:
                for (pos_x, pos_y, w, h) in face_list:
                    print(f"pos_x = {pos_x}, pos_y = {pos_y}, w = {w}, h = {h}")
                    cv2.rectangle(img1, (pos_x, pos_y), (pos_x + w, pos_y + h), (0,0,255), thickness=5)

            # Please modify the value to fit your PC screen size.
            img2 = cv2.resize(img1, (1280, 720))

            # Display video.
            cv2.imshow(winname, img2)

            if initialized==False:
                # Specify window position only once at startup.
                cv2.moveWindow(winname, 100, 100)
                initialized = True
            
            # Press the "q" key to finish.
            k = cv2.waitKey(1) & 0xff   # necessary to display the video by imshow ()
            if k == ord("q"):
                break

            # Exit the program if there is no specified window.
            if not IsWindowVisible(winname):
                break

        except KeyboardInterrupt:
            # Press '[ctrl] + [c]' on the console to exit the program.
            print("KeyboardInterrupt")
            break
        
    cv2.destroyAllWindows()

 

 

[動画] OpenCV で顔検知してみた様子

 

 


5. 連番の JPEG ファイルで保存する

受信した画像を 1 から始まる連番のファイル名 (image_NNNNNN.jpg) で JPEG ファイルとして保存してみます。

 

 

[評価環境]

言語 : Python, 3.10.4
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

[プログラムソース "connect_with_jpeg_4.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG(1 shot).
    JPEG(1 shot) で i-PRO カメラと接続してみる

[Details]
    Save the received JPEG image as a file.
    Add a 6-digit number to the end of the file name and save it as a serial number.

    受信した JPEG 画像をファイル保存します。
    ファイル名の末尾に6ケタの番号を付けて連番で保存します。

[Library install]
    cv2:        pip install opencv-python
    numpy:      pip install numpy
    requests:   pip install requests
'''

import requests
from requests.auth import HTTPDigestAuth
import numpy as np
import cv2
import os


user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution
pathOut     = 'image'           # Image file save folder name

# URL
url = f"http://{host}/cgi-bin/camera?resolution={resolution}"

# Exception 定義
BackendError = type('BackendError', (Exception,), {})

def IsWindowVisible(winname):
    '''
    [Abstract]
        Check if the target window exists.
        対象ウィンドウが存在するかを確認する。
    [Param]
        winname :       Window title
    [Return]
        True :          exist
                        存在する
        False :         not exist
                        存在しない
    [Exception]
        BackendError :
    '''
    try:
        ret = cv2.getWindowProperty(winname, cv2.WND_PROP_VISIBLE)
        if ret == -1:
            raise BackendError('Use Qt as backend to check whether window is visible or not.')

        return bool(ret)

    except cv2.error:
        return False


def SaveBinaryData(data, filename):
    '''
    [Abstract]
        バイナリデータを指定ファイル名で保存する
    [Param]
        data :      保存するバイナリデータ
        filename :  ファイル名
    '''
    fout = open(filename, 'wb')
    fout.write(data)
    fout.close()


if __name__ == '__main__':
    '''
    [Abstract]
        main function
    '''
    initialized = False
    count = 0
    if not os.path.exists(pathOut):
        os.mkdir(pathOut)

    while True:
        try:
            # Request and receive image from camera.
            rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw))

            # Save jpeg file.
            count += 1
            filename = os.path.join(pathOut, 'image_{:06d}.jpg'.format(count))
            SaveBinaryData(rs.content, filename)

            # Convert from binary to ndarray.
            img_buf= np.frombuffer(rs.content, dtype=np.uint8)

            # Convert from ndarray to OpenCV image.
            img1 = cv2.imdecode(img_buf, cv2.IMREAD_UNCHANGED)

            # Please modify the value to fit your PC screen size.
            img2 = cv2.resize(img1, (1280, 720))

            # Display video.
            cv2.imshow(winname, img2)

            if initialized==False:
                # Specify window position only once at startup.
                cv2.moveWindow(winname, 100, 100)
                initialized = True
            
            # Press the "q" key to finish.
            k = cv2.waitKey(1) & 0xff   # necessary to display the video by imshow ()
            if k == ord("q"):
                break

            # Exit the program if there is no specified window.
            if not IsWindowVisible(winname):
                break
    
        except KeyboardInterrupt:
            # Press '[ctrl] + [c]' on the console to exit the program.
            print("KeyboardInterrupt")
            break
    
    cv2.destroyAllWindows()

 

 

 

6. 映像切断時の再接続処理を追加

ここまでのプログラムは、カメラとの接続を切断すると接続が復活しませんでした。
例えばカメラを再起動するなどしても自動的に再接続を行って映像表示できるようにプログラムを修正してみます。

"connect_with_jpeg_2.py" を元に再接続処理を追加してこの問題を解決してみたいと思います。

 

NOTE

  • requests.get 関数はカメラと都度接続する関数なので、いわゆる再接続の処理は不要でした。
    タイムアウト発生時などの異常処理を追加するだけで期待する動作を実現できました。
  • 切断の試験はカメラの電源をOff/Onする、通信をOff/Onする、などで試験してください。
  • requests.get 関数は引数としてタイムアウト時間を設定することができました。下記例では 10秒 を設定しています。
    適当な値へ変更するなどして挙動の変化を試してみてはいかがでしょうか。

 

[評価環境]

言語 : Python, 3.10.4
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

 

[プログラムソース "connect_with_jpeg_5.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG(1 shot).
    JPEG(1 shot) で i-PRO カメラと接続してみる

[Details]
    Add reconnection when video is disconnected to "connect_with_jpeg_2.py".
    "connect_with_jpeg_2.py" へ映像切断時の再接続処理を追加する。

[Library install]
    cv2:        pip install opencv-python
    numpy:      pip install numpy
    requests:   pip install requests
'''

import requests
from requests.auth import HTTPDigestAuth
import numpy as np
import cv2
from urllib3 import HTTPConnectionPool

user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution

# URL
url = f"http://{host}/cgi-bin/camera?resolution={resolution}"

#
initialized = False

# Exception Definition
BackendError = type('BackendError', (Exception,), {})

def IsWindowVisible(winname):
    '''
    [Abstract]
        Check if the target window exists.
        対象ウィンドウが存在するかを確認する。
    [Param]
        winname :       Window title
    [Return]
        True :          exist
                        存在する
        False :         not exist
                        存在しない
    [Exception]
        BackendError :
    '''
    try:
        ret = cv2.getWindowProperty(winname, cv2.WND_PROP_VISIBLE)
        if ret == -1:
            raise BackendError('Use Qt as backend to check whether window is visible or not.')

        return bool(ret)

    except cv2.error:
        return False


while True:
    try:
        # Request and receive image from camera.
        rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw), timeout=10)

        # Convert from binary to ndarray.
        img_buf= np.frombuffer(rs.content, dtype=np.uint8)

        # Convert from ndarray to OpenCV image.
        img1 = cv2.imdecode(img_buf, cv2.IMREAD_UNCHANGED)

        # Please modify the value to fit your PC screen size.
        img2 = cv2.resize(img1, (1280, 720))

        # Display image.
        cv2.imshow(winname, img2)

        if initialized==False:
            # Specify window position only once at startup.
            cv2.moveWindow(winname, 100, 100)
            initialized = True
            
        # Press the "q" key to finish.
        k = cv2.waitKey(1) & 0xff   # necessary to display the video by imshow ()
        if k == ord("q"):
            break

        # Exit the program if there is no specified window.
        if not IsWindowVisible(winname):
            break

    except KeyboardInterrupt:
        # Press '[ctrl] + [c]' on the console to exit the program.
        print("KeyboardInterrupt")
        break

    except requests.ConnectTimeout as e:
        # Connection timeout.
        print(e)

    except requests.exceptions.Timeout as e:
        # Read timeout.
        print(e)

    except Exception as e:
        # Other unexpected exceptions.
        print(e)

cv2.destroyAllWindows()

 

補足:

上記ソースコードでは例外処理を3つ加えています。

(1) requests.ConnectTimeout

接続時タイムアウトです。カメラの電源をOffにしているときなどカメラと接続できない状態にあるときに接続しに行くと発生します。

(2) requests.exceptions.Timeout

読み取り時タイムアウトです。カメラと接続できている状態でカメラの電源をOffにするなどすると1回だけこの例外が発生するようです。この例外を1回発生させた後は requests.ConnectTimeout を発生するようになります。

(3) Exception

その他の例外です。意図しない例外を発生したときにその内容を確認する意図で記載しました。このプログラムを作成時にデバッグを目的に記載したもので不要な内容ですが、参考に残しています。システム終了以外の全ての組み込み例外はこの Exception クラスから派生しているので、この記載でほとんどの例外を補足することができます。

 

 

 

7. GUIで映像表示してみる(tkinter)

ここまでのプログラムは全てOpenCVが作成するウィンドウ表示でした。
ここでは独自の GUI を作成してここに映像表示する例を示します。

GUI 表示の実現方法もいろいろありますが、ここでは Python 標準の tkinter を使用してみます。

 

tkinter のインストール方法は環境により異なるようです。各人の環境にあった方法をインターネットで調べて実施してください。

 

ポイント

  • tkinter で動画を表示するときは、after() 関数で繰り返し処理を行います。
  • tkinter で表示するために ImageTk.PhotoImage という型に変換する必要があります。

 

RTSP で画像を取得する : 7-3. メニュー・ボタンを追加して GUI アプリらしくしてみる」で既に GUI 版を作成済みなので、プログラム "connect_with_rtsp_6_3.py" をベースに変更箇所のみをわかるように以下で記載します。ほとんど同じ内容で実現できます。

 

[評価環境]

言語 : Python, 3.10.4
  Tcl/Tk, 8.6
OS : Windows 11 home, 21H2
Windows 10 Pro, 21H1

 

[プログラムソース "connect_with_jpeg_6.py"]

'''
[Abstract]
    Try connecting to an i-PRO camera with JPEG.
    JPEG で i-PRO カメラと接続してみる。

[Details]
    Display the video with GUI using tkinter.
    Add menus and buttons to make it look like a GUI app.
    
    tkinter を使ったGUIで映像を表示します。
    メニューとボタンを追加してGUIアプリらしくします。
    
[Library install]
    PIL :   pip install pillow
'''

import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk, ImageOps

import multiprocessing as mp
import time
import io
import requests
from requests.auth import HTTPDigestAuth


user_id     = "user-id"         # Change to match your camera setting
user_pw     = "password"        # Change to match your camera setting
host        = "192.168.0.10"    # Change to match your camera setting
winname     = "VIDEO"           # Window title
resolution  = 1920              # Resolution
url         = f"http://{host}/cgi-bin/camera?resolution={resolution}"


class Application(tk.Frame):
    def __init__(self, master = None):
        super().__init__(master)
        self.pack()

        # Window settings.
        self.master.title("Display i-PRO camera with tkinter")      # Window title
        self.master.geometry("800x600+100+100")                     # Window size, position

        # Event registration for window termination.
        self.master.protocol("WM_DELETE_WINDOW", self.on_closing_window)

        # Create menu.
        menubar = tk.Menu(self.master)
        self.master.configure(menu=menubar)
        filemenu = tk.Menu(menubar)
        menubar.add_cascade(label='File', menu=filemenu)
        filemenu.add_command(label='Quit', command = self.on_closing_window)

        # Create button_frame
        self.button_frame = tk.Frame(self.master, padx=10, pady=10, relief=tk.RAISED, bd=2)
        self.button_frame.pack(side = tk.BOTTOM, fill=tk.X)

        # Create quit_button
        self.quit_button = tk.Button(self.button_frame, text='Quit', width=10, command = self.on_closing_window)
        self.quit_button.pack(side=tk.RIGHT)
        
        # Create canvas.
        self.canvas = tk.Canvas(self.master)

        # Add mouse click event to canvas.
        self.canvas.bind('<Button-1>', self.canvas_click)

        # Place canvas.
        self.canvas.pack(expand = True, fill = tk.BOTH)

        # Create image receiving process and queue
        self.imageQueue = mp.Queue()
        self.request = mp.Value('i', 0)     # -1 : Exit ReceiveImageProcess.
                                            #  0 : Normal.
                                            #  1 : Connect camera.
                                            #  2 : Release camera.
        self.p = mp.Process(target=ReceiveImageProcess, args=(self.imageQueue, self.request))
        self.p.start()

        # Raise a video display event (disp_image) after 500m
        self.disp_id = self.after(500, self.disp_image)

    def on_closing_window(self):
        ''' Window closing event. '''

        if messagebox.askokcancel("QUIT", "Do you want to quit?"):
            # Request terminate process self.p.
            self.request.value = -1

            # Waiting for process p to finish
            time.sleep(1)

            # Flash buffer.
            # The program cannot complete p.join() unless the imageQueue is emptied.
            for i in range(self.imageQueue.qsize()):
                pil_image = self.imageQueue.get()

            # Wait for process p to be terminated.
            self.p.join()
            self.master.destroy()
            print("Finish Application.")

    def canvas_click(self, event):
        ''' Event handling with mouse clicks on canvas '''

        if self.disp_id is None:
            # Connect camera.
            self.request.value = 1
            # Display image.
            self.disp_image()

        else:
            # Release camera.
            self.request.value = 2
            # Cancel scheduling
            self.after_cancel(self.disp_id)
            self.disp_id = None

    def disp_image(self):
        ''' Display image on Canvas '''

        # If there is data in the imageQueue, the program receives the data and displays the video.
        num = self.imageQueue.qsize()
        if num > 0:
            if (num > 5):
                num -= 1
            for i in range(num):
                pil_image = self.imageQueue.get()

            # Get canvas size.
            canvas_width = self.canvas.winfo_width()
            canvas_height = self.canvas.winfo_height()

            # Resize the image to the size of the canvas without changing the aspect ratio.
            # アスペクトを維持したまま画像を Canvas と同じサイズにリサイズ
            pil_image = ImageOps.pad(pil_image, (canvas_width, canvas_height))

            # Convert image from PIL.Image to PhotoImage
            # PIL.Image から PhotoImage へ変換する
            self.photo_image = ImageTk.PhotoImage(image=pil_image)

            # Display image on the canvas.
            self.canvas.create_image(
                canvas_width / 2,       # Image display position (center of the canvas)
                canvas_height / 2,                   
                image=self.photo_image  # image data
                )
            
        else:
            pass

        # Raise a video display event (disp_image) after 1ms.
        self.disp_id = self.after(1, self.disp_image)


def ReceiveImageProcess(imageQueue, request):
    '''
    Receive Image Process.

    Args:
        imageQueue      [o] This process stores the received image data in the imageQueue.
        request         [i] Shared memory for receiving requests from the main process.
                            -1: Terminate process.
                             2: Do not get camera image.
                             *: At other values, the program gets the camera image.
    Returns:
        None
    Raises
        None
    '''

    while request.value != -1:
        if request.value != 2:
            try:
                # Request and receive image from camera.
                rs = requests.get(url, auth=HTTPDigestAuth(user_id, user_pw), timeout=10)
                if imageQueue.qsize() < 10:
                    image_bin = io.BytesIO(rs.content)
                    pil_image = Image.open(image_bin)
                    imageQueue.put(pil_image)

            except requests.ConnectTimeout as e:
                print(e)

            except requests.exceptions.Timeout as e:
                print(e)

            except Exception as e:
                print(e)

        else:
            time.sleep(1)


if __name__ == "__main__":
    '''
    __main__ function.
    '''
    root = tk.Tk()
    app = Application(master = root)
    app.mainloop()

 

[動画] tkinter で作成した GUI アプリ

 

 

ソースコード所在

本ページで紹介のソースコードは、下記 github より取得できます。

下記 github のソースコードと本ページの内容は差異がある場合があります。

i-pro-corp/python-examples: Examples for i-PRO cameras. (github.com)

 

 

ライセンス

本ページの情報は、特記無い限り下記ライセンスで提供されます。


Copyright 2022 i-PRO Co., Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

 

 

参考

 

 


 

変更履歴

2023/10/20 - IP簡単設定ソフトウェア、IP Setting Software リンク先を更新, 木下英俊
2023/3/1 - 説明および表現を一部更新, 木下英俊
2022/7/20 - 微修正, 木下英俊
2022/5/26 - 新規作成, 木下英俊

 

i-PRO - Programming Items トップページ

プライバシーポリシー