色情報をヒストグラムにするために、OpenCV の cv2.calcHist が便利だった。第一引数に画像情報を渡し、ヒストグラムにすることができる。
このヒストグラムを表示するために、 np.empty((256, 256, 3), np.uint8) のように表示領域を作り、 cv2.line で線を引いた。また、 HSV 空間でのH(色相)と数値の対応を覚えていないので、hsvcol という関数を定義し、 cv2.line で引く線の色を設定した。
出力したヒストグラムつき動画
右端に4つのヒストグラムを連結した。ヒストグラムは上から順に、RGB、H(色相)、S(彩度)、V(明るさ)の分布を示している。
ヒストグラムを作成するコード
import cv2
import sys
import numpy as np
import moviepy.editor as mp
# 画像を加工する
def mkimg(img):
resized_his = cv2.resize(mkhispic(img),(256,height))
cv2.imshow("Frameaa", resized_his)
return cv2.hconcat([img,resized_his])
# ヒストグラム用
c_rgb = np.empty((256, 256, 3), np.uint8)
color = ((255, 0, 0), (0, 255, 0), (0, 0, 255))
c_hsv = np.empty((3, 256, 256, 3), np.uint8)
# ヒストグラム描画
def mkhispic(img):
hsvframe = cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
c_rgb.fill(255)
c_hsv.fill(255)
for channel in range(3):
# ヒストグラムを計算
h_rgb = cv2.calcHist([frame], [channel], None, [256], [0, 256])
h_hsv = cv2.calcHist([hsvframe], [channel], None, [256], [0, 256])
# 折れ線の開始位置(左下)
prev_xy_rgb = (0, 255)
for x in range(256):
# 座標を取得し、線を引く
current_xy_rgb = (x, 255 - int(h_rgb [x] / 1000))
current_xy_hsv = (x, 255 - int(h_hsv [x] / 1000))
cv2.line(c_rgb, prev_xy_rgb, current_xy_rgb, color[channel])
cv2.line(c_hsv[channel], (x, 255), current_xy_hsv, hsvcol(channel, x))
# 現在座標を前座標に保存
prev_xy_rgb = current_xy_rgb
# ヒストグラムにタイトルをつける
cv2.putText(c_rgb, "RGB", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1, 4)
cv2.putText(c_hsv[0], "H", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1, 4)
cv2.putText(c_hsv[1], "S", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1, 4)
cv2.putText(c_hsv[2], "V", (10, 30), cv2.FONT_HERSHEY_PLAIN, 1, (0, 0, 0), 1, 4)
return cv2.vconcat([c_rgb, c_hsv[0], c_hsv[1], c_hsv[2]])
# hsvの状況を色で表現
def hsvcol(channel,v):
if channel == 0:
a = cv2.cvtColor(np.uint8([[[v, 255, 255]]]),cv2.COLOR_HSV2BGR)[0, 0, :]
elif channel == 1:
a = cv2.cvtColor(np.uint8([[[0, v, 255]]]),cv2.COLOR_HSV2BGR)[0, 0, :]
elif channel == 2:
a = cv2.cvtColor(np.uint8([[[0, 0, v]]]),cv2.COLOR_HSV2BGR)[0, 0, :]
return (int(a[0]), int(a[1]), int(a[2]))
# 動画関連 -------------------------------------------------------------
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 + 256, 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("Frame", frame)
cv2.imshow("newf", write_frame)
cv2.moveWindow("newf",3700,0)
# qキーが押されたら途中終了
if cv2.waitKey(25) & 0xFF == ord('q'):
break
writer.release()
video.release()
cv2.destroyAllWindows()
# 最後に音をつける
set_audio(srcfile,imgfile,outfile)
コメント