2CAMERA撮影した画像を連結する(python+OPEN CV)

概要

 1つの対象物を異なる角度から撮影したり、複数の対象物を同時撮影したい場合に利用する為に、2カメラ撮影後、撮影画像を連結する python プログラムを作成しましたので記載します。

◆検証環境◆

① OS : Windows10 64bit
② 言語 : python + OpenCV + pypylon
③ 装置 : Basler acA2500-14um(USB3) ※ 2台
      

結果

 (3) (4)にカメラ1,2の単体画像を示します。(1) (2) は単体画像を横方向・縦方向に連結した結果です。

(1)横方向連結(カメラ1・2連結画像)

(2)縦方向連結(カメラ1・2連結画像)

(3)カメラ1画像

(4)カメラ2画像

  

プログラム① (基本)

 このプログラムの私にとってのポイントは、カメラ本体記載のシリアル番号(S/N)で、対象カメラを指定できることです。行番11~12でカメラ1のシリアル番号を設定し、行番13でカメラ1インスタンスを生成します。 同様に行番17~19でカメラ2のインスタンスを生成しています。
 以後、GitHubにあるサンプルコード(opencv.py)を参考に2カメラ対応プログラムを作成しました。
 2カメラ画像の連結は、横方向連結は画像高さが同じであること。縦方向連結は画像幅が同じであることが条件です。この条件を満たせば連結は簡単で、行番62(横連結),行番68(縦連結)となっています。

# Basler acA2500-14um (USB3)   画像幅・高さ(1944X2592)

from pypylon import pylon
import cv2
# import numpy as np

s_n_1 = "********"
s_n_2 = "********"

# シリアルナンバー指定によるデバイス起動1
inf1 = pylon.DeviceInfo()
inf1.SetSerialNumber(s_n_1)
cmr1 = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice(inf1))
cmr1.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) 

# シリアルナンバー指定によるデバイス起動2
inf2 = pylon.DeviceInfo()
inf2.SetSerialNumber(s_n_2)
cmr2 = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice(inf2))
cmr2.StartGrabbing(pylon.GrabStrategy_LatestImageOnly) 

# 取得データコンバータ設定(opencv bgr format)
converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed
converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned

# 連続撮影
while cmr1.IsGrabbing() and cmr2.IsGrabbing():

    # カメラ1
    img_1 = None
    g_Rslt1 = cmr1.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
    if g_Rslt1.GrabSucceeded():
        image_1 = converter.Convert(g_Rslt1)
        img_1 = image_1.GetArray()
        
    g_Rslt1.Release()

    # カメラ2
    img_2 = None
    g_Rslt2 = cmr2.RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)
    if g_Rslt2.GrabSucceeded():
        image_2 = converter.Convert(g_Rslt2)
        img_2 = image_2.GetArray()
        
    g_Rslt2.Release()


    # カメラ1・2画像合成
    if (not img_1 is None) and (not img_2 is None) :
        
        # cv2.namedWindow('camera_1', cv2.WINDOW_NORMAL)
        # cv2.imshow('camera_1', img_1)
        # cv2.namedWindow('camera_2', cv2.WINDOW_NORMAL)
        # cv2.imshow('camera_2', img_2)
     
        h1, w1, c1 = img_1.shape    # 画像幅・高さ取得
        h2, w2, c2 = img_2.shape    # 画像幅・高さ取得

        # 横方向合成
        if h1 == h2:
            img_merge_v = cv2.hconcat([img_1, img_2])
            cv2.namedWindow('img_mrg_v', cv2.WINDOW_NORMAL)
            cv2.imshow('img_mrg_v', img_merge_v)

        # 縦方向合成
        # if w1 == w2:
        #     img_merge_h = cv2.vconcat([img_1, img_2])
        #     cv2.namedWindow('img_mrg_h', cv2.WINDOW_NORMAL)
        #     cv2.imshow('img_mrg_h', img_merge_h)

    k = cv2.waitKey(1)
    if k == 27:
        break

# デバイス開放  
cmr1.StopGrabbing()
cmr2.StopGrabbing()

cv2.destroyAllWindows()

 

プログラム② (発展)

 基本プログラムでは、 カメラ本体記載のシリアル番号(S/N) をプログラム内に直接記載しましたが、このプログラムでは接続されているカメラを自動認識・撮影します。同じ解像度のカメラであれば、接続数によって、プログラムを書き換える必要はありません。

# Basler acA2500-14um (USB3)   画像幅・高さ(1944X2592)

from pypylon import pylon
import cv2


# 撮影中チェック用
def CAMERA_IsGrabbing(CAMERA_ARY):
    chk_rslt = True  
    for CMR in CAMERA_ARY :
        if not CMR.IsGrabbing() :
            chk_rslt = False
    return chk_rslt

# 撮影停止
def CAMERA_StopGrabbing(CAMERA_ARY):
    for CMR in CAMERA_ARY :
        CMR.StopGrabbing()


tlFactory = pylon.TlFactory.GetInstance()
devices = tlFactory.EnumerateDevices()
cameras = pylon.InstantCameraArray(len(devices))

MDL_ARY = []
S_N_ARY = []
CMR_ARY = []

# 撮影開始
for i, cam in enumerate(cameras):
    # 下記 4行は参考。本プログラム機能上は不要。
    cam.Attach(tlFactory.CreateDevice(devices[i]))
    MDL_ARY.append(cam.GetDeviceInfo().GetModelName())      # GET DEVICE MODEL
    S_N_ARY.append(cam.GetDeviceInfo().GetSerialNumber())   # GET DEVICE Serial Number
    # print("No", i ," ,  Model: ", MDL_ARY[i] , "  ,  S/N: ", S_N_ARY[i])

    # 撮影開始
    CMR_ARY.append(pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateDevice(devices[i])))
    CMR_ARY[i].StartGrabbing(pylon.GrabStrategy_LatestImageOnly)                  

# 取得データコンバータ設定(opencv bgr format)
converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed
converter.OutputBitAlignment = pylon.OutputBitAlignment_MsbAligned

# 連続撮影
while CAMERA_IsGrabbing(CMR_ARY) :
    IMG_ARY = []
    # cnt_grab_success = 0

    # カメラ画像取得
    for idx in range(len(CMR_ARY)):
        IMG_ARY.append(None)

        tmp_Rslt = CMR_ARY[idx].RetrieveResult(5000, pylon.TimeoutHandling_ThrowException)

        if tmp_Rslt.GrabSucceeded():
            tmp_img = converter.Convert(tmp_Rslt)
            IMG_ARY[idx] = tmp_img.GetArray()
            # cnt_grab_success += 1
        
        tmp_Rslt.Release()

    # 画像マージ実行(全カメラ画像取得成功時)
    # 全画像高さが同じであること
    if len(CMR_ARY) == len(IMG_ARY) :
        for idx in range(len(IMG_ARY)):
            if idx == 0 :
                img_merged = IMG_ARY[idx]
            else :
                img_merged = cv2.hconcat([img_merged, IMG_ARY[idx]])

        cv2.namedWindow('img_merged', cv2.WINDOW_NORMAL)
        cv2.imshow('img_merged', img_merged)


    k = cv2.waitKey(1)
    if k == 27:
        break

CAMERA_StopGrabbing(CMR_ARY)        # デバイス解放
cv2.destroyAllWindows()

まとめ

 少し離れたところにある複数の7セグLED解析を1つのパソコンで行いたかったので、今回の検討をしています。
 また、同じ対象物でも異なる角度から複合的に解析することで、精度向上等に活用出来るかもしれません。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です