###やりたいこと
決められた範囲だけを背景差分法で動体物(テニスボール)を検出したい
質問内容
自分で決めた範囲だけを処理するにはどうすればいいですか?
現状
マウスで範囲を選択してボール検出(ボール以外も検出していますが...)ができるプログラムを作成しました。
しかし、マウスで選択した範囲だけ処理するというのができなかったため、自分で検出したい範囲(座標)を決めて、
その範囲だけを処理するプログラムに変更することにしました。そこで、処理する範囲をどのようなコードで決めて
処理をすればいいか分からない状態です。
※作成したプログラムは下記に載せておきます。
プログラム
Python
1# -*- coding: utf-8 -*- 2 3import numpy as np 4 5import cv2 6 7from time import time 8 9import subprocess 10 11 12 13VIDEO_DATE = "tennis.AVI" 14 15WINDOW_NAME = "MouseEvent" 16 17 18 19def dilation(dilationSize, kernelSize, img): # 膨張した画像にして返す 20 21 kernel = np.ones((kernelSize, kernelSize), np.uint8) 22 23 element = cv2.getStructuringElement(cv2.MORPH_RECT, (2 * dilationSize + 1, 2 * dilationSize + 1), (dilationSize, dilationSize)) 24 25 dilation_img = cv2.dilate(img, kernel, element) 26 27 return dilation_img 28 29 30 31 32def detect(gray_diff, thresh_diff=95, dilationSize=9, kernelSize=20): # 一定面積以上の物体を検出 33 34 retval, black_diff = cv2.threshold(gray_diff, thresh_diff, 255, cv2.THRESH_BINARY) # 2値化 35 36 dilation_img = dilation(dilationSize, kernelSize, black_diff) # 膨張処理 37 38 img = dilation_img.copy() 39 40 image, contours, hierarchy = cv2.findContours(dilation_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 境界線検出 41 42 43 44 ball_pos = [] 45 46 47 48 for i in range(len(contours)): # 重心位置を計算 49 50 count = len(contours[i]) 51 52 53 area = cv2.contourArea(contours[i]) # 面積計算 54 55 x, y = 0.0, 0.0 56 57 for j in range(count): 58 59 x += contours[i][j][0][0] 60 61 y += contours[i][j][0][1] 62 63 64 65 66 x /= count 67 68 y /= count 69 70 x = int(x) 71 72 y = int(y) 73 74 ball_pos.append([x, y]) 75 76 77 return ball_pos, img 78 79 80 81 82def displayCircle(image, ballList, thickness=5): 83 84 for i in range(len(ballList)): 85 86 x = int(ballList[i][0]) 87 88 y = int(ballList[i][1]) 89 90 cv2.circle(image, (x, y), 10, (0, 0, 255), thickness) 91 92 return image 93 94 95 96 97def resizeImage(image, w=2, h=2): 98 99 height = image.shape[0] 100 101 width = image.shape[1] 102 103 resizedImage = cv2.resize(image, (int(width / w), int(height / h))) 104 105 return resizedImage 106 107 108 109 110def blackToColor(bImage): 111 112 colorImage = np.array((bImage, bImage, bImage)) 113 114 colorImage = colorImage.transpose(1, 2, 0) 115 116 return colorImage 117 118 119 120class PointList(): 121 122 def __init__(self, npoints): 123 124 self.video = cv2.VideoCapture(VIDEO_DATE) 125 126 self.frame = None 127 128 self.npoints = npoints 129 130 self.ptlist = np.empty((npoints, 2), dtype=int) 131 132 self.pos = 0 133 134 cv2.setMouseCallback(WINDOW_NAME, self.onMouse) 135 136 137 138 def add(self, x, y): 139 140 if self.pos < self.npoints: 141 142 self.ptlist[self.pos, :] = [x, y] 143 144 self.pos += 1 145 146 return True 147 148 return False 149 150 151 152 def run(self): 153 154 ok, self.frame = self.video.read() # 最初のフレームを読み込む 155 156 if not ok: 157 158 print('Cannot read video file') 159 160 sys.exit() 161 162 self.frame_pre = self.frame.copy() 163 164 165 166 while True: 167 168 ok, self.frame = self.video.read() # フレームを読み込む 169 170 if not ok: 171 172 break 173 174 self.frame_next = self.frame.copy() 175 176 177 178 if(self.pos == self.npoints): 179 180 cv2.line(self.frame, (self.ptlist[0][0], self.ptlist[0][1]), 181 182 (self.ptlist[1][0], self.ptlist[1][1]), (0, 255, 0), 3) 183 184 cv2.line(self.frame, (self.ptlist[1][0], self.ptlist[1][1]), 185 186 (self.ptlist[2][0], self.ptlist[2][1]), (0, 255, 0), 3) 187 188 cv2.line(self.frame, (self.ptlist[2][0], self.ptlist[2][1]), 189 190 (self.ptlist[3][0], self.ptlist[3][1]), (0, 255, 0), 3) 191 192 cv2.line(self.frame, (self.ptlist[3][0], self.ptlist[3][1]), 193 194 (self.ptlist[0][0], self.ptlist[0][1]), (0, 255, 0), 3) 195 196 color_diff = cv2.absdiff(self.frame_next, self.frame_pre) # フレーム間の差分計算 197 198 gray_diff = cv2.cvtColor(color_diff, cv2.COLOR_BGR2GRAY) # グレースケール変換 199 200 retval, black_diff = cv2.threshold(gray_diff,30, 255, cv2.THRESH_BINARY) 201 202 203 204 ball, dilation_img = detect(gray_diff) 205 206 207 208 self.frame = displayCircle(self.frame, ball, 2) # 丸で加工 209 210 cImage = blackToColor(dilation_img) # 2値化画像をカラーの配列サイズと同じにする 211 212 213 214 self.frame_pre = self.frame_next.copy() # 次のフレームの読み込み 215 216 217 218 cv2.imshow(WINDOW_NAME, self.frame) 219 220 if cv2.waitKey(10) ==27: # Escキーで抜ける 221 222 break 223 224 225 226 def onMouse(self,event, x, y, flag, params): 227 228 if event == cv2.EVENT_MOUSEMOVE: # マウスが移動したときにx線とy線を更新する 229 230 self.frame2 = np.copy(self.frame) 231 232 h, w = self.frame2.shape[0], self.frame2.shape[1] 233 234 cv2.line(self.frame2, (x, 0), (x, h - 1), (255, 0, 0)) 235 236 cv2.line(self.frame2, (0, y), (w - 1, y), (255, 0, 0)) 237 238 cv2.imshow(WINDOW_NAME, self.frame2) 239 240 241 242 if event == cv2.EVENT_LBUTTONDOWN: # レフトボタンをクリックしたとき、ptlist配列にx,y座標を格納する 243 244 if self.add(x, y): 245 246 print('[%d] ( %d, %d )' % (ptlist.pos - 1, x, y)) 247 248 cv2.circle(self.frame, (x, y), 3, (0, 0, 255), 3) 249 250 cv2.imshow(WINDOW_NAME, self.frame) 251 252 else: 253 254 print('All points have selected. Press ESC-key.') 255 256 257 258if __name__ == '__main__': 259 260 cv2.namedWindow(WINDOW_NAME) 261 262 npoints = 4 263 264 ptlist = PointList(npoints) 265 266 ptlist.run() 267 268 cv2.destroyAllWindows()

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/10/10 21:42 編集