質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

受付中

範囲指定と一定サイズ以下の差分処理の書き方

mituo
mituo

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1回答

0評価

0クリップ

330閲覧

投稿2021/12/09 07:35

編集2022/01/12 10:55

前提・実現したいこと

テニスの動画を差分処理のみを用いて、ボールのトラッキングを行うプログラムを書いています。
プログラムを実行してみたところ動きはしたのですが、ノイズが多かったことと
差分処理のため選手の動きも出てしまうことが問題で改善したいと考えています。
そこで、
1.テニスコート内のものだけ差分処理を行う
2.テニスボールの大きさ以下のものだけ差分処理を行う
という2点の改善をしたいです。

該当のソースコード1

Python

import time import math import cv2 import sympy import numpy as np def isCourt(p):#ボール座標がコートの中にあるかを判定 from sympy.geometry import Point, Polygon poly = Polygon((520,178), (905,178), (1065,600), (360,600)) point=p return poly.encloses_point(point) def dilation(dilationSize,kernelSize,img):#膨張処理 kernel=np.ones((kernelSize,kernelSize),np.uint8) element=cv2.getStructuringElement(cv2.MORPH_RECT,(2*dilationSize+1,2*dilationSize+1),(dilationSize,dilationSize)) dilation_img = cv2.dilate(img,kernel,element) return dilation_img def detect(gray_diff):# retval, black_diff = cv2.threshold(gray_diff, 30, 255, cv2.THRESH_BINARY) img=black_diff dilation_img=dilation(18,20,img) img2=dilation_img.copy() img2=cv2.cvtColor(img2,cv2.COLOR_GRAY2RGB) contours, hierarchy = cv2.findContours(dilation_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) temp=[] p_array=[] area_array=[] ball_p=[] for i in range(len(contours)): count=len(contours[i]) temp.append(count) area = cv2.contourArea(contours[i])#面積計算 area_array.append(area) x=0.0 y=0.0 for j in range(count): x+=contours[i][j][0][0] y+=contours[i][j][0][1] x/=count y/=count x=int(x) y=int(y) p_array.append([x,y]) if(area<1000):#面積が一定以下 if(isCourt([x,y])):#コート内かどうか cv2.drawContours(img2,contours,i,(0,255,255),2)#黄 ball_p=[x,y] return img2,p_array,area_array,ball_p VIDEO_DATA = "Movie.mp4" ESC_KEY = 0x1b DURATION = 1.0 cv2.namedWindow("tennis") video = cv2.VideoCapture(VIDEO_DATA) fps = video.get(cv2.CAP_PROP_FPS) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) width = video.get(cv2.CAP_PROP_FRAME_WIDTH) # 形式はMP4Vを指定 fourcc = cv2.VideoWriter_fourcc(*'MJPG') # 出力先のファイルを開く out = cv2.VideoWriter('output.avi',fourcc,20.0, (int(width), int(height))) # 最初のフレームの読み込み end_flag, frame_next = video.read()#read() 1つ1つのフレームを読み込む height, width, channels = frame_next.shape motion_history = np.zeros((height, width), np.float32) frame_pre = frame_next.copy() p=[] a=[] ball=[] while(end_flag): #for i in range(150): color_diff = cv2.absdiff(frame_next, frame_pre)# フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY)# グレースケール変換 retval, black_diff = cv2.threshold(gray_diff, 100, 1, cv2.THRESH_BINARY)# 2値化 proc_time = time.time()# プロセッサ処理時間(sec)を取得 cv2.motempl.updateMotionHistory(black_diff, motion_history, proc_time, DURATION)# モーション履歴画像の更新 hist_color = np.array(np.clip((motion_history - (proc_time - DURATION)) / DURATION, 0, 1) * 255, np.uint8)# 古いモーションの表示を経過時間に応じて薄くする hist_gray = cv2.cvtColor(hist_color, cv2.COLOR_GRAY2BGR)# グレースケール変換 img,p_temp,a_temp,ball_temp=detect(gray_diff) #if(i>50): p.append(p_temp) a.append(a_temp) if(len(ball_temp)>0): ball.append(ball_temp) ball_array=np.array(ball) court_array=np.array([[520,178], [905,178], [1065,600], [360,600]]) service1_array=np.array([[440,250],[1000,250]]) service2_array=np.array([[380,420],[1050,420]]) service3_array=np.array([[712,250],[712,420]]) img=cv2.polylines(img,[ball_array],False,(0,255,255)) img=cv2.polylines(img,[court_array],True,(0,255,0)) img=cv2.polylines(img,[service1_array],True,(0,255,0)) img=cv2.polylines(img,[service2_array],True,(0,255,0)) img=cv2.polylines(img,[service3_array],True,(0,255,0)) cv2.imshow("tennis", img)# モーション画像を表示 out.write(img) if cv2.waitKey(20) == ESC_KEY:# Escキー押下で終了 break # 次のフレームの読み込み frame_pre = frame_next.copy() end_flag, frame_next = video.read() # 終了処理 cv2.destroyAllWindows() out.release() video.release()

