エッジ検出による三角構図の検出をしようと考えていますがうまくいきません
[0, 0, 0, ... , 0, 0, 0, 1080.0, 1080.0, 1080.0, ... , 1080.0, 1080.0, 1080.0]
↑出力結果
前提
初心者ですのでわからない部分もありますが、ご容赦ください。
Pythonで山岳風景動画を入力後、(1フレームではなく)1秒ごとに切り取って全てを画像にした後、一枚一枚画像にエッジ検出をかけてその中から各画像ごとに三角構図を作り出すプログラムを書きたいです。
具体的な質問をする前にイメージを持ってもらいたいので検出方法を説明させてください。私の想定では上のようなエッジ検出された画像の中で、山の頂上(エッジの中で一番y軸が高いところとして判定)、画像一番左端にくるエッジの中で一番y軸が高いところ(画像で言えば大体 (0,320)くらいのところ)、画像一番右端にくるエッジの中で一番y軸が高いところ(画像で言えば大体 (1850,300)くらいのところ)、の三点を結んで三角形を作りたいです。
添付している画像は複数枚出力される結果のうち一番最初に出てきた画像です。
解決したいこと
出力にかける時間を減らすのと、きちんとしたy座標が描画されるようにするにはどこにどう修正を加えれば良いでしょうか?
下のコードで実行すると出力に大幅に時間がかかるほか、出力されたどの結果も各y座標がすべて同じような高さになってしまいます。
エラーはありませんが、実行結果がおかしいです。三角形を作るはずが一直線になってしまいました。エッジ検出は添付画像の通りうまく作動していると思います。
発生している問題・エラー
出力結果は添付画像とセットで上においています(処理が遅く、一枚目の結果のみになります)
...の部分は省略しました
該当するソースコード
from numpy.ma.core import sqrt
import cv2
import sys
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
class Vector2:
x = 0
y = 0
class Triangle:
ver = Vector2()
r = Vector2()
l = Vector2()
def dacor(yRec, x):
if abs(yRec[x] - yRec[x - 1]) > 200:
return True;
else:
return False;
def area(ver, lMax, rMax):
dl = sqrt(pow(ver.x - lMax.x , 2) + pow(ver.y - lMax.y , 2))
dr = sqrt(pow(ver.x - rMax.x , 2) + pow(ver.y - rMax.y , 2))
db = sqrt(pow(rMax.x - lMax.x , 2) + pow(rMax.y - lMax.y , 2))
s = 1 / 2 * (dl + db + dr)
st = sqrt(s * (s - dl) * (s - db) * (s - dr))
return st;
def saturation(pixel):
return (pixel.max() - pixel.min()) / pixel.max();
def middle(yRec):
for item in yRec:
if item > min(yRec) and item < max(yRec):
return item;
return 0;
def functionKOZUESC(frame, width, height, nowframe):
plt.imshow()
plt.show()
return 0;
def functionKOZU(frame, width, height, nowframe):
x = 0
y = 0
sum = 0
average = 0
flag = False
edgeFlag = False
yRec = [height] * int(width)
brack = 255
tri = Triangle()
while y < height:
while x < width :
sum += saturation(frame[y][x])
x += 1
y += 1
average = sum / (width * height)
if average < 30:
highTh = 400
lowTh = 50
else:
highTh = 530
lowTh = 200
img_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
edge_img = cv2.Canny(img_gray, highTh, lowTh)
flag = False
x = 0
y = 0
for x,i in enumerate(edge_img):
for y, j in enumerate(i):
if j == brack:
yRec[x] = y
flag = True
if x -1 >= 0:
if not flag:
yRec[x] = yRec[x - 1]
if dacor(yRec, x):
yRec[x] = yRec[x - 1]
else:
if not flag:
yRec[x] = middle(yRec)
flag = False
print(yRec)
x = 0
edgeFlag = False
rMax = Vector2()
lMax = Vector2()
ver = Vector2()
while x < width:
if yRec[x] == min(yRec):
ver.y = yRec[x]
ver.x = x
edgeFlag = True
if not edgeFlag:
if yRec[x] > rMax.y:
lMax.y = yRec[x]
lMax.x = x
else:
if yRec[x] > lMax.y:
rMax.y = yRec[x]
rMax.x = x
x += 1
plt.imshow(edge_img)
plt.show()
s = area(ver, lMax, rMax)
if s > 0:
tri.ver = ver
tri.r = rMax
tri.l = lMax
return tri
cap = cv2.VideoCapture('drive/MyDrive/サンプル動画/sample_video2.mp4')
if not (cap.isOpened()):
sys.exit('Can not Open VideoFile. Pleas Chack flie path.')
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS)
fcount = cap.get(cv2.CAP_PROP_FRAME_COUNT)
nowframe = 0
kozu = np.array([Triangle()])
while cap.get(cv2.CAP_PROP_POS_FRAMES) < fcount:
ret, frame = cap.read()
if not ret and cap.get(cv2.CAP_PROP_POS_FRAMES) <= fcount:
sys.exit('Error, Can Not Read Frame' + str(nowframe))
kozu = np.append(kozu ,functionKOZU(frame, width, height, nowframe))
nowframe += fps
cap.set(cv2.CAP_PROP_POS_FRAMES, nowframe)
#for item in kozu:
# print(item.ver.y)
# print(item.l.y)
# print(item.r.y)
自分で試したこと
for x,i in enumerate(edge_img):
for y, j in enumerate(i):
if j == brack:
yRec[x] = y
flag = True
if x -1 >= 0:
if not flag:
yRec[x] = yRec[x - 1]
if dacor(yRec, x):
yRec[x] = yRec[x - 1]
else:
if not flag:
yRec[x] = middle(yRec)
flag = False
この部分を
while x < width:
while y < height:
if not flag:
if edge_img[y][x] == brack:
yRec[x] = y
flag = True
y += 1
if x -1 >= 0:
if not flag:
yRec[x] = yRec[x - 1]
if dacor(yRec, x):
yRec[x] = yRec[x - 1]
else:
if not flag:
yRec[x] = middle(yRec)
x += 1
flag = False
に置き換えてやってみましたが、ループが終わらないなどうまくいきませんでした。