はじめに
ここでは、skimage.transform の hough_ellipseを用いた楕円の検出について説明する。
コード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import matplotlib.pyplot as plt
from skimage import data, color, img_as_ubyte
from skimage.feature import canny
from skimage.transform import hough_ellipse
from skimage.draw import ellipse_perimeter
from skimage.color import rgb2gray,rgba2rgb
# Load picture, convert to grayscale and detect edges
image_rgb = plt.imread('https://1.bp.blogspot.com/-jp5SUi6-w9A/UZMszsKm4cI/AAAAAAAASHw/fL-ySyFKg8w/s800/fabric_mark_ellipse.png')
image_gray = rgb2gray(rgba2rgb(image_rgb))
edges = canny(image_gray,sigma=1.0,low_threshold=0.1, high_threshold=0.8)
fig, ax = plt.subplots(dpi=140)
ax.imshow(edges, cmap=plt.cm.gray)
plt.savefig('fabric_mark_ellipse_edge.jpg',dpi=130)
# Perform a Hough Transform
# The accuracy corresponds to the bin size of a major axis.
# The value is chosen in order to get a single high accumulator.
# The threshold eliminates low accumulators
result = hough_ellipse(edges, accuracy=4, threshold=1,
min_size=300, max_size=240)
result.sort(order='accumulator')
result
array([(2, 154. , 357. , 300.28153456, 58.78775383, 1.61410257),
(2, 154. , 358. , 300.37476592, 54.69917732, 1.62075472),
(2, 154.5, 351. , 300.0337481 , 100. , 1.5857952 ), ...,
(9, 242. , 348. , 214.40149253, 328.07468662, 3.12025443),
(9, 242.5, 348.5, 217.14511277, 327.61028677, 3.11564428),
(9, 244. , 348. , 327. , 220.68982759, 1.57079633)],
dtype=[('accumulator', '<i8'), ('yc', '<f8'), ('xc', '<f8'), ('a', '<f8'), ('b', '<f8'), ('orientation', '<f8')])
# Estimated parameters for the ellipse
best = list(result[-1])
yc, xc, a, b = [int(round(x)) for x in best[1:5]]
orientation = best[5]
# Draw the ellipse on the original image
cy, cx = ellipse_perimeter(yc, xc, a, b, orientation)
# Draw the edge (white) and the resulting ellipse (red)
edges = color.gray2rgb(img_as_ubyte(edges))
edges[cy, cx] = (250, 0, 0)
fig2, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, figsize=(8, 4),
sharex=True, sharey=True,dpi=150)
ax1.set_title('Original picture')
ax1.imshow(image_rgb)
ax2.set_title('Edge (white) and result (red)')
ax2.imshow(edges)
plt.savefig("daen_hough.jpg",dpi=100)
plt.show()

解説
モジュールのインポート
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import matplotlib.pyplot as plt
from skimage import data, color, img_as_ubyte
from skimage.feature import canny
from skimage.transform import hough_ellipse
from skimage.draw import ellipse_perimeter
from skimage.color import rgb2gray,rgba2rgb
バージョン
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#version
import matplotlib
print(matplotlib.__version__)
3.3.4
import skimage
print(skimage.__version__)
0.18.1
画像データの読み込み
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
image_rgb = plt.imread('https://1.bp.blogspot.com/-jp5SUi6-w9A/UZMszsKm4cI/AAAAAAAASHw/fL-ySyFKg8w/s800/fabric_mark_ellipse.png')
image_gray = rgb2gray(rgba2rgb(image_rgb))
rgb2grayでグレースケールに変換する。画像は下記サイトの楕円を採用した。

キャニー法によるエッジの検出と表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
edges = canny(image_gray,sigma=1.0,low_threshold=0.1, high_threshold=0.8)
fig, ax = plt.subplots(dpi=140)
ax.imshow(edges, cmap=plt.cm.gray)
plt.savefig('fabric_mark_ellipse_edge.jpg',dpi=130)
canny法でエッジを検出し、ax.imshow(edges, cmap=plt.cm.gray)で表示する。

canny法については、下記で解説した。

ハフ変換による楕円の検出
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
result = hough_ellipse(edges, accuracy=4, threshold=1,
min_size=300, max_size=240)
result.sort(order='accumulator')
result
array([(2, 154. , 357. , 300.28153456, 58.78775383, 1.61410257),
(2, 154. , 358. , 300.37476592, 54.69917732, 1.62075472),
(2, 154.5, 351. , 300.0337481 , 100. , 1.5857952 ), ...,
(9, 242. , 348. , 214.40149253, 328.07468662, 3.12025443),
(9, 242.5, 348.5, 217.14511277, 327.61028677, 3.11564428),
(9, 244. , 348. , 327. , 220.68982759, 1.57079633)],
dtype=[('accumulator', '<i8'), ('yc', '<f8'), ('xc', '<f8'), ('a', '<f8'), ('b', '<f8'), ('orientation', '<f8')])
hough_ellipse()により、ハフ変換による楕円の検出ができる。
edgesはハフ変換したい画像とする。
accuracyは、精度のことで、短軸方向のaccumulatorのビンサイズとなる。
thresholdはaccumulatorのしきい値で、min_sizeは、楕円の長い方の半径の最小値、max_sizeは楕円の短い方の半径の最大値となっている。
resultをaccumulatorの順にソートして表示している。
結果は、 (‘accumulator’,’yc’, ‘xc’, ‘a’, ‘b’, ‘orientation’)で返ってきて、(yc, xc)
は中心の座標、 (a, b)
はそれぞれ長軸と短軸のことである。orientationは楕円の向きを示す。
より誤差が少なく近似されている楕円の選出
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
best = list(result[-1])
yc, xc, a, b = [int(round(x)) for x in best[1:5]]
orientation = best[5]
accumulatorの順にソートしたので最後列のデータが最も誤差が少なく近似されている楕円だと思われる。
結果をリスト形式として、それぞれのデータをスライスで取り出す。
検出した楕円の表示のための準備
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Draw the ellipse on the original image
cy, cx = ellipse_perimeter(yc, xc, a, b, orientation)
# Draw the edge (white) and the resulting ellipse (red)
edges = color.gray2rgb(img_as_ubyte(edges))
edges[cy, cx] = (250, 0, 0)
ellipse_perimeter()により画像中に楕円を生成する。座標と各方向の半径、方向を設定することで楕円を生成できる。
生成した楕円に色をつけるために、gray2rgb(img_as_ubyte)により [0〜255]で色を指定できるRGB形式に変換する。
edges[cy, cx] = (250, 0, 0)により、楕円部分のみを赤色にすることができる。
図の表示
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fig2, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, figsize=(8, 4),
sharex=True, sharey=True,dpi=150)
ax1.set_title('Original picture')
ax1.imshow(image_rgb)
ax2.set_title('Edge (white) and result (red)')
ax2.imshow(edges)
plt.savefig("daen_hough.jpg",dpi=100)
plt.show()
コードをダウンロード(.pyファイル)
コードをダウンロード(.ipynbファイル)
コメント