前提・実現したいこと
python3上で物体の画像抽出→大きさの計測を行うプログラムを作成しています。
使用:Jupyter Notebook
発生している問題・エラーメッセージ
ValueError Traceback (most recent call last) <ipython-input-7-b16976612a1a> in <module> 161 162 if __name__ == '__main__': --> 163 main() <ipython-input-7-b16976612a1a> in main() 128 # 直行を求める 129 ex = WidthScanner(rv1, mx, my) --> 130 spt, ept, dist = ex.getPoints(res) 131 cv2.line(res, (int(spt[0]), int(spt[1])), 132 (int(ept[0]), int(ept[1])), (255,0,0), 1, lineType=cv2.LINE_AA) <ipython-input-7-b16976612a1a> in getPoints(self, binimg) 16 17 def getPoints(self, binimg): ---> 18 h,w = binimg.shape 19 # 中央線より上をスキャン 20 x1 = 0 ValueError: too many values to unpack (expected 2)
#コード
import cv2 import math import numpy as np class WidthScanner: def __init__(self, coef, mx, my): self._imx = int(mx) self._imy = int(my) self.delta = -1 / coef[0] self.b = my - mx * self.delta def getX(self, y): x = (y - self.b) / self.delta return x def getPoints(self, binimg): h,w = binimg.shape # 中央線より上をスキャン x1 = 0 y1 = 0 for y in range(self._imy, 0, -1): x = int(self.getX(y)) if binimg[y,x] == 0: break else: x1 = x y1 = y # 中央線より下をスキャン x2 = 0 y2 = 0 for y in range(self._imy, h, 1): x = int(self.getX(y)) if binimg[y,x] == 0: break else: x2 = x y2 = y dist = math.sqrt((x1-x2)**2+(y1-y2)**2) return (x1,y1), (x2, y2), dist def main(): img = cv2.imread("test image/try3.bmp", cv2.IMREAD_COLOR) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) _, bw = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU) bw = cv2.bitwise_not(bw) # モルフォロジー変換 kernel5x5 = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) bw = cv2.morphologyEx(bw, cv2.MORPH_CLOSE, kernel5x5, iterations=2) target_lb_id = 1 # ラベリング nLabels, labelImages, data, center = cv2.connectedComponentsWithStats(bw) tobjx = data[target_lb_id, 0] tobjy = data[target_lb_id, 1] tobjw = data[target_lb_id, 2] tobjh = data[target_lb_id, 3] h, w = bw.shape[:2] btarget = np.zeros((h, w), np.uint8) btarget[labelImages == target_lb_id] = 255 img_mrg = cv2.merge((btarget,btarget,btarget)) res = cv2.bitwise_and(img,cv2.merge((btarget,btarget,btarget)) ) # 輪郭取得 contours, _ = cv2.findContours(btarget, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for i, cnt in enumerate(contours): cv2.drawContours(res,[cnt],0,(0,0,255),1) # 回帰計算 ypts, xpts = np.where(btarget == 255) rv = np.polyfit(xpts ,ypts, 3) expr = np.poly1d(rv) for x in range(tobjx, tobjx+tobjw): v = expr(x) res[int(v),x,:] = (255,255,0) # 曲線描画 # ターゲットオブジェクト認識領域描画 cv2.rectangle(res,(tobjx,tobjy),(tobjx+tobjw,tobjy+tobjh),(0,255,255),1) cv2.imshow('res', res) cv2.imshow('bw', bw) cv2.imshow('btarget', btarget) cv2.waitKey(0) cv2.destroyAllWindows() # 枠を描画 cv2.rectangle(res,(tobjx,tobjy),(tobjx+tobjw,tobjy+tobjh),(0,255,255),1) cv2.imshow('t', cv2.rectangle(res,(tobjx,tobjy),(tobjx+tobjw,tobjy+tobjh),(0,255,255),1)) cv2.waitKey(0) cv2.destroyAllWindows() # for x in range(tobjx, tobjx+tobjw): # v = expr(x) # res[int(v),x,:] = (255,255,0) # 幅を測る offsetx = 10;incx = 16;lbno = 1 cary = np.zeros((incx,), np.float32) carx = np.zeros((incx,), np.float32) for sx in range(tobjx+incx, tobjx+tobjw-incx, incx): cary = np.zeros((incx,), np.uint8) for x in range(sx, sx+incx): vy = expr(x) carx[sx-x] = x cary[sx-x] = vy rv1 = np.polyfit(carx ,cary,1) expr1 = np.poly1d(rv1) # スキャンセグメントの中間座標 mx = sx + incx // 2 my = expr(mx) # 直行を求める ex = WidthScanner(rv1, mx, my) spt, ept, dist = ex.getPoints(res) cv2.line(res, (int(spt[0]), int(spt[1])), (int(ept[0]), int(ept[1])), (255,0,0), 1, lineType=cv2.LINE_AA) cv2.putText(res, str(lbno), (int(spt[0]-6), int(spt[1])-8), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0,255,255), 1,cv2.LINE_AA) print('%2d.直径 %.2f' % (lbno, dist)) lbno += 1 # 長さを測る total_len = 0 vy = expr(x) scan_flag = False by = 0 for x in range(tobjx, tobjx+tobjw): if scan_flag == False : bx = x by = vy elif scan_flag == True : if res[int(vy), x] == 255: sdist = math.sqrt((bx - x)** 2 + (by - vy) ** 2) total_len += sdist cv2.line(res, (int(x), int(vy)), (int(bx), int(by)), (255,0,255), 2, lineType=cv2.LINE_AA) bx = x by = vy else: break print('トータル長(pixel)=%.2f' %(total_len)) if __name__ == '__main__': main()
補足情報
https://emotionexplorer.blog.fc2.com/blog-entry-267.html?sp
こちらをベースにコードを書いています。
必要がなさそうな部分、エラーが出る部分をかなり削ったり書き換えたりしてます。
使用画像は白背景に黒の楕円を描いたものです。
「res」はカラーなのに、「ex.getPoints(res)」でそれを処理する「getPoints()」はグレースケールを前提として書かれてるので、矛盾が起きてます
h,w = binimg.shape
のすぐ上に
print(binimg.shape)
を追加して実行したら、現状出てるエラーの原因が分かると思います
それを直しても、別のエラーが出ます
if binimg[y,x] == 0:
のすぐ上に
print(binimg[y,x])
を追加して実行してみてください
# 直行を求める
以下のresをbw(2値画像)に変更したところ無事にプログラムが動きました。
ありがとうございます。
#長さを測る の部分については値が0になりましたが確認したところ参考元から必要な部分を削りすぎていたようです。
また、コードの参考元も同様に変更したところ無事動きましたので重ねてお礼申し上げます。