openCVのcv2.findContoursで画像の輪郭抽出が可能です。第2変数に輪郭のリストが渡されるのでそれを使って、座標を指定して、輪郭色を抽出し判定して保存すれば良いのかな。って思います。ということで、与えられた画像の中から楕円形の輪郭を抽出し、矩形で囲み表示するスクリプトを作成しました。切り取ったり保存したりはやってません。
試してみた所感として、幾つかの問題点を挙げておきます。
1.下処理として二値化する際に明るさの影響を結構受けるようで、手書きで試してみたものは上手くいかず、Keynoteで作成した楕円に対して試してみました。よってデータが紙媒体だと苦戦しそうです。(二値化のパラメタの調整など頑張ればなんとかなるけど、データにムラがあると厳しそう。)
2.cv2.findContoursで輪郭が取得できるのですが、誤差があるので座標の特定の仕方に工夫が入りそうです。私が試したデータでは(2,0)のズレがあったので無理やり調整しました。
初心者というのがどのレベルなのか分かりませんが、私も難しい内容だな..と思いました。めげずに頑張ってください!
参考になりましたら、幸いです。
以下、試したコードまで。
python:test.py
1import cv2, matplotlib
2import numpy as np
3import matplotlib.pyplot as plt
4from PIL import Image
5
6# データの読み込みと下処理
7ellipsess = cv2.imread('teratail_test.png')
8ellipsess_gray = cv2.cvtColor(ellipsess, cv2.COLOR_BGR2GRAY)
9ellipsess_preprocessed = cv2.GaussianBlur(ellipsess_gray, (5, 5), 0)
10_, ellipsess_binary = cv2.threshold(ellipsess_preprocessed, 30, 255, cv2.THRESH_TOZERO)
11ellipsess_binary = cv2.bitwise_not(ellipsess_binary)
12
13# 輪郭の抽出
14img,ellipses_contours, _ = cv2.findContours(ellipses_binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
15
16ellipses_and_contours = np.copy(ellipses)
17
18# 大きさを指定してそれより小さい輪郭を排除
19min_ellipse_area = 1000
20large_contours = [cnt for cnt in ellipses_contours if cv2.contourArea(cnt) > min_ellipse_area]
21
22# 輪郭の書き込み
23cv2.drawContours(ellipses_and_contours, large_contours, -1, (0,128,128))
24
25# 表示
26plt.imshow(ellipses_and_contours)
27
28# # 色ごとに保存するなら
29# 画像の数のループ:
30# pixelValue = ellipsess[ellipsess_contours[0][0][0][1]+2,ellipsess_contours[0][0][0][0]]
31# if pixelValue[0] > pixelValue[2]:
32# # 赤色の場合
33# # cv2.boundingRect()で座標を指定して切り取る
34# # cv2.imwrite()で保存する
35# else:
36# # 青色の場合