'22/07/03更新:グレースケールと輪郭強調だけでは対応できない場合の対策例として、その間の画像加工のコードの記述例を追記しました。
・しきい値調整(トライアングル, 大津処理)
・ヒストグラム平坦化
・白黒反転
・パイラテラルフィルタ
・ノイズ除去
本記事では、下図のような図形の境界の座標を抽出する雛形コードを載せました。

本プログラムの処理についての説明をします。まず、OpenCVで画像をオブジェクトで読み込み後にグレースケールに変換します。

次に、cv2.adaptiveThreshold()メソッドを用いることで輪郭を検出できます(下図)。

そして、cv2.findContours()メソッドを使用して座標を抽出します。この時、下図の赤枠のように画像の縁の座標も取得する仕様になっています。

この画面サイズを表す赤枠は、原点(x, y)=(0, 0)を必ず通ります。これを判定基準に赤枠データを削除したのが下図です。

下図は、上図の〇、△、□の図形の(x, y)座標データです。列で識別できるようにしました。

▼本プログラム
スクリプト内で画像加工方法を3つに分けています。それはフラグで選択して分岐して処理する仕様にしています。flag_image_process = 'simple_gray' # simple_gray, triangle, multy
import os, sys
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
file_path = './pictures/shape.jpg'
save_dir = './save_dir/'
flag_image_process = 'simple_gray'
file_name = os.path.basename(file_path)
fname, ext = os.path.splitext(file_name)
print(fname, ext)
img = cv2.imread(file_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite(f'{save_dir}{fname}_01_gray_src{ext}', gray)
if flag_image_process == 'simple_gray':
dst = gray.copy()
elif flag_image_process == 'triangle':
retval, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_TRIANGLE)
cv2.imwrite(f'{save_dir}{fname}_02_thresh_triangle_src{ext}', dst)
elif flag_image_process == 'multy':
dst = cv2.equalizeHist(gray)
cv2.imwrite(f'{save_dir}{fname}_02_contra_src{ext}', dst)
dst = 255 - dst
cv2.imwrite(f'{save_dir}{fname}_03_re_gray_src{ext}', dst)
dst = cv2.bilateralFilter(dst, 5, 100, 100)
cv2.imwrite(f'{save_dir}{fname}_04_bilateral_src{ext}', dst)
dst = cv2.fastNlMeansDenoising(dst, h = 20)
cv2.imwrite(f'{save_dir}{fname}_05_noise_removal_src{ext}', dst)
retval, dst = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
cv2.imwrite(f'{save_dir}{fname}_06_thresh_otsu_src{ext}', dst)
else:
print('check flag')
sys.exit()
block_size = 5
contour = cv2.adaptiveThreshold(dst, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, block_size, 4)
cv2.imwrite(f'{save_dir}{fname}_07_contour_src{ext}', contour)
contours, hierarchy = cv2.findContours(contour, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
print(len(contours))
print(hierarchy)
x_list = []
y_list = []
df_group_list = []
for i in range(len(contours)):
if hierarchy[0][i][-1] == -1:
buf_np = contours[i].flatten()
for i, elem in enumerate(buf_np):
if i%2 == 0:
x_list.append(elem)
else:
y_list.append(elem * (-1))
mylist = list(zip(x_list, y_list))
df_buf = pd.DataFrame(mylist, columns = ['x', 'y'])
df_group_list.append(df_buf)
x_list.clear()
y_list.clear()
print('df_group_list', len(df_group_list))
for i, df_buf in enumerate(df_group_list, start=1):
plt.scatter(df_buf['x'], df_buf['y'], s = 0.5)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.savefig(f'{save_dir}{fname}_08_scatter.jpg')
plt.close()
if True:
for i, df_buf in enumerate(df_group_list):
if not df_buf[(df_buf['x'] == 0) & (df_buf['y'] == 0)].empty:
df_group_list.pop(i)
DF_name_list = []
DF_list = []
for i, df_buf in enumerate(df_group_list, start=1):
plt.scatter(df_buf['x'], df_buf['y'], s = 0.5)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
DF_name_list.extend(['id_'+ '{0:03}'.format(i) + '_x', 'id_'+ '{0:03}'.format(i) + '_y'])
DF_list.append(df_buf)
DF = pd.concat(DF_list, axis=1)
DF.columns = DF_name_list
DF.to_excel(f'{save_dir}{fname}_09.xlsx', index=False)
plt.savefig(f'{save_dir}{fname}_09_scatter_fix.jpg')
plt.close()
以上
<広告>
リンク
リンク