該当のソースコード2

Python

import time import math import cv2 import sympy import numpy as np def isCourt(p):#ボール座標がコートの中にあるかを判定 from sympy.geometry import Point, Polygon poly = Polygon((520,178), (895,178), (1065,600), (360,600)) point=p return poly.encloses_point(point) def dilation(dilationSize,kernelSize,img):#膨張処理 kernel=np.ones((kernelSize,kernelSize),np.uint8) element=cv2.getStructuringElement(cv2.MORPH_RECT,(2*dilationSize+1,2*dilationSize+1),(dilationSize,dilationSize)) dilation_img = cv2.dilate(img,kernel,element) return dilation_img def detect(gray_diff):# retval, black_diff = cv2.threshold(gray_diff, 30, 255, cv2.THRESH_BINARY) img=black_diff dilation_img=dilation(18,20,img) img2=dilation_img.copy() img2=cv2.cvtColor(img2,cv2.COLOR_GRAY2RGB) contours, hierarchy = cv2.findContours(dilation_img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE,offset=(xmin,ymin)) temp=[] p_array=[] area_array=[] ball_p=[] for i in range(len(contours)): count=len(contours[i]) temp.append(count) area = cv2.contourArea(contours[i])#面積計算 area_array.append(area) x=0.0 y=0.0 for j in range(count): x+=contours[i][j][0][0] y+=contours[i][j][0][1] x/=count y/=count x=int(x) y=int(y) p_array.append([x,y]) if(area<1000):#面積が一定以下 if(isCourt([x,y])):#コート内かどうか cv2.drawContours(img2,contours,i,(0,255,255),2)#黄 ball_p=[x,y] return img2,p_array,area_array,ball_p xmin,xmax=360,1065 ymin,ymax=178,600 VIDEO_DATA = "Nishikori (錦織) VS Tsonga (ツォンガ).mp4" ESC_KEY = 0x1b DURATION = 1.0 cv2.namedWindow("motion") video = cv2.VideoCapture(VIDEO_DATA) fps = video.get(cv2.CAP_PROP_FPS) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) width = video.get(cv2.CAP_PROP_FRAME_WIDTH) fourcc = cv2.VideoWriter_fourcc(*'MJPG') out = cv2.VideoWriter('output.avi',fourcc,20.0, (int(width), int(height))) end_flag, frame_next = video.read()#read() 1つ1つのフレームを読み込む detframe=frame_next[ymin:ymax,xmin:xmax] height, width, channels = detframe.shape motion_history = np.zeros((height, width), np.float32) frame_pre = detframe.copy() p=[] a=[] ball=[] while(end_flag): color_diff = cv2.absdiff(detframe, frame_pre)# フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY)# グレースケール変換 retval, black_diff = cv2.threshold(gray_diff, 100, 1, cv2.THRESH_BINARY)# proc_time = time.time()# プロセッサ処理時間(sec)を取得 cv2.motempl.updateMotionHistory(black_diff, motion_history, proc_time, DURATION)# モーション履歴画像の更新 hist_color = np.array(np.clip((motion_history - (proc_time - DURATION)) / DURATION, 0, 1) * 255, np.uint8)# 古いモーションの表示を経過時間に応じて薄くする hist_gray = cv2.cvtColor(hist_color, cv2.COLOR_GRAY2BGR)# グレースケール変換 img,p_temp,a_temp,ball_temp=detect(gray_diff) p.append(p_temp) a.append(a_temp) if(len(ball_temp)>0): ball.append(ball_temp) ball_array=np.array(ball) court_array=np.array([[520,178], [895,178], [1065,600], [360,600]]) img = cv2.polylines(img,[ball_array],False,(0,255,255)) img=cv2.polylines(img,[court_array],True,(0,255,0)) cv2.imshow("motion", img)# モーション画像を表示 out.write(img) if cv2.waitKey(20) == ESC_KEY:# Escキー押下で終了 break frame_pre = detframe.copy() end_flag, frame_next = video.read() cv2.destroyAllWindows() out.release() video.release()

試したこと

ソースコード1では下記のような映像が表示されました。イメージ説明
ボールの軌道をトラッキングしたかったのですがノイズが多いためコート内のものだけを
差分処理しようと考え、ソースコード2のように修正しました。
ソースコード2では下記のような画像が表示されました。
イメージ説明
理想としてはコート内の差分処理をきれいに行った後、ボールのサイズ以下の
もののみの差分処理を行うことで、きれいにボールのトラッキングをしたいです。
お力添えの方よろしくお願い致します。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

tiitoi

2021/12/09 08:43

detframe=frame_next[ymin:ymax,xmin:xmax] がコードに見当たらないのですが、どこのことを指していますか?
mituo

2021/12/10 00:12

言葉が足らず申し訳ございません。 上のプログラムを""試したこと""のように書き換えた結果がうまく実行できなかったので、改善した ソースプログラムではなく改善前のソースプログラムを提示しました。 改善後のプログラムは74行目以降、下記の通りです。 end_flag, frame_next = video.read()#read() 1つ1つのフレームを読み込む detframe=frame_next[ymin:ymax,xmin:xmax] height, width, channels = detframe.shape motion_history = np.zeros((height, width), np.float32) frame_pre = detframe.copy() p=[] a=[] ball=[] while(end_flag): #for i in range(150): color_diff = cv2.absdiff(detframe, frame_pre)# フレーム間の差分計算 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY)# グレースケール変換 retval, black_diff = cv2.threshold(gray_diff, 100, 1, cv2.THRESH_BINARY)# 2値化 proc_time = time.time()# プロセッサ処理時間(sec)を取得 cv2.motempl.updateMotionHistory(black_diff, motion_history, proc_time, DURATION)# モーション履歴画像の更新 hist_color = np.array(np.clip((motion_history - (proc_time - DURATION)) / DURATION, 0, 1) * 255, np.uint8)# 古いモーションの表示を経過時間に応じて薄くする hist_gray = cv2.cvtColor(hist_color, cv2.COLOR_GRAY2BGR)# グレースケール変換 img,p_temp,a_temp,ball_temp=detect(gray_diff) #if(i>50): p.append(p_temp) a.append(a_temp) if(len(ball_temp)>0): ball.append(ball_temp) ball_array=np.array(ball) court_array=np.array([[520,178], [895,178], [1065,600], [360,600]]) img = cv2.polylines(img,[ball_array],False,(0,255,255)) img=cv2.polylines(img,[court_array],True,(0,255,0)) cv2.imshow("motion", img)# モーション画像を表示 out.write(img) if cv2.waitKey(20) == ESC_KEY:# Escキー押下で終了 break # 次のフレームの読み込み frame_pre = detframe.copy() end_flag, frame_next = video.read() # 終了処理 cv2.destroyAllWindows() out.release() video.release()
fana

2021/12/10 01:17

> しかし、実行結果は画面が小さくなっただけでした。 とはどういう意味か?(何が問題なのか?) あるサイズの映像のうちの一部のみを処理対象としたのであれば,その処理対象の大きさというのは当然ながら元の映像のサイズ以下となるであろうが,それが不満だという話か? (処理対象を変えたならば isCourt にハードコーディングされている座標値みたなのも修正すべきではないかと見えるが,それはそれとして.)
mituo

2021/12/10 02:02

求めている実行結果は観客も含めた全体の映像が表示された上でテニスコート内だけで差分処理が行われたものを表示したいと考えています。 しかし今の実行結果だとコートの左上の部分の画像だけがただ表示されるようになってしまいました。 プログラム初心者なためあまり理解してないままで修正してしまったため、うまく説明できなく 申し訳ございません。 isCourtにハードコーディングされている座標値の修正を行えば上記のような動作ができるのでしょうか? 詳しく修正方法をお聞きしたいです。 申し訳ございませんがよろしくお願いいたします。
tiitoi

2021/12/10 02:19

インデントが崩れてコードが読めないため、2つ目のコメントにあるコードを質問欄を編集して記載していただけますか? あと、質問欄に理想と現状こうなっているという2つの画像を貼っていただけますか? コードを見てもどのような画像に対して処理を行おうとしているのか不明のため、具体的なアドバイスは困難です。
mituo

2021/12/10 02:49

修正させていただきました。コードは読めますでしょうか? 説明が分かりにくかったら申し訳ございません。 よろしくお願い致します。
mituo

2021/12/10 03:10

何度も申し訳ございません。よろしくお願い致します。
fana

2021/12/10 03:12 編集

> しかし今の実行結果だとコートの左上の部分の画像だけが… まず,何をもって,現状が「コートの左上の部分」だと判断したのでしょう? …というところから突き詰めていく(疑ってちゃんと確認する)必要があるのではありませんか? 緑の線はあなたが勝手に固定の座標値を用いて描画しているだけのものなのですよね? 少なくとも提示された画像には他の(処理対象が元の映像のどこら辺になったのか?を判断できるような)情報があるようには見えません. (画像の一部を切り出したりしたならば,まずは単にそれを表示してみる,というところからやってますか?)

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。