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

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

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

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

3526閲覧

OpenCV重心の描画について

mosu

総合スコア15

OpenCV

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

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/02/21 14:50

編集2019/02/22 03:54

エラーが起きた時の二値画像です。
エラー時のframe画像
opencv,pythonにおいて、検知物に対して重心を求めそれを描画したいのですがエラーメッセージが表示され描画することができません。どのようにしたらよいでしょうか。
エラーメッセージ:
ZeroDivisionError Traceback (most recent call last)
<ipython-input-1-588636b314e4> in <module>()
49 maxCont=c
50 mu = cv2.moments(cnt)
---> 51 z,w= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"])
52 cv2.circle(frame, (z,w), 4, (0,0,255),3 )
53

ZeroDivisionError: float division by zero

python

1 import numpy as np 2import cv2 3import sys 4 5 6 7 8bodycascade = cv2.CascadeClassifier(r'C:\Users\Gen\Desktop\bodycascades.xml') 9#2動画のパス、ウェブカメラを使用する際は引数を0、別のカメラを使うなら1にする。 10path=(r"Pro.mp4") 11cv2.ocl.setUseOpenCL(False) 12 13 14#3パス先の動画を格納、1で0を指定したのならウェブカメラからの映像を格納 15cap = cv2.VideoCapture(path) 16#4背景差分処理を行う関数 (history,閾値(どの程度の変化までを読み込むか)、影の描画の有無(Falseはなし)) 17fgbg = cv2.createBackgroundSubtractorMOG2(5000,100,False) 18 19#5cap(動画読み込み)が行われている間以下の処理を行う 20while (cap.isOpened): 21 22 #6retがTrue(きちんと動画が読み込まれている)なら動画を読み込む 23 ret, frame = cap.read() 24 25#7retがTrueなら 26 if ret==True: 27 gray=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) 28 29 #84を読み込んだ映像に適用 30 fgmask = fgbg.apply(frame) 31 #9ガウシアンぼかしを使うことで白ゴマ(ノイズを除去) 32 blur=cv2.GaussianBlur(fgmask,(15,15),0) 33 (im2, contours, hierarchy) = cv2.findContours(fgmask.copy(), cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 34 cnt = contours[0] 35 36 37 #11:輪郭を抽出したらそれを処理し続ける 38 for c in contours: 39 #12:輪郭の大きさが13000以下ははじく 40 if cv2.contourArea(c) < 13000: 41 continue 42 #13:輪郭から矩形を作る 43 (x, y, w, h) = cv2.boundingRect(c) 44 #14:矩形を描画 45 rect=cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) 46 max_area=[] 47 area=cv2.contourArea(c) 48 max_area.append(area) 49 print(area) 50 cnt = contours[0] 51 for c in contours: 52 if len(cnt)<len(c): 53 maxCont=c 54 mu = cv2.moments(cnt) 55 z,w= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"]) 56 print(mu,cnt) 57 cv2.circle(frame, (z,w), 4, (0,0,255),3 ) 58 59 60 61 #15:AIを導入 62 #bodyrect = bodycascade.detectMultiScale(frame, scaleFactor=1.2, minNeighbors=2, minSize=(5,5)) 63 #for rect in bodyrect: 64 #text = 'person' 65 #font = cv2.FONT_HERSHEY_PLAIN 66 #16:人を検知したらpersonと表示する。 67 #cv2.putText(frame,text,(rect[0],rect[1]-10),font, 2, (255, 255, 255), 2, cv2.LINE_AA) 68 #cv2.line(frame,(0,531),(1300,560),(255,0,0),2) 69 #17:結果を表示 70 cv2.imshow('foreground and background',fgmask) 71 cv2.imshow('rgb',frame) 72 if cv2.waitKey(1) & 0xFF == ord("q"): 73 break 74 75 76 77cap.release() 78cv2.destroyAllWindows() 79

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tiitoi

2019/02/21 15:02 編集

> ZeroDivisionError: float division by zero エラーの通り、0除算が起きてるものと思われます。 print(mu, cnt) とするとどうなっていますか?
mosu

2019/02/21 15:04

毎度ありがとうございます。 このような結果になりました。 919601.0 {'m00': 919601.0, 'm10': 588084839.5, 'm01': 330596559.5, 'm20': 501440339813.6666, 'm11': 211416499800.25, 'm02': 158465950853.66666, 'm30': 481006645966259.8, 'm21': 180267802163013.16, 'm12': 101338975570919.83, 'm03': 85452763997839.75, 'mu20': 125360084953.41663, 'mu11': 0.0, 'mu02': 39616487713.41666, 'mu30': 0.125, 'mu21': 0.0078125, 'mu12': 0.0, 'mu03': 0.015625, 'nu20': 0.1482382939267501, 'nu11': 0.0, 'nu02': 0.04684649465728433, 'nu30': 1.5413860559627908e-16, 'nu21': 9.633662849767443e-18, 'nu12': 0.0, 'nu03': 1.9267325699534885e-17} 13423.0 {'m00': 2.0, 'm10': 67.5, 'm01': 864.0, 'm20': 2278.5, 'm11': 29159.666666666664, 'm02': 373248.6666666666, 'm30': 76924.75, 'm21': 984289.4166666666, 'm12': 12596854.583333334, 'm03': 161244000.0, 'mu20': 0.375, 'mu11': -0.33333333333575865, 'mu02': 0.6666666666278616, 'mu30': 0.0625, 'mu21': -0.08333333325572312, 'mu12': 0.08333333712653257, 'mu03': 5.960464477539063e-08, 'nu20': 0.09375, 'nu11': -0.08333333333393966, 'nu02': 0.1666666666569654, 'nu30': 0.011048543456039806, 'nu21': -0.014731391261000064, 'nu12': 0.014731391945268967, 'nu03': 1.0536712127723509e-08} 14613.0 --------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-1-85eed41cb708> in <module>() 49 maxCont=c 50 mu = cv2.moments(cnt) ---> 51 z,w= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"]) 52 print(mu) 53 #cv2.circle(frame, (z,w), 4, (0,0,255),3 ) ZeroDivisionError: float division by zero
mosu

2019/02/21 15:09

すみません、こちらです。 919601.0 {'m00': 919601.0, 'm10': 588084839.5, 'm01': 330596559.5, 'm20': 501440339813.6666, 'm11': 211416499800.25, 'm02': 158465950853.66666, 'm30': 481006645966259.8, 'm21': 180267802163013.16, 'm12': 101338975570919.83, 'm03': 85452763997839.75, 'mu20': 125360084953.41663, 'mu11': 0.0, 'mu02': 39616487713.41666, 'mu30': 0.125, 'mu21': 0.0078125, 'mu12': 0.0, 'mu03': 0.015625, 'nu20': 0.1482382939267501, 'nu11': 0.0, 'nu02': 0.04684649465728433, 'nu30': 1.5413860559627908e-16, 'nu21': 9.633662849767443e-18, 'nu12': 0.0, 'nu03': 1.9267325699534885e-17} [[[ 0 0]] [[ 0 719]] [[1279 719]] [[1279 0]]] 13423.0 {'m00': 2.0, 'm10': 67.5, 'm01': 864.0, 'm20': 2278.5, 'm11': 29159.666666666664, 'm02': 373248.6666666666, 'm30': 76924.75, 'm21': 984289.4166666666, 'm12': 12596854.583333334, 'm03': 161244000.0, 'mu20': 0.375, 'mu11': -0.33333333333575865, 'mu02': 0.6666666666278616, 'mu30': 0.0625, 'mu21': -0.08333333325572312, 'mu12': 0.08333333712653257, 'mu03': 5.960464477539063e-08, 'nu20': 0.09375, 'nu11': -0.08333333333393966, 'nu02': 0.1666666666569654, 'nu30': 0.011048543456039806, 'nu21': -0.014731391261000064, 'nu12': 0.014731391945268967, 'nu03': 1.0536712127723509e-08} [[[ 34 431]] [[ 33 432]] [[ 33 433]] [[ 34 433]] [[ 34 432]] [[ 35 431]] [[ 38 431]]] 14613.0 --------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-2-dd6e3b70b779> in <module>() 49 maxCont=c 50 mu = cv2.moments(cnt) ---> 51 z,w= int(mu["m10"]/mu["m00"]) , int(mu["m01"]/mu["m00"]) 52 print(mu,cnt) 53 #cv2.circle(frame, (z,w), 4, (0,0,255),3 ) ZeroDivisionError: float division by zero
guest

回答1

0

ベストアンサー

正しい輪郭が選択できていないのではないでしょうか?
cv2.drawContours でモーメントを計算している cnt が、意図した輪郭か確認してみてください。

検出された輪郭のうち、一番大きい輪郭の重心を計算するサンプル。

python

1import cv2 2 3# 画像を読み込む。 4img = cv2.imread('test.png') 5 6# 輪郭を抽出する。 7gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 8# OpenCV 3系なら返り値3つ 9# _, contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 10contours, hierarchy = cv2.findContours(gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 11 12# 一番大きい輪郭を選択する。 13max_cnt = max(contours, key=lambda x: cv2.contourArea(x)) 14 15# 重心 16M = cv2.moments(max_cnt) 17cx = int(M["m10"] / M["m00"]) 18cy = int(M["m01"] / M["m00"])

追記

python

1import cv2 2import matplotlib.pyplot as plt 3from matplotlib.patches import Polygon 4 5img = cv2.imread('test.jpeg') 6gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 7 8# 輪郭抽出する。 9_, contours, hierarchy = cv2.findContours( 10 gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) 11 12# 面積が一定以上の輪郭だけ抽出 13contours = list(filter(lambda x: cv2.contourArea(x) > 500, contours)) 14 15# 重心と外接矩形を計算する。 16def get_centroid(cnt): 17 M = cv2.moments(cnt) 18 return int(M['m10'] / M['m00']), int(M['m01'] / M['m00']) 19 20rects = [cv2.boundingRect(x) for x in contours] 21centers = [get_centroid(x) for x in contours] 22 23# 重心と外接矩形を描画する。 24for [x, y, w, h], [cx, cy] in zip(rects, centers): 25 cv2.rectangle(img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2) 26 cv2.circle(img, (cx, cy), radius=2, color=(0, 255, 0), thickness=-1) 27 28cv2.imwrite('output.png', img)

イメージ説明

投稿2019/02/21 15:24

編集2019/02/22 05:00
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mosu

2019/02/22 02:44

選択した輪郭は正しいようですが、再びfloat division by zeroと表示されました。 全体のプログラムを乗せたほうがよいでしょうか。 contourの重心ではなく、boundingrect()で取得した最小矩形の中心(高さ/2、幅/2)の位置に点を表示させ続けることは可能でしょうか。
tiitoi

2019/02/22 03:31 編集

エラーが出たときの2値画像をimwriteで保存して、貼っていただければ検証しますが、それがないと原因について言及するのは難しいです
mosu

2019/02/22 03:55

わかりました。 ありがとうございます。 質問を更新しました。
tiitoi

2019/02/22 05:02

提示された2値画像で試しましたが、2値化結果がもう少しきれいにできないと輪郭抽出がうまくできていないようで、画像のようになりました。 ただ、零割が起こるという現象は確認できませんでした。
tiitoi

2019/02/22 05:12

> boundingrect()で取得した最小矩形の中心(高さ/2、幅/2)の位置に点を表示させ続けることは可能でしょうか。 これは可能です。重心にこだわりがないのであれば、こちらのほうが簡単です。
mosu

2019/02/22 05:31

ありがとうございます。 動画上では連続的に二値化結果が表示されているためfindContour()関数の第一引数を大きくすれば輪郭抽出は問題ないと思われます。 最小矩形の中心を表示する際は、零割の問題は起こらないですよね。 具体的にどのようなプログラムで実現できるでしょうか。 頼りっぱなしで申し訳ないです。
tiitoi

2019/02/22 05:35

長方形の中心でよいのであれば、以下でどうでしょうか x, y, w, h = cv2.boundingRect(x) cx, cy = x + w / 2, y + h / 2
mosu

2019/02/22 06:34

rect=cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) の下に、 for x in rect: x, y, w, h = cv2.boundingRect(x) cx, cy = x + w / 2, y + h / 2 rect2=cv2.rectangle(frame,(cx,cy),(x+w,y+h),(0,0,255),3) これを挿入するということで大丈夫ですか。
tiitoi

2019/02/22 06:39

中心点と長方形は別々に描画する必要があるかと。 # 長方形の描画 x, y, w, h = cv2.boundingRect(x) cv2.rectangle(img, (x, y), (x + w, y + h), color=(0, 255, 0), thickness=2) # 中心点の描画 cx, cy = x + w / 2, y + h / 2 cv2.circle(img, (cx, cy), radius=2, color=(0, 255, 0), thickness=-1)
mosu

2019/02/22 07:00

ありがとうございます。 そのプログラムを挿入したところ以下のエラーが起きたのですが、cx,cyが浮動小数点がたになっているためこのエラーが起きているのでしょうか。 TypeError Traceback (most recent call last) <ipython-input-11-35b48d28457c> in <module>() 57 #cv2.circle(frame, (z,w), 4, (0,0,255),3 ) 58 cx, cy = x + w / 2, y + h / 2 ---> 59 cv2.circle(frame, (cx, cy), radius=2, color=(0, 255, 0), thickness=3) 60 61 TypeError: integer argument expected, got float
tiitoi

2019/02/22 07:12

すいません。int にキャストしてあげてください cx, cy = int(x + w / 2), int(y + h / 2)
mosu

2019/02/22 07:27

できました。 本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問