#はじめに
今回は、前回記事二領域間の最短距離を求めるプログラムについて、修正を行った内容です。
前回は、画像サイズをそのまま処理していたことと、必ずしも二領域間の最短距離を求めることができていなかった課題がありました。
画像を二値化処理させる。さらに、二領域間の最短距離を算出できるようにした。
https://qiita.com/Fumio-eisan/items/05a6506da8cc88d89e49
要点は下記です。
- 画像を小さくして処理しやすくする
- 任意の領域を二値化させる
- 領域間の距離を求め、そこから最短距離を求める
##画像を小さくして処理しやすくする
今回はこちらの焼肉画像を用いて二つの肉の最短距離を求めたいと思います。
前回の記事ではそのままの画像サイズで処理を行っていました。この場合、**画像サイズが大きくなると領域を囲む処理が重くなってしまいます。**従って、画像サイズを小さくして処理しやすくします。
今回は、幅を300ピクセルに固定して同じアスペクト比(幅:高さ比)で縮小させます。
def scale_to_width(img, width):
scale = width / img.shape[1]
return cv2.resize(img, dsize=None, fx=scale, fy=scale)
img = scale_to_width(img, 300)#300ピクセルに固定
##画像を二値化させる
次に、二値化により肉部分だけを色を抽出したいと思います。cv2.inRangeメソッドによって特定の色を白、特定の色を黒とします。
import numpy as np
bgrLower = np.array([0, 0, 130]) # 抽出する色の下限(BGR)
bgrUpper = np.array([120,120, 255]) # 抽出する色の上限(BGR)
img_mask = cv2.inRange(img, bgrLower, bgrUpper)
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(1,1,1)
ax.imshow(img_mask)
ax.axis("off")
見事肉だけ白く表示させることができました。ただ、これは元画像の色合いによって**手動で抽出する色を調整する必要があるため、手間になります。**この表示させたい色だけを抽出して二値化させる手法は、別途まとめたいと思います。
##領域間の距離を求め、そこから最短距離を求める
次に、領域間の距離を求めます。前回は、各領域のx座標最大値/最小値を取る座標を取得させてから距離を求めました。しかし、その求め方は必ずしも最短距離をとれるわけではありません(下右図の例)。
対策としては、各領域を囲む点通しの組み合わせによる距離を全て求めて、それが最小値を取る座標を取得することです。
この時、画像サイズを調整しないとかなり計算数が大きくなるため、前に示した画像サイズを縮小化させることが効いてきます。
import numpy as np
dd=np.array([300])#空白の配列だとif min(dd)> dでエラーが出るため
for i in range(len(contours[0])):
x3 = contours[0][i][0][0]
y3 = contours[0][i][0][1]
for ii in range (len(contours[1])):
x4 = contours[1][ii][0][0]
y4 = contours[1][ii][0][1]
d = get_distance(x3, y3, x4, y4)
if min(dd) > d:
x3min =x3
y3min =y3
x4min =x4
y4min =y4
dd = np.append(dd,d)
26.248809496813376
無事に最短距離を求めることができました。
#おわりに
画像ファイルを小さくするだけで、処理がかなり早くなりました。一方、色の抽出は手動で行いますので、ここは改善の余地があります。二値化したいところだけ自在に分けられるような改造を検討したいと思います。
簡単ですが改善しましたので、下記に格納しています(日付が新しいものがバージョンアップしたものです)。