まだ春のパン祭りの続きですが、1点だけ処理の調整を試したいと思います。
-- 追記 --
今までmarkdown記法でブログを書いていると、ときどき画像がうまく表示されない(半角スペース4つのブロックの後に画像が表示されない)問題があって、前にはてなブログさんに修正の希望を出していましたが、どうも前回の記事を書いているときから、直っているようでした。
はてなさんありがとう~
変更内容
今まで見た点数輪郭では、"0"を除いて、その内部には輪郭を含みませんでした。
これを利用して、ICP処理を実施する前に候補輪郭を絞り、処理の高速化ができないか、試してみます。
"0"の輪郭は除外されてしまいますが、点数計算に影響ないので問題なし。
まずは今まで通りのスクリプト読み込みですが、どうも途中から関数を更新したりするのがうまくいかなかったので、全部コピペしておきます。
###################################################### # Importing libraries ###################################################### import cv2 import numpy as np from matplotlib import pyplot as plt import math import copy import random import json ###################################################### # Detecting contours ###################################################### def reduce_resolution(img, res_th=800): h, w, chs = img.shape if h > res_th or w > res_th: k = float(res_th)/h if w > h else float(res_th)/w else: k = 1.0 rtn_img = cv2.resize(img, None, fx=k, fy=k, interpolation=cv2.INTER_AREA) return rtn_img def harupan_binarize(img, sat_th=100): hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # Convert hue value (rotation, mask by saturation) hsv[:,:,0] = np.where(hsv[:,:,0] < 50, hsv[:,:,0]+180, hsv[:,:,0]) hsv[:,:,0] = np.where(hsv[:,:,1] < sat_th, 0, hsv[:,:,0]) # Thresholding with cv2.inRange() binary_img = cv2.inRange(hsv[:,:,0], 135, 190) return binary_img def detect_candidate_contours(image, res_th=800, sat_th=100): img = reduce_resolution(image, res_th) binimg = harupan_binarize(img, sat_th) # Retrieve all points on the contours (cv2.CHAIN_APPROX_NONE) contours, hierarchy = cv2.findContours(binimg, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) indices0 = [i for i,hier in enumerate(hierarchy[0,:,:]) if hier[3] == -1] indices1 = [i for i,hier in enumerate(hierarchy[0,:,:]) if hier[3] in indices0] contours1 = [contours[i] for i in indices1] contours1_filtered = [ctr for ctr in contours1 if cv2.contourArea(ctr) > float(res_th)*float(res_th)/4000] return contours1_filtered, img # image: Entire image containing multiple contours # contours: Contours contained in "image" (Retrieved by cv2.findContours(), the origin is same as "image") def refine_contours(image, contours): subctrs = [] subimgs = [] binimgs = [] thresholds = [] n_ctrs = [] for ctr in contours: img, _ = create_contour_area_image(image, ctr) # Thresholding using G value in BGR format thresh, binimg = cv2.threshold(img[:,:,1], 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) # Add black region around thresholded image, to detect contours correctly binimg = cv2.copyMakeBorder(binimg, 2,2,2,2, cv2.BORDER_CONSTANT, 0) ctrs2, _ = cv2.findContours(binimg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) max_len = 0 for ctr2 in ctrs2: if max_len <= ctr2.shape[0]: max_ctr = ctr2 max_len = ctr2.shape[0] subctrs += [max_ctr] subimgs += [img] binimgs += [binimg] thresholds += [thresh] n_ctrs += [len(ctrs2)] debug_info = (binimgs, thresholds, n_ctrs) return subctrs, subimgs, debug_info ###################################################### # Auxiliary functions ###################################################### def create_contour_area_image(img, ctr): x,y,w,h = cv2.boundingRect(ctr) rtn_img = img[y:y+h,x:x+w,:].copy() rtn_ctr = ctr.copy() origin = np.array([x,y]) for c in rtn_ctr: c[0,:] -= origin return rtn_img, rtn_ctr # ctr: Should be output of create_contour_area_image() (Origin of points is the origin of bounding box) # img_shape: Optional, tuple of (image_height, image_width), if omitted, calculated from ctr def create_solid_contour(ctr, img_shape=(int(0),int(0))): if img_shape == (int(0),int(0)): _,_,w,h = cv2.boundingRect(ctr) else: h,w = img_shape img = np.zeros((h,w), 'uint8') img = cv2.drawContours(img, [ctr], -1, 255, -1) return img # ctr: Should be output of create_contour_area_image() (Origin of points is the origin of bounding box) def create_upright_solid_contour(ctr): ctr2 = ctr.copy() (cx,cy),(w,h),angle = cv2.minAreaRect(ctr2) M = cv2.getRotationMatrix2D((cx,cy), angle, 1) for i in range(ctr2.shape[0]): ctr2[i,0,:] = ( M @ np.array([ctr2[i,0,0], ctr2[i,0,1], 1]) ).astype('int') rect = cv2.boundingRect(ctr2) img = np.zeros((rect[3],rect[2]), 'uint8') ctr2 -= rect[0:2] M[:,2] -= rect[0:2] img = cv2.drawContours(img, [ctr2], -1, 255,-1) return img, M, ctr2 ###################################################### # Dataset classes ###################################################### class contour_dataset: def __init__(self, ctr): self.ctr = ctr.copy() self.rrect = cv2.minAreaRect(ctr) self.box = cv2.boxPoints(self.rrect) self.solid = create_solid_contour(ctr) self.pts = np.array([p for p in ctr[:,0,:]]) class template_dataset: def __init__(self, ctr, num, selected_idx=[0]): self.ctr = ctr.copy() self.num = num self.rrect = cv2.minAreaRect(ctr) self.box = cv2.boxPoints(self.rrect) if num == 0: self.solid,_,_ = create_upright_solid_contour(ctr) else: self.solid = create_solid_contour(ctr) self.pts = np.array([ctr[idx,0,:] for idx in selected_idx]) ###################################################### # ICP ###################################################### # pts: list of 2D points, or ndarray of shape (n,2) # query: 2D point to find nearest neighbor def find_nearest_neighbor(pts, query): min_distance_sq = float('inf') min_idx = 0 for i, p in enumerate(pts): d = np.dot(query - p, query - p) if(d < min_distance_sq): min_distance_sq = d min_idx = i return min_idx, np.sqrt(min_distance_sq) # src, dst: ndarray, shape is (n,2) (n: number of points) def estimate_affine_2d(src, dst): n = min(src.shape[0], dst.shape[0]) x = dst[0:n].flatten() A = np.zeros((2*n,6)) for i in range(n): A[i*2,0] = src[i,0] A[i*2,1] = src[i,1] A[i*2,2] = 1 A[i*2+1,3] = src[i,0] A[i*2+1,4] = src[i,1] A[i*2+1,5] = 1 M = np.linalg.inv(A.T @ A) @ A.T @ x return M.reshape([2,3]) # Find optimum affine matrix using ICP algorithm # src_pts: ndarray, shape is (n_s,2) (n_s: number of points) # dst_pts: ndarray, shape is (n_d,2) (n_d: number of points, n_d should be larger or equal to n_s) # initial_matrix: ndarray, shape is (2,3) def icp(src_pts, dst_pts, max_iter=20, initial_matrix=np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]])): default_affine_matrix = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]) if dst_pts.shape[0] < src_pts.shape[0]: print("icp: Insufficient destination points") return default_affine_matrix, False if initial_matrix.shape != (2,3): print("icp: Illegal shape of initial_matrix") return default_affine_matrix, False M = initial_matrix # Store indices of the nearest neighbor point of dst_pts to the converted point of src_pts nn_idx = [] for i in range(max_iter): nn_idx_tmp = [] dst_pts_list = [p for p in dst_pts] idx_list = list(range(0,dst_pts.shape[0])) for p in src_pts: p2 = M @ np.array([p[0], p[1], 1]) idx, d = find_nearest_neighbor(dst_pts_list, p2) nn_idx_tmp += [idx_list[idx]] del dst_pts_list[idx] del idx_list[idx] if nn_idx != [] and nn_idx == nn_idx_tmp: break dst_pts2 = np.zeros_like(src_pts) for j,idx in enumerate(nn_idx_tmp): dst_pts2[j,:] = dst_pts[idx,:] M = estimate_affine_2d(src_pts, dst_pts2) nn_idx = nn_idx_tmp if i == max_iter -1: return M, False return M, True ###################################################### # Calculating similarity and determining the number ###################################################### def binary_image_similarity(img1, img2): if img1.shape != img2.shape: print('binary_image_similarity: Different image size') return 0.0 xor_img = cv2.bitwise_xor(img1, img2) return 1.0 - np.float(np.count_nonzero(xor_img)) / (img1.shape[0]*img2.shape[1]) # src, dst: contour_dataset or template_dataset (holding member variables box, solid) def get_transform_by_rotated_rectangle(src, dst): # Rotated patterns are created when starting index is slided dst_box2 = np.vstack([dst.box, dst.box]) max_similarity = 0.0 max_converted_img = np.zeros((dst.solid.shape[1], dst.solid.shape[0]), 'uint8') for i in range(4): M = cv2.getAffineTransform(src.box[0:3], dst_box2[i:i+3]) converted_img = cv2.warpAffine(src.solid, M, dsize=(dst.solid.shape[1], dst.solid.shape[0]), flags=cv2.INTER_NEAREST) similarity = binary_image_similarity(converted_img, dst.solid) if similarity > max_similarity: M_rtn = M max_similarity = similarity max_converted_img = converted_img return M_rtn, max_similarity, max_converted_img def get_similarity_with_template(target_data, template_data, sim_th_high=0.95, sim_th_low=0.7): _,(w1,h1), _ = target_data.rrect _,(w2,h2), _ = template_data.rrect r = w1/h1 if w1 < h1 else h1/w1 r = r * h2/w2 if w2 < h2 else r * w2/h2 M, sim_init, _ = get_transform_by_rotated_rectangle(template_data, target_data) if sim_init > sim_th_high or sim_init < sim_th_low or r > 1.4 or r < 0.7: dsize = (template_data.solid.shape[1], template_data.solid.shape[0]) flags = cv2.INTER_NEAREST|cv2.WARP_INVERSE_MAP converted_img = cv2.warpAffine(target_data.solid, M, dsize=dsize, flags=flags) return sim_init, converted_img M, _ = icp(template_data.pts, target_data.pts, initial_matrix=M) Minv = cv2.invertAffineTransform(M) converted_ctr = np.zeros_like(target_data.ctr) for i in range(target_data.ctr.shape[0]): converted_ctr[i,0,:] = (Minv[:,0:2] @ target_data.ctr[i,0,:]) + Minv[:,2] converted_img = create_solid_contour(converted_ctr, img_shape=template_data.solid.shape) val = binary_image_similarity(converted_img, template_data.solid) return val, converted_img def get_similarity_with_template_zero(target_data, template_data): dsize = (template_data.solid.shape[1], template_data.solid.shape[0]) converted_img = cv2.resize(target_data.solid, dsize=dsize, interpolation=cv2.INTER_NEAREST) val = binary_image_similarity(converted_img, template_data.solid) return val, converted_img def get_similarities(target, templates): similarities = [] converted_imgs = [] for tmpl in templates: if tmpl.num == 0: sim,converted_img = get_similarity_with_template_zero(target, tmpl) else: sim,converted_img = get_similarity_with_template(target, tmpl) similarities += [sim] converted_imgs += [converted_img] return similarities, converted_imgs def calc_harupan(img, templates, svm): ctrs, resized_img = detect_candidate_contours(img, sat_th=50) print('Number of candidates: ', len(ctrs)) subctrs, _, _ = refine_contours(resized_img, ctrs) subctr_datasets = [contour_dataset(ctr) for ctr in subctrs] ######## #### Simple code # similarities = [get_similarities(d, templates)[0] for d in subctr_datasets] #### Code printing progress similarities = [] for i,d in enumerate(subctr_datasets): print(i, end=' ') similarities += [get_similarities(d, templates)[0]] print('') ######## _, result = svm.predict(np.array(similarities, 'float32')) result = result.astype('int') score = 0.0 texts = {0:'0', 1:'1', 2:'2', 3:'3', 5:'.5'} font = cv2.FONT_HERSHEY_SIMPLEX for res, ctr in zip(result, ctrs): if res[0] == 5: score += 0.5 elif res[0] != -1: score += res[0] # Annotating recognized numbers for confirmation if res[0] != -1: resized_img = cv2.drawContours(resized_img, [ctr], -1, (0,255,0), 3) x,y,_,_ = cv2.boundingRect(ctr) resized_img = cv2.putText(resized_img, texts[res[0]], (x,y), font, 1, (230,230,0), 5) return score, resized_img ###################################################### # Loading template data and SVM model ###################################################### def load_svm(filename): return cv2.ml.SVM_load(filename) def load_templates(filename): with open(filename, mode='r') as f: load_data = json.load(f) templates_rtn = [] for d in load_data: templates_rtn += [template_dataset(np.array(d['ctr']), d['num'], d['pts'])] return templates_rtn
画像読み込みと、%matplotlib inline
のマジックコマンドも書いておきます。
学習済みSVM、テンプレートデータの読み込みも行います。
%matplotlib inline img1 = cv2.imread('harupan_190428_1.jpg') img2 = cv2.imread('harupan_190428_2.jpg') img3 = cv2.imread('harupan_200317_1.jpg') img4 = cv2.imread('harupan_210227_2.jpg') img5 = cv2.imread('harupan_210402_1.jpg') img6 = cv2.imread('harupan_210402_2.jpg') img7 = cv2.imread('harupan_210414_1.jpg') img8 = cv2.imread('harupan_220330_1.jpg') img9 = cv2.imread('harupan_220330_2.jpg') svm = cv2.ml.SVM_load('harupan_data/harupan_svm_220412.dat') templates2019 = load_templates('harupan_data/templates2019_220412.json') templates2020 = load_templates('harupan_data/templates2020_220412.json') templates2021 = load_templates('harupan_data/templates2021_220412.json')
また、変更の効果の確認のため、一旦今まで通りの処理を各画像で実施します。
処理時間は、timeit.timeit()
で測定します。
import timeit def test_harupan_timeit(img, templates, svm): score, result_img = calc_harupan(img, templates, svm) n_loop = 5 result = timeit.timeit('calc_harupan(img, templates, svm)', globals=globals(), number=n_loop) print('Score: ', score) print('Average process time: ', result/n_loop) plt.figure(figsize=(6.4,4.8), dpi=200) plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)), plt.xticks([]), plt.yticks([]) plt.show() return result/n_loop
imgs = [img1, img2, img3, img4, img5, img6, img7, img8, img9] templates_sel = [0,0,1,2,2,2,2,2,2] ts = [] for img, sel in zip(imgs, templates_sel): if sel == 0: templates = templates2019 elif sel == 1: templates = templates2020 else: templates = templates2021 ts += [test_harupan_timeit(img, templates, svm)]
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Number of candidates: 36
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
Score: 26.0
Average process time: 8.82181928
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Score: 26.5
Average process time: 8.280414280000002
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Number of candidates: 40
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Score: 25.0
Average process time: 6.180490499999999
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Number of candidates: 35
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
Score: 21.5
Average process time: 5.870072019999998
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Number of candidates: 39
0 1 2 3 4 5 6 7 8 9 icp: Insufficient destination points
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
Score: 28.0
Average process time: 4.848178239999998
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Number of candidates: 34
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Score: 28.0
Average process time: 4.4394959000000025
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Score: 25.0
Average process time: 4.83998542
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Score: 26.0
Average process time: 3.852909180000006
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Number of candidates: 24
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Score: 26.0
Average process time: 6.385288779999996
for t in ts: print(t)
8.82181928
8.280414280000002
6.180490499999999
5.870072019999998
4.848178239999998
4.4394959000000025
4.83998542
3.852909180000006
6.385288779999996
スクリプト変更
スクリプトのうち、detect_candidate_contours()
関数を以下のように変更します。
- 階層情報込みで輪郭検出 (今まで通り)
- 2段目の階層にある輪郭を取り出し (今まで通り)
- それより下の階層に輪郭を含まない輪郭を選択する
変更後、スクリプトの関数を上書きします。以下参照。
def detect_candidate_contours(image, res_th=800, sat_th=100): img = reduce_resolution(image, res_th) binimg = harupan_binarize(img, sat_th) # Retrieve all points on the contours (cv2.CHAIN_APPROX_NONE) contours, hierarchy = cv2.findContours(binimg, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) # Pick up contours that have no parents indices = [i for i,hier in enumerate(hierarchy[0,:,:]) if hier[3] == -1] # Pick up contours that reside in above contours indices = [i for i,hier in enumerate(hierarchy[0,:,:]) if (hier[3] in indices) and (hier[2] == -1) ] contours = [contours[i] for i in indices] contours = [ctr for ctr in contours if cv2.contourArea(ctr) > float(res_th)*float(res_th)/4000] return contours, img
ts2 = [] for img, sel in zip(imgs, templates_sel): if sel == 0: templates = templates2019 elif sel == 1: templates = templates2020 else: templates = templates2021 ts2 += [test_harupan_timeit(img, templates, svm)]
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Score: 26.0
Average process time: 7.390565659999993
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 26.5
Average process time: 6.902831980000007
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 25.0
Average process time: 3.8497284000000036
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Score: 19.5
Average process time: 2.6001762999999984
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Score: 28.0
Average process time: 3.600558000000001
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Score: 28.0
Average process time: 3.107207219999998
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Score: 25.0
Average process time: 3.779431460000012
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
Average process time: 3.1119086799999875
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
Average process time: 5.48430937999999
for t1,t2 in zip(ts, ts2): print('{:.3f} vs '.format(t1), '{:.3f}'.format(t2))
8.822 vs 7.391
8.280 vs 6.903
6.180 vs 3.850
5.870 vs 2.600
4.848 vs 3.601
4.439 vs 3.107
4.840 vs 3.779
3.853 vs 3.112
6.385 vs 5.484
少し処理時間は短くなりましたが、劇的には改善せず。
あと4つ目の画像で1つ点数文字の認識が消えてしまった…
もうちょい処理を検討…
変更2
上の9画像を見ると、点数文字が比較的小さく写っているもののほうが処理時間が短いような。
ICPでのマッチング候補点数が少なくなることによるかと思われます。
ということで、ICPで使う輪郭点を間引きます。
contour_datasets
クラスのコンストラクタ内の処理を変更することになります。
どれくらい間引くかですが、前に選択したテンプレートで輪郭点数を見ると、1つの文字当たり100~200点くらいだったので、同程度あれば大丈夫だろうか。
間引き処理
100点に間引きをすることをターゲットにすると、
- 例えば353点あるとして、これが一列に等間隔(整数点位置)で並んでいるイメージ
- これを100点分の長さに圧縮する
- 圧縮後の各点について、一番近い整数点位置に対応付け
- 同じ整数点に複数の点が対応付けられるが、そのうち1つを代表で選ぶ
という感じ。
cv2.resize()
で画像を縮小するときにcv2.INTER_NEAREST
を選ぶのと同じようなことかと思われます。
class contour_dataset: def __init__(self, ctr): self.ctr = ctr.copy() self.rrect = cv2.minAreaRect(ctr) self.box = cv2.boxPoints(self.rrect) self.solid = create_solid_contour(ctr) n = 100 if n >= ctr.shape[0]: self.pts = np.array([p for p in ctr[:,0,:]]) else: r = n / ctr.shape[0] self.pts = np.zeros((100,2), 'int') pts = [] for i in range(ctr.shape[0]): f = math.modf(i*r)[0] if (f <= r/2) or (f > 1.0 - r/2): pts += [ctr[i,0,:]] self.pts = np.array(pts) print('points : ', ctr.shape[0], ' -> ', len(pts))
def test_harupan(img, templates, svm): score, result_img = calc_harupan(img, templates, svm) print('Score: ', score) plt.figure(figsize=(6.4,4.8), dpi=200) plt.imshow(cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)), plt.xticks([]), plt.yticks([]) plt.show()
for img, sel in zip(imgs, templates_sel): if sel == 0: templates = templates2019 elif sel == 1: templates = templates2020 else: templates = templates2021 test_harupan(img, templates, svm)
Number of candidates: 22
points : 110 -> 107
points : 128 -> 100
points : 123 -> 101
points : 125 -> 101
points : 201 -> 100
points : 132 -> 100
points : 199 -> 100
points : 135 -> 101
points : 123 -> 101
points : 123 -> 101
points : 201 -> 100
points : 126 -> 100
points : 210 -> 97
points : 133 -> 99
points : 137 -> 101
points : 199 -> 100
points : 126 -> 100
points : 142 -> 100
points : 212 -> 100
points : 223 -> 100
points : 134 -> 100
points : 139 -> 101
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Score: 26.0
Number of candidates: 23
points : 112 -> 100
points : 130 -> 97
points : 125 -> 101
points : 128 -> 100
points : 205 -> 99
points : 134 -> 100
points : 204 -> 100
points : 139 -> 101
points : 127 -> 100
points : 127 -> 100
points : 207 -> 100
points : 131 -> 100
points : 220 -> 100
points : 140 -> 100
points : 142 -> 100
points : 207 -> 100
points : 130 -> 97
points : 153 -> 101
points : 235 -> 101
points : 226 -> 99
points : 143 -> 100
points : 150 -> 100
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 26.5
Number of candidates: 23
points : 146 -> 100
points : 144 -> 100
points : 169 -> 100
points : 143 -> 100
points : 143 -> 100
points : 160 -> 100
points : 169 -> 100
points : 208 -> 100
points : 145 -> 99
points : 145 -> 99
points : 144 -> 100
points : 145 -> 99
points : 148 -> 100
points : 144 -> 100
points : 145 -> 99
points : 203 -> 101
points : 144 -> 100
points : 199 -> 100
points : 143 -> 100
points : 200 -> 100
points : 162 -> 100
points : 149 -> 100
points : 150 -> 100
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 25.0
Number of candidates: 25
points : 147 -> 99
points : 180 -> 100
points : 145 -> 99
points : 125 -> 101
points : 126 -> 100
points : 190 -> 96
points : 122 -> 98
points : 119 -> 101
points : 119 -> 101
points : 103 -> 101
points : 128 -> 100
points : 190 -> 96
points : 300 -> 100
points : 193 -> 100
points : 129 -> 100
points : 128 -> 100
points : 132 -> 100
points : 134 -> 100
points : 140 -> 100
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Score: 19.5
Number of candidates: 31
points : 119 -> 101
points : 157 -> 100
points : 122 -> 98
points : 103 -> 101
points : 167 -> 100
points : 118 -> 102
points : 152 -> 100
points : 112 -> 100
points : 143 -> 100
points : 133 -> 99
points : 138 -> 100
points : 236 -> 100
points : 162 -> 100
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Score: 28.0
Number of candidates: 28
points : 101 -> 101
points : 124 -> 100
points : 115 -> 96
points : 111 -> 100
points : 107 -> 101
points : 108 -> 100
points : 193 -> 100
points : 123 -> 101
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Score: 28.0
Number of candidates: 18
points : 145 -> 99
points : 138 -> 100
points : 138 -> 100
points : 139 -> 101
points : 138 -> 100
points : 138 -> 100
points : 136 -> 100
points : 219 -> 100
points : 207 -> 100
points : 140 -> 100
points : 131 -> 100
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Score: 25.0
Number of candidates: 20
points : 107 -> 101
points : 111 -> 100
points : 111 -> 100
points : 101 -> 101
points : 102 -> 100
points : 113 -> 99
points : 104 -> 100
points : 107 -> 101
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
Number of candidates: 20
points : 149 -> 100
points : 145 -> 99
points : 120 -> 100
points : 184 -> 100
points : 136 -> 100
points : 142 -> 100
points : 167 -> 100
points : 163 -> 100
points : 174 -> 100
points : 167 -> 100
points : 113 -> 99
points : 103 -> 101
points : 130 -> 97
points : 115 -> 96
points : 160 -> 100
points : 157 -> 100
points : 123 -> 101
points : 142 -> 100
points : 158 -> 101
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
点数文字の認識は、特に悪くなってはいなさそうです。これでいけそう。
間引き後の輪郭点数は、ときどき100点から少し離れています。小数の丸めと比較のあたりの問題化とは思いますが、まあこれで進めます。
デバッグ表示を消して、改めて処理時間測定します。
class contour_dataset: def __init__(self, ctr): self.ctr = ctr.copy() self.rrect = cv2.minAreaRect(ctr) self.box = cv2.boxPoints(self.rrect) self.solid = create_solid_contour(ctr) n = 100 if n >= ctr.shape[0]: self.pts = np.array([p for p in ctr[:,0,:]]) else: r = n / ctr.shape[0] self.pts = np.zeros((100,2), 'int') pts = [] for i in range(ctr.shape[0]): f = math.modf(i*r)[0] if (f <= r/2) or (f > 1.0 - r/2): pts += [ctr[i,0,:]] self.pts = np.array(pts)
ts3 = [] for img, sel in zip(imgs, templates_sel): if sel == 0: templates = templates2019 elif sel == 1: templates = templates2020 else: templates = templates2021 ts3 += [test_harupan_timeit(img, templates, svm)]
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Number of candidates: 22
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
Score: 26.0
Average process time: 3.411894039999993
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 26.5
Average process time: 3.6053899799999956
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Number of candidates: 23
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Score: 25.0
Average process time: 1.5578179599999884
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Number of candidates: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Score: 19.5
Average process time: 1.460823019999998
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Number of candidates: 31
0 1 2 3 4 5 6 icp: Insufficient destination points
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Score: 28.0
Average process time: 2.703369799999996
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Number of candidates: 28
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
Score: 28.0
Average process time: 2.9763017799999942
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Number of candidates: 18
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Score: 25.0
Average process time: 1.883919160000005
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
Average process time: 2.917304880000006
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Number of candidates: 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Score: 26.0
Average process time: 2.4312215799999874
for t1,t2,t3 in zip(ts, ts2, ts3): print('{:.3f} vs '.format(t1), '{:.3f} vs'.format(t2), '{:.3f}'.format(t3))
8.822 vs 7.391 vs 3.412
8.280 vs 6.903 vs 3.605
6.180 vs 3.850 vs 1.558
5.870 vs 2.600 vs 1.461
4.848 vs 3.601 vs 2.703
4.439 vs 3.107 vs 2.976
4.840 vs 3.779 vs 1.884
3.853 vs 3.112 vs 2.917
6.385 vs 5.484 vs 2.431
概ね速くなりました。
元々輪郭点数が少なかったものはそれほど変わらず。
人間の体感的には少し待ちが出そうですが、一応リアルタイム処理できるかな?
以上
今度こそ調整は終了にしようかと。
気が変わらなければ、次回はPCのカメラ画像からのリアルタイム処理の作成になります。