OpenCV で画像のサイズを変更して連結する

OpenCV で画像のサイズを変更するには、 cv2.resize(元画像, dsize=(幅, 高さ)) とすれば良い。連結するには、 cv2.vconcat() と cv2.hconcat() を使うが、 concat_tile 関数を定義して、画像の2次元リストを渡して処理をした。

ちなみに画像のトリミングは、 img[ymin:ymax, xmin:xmax] と、OpenCV を使わずにできる。

作成した動画

今回、トビを追尾し拡大する過程(トビを判定するマスクを作成し、重心を算出、切り取り)を1画面に連結した。左上が元画像。右上がターゲットの重心算出用のマスク画像。左下が拡大範囲。右下が拡大画像。

cv2.resize でサイズを整え、concat_tile 関数を定義して連結した。

コード

import cv2
import sys
import numpy as np
import moviepy.editor as mp

# 画像を加工する                                                                                                                  
def mkimg(img):
    # トリミング画像を作る                                                                                                        

    # マスクから、目標画像の中心(x, y)を算出                                                                                      
    mask, maskGray = mkmask(img,0,255,0,255,0,100)
    mu = cv2.moments(maskGray,False)
    x, y= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"])

    # トリミングの範囲を作る                                                                                                      
    trim_width = int(width / 3)
    trim_height = int(height / 3)

    # 左上の座標 重心からのズレを設定                                                                                            
    xmin, ymin = x - int(trim_width/2), y - int(trim_height/2)

    # トリミングの範囲が画像外にならないように調整                                                                                
    xmin, ymin = min(max(0, xmin), width - trim_width), min(max(0, ymin), height - trim_height)

    # 右下を設定し、トリミング後の画像を作成                                                                                      
    xmax, ymax = xmin + trim_width, ymin + trim_height
    trim_img = img[ymin:ymax, xmin:xmax]

    # レクタングルつき画像を作成                                                                                                  
    img_rec = img.copy()
    cv2.rectangle(img_rec, (xmin, ymin),(xmax, ymax),(0, 0, 255),3)

    # 作成過程の画像をそれぞれリサイズする                                                                                        
    hwidth = int(width/2)
    hheight = int(height/2)
    img_r1c1 = cv2.resize(img, dsize=(hwidth, hheight))
    img_r1c2 = cv2.resize(mask, dsize=(hwidth, hheight))
    img_r2c1 = cv2.resize(img_rec, dsize=(hwidth, hheight))
    img_r2c2 = cv2.resize(trim_img, dsize=(hwidth, hheight))

    # 画像を連結                                                                                                                  
    img_tile = concat_tile([[img_r1c1, img_r1c2],
                            [img_r2c1, img_r2c2]])
    return img_tile

# cv2.vconcat()とcv2.hconcat()を組み合わせて、画像を縦・横にタイル状に連結                                                        
# https://note.nkmk.me/python-opencv-hconcat-vconcat-np-tile/                                                                     
def concat_tile(im_list_2d):
    return cv2.vconcat([cv2.hconcat(im_list_h) for im_list_h in im_list_2d])

# HSV情報からmaskを作成                                                                                                           
def mkmask(img,hmin,hmax,smin,smax,vmin,vmax):
    h,s,v = np.float32(cv2.split(cv2.cvtColor(img,cv2.COLOR_BGR2HSV)))  # 色空間をBGRからHSVに変換                                
    mask = (cv2.inRange(h,hmin,hmax)/255) \
         * (cv2.inRange(s,smin,smax)/255) \
         *  cv2.inRange(v,vmin,vmax)
    return cv2.cvtColor(ct(mask), cv2.COLOR_GRAY2BGR), mask

# 値を0-255にclipして、typeをuint8にする                                                                                          
def ct(img):
    return np.clip(img,0,255).astype(np.uint8)

# 動画関連 -------------------------------------------------------------                                                          
def set_audio(srcfile,imgfile,outfile):
    # Extract audio from input video.                                                                                             
    clip_input = mp.VideoFileClip(srcfile)
    clip_input.audio.write_audiofile('audio.mp3')
    # Add audio to output video.                                                                                                  
    clip = mp.VideoFileClip(imgfile).subclip()
    clip.write_videofile(outfile, audio='audio.mp3')

# 動画のファイル名 設定                                                                                                          
srcfile = sys.argv[1]
imgfile = "out.mp4"
outfile = sys.argv[1].replace(".mp4","out.mp4").replace(".MP4","out.MP4")
video = cv2.VideoCapture(srcfile)

# 幅と高さを取得                                                                                                                  
width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
size  = (width, height)

# 総フレーム数/フレームレートを取得                                                                                               
frame_count = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
frame_rate = int(video.get(cv2.CAP_PROP_FPS))

# 保存用                                                                                                                          
fmt = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
writer = cv2.VideoWriter(imgfile, fmt, frame_rate, size)

for i in range(frame_count):
    ret, frame = video.read()
    write_frame = mkimg(frame)
    writer.write(write_frame)

    cv2.imshow("newf", write_frame)

    # qキーが押されたら途中終了                                                                                                   
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

writer.release()
video.release()
cv2.destroyAllWindows()

# 最後に音をつける                                                                                                                
set_audio(srcfile,imgfile,outfile)

コメント

タイトルとURLをコピーしました