def __init__(self, delay, contours, DEBUG): if DEBUG: calculation_log( 'constructor of contours_analysis_results in single_image was called' ) self.contours = contours self.delay = delay self.__DEBUG = DEBUG if DEBUG: calculation_log('datas were setted.') if len(self.contours) != 0: self.__set_main_Y_of_nozzle() self.__set_convex_hull_area_of_nozzle() self.__set_area_of_nozzle() self.__set_arclength_of_nozzle() self.__set_convex_hull_arclength_of_nozzle() self.__set_solidity_of_nozzle() self.__set_freq_Y_of_nozzle() self.__set_num_contours() self.__set_max_reg_length_in_delay() self.__set_max_mainXY() self.__set_satellite_suspicious_XY() self.__set_volume_without_nozzle() return None
def __set_solidity_of_nozzle(self): ''' ノズルのSolidity値を取得する関数 ''' if self.__DEBUG: calculation_log('set solidity_of_nozzle') solidity_of_nozzle = self.convex_hull_area_of_nozzle / self.area_of_nozzle self.solidity_of_nozzle = solidity_of_nozzle return None
def __set_freq_Y_of_nozzle(self): ''' ノズルの最頻出Y座標を取得する関数 ''' if self.__DEBUG: calculation_log('set freq_Y_of_nozzle') self.freq_Y_of_Nozzle = self.contours[0].freq_Y self.num_freq_Y_of_Nozzle = self.contours[0].freq_num return None
def __set_arclength_of_nozzle(self): ''' ノズルのArclength値を取得する関数 ''' if self.__DEBUG: calculation_log('set arclength_of_nozzle') arclength_of_nozzle = self.contours[0].arclength self.arclength_of_nozzle = arclength_of_nozzle return None
def __set_convex_hull_area_of_nozzle(self): ''' ノズルのConvex_Hull_Area値を取得する関数 ''' if self.__DEBUG: calculation_log('set convex_hull_area_of_nozzle') convex_hull_area_of_nozzle = self.contours[0].convex_hull_contour_area self.convex_hull_area_of_nozzle = convex_hull_area_of_nozzle return None
def __set_convex_hull_arclength_of_nozzle(self): ''' ノズルのconvex_hull_arclength値を取得する関数 ''' if self.__DEBUG: calculation_log('set convex_hull_arclength_of_nozzle') convex_hull_arclength_of_nozzle = self.contours[ 0].convex_hull_contour_arclength self.convex_hull_arclength_of_nozzle = convex_hull_arclength_of_nozzle return None
def __set_num_contours(self): ''' 画像内の輪郭数をカウントする関数 ※ノイズ除去前ゆえ、ノイズが含まれる可能性がある。 ''' if self.__DEBUG: calculation_log('set num_contours') num_contours = len(self.contours) self.num_contours = num_contours return None
def __set_freq_Y(self): if self.__DEBUG: calculation_log('freq_Y method was called.') target_cnt = [ cnts for cnts in self.analysisResults if cnts.solidity_of_nozzle == self.solidity ][0] self.freq_Y = target_cnt.freq_Y_of_Nozzle self.freq_Y_cnt = target_cnt.num_freq_Y_of_Nozzle return None
def __set_max_mainXY(self): ''' メイン液滴と推定される座標を取得 (main_Y座標最大となる輪郭のmain_X、main_Y座標を取得) ''' if self.__DEBUG: calculation_log('set max_MainXY') mainXY = sorted(self.contours, key=lambda cnt: cnt.area, reverse=True)[0] self.max_mainY = mainXY.main_Y self.max_mainX = mainXY.main_X return None
def __set_num_initial_contour(self): if self.__DEBUG: calculation_log('num_ave_contour_method was called.') if self.flag_separated_is_detected: retNum_list = [ len(rst.contours) for rst in self.analysisResults if rst.delay < self.delay_separated ] else: retNum_list = [len(rst.contours) for rst in self.analysisResults] self.num_contours_at_first = retNum_list return None
def __set_max_reg_length_in_delay(self): ''' リガメント値が最大となる輪郭のリガメント値を取得 ''' if self.__DEBUG: calculation_log('set max_reg_length') set_value = -1 if not self.num_contours < 2: eval_cnts = self.contours[1:] reg_length_list = [cnt.get_regament_length() for cnt in eval_cnts] set_value = max(reg_length_list) self.max_reg_length_in_delay = set_value return None
def __set_arc_solidity(self): ''' ''' if self.__DEBUG: calculation_log('arc_solidity method was called.') rsts = [ cnts.convex_hull_arclength_of_nozzle / cnts.arclength_of_nozzle for cnts in self.analysisResults ] arc_solidity = max(rsts) self.arc_solidity = arc_solidity return None
def __set_volume_without_nozzle(self): ''' ノズル輪郭をのぞく輪郭の体積値の和を取得 ''' if self.__DEBUG: calculation_log('set volume without_nozzle') set_value = 0 if not self.num_contours < 2: eval_cnts = self.contours[1:] volume_list = [cnt.volume for cnt in eval_cnts] set_value = max(volume_list) self.volume_without_nozzle = set_value return None
def __set_solidity(self): ''' Solidity値取得関数 各画像の面積最大輪郭(=ノズル輪郭)の凸包輪郭面積 / 実面積比の最小値を取得する。 ノズルに異物がついているとこの値は大きくなるので、ある閾値を越えた場合に異物があると判定する。 詳細アルゴリズムはコメントにて記載する。 ''' if self.__DEBUG: calculation_log('solidity method was called.') solidity_list = [ cnts.solidity_of_nozzle for cnts in self.analysisResults ] #クラスプロパティにセット self.solidity = min(solidity_list) return None
def __set_volume(self): ''' ''' if self.__DEBUG: calculation_log('volume method was called.') lstReached = list( filter( lambda dat: len( [d for d in dat.contours if d.main_Y == d.imgYMax]) != 0, self.analysisResults)) if len(lstReached) == 0: delay_upper_limit = 1000 reaching_delay = delay_upper_limit else: reaching_delay = list( filter( lambda dat: len( [d for d in dat.contours if d.main_Y == d.imgYMax]) != 0, self.analysisResults))[0].delay lst = [ dat for dat in self.analysisResults if (dat.delay >= self.delay_separated) and ( dat.delay < reaching_delay) ] if len(lst) == 0: volumeAve = -1 volumeStdDiv = -1 volumeList = [ data.volume_without_nozzle for data in lst if len(data.contours) > 1 ] if len(volumeList) == 0: volumeAve = 0 volumeStdDiv = 0 else: volumeAve = sum(volumeList) / len(volumeList) volumeStdDiv = sum([ math.sqrt((vol - volumeAve)**2 / len(volumeList)) for vol in volumeList ]) self.volume_ave = volumeAve self.volume_std_div = volumeStdDiv return None
def __set_satellite_suspicious_XY(self): ''' サテライト液滴座標と推定される座標を取得 ''' if self.__DEBUG: calculation_log('set sattelite_like_XY') set_num_X = 0 set_num_Y = 0 if self.num_contours < 2: set_num_X = -1 set_num_Y = -1 else: eval_cnts = sorted(self.contours, key=lambda cnt: cnt.satellite_Y) set_num_X = eval_cnts[1].satellite_X set_num_Y = eval_cnts[1].satellite_Y self.satellite_suspicious_X = set_num_X self.satellite_suspicious_Y = set_num_Y return None
def __set_magnitude_of_doublet_droplet(self): ''' 二重吐出度計算関数 ''' if self.__DEBUG: calculation_log( 'detect magnitude of doublet_droplet method was called.') if self.flag_separated_is_detected: seeking_results_list = [ cnts.solidity_of_nozzle for cnts in self.analysisResults if cnts.delay >= self.delay_separated ] if len(seeking_results_list) == 1: self.magnitude_of_doublet_droplet = -1 else: diff_solidity_after_separation = max( seeking_results_list) - min(seeking_results_list) self.magnitude_of_doublet_droplet = diff_solidity_after_separation else: self.magnitude_of_doublet_droplet = -1 return None
def __set_droplet_separated(self): ''' 液滴分離検知関数 液滴吐出開始を検知し、吐出有無およびそのディレイタイムをflag_separated_is_detected、およびdelay_separatedに値をセットする。 分離検知が無い場合はdelay_separated = -1.0 詳細アルゴリズムはコメントにて記載 ''' if self.__DEBUG: calculation_log('separation method was called.') delay_separated = -1.0 flag_separated_is_detected = False seeking_results_list = [ data for data in self.analysisResults if data.delay >= self.delay_faced ] solidity_base = self.solidity for i in range(1, len(seeking_results_list)): eval_delay = seeking_results_list[i].delay flag_convexhull_contour_area = (seeking_results_list[i].convex_hull_area_of_nozzle +\ self.__area_mirgin_detect_separation < seeking_results_list[i-1].convex_hull_area_of_nozzle) flag_convexhull_contour_arclength = (seeking_results_list[i].arclength_of_nozzle + self.__arc_length_mirgin_detect_separation <\ seeking_results_list[i-1].arclength_of_nozzle) solidity_at_seeking_result = seeking_results_list[ i].solidity_of_nozzle eval_ratio = solidity_at_seeking_result / solidity_base flag_solidity_is_plausible = eval_ratio < self.__solidity_mirgin_detect_separation flag_length_of_contours = (len(seeking_results_list[i].contours) > 1) if self.__DEBUG: calculation_log( 'delay at {}, solidity is {}, eval ratio is {}, and flag is {}' .format(eval_delay, solidity_at_seeking_result, eval_ratio, flag_solidity_is_plausible)) if flag_convexhull_contour_area and flag_convexhull_contour_arclength and flag_solidity_is_plausible and flag_length_of_contours: delay_separated = eval_delay flag_separated_is_detected = True break if self.__DEBUG: calculation_log('separated_delay is {}'.format(delay_separated)) self.flag_separated_is_detected = flag_separated_is_detected self.delay_separated = delay_separated return None
def __set_droplet_faced(self): ''' 液滴吐出開始検知関数 液滴吐出開始を検知し、吐出有無およびそのディレイタイムをflag_faced_is_detected、およびdelay_facedに値をセットする。 吐出開始検知が無い場合はdelay_faced = -1.0 詳細アルゴリズムはコメントにて記載。 ''' if self.__DEBUG: calculation_log('detect_faced method was called.') #初期値のセット delay_faced = -1.0 flag_faced_is_detected = False # for i in range(1, len(self.analysisResults)): evaluation_delay = self.analysisResults[i].delay before_convex_hull_area = self.analysisResults[ i - 1].convex_hull_area_of_nozzle after_convex_hull_area = self.analysisResults[ i].convex_hull_area_of_nozzle flag_detection = after_convex_hull_area - self.__area_mirgin_detect_faced > before_convex_hull_area if self.__DEBUG: calculation_log( 'delay : {}, evaluation_area : {} evaluation_area_before : {}' .format(evaluation_delay, after_convex_hull_area, before_convex_hull_area)) if flag_detection: delay_faced = evaluation_delay flag_faced_is_detected = True if self.__DEBUG: calculation_log( 'detect_faced delay is {}.'.format(delay_faced)) break self.flag_faced_is_detected = flag_faced_is_detected self.delay_faced = delay_faced return None
def drawContours(delay, path, min_area_thresh, binarize_thresh, auto_binarize, draw_convexhull, draw_coords, exportImage, draw_reg_Detected, mkdir, DEBUG): ''' デバッグ時輪郭解析結果出力関数 ''' if mkdir: if not os.path.exists(os.path.dirname(path) + "/drawRsts"): os.makedirs(os.path.dirname(path) + "/drawRsts", exist_ok = True) if DEBUG: calculation_log('mkdir at {}/drawRsts'.format(os.path.dirname(path))) im = cv2.imread(path) imGray = cv2.imread(path,0) #二値化、オートバイナライズか否かで挙動違う ret, im_bin = cv2.threshold( imGray, binarize_thresh, 255, (cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) if auto_binarize else (cv2.THRESH_BINARY_INV)) #輪郭抽出 contours, hierarchy = cv2.findContours(im_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #閾値でフィルタ contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_area_thresh].sort( key=lambda cnt: min(cnt, key = lambda pt2:pt2[0,1])[0,1]) im = cv2.drawContours(im, [contours[0]], -1, (0,255,0), 2) if len(contours) > 1: im = cv2.drawContours(im, contours[1:], -1, (0,255,0), 1) if draw_convexhull: hulls = [cv2.convexHull(cnt) for cnt in contours] im = cv2.drawContours(im, [hulls[0]], -1, (255,255,0), 2) if len(hulls) > 1: im = cv2.drawContours(im, hulls[1:], -1, (255,255,0), 1) if draw_coords: coords = analyse_Image( delay = delay, path=path, min_area_thresh = min_area_thresh, binarize_thresh=binarize_thresh, auto_binarize = auto_binarize ) symbol_size = 5 for i in range(len(coords)): main_X = coords[i].main_X main_Y = coords[i].main_Y im = cv2.rectangle(im, ((int)(main_X-symbol_size),(int)(main_Y-symbol_size)), ((int)(main_X+symbol_size),(int)(main_Y+symbol_size)), (0,0,255), 2 if i == 0 else 1) satellite_X = coords[i].satellite_X satellite_Y = coords[i].satellite_Y im = cv2.rectangle(im, ((int)(satellite_X-symbol_size),(int)(satellite_Y-symbol_size)), ((int)(satellite_X+symbol_size),(int)(satellite_Y+symbol_size)), (0,255,255), 2 if i == 0 else 1) center_X = coords[i].center_X center_Y = coords[i].center_Y im = cv2.rectangle(im, ((int)(center_X-symbol_size),(int)(center_Y-symbol_size)), ((int)(center_X+symbol_size),(int)(center_Y+symbol_size)), (255,255,255), 2 if i == 0 else 1) savePath = (os.path.dirname(path) + '/drawRsts/'+ os.path.splitext(os.path.basename(path))[0] + \ '_drawResult.jpg') if mkdir else (os.path.splitext(path)[0] + "_drawResult.jpg") cv2.imwrite(savePath, im) del im if DEBUG: calculation_log('export debug image at {}'.format(savePath)) return None
def drawTrackingResult(dirPath, trackingRsts, draw_Fitting_Line, DEBUG): ''' 追尾結果描画関数。privateメソッド。 指定ディレクトリ内に「tracikngRsts」ディレクトリを生成し、その中に 対応する追尾結果を描画する。 画像は.jpgのみ。 Parameters ---------- dirPath : str 描画対象画像格納フォルダ trackingRsts : Tracking_Resultsクラス 描画対象結果格納追尾結果クラス draw_Fitting_Line : bool フィッティング結果描画の有無を指定 DEBUG : bool デバッグモード指定 Return ---------- なし ''' extension = '.jpg' pathes = glob.glob(dirPath + "/*" + extension) if os.path.exists(dirPath + "/trackingRsts"): delPathes = glob.glob(dirPath + "/trackingRsts/*.jpg") for f in delPathes: os.remove(f) os.makedirs(dirPath + "/trackingRsts", exist_ok=True) if DEBUG: calculation_log('mkdir at {}/trackingRsts'.format(dirPath)) signature_size = 5 for i in range(len(pathes)): f = pathes[i] #画像データの読み込み、opencv→numpyデータアレイ化 im = cv2.imread(f) #ファイル名からディレイ時間を読み取り delay = 0.0 max_delay_description_field_length = 10 j = max_delay_description_field_length flag_delay_is_get = False while j > len(extension): try: delay = float(f[-j:-len(extension)]) flag_delay_is_get = True break except: j = j - 1 if not flag_delay_is_get: delay = -1.0 print("delay_not_estimated at {}".format(f)) if (float)(delay) in [(float)(de.delay) for de in trackingRsts.results if not math.isnan(de.main_X)]: x = [ rst for rst in trackingRsts.results if (float)(rst.delay) == (float)(delay) ][0].main_X y = [ rst for rst in trackingRsts.results if (float)(rst.delay) == (float)(delay) ][0].main_Y im = cv2.rectangle(im,((int)(x-signature_size),(int)(y-signature_size)),((int)(x+signature_size),(int)(y+signature_size)),\ (0,0,255),3) if (float)(delay) in [(float)(de.delay) for de in trackingRsts.results if not math.isnan(de.satellite_X)]: x = [ rst for rst in trackingRsts.results if (float)(rst.delay) == (float)(delay) ][0].satellite_X y = [ rst for rst in trackingRsts.results if (float)(rst.delay) == (float)(delay) ][0].satellite_Y im = cv2.rectangle(im,((int)(x-signature_size),(int)(y-signature_size)),((int)(x+signature_size),(int)(y+signature_size)),\ (255,0,0),3) if draw_Fitting_Line == True: lineMainResults, lineSatelliteResults = trackingRsts.get_Main_vector_slope_intercept( ), trackingRsts.get_Satellite_vector_slope_intercept() if not any([math.isnan(value) for value in lineMainResults]): im = cv2.line(im, ((int)(lineMainResults[5]), 0), ((int)(lineMainResults[4] * im.shape[0] + lineMainResults[5]), im.shape[0]), (64, 64, 128), 1) predMainX = (int)(lineMainResults[0] * delay + lineMainResults[1]) predMainY = (int)(lineMainResults[2] * delay + lineMainResults[3]) im = cv2.circle(im, (predMainX, predMainY), signature_size, (64, 64, 128), 1) if not any([math.isnan(value) for value in lineSatelliteResults]): im = cv2.line(im, ((int)(lineSatelliteResults[5]), 0), ((int)(lineSatelliteResults[4] * im.shape[0] + lineSatelliteResults[5]), im.shape[0]), (128, 64, 64), 1) predSatX = (int)(lineSatelliteResults[0] * delay + lineSatelliteResults[1]) predSatY = (int)(lineSatelliteResults[2] * delay + lineSatelliteResults[3]) im = cv2.circle(im, (predSatX, predSatY), signature_size, (128, 64, 64), 2) savePath = dirPath + "/trackingRsts/" + os.path.splitext( os.path.basename(f))[0] + "_drawTRResults.jpg" cv2.imwrite(savePath, im) if DEBUG: calculation_log( 'tracking result file is exported at {}'.format(savePath)) return None
def get_autoTracking_Results(directory_path, camera_resolution, API_VER, exec_mode): ''' 追尾→特徴量抽出関数 ・パラメータ:dirpath : str ディレクトリパス camera_resolution : float カメラ分解能、[um/pix] exec_mode : str 起動モード、DEBUGでデバッグモード、文字列等出力 ''' flag_is_debugmode = (exec_mode == DEBUG_MODE) #デバッグモードの指定確認。 if flag_is_debugmode: calculation_log('analyse dir path = {}'.format(directory_path)) calculation_log('exec_mode = {}'.format(exec_mode)) flag_contour_select_was_done = False if flag_is_debugmode: calculation_log('contour selection function is calling') #輪郭抽出計算の実施。 try: contour_rsts, flag_image_modified_deeply = FindContourAnalysis.analyse_Images_List( directoryPath=directory_path, min_area_thresh=input_params_dic["min_area_thresh"], binarize_thresh=input_params_dic["binarize_thresh"], auto_binarize=input_params_dic["auto_binarize"], area_mirgin_detect_faced=input_params_dic["areaThresh_faced"], area_mirgin_detect_separation=input_params_dic[ "areaThresh_separated"], arc_length_mirgin_detect_separation=input_params_dic[ "arclengthThresh"], solidity_mirgin_detect_separation=input_params_dic[ "solidity_ratio_thresh"], noise_remove_topological_dist_thresh=input_params_dic[ "noise_remove_topological_dist_thresh"], noise_remove_area_thresh=input_params_dic[ "noise_remove_area_thresh"], mkdir=flag_is_debugmode, draw_contour=flag_is_debugmode, draw_convexhull=flag_is_debugmode, draw_coords=flag_is_debugmode, exportImage=flag_is_debugmode, draw_reg_Detected=flag_is_debugmode, DEBUG=flag_is_debugmode) flag_contour_select_was_done = True if flag_is_debugmode: calculation_log('contour selection was done') if contour_rsts is None: result = { "analysis_date_time": nan_to_minus1( datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')), "file_name": nan_to_minus1(directory_path), "condition": "num_files are not more than 2.", "camera_resolution[um/pix]": nan_to_minus1(camera_resolution), "API_VER": nan_to_minus1(API_VER), "CONTOUR_CODE_VER": nan_to_minus1(FindContourAnalysis.get_code_ver()), "AUTO_TRACKING_CODE_VER": nan_to_minus1(AutoTracking.get_code_ver()), "THRESH_VALUES_VER": THRESH_VALUES_VER, } return result #輪郭抽出失敗時処理 except: if flag_is_debugmode: calculation_log('contour_selection was failure.') result = { "analysis_date_time": datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S'), "filename": directory_path.split('/')[-1], 'condition': 'contour selection was failure.' } #輪郭抽出成功→疑似追尾実行 if flag_contour_select_was_done: flag_tracking_was_done = False #疑似追尾実施。 try: trackingResults = AutoTracking.auto_Tracking( dirPath=directory_path, rsts=contour_rsts, draw_Tracking_Results=flag_is_debugmode, draw_Fitting_Line=flag_is_debugmode, DEBUG=flag_is_debugmode) flag_tracking_was_done = True if flag_is_debugmode: calculation_log('auto_tracking was done') #疑似追尾失敗時処理 except: if flag_is_debugmode: calculation_log('auto_tracking was failed') result = { "analysis_date_time": datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S'), "filename": directory_path.split('/')[-1], 'condition': 'auto_tracking was failure.' } ##以下、吐出開始、分離検知ディレイ修正コマンド ##テスト版につきしばらく実行しない。 #疑似追尾成功→特徴量計算 if flag_tracking_was_done: try: #出力用の値の整理 #ファイル名取得 directory_path_show = directory_path.split('/')[-1] if flag_is_debugmode: calculation_log( 'dir_path is {}'.format(directory_path_show)) #1枚目輪郭数取得 num_first_contours = (float)(sum( contour_rsts.num_contours_at_first)) / (float)(len( contour_rsts.num_contours_at_first)) if flag_is_debugmode: calculation_log( 'num_first_contours is {}'.format(num_first_contours)) #solidity値取得 solidity = contour_rsts.solidity if flag_is_debugmode: calculation_log('solidity is {}'.format(solidity)) #arc_solidity値取得 arc_solidity = contour_rsts.arc_solidity if flag_is_debugmode: calculation_log('arc_solidity is {}'.format(arc_solidity)) #液滴吐出開始検知有無およびディレイ取得 flag_droplet_faced, faced_delay = contour_rsts.flag_faced_is_detected, contour_rsts.delay_faced if flag_is_debugmode: calculation_log( 'faced_delay is {} and flag_droplet_faced is {}'. format(faced_delay, flag_droplet_faced)) #液滴分離検知有無およびディレイ取得 flag_droplet_separated, separated_delay = contour_rsts.flag_separated_is_detected, contour_rsts.delay_separated if flag_is_debugmode: calculation_log( 'separated delay is {} and flag_separated_delay is {}'. format(separated_delay, flag_droplet_separated)) #最大リガメント長さおよびディレイ取得 max_regament_length_delay, max_regament_length = contour_rsts.delay_max_regament_detected, contour_rsts.max_regament_length if flag_is_debugmode: calculation_log( 'max_remament_length_delay is {} and the length is {}'. format(max_regament_length_delay, max_regament_length)) #メイン液滴平均速度および標準偏差取得 main_average_velocity, main_velocity_stdiv = trackingResults.Get_Main_Velocity( ) if flag_is_debugmode: calculation_log( 'main_ave_velocity is {} and main_velocity_stdiv is {}' .format(main_average_velocity, main_velocity_stdiv)) #メイン液滴角度取得 main_angle = trackingResults.Get_Main_Angle_degrees() if flag_is_debugmode: calculation_log('main_angle is {}'.format(main_angle)) #サテライト液滴平均速度および標準偏差取得 satellite_average_velocity, satellite_velocity_stdiv = trackingResults.Get_Satellite_Velocity( ) if flag_is_debugmode: calculation_log( 'satellite_ave_velocity is {} and satellite_velocity_stdiv is {}' .format(satellite_average_velocity, satellite_velocity_stdiv)) #サテライト液滴角度取得 satellite_angle = trackingResults.Get_Satellite_Angle_degrees() if flag_is_debugmode: calculation_log( 'satellite_angle is {}'.format(satellite_angle)) #実メイン液滴速度取得 main_average_velocity_stdized = main_average_velocity * camera_resolution if flag_is_debugmode: calculation_log('main_ave_vel_stdized is {}'.format( main_average_velocity_stdized)) #実サテライト液滴速度取得 satellite_average_velocity_stdized = satellite_average_velocity * camera_resolution if flag_is_debugmode: calculation_log('satellite_ave_vel_stdized is {}'.format( satellite_average_velocity_stdized)) #メイン-サテライト液滴角度差取得 diff_angle = abs( inf_to_value(main_angle) - inf_to_value(satellite_angle)) if flag_is_debugmode: calculation_log('diff_angle is {}'.format(diff_angle)) #逸脱液滴検出 flag_exotic_droplet, max_exotic_area = contour_rsts.Check_exotic_droplet_exists( trackingResults, thresh_values_dic['pix_mirgin']) if flag_is_debugmode: calculation_log('flag exotic droplet is {}'.format( flag_exotic_droplet)) #5分割領域ごとの各液滴速度、標準偏差取得 y_max = contour_rsts.analysisResults[0].contours[0].imgYMax if flag_is_debugmode: calculation_log('y_max = {}'.format(y_max)) y_diff = (float)(y_max) / (float)(num_div_velocity_layer) if flag_is_debugmode: calculation_log('y_diff = {}'.format(y_diff)) vel_add_dics = [] for i in range(num_div_velocity_layer): base = i * y_diff top = (i + 1) * y_diff main_vel_res = trackingResults.Get_Main_Velocity(base, top) sat_vel_res = trackingResults.Get_Satellite_Velocity( base, top) vel_add_dics.append({ "layered_main_{}_ave[pix/us]".format(i): nan_to_minus1(main_vel_res[0]), "layered_main_{}_stdiv[pix/us]".format(i): nan_to_minus1(main_vel_res[1]), "layered_sat_{}_ave[pix/us]".format(i): nan_to_minus1(sat_vel_res[0]), "layered_sat_{}_ave[pix/us]".format(i): nan_to_minus1(sat_vel_res[1]), }) if flag_is_debugmode: calculation_log( 'dic_elem_{} was generated as {}'.format( i, vel_add_dics[i])) #以下、テストコード leg_ref = (nan_to_minus1(contour_rsts.delay_separated) - nan_to_minus1(contour_rsts.delay_faced) ) * nan_to_minus1(main_average_velocity) leg_eval_ratio = nan_to_minus1(leg_ref) / nan_to_minus1( max_regament_length) print("leg_ref_is calculated") if nan_to_minus1(leg_eval_ratio) < 0: leg_eval_ratio = -1 contour_rsts.modify_faced_delay_and_freq_Y(trackingResults) contour_rsts.modify_separated_delay(trackingResults) print('modified_calculated') try: max_main_angle_disturbance = max([ abs(angle_elem - main_angle) for angle_elem in contour_rsts.get_main_angle_list(trackingResults) ]) max_satellite_angle_disturbance = max([ abs(angle_elem - satellite_angle) for angle_elem in contour_rsts.get_satellite_angle_list(trackingResults) ]) except: max_main_angle_disturbance = -1 max_satellite_angle_disturbance = -1 try: if flag_is_debugmode: print('draw start, directory_path is {}'.format( directory_path)) if not os.path.exists(directory_path + "/drawModifiedNozzleXY"): print('makedirs start for {}'.format( directory_path + "/drawModifiedNozzleXY")) os.makedirs(directory_path + "/drawModifiedNozzleXY", exist_ok=True) if flag_is_debugmode: calculation_log( 'mkdir at {}/drawModifiedNozzleXY'.format( directory_path)) print("globbing") pathes = glob.glob(directory_path + "/*.jpg") print("globed") signature_size = 5 print("path is {}".format(pathes[0])) im = cv2.imread(pathes[0]) print("imread") x = contour_rsts.modified_freq_X y = contour_rsts.modified_freq_Y im = cv2.rectangle(im,((int)(x-signature_size),(int)(y-signature_size)),((int)(x+signature_size),(int)(y+signature_size)),\ (0,0,255),3) print('imdrawn') savePath = directory_path + "/drawModifiedNozzleXY/" + os.path.splitext( os.path.basename(pathes[0]))[0] + "_modifiedXY.jpg" print('export succeed.') cv2.imwrite(savePath, im) del im except: calculation_log('drawing_modofied_XY_failure') #テストコード、ここまで #dictionaryへの出力 result = { "analysis_date_time": nan_to_minus1( datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S')), "file_name": nan_to_minus1(directory_path_show), "condition": "calculation was done.", "camera_resolution[um/pix]": nan_to_minus1(camera_resolution), "API_VER": nan_to_minus1(API_VER), "ave_num_contours_before_separation": nan_to_minus1(num_first_contours), "solidity[U]": nan_to_minus1(solidity), "arc_solidity[u]": nan_to_minus1(arc_solidity), "flag_droplet_faced": nan_to_minus1(flag_droplet_faced), "faced_delay[us]": nan_to_minus1(faced_delay), "flag_droplet_separated": nan_to_minus1(flag_droplet_separated), "separated_delay[us]": nan_to_minus1(separated_delay), "max_regament_delay[us]": nan_to_minus1(max_regament_length_delay), "max_regament_length[pix]": nan_to_minus1(max_regament_length), "most_freq_Y[pix]": nan_to_minus1(contour_rsts.freq_Y), "CONTOUR_CODE_VER": nan_to_minus1(FindContourAnalysis.get_code_ver()), "main_average_velocity[pix/us]": nan_to_minus1(main_average_velocity), "main_average_velocity[m/s]": nan_to_minus1(main_average_velocity_stdized), "main_velocity_stddiv[pix/us]": nan_to_minus1(main_velocity_stdiv), "main_angle[degrees]": nan_to_minus1(inf_to_value(main_angle)), "satellite_average_velocity[pix/us]": nan_to_minus1(satellite_average_velocity), "satellite_average_velocity[m/s]": nan_to_minus1(satellite_average_velocity_stdized), "satellite_velocity_stddiv[pix/us]": nan_to_minus1(satellite_velocity_stdiv), "satellite_angle[degrees]": nan_to_minus1(inf_to_value(satellite_angle)), "main-satellite_angle_diff[degrees]": nan_to_minus1(diff_angle), "main_linearity_error[pix]": nan_to_minus1( inf_to_value(trackingResults. Get_MainXY_Fit_Error_Min_Max_Range()[1]) - inf_to_value(trackingResults. Get_MainXY_Fit_Error_Min_Max_Range()[0])), "satellite_linearity_error[pix]": nan_to_minus1( inf_to_value(trackingResults. Get_SatelliteXY_Fit_Error_Min_Max_Range() [1]) - inf_to_value(trackingResults. Get_SatelliteXY_Fit_Error_Min_Max_Range() [0])), "AUTO_TRACKING_CODE_VER": nan_to_minus1(AutoTracking.get_code_ver()), "anormaly_ejections_at_first_image": nan_to_minus1(num_first_contours > 1.5), "main_velocity_is_too_fast": nan_to_minus1(main_average_velocity_stdized > thresh_values_dic['velocity_upperthresh']), "main_velocity_is_too_slow": nan_to_minus1(main_average_velocity_stdized < thresh_values_dic['velocity_lowerthresh']), "nozzle_needs_to_be_clean": nan_to_minus1( solidity > thresh_values_dic['Solidity_upperthresh']), "suspicious_visco-elasticity": nan_to_minus1( (separated_delay > thresh_values_dic["sep_thresh"]) and (main_average_velocity_stdized > thresh_values_dic["velocity_septhresh"])), "angle-diff_is_too_large": nan_to_minus1(( diff_angle > thresh_values_dic["diff_angle_thresh"] ) if not math.isnan(diff_angle) else True), "exotic-droplet_exists": nan_to_minus1(flag_exotic_droplet), "THRESH_VALUES_VER": THRESH_VALUES_VER, "RESERVED0": "layered_main_4_ave : leg_eval_ratio, layered_main_4_stdiv : max_exotic_area, layered_sat_4_ave : flag_image_modified_deeply, layered_sat_4_stdiv : max_main_angle_disturbance, layered_main_3_ave : max_satellite_angle_disturbance, layered_main_3_stdiv : modified_delay_faced, layered_sat_3_ave : modified_delay_separated, layered_sat_3_stdiv : modified_freq_Y, layered_main_2_ave : modified_freq_X", "RESERVED1": "aaa", "RESERVED2": "aaa", "RESERVED3": "aaa", "RESERVED4": "aaa", } #result = add_message(result) if flag_is_debugmode: calculation_log('json elem was exported.') #5分割各液滴速度 - 標準偏差結果追記 for dic_elem in vel_add_dics: result.update(dic_elem) result.update({ "layered_main_4_ave[pix/us]": nan_to_minus1(inf_to_value(leg_eval_ratio)), "layered_main_4_stdiv[pix/us]": nan_to_minus1(max_exotic_area), "layered_sat_4_ave[pix/us]": 1 if flag_image_modified_deeply else 0, "layered_sat_4_stdiv[pix/us]": nan_to_minus1(max_main_angle_disturbance), "layered_main_3_ave[pix/us]": nan_to_minus1(max_satellite_angle_disturbance), "layered_main_3_stdiv[pix/us]": nan_to_minus1(contour_rsts.modified_delay_faced), "layered_sat_3_ave[pix/us]": nan_to_minus1(contour_rsts.modified_delay_separated), "layered_sat_3_stdiv[pix/us]": nan_to_minus1(contour_rsts.modified_freq_Y), "layered_main_2_ave[pix/us]": nan_to_minus1(contour_rsts.modified_freq_X), }) if flag_is_debugmode: calculation_log(result) #計算失敗時処理 except: if flag_is_debugmode: calculation_log('get_feature_params was failure.') result = { "analysis_date_time": datetime.datetime.now().strftime('%Y-%m-%d_%H:%M:%S'), "filename": directory_path, 'condition': 'get_feature_params was failure.' } return result
def Check_exotic_droplet_exists(self, tracking_Results, pix_mirgin): ''' エキゾチック輪郭(逸脱輪郭)検出関数 Parameters ---------- tracking_Results : Tracking_Resultsクラス 追尾結果クラス pix_mirgin : int 逸脱判定時画像上マージン値[pix]、必ず正の値をとる。 Return ---------- flag_exotic_droplet_exists : bool 逸脱輪郭検出有無、Trueで逸脱輪郭検出 ''' if self.__DEBUG: calculation_log('eval cnts is called.') #追尾結果より、メイン-サテライト液滴トラッキング近似結果の取得 main_slope_params = tracking_Results.get_Main_vector_slope_intercept() sat_slope_params = tracking_Results.get_Satellite_vector_slope_intercept( ) if self.__DEBUG: calculation_log( 'slopes were calculated. main : {}, sat: {}'.format( main_slope_params, sat_slope_params)) #逸脱輪郭検出フラグの宣言 flag_exotic_droplet_exists = False cnt_exotic_areas = [] for cnt_list in self.analysisResults: flag_exotic_droplet_detected = False if self.__DEBUG: calculation_log('cnt_list with delay {} is called'.format( cnt_list.delay)) if len(cnt_list.contours) == 1: if self.__DEBUG: calculation_log('length is 1.') continue #通常輪郭存在領域の指定 #max_x:X座標右端、サテライトかメイン液滴x座標 + mirgin値の最大値 max_x = max([main_slope_params[0] * cnt_list.delay + main_slope_params[1] + pix_mirgin,\ sat_slope_params[0] * cnt_list.delay + sat_slope_params[1] + pix_mirgin]) #min_x:X座標左端、サテライトかメイン液滴x座標 - mirgin値の最大値 min_x = min([main_slope_params[0] * cnt_list.delay + main_slope_params[1] - pix_mirgin,\ sat_slope_params[0] * cnt_list.delay + sat_slope_params[1] - pix_mirgin]) #max_y:Y座標下端、メイン液滴y座標 + mirgin値、または画像下端Y座標の最大値 max_y = min([main_slope_params[2] * cnt_list.delay + main_slope_params[3] + pix_mirgin,\ cnt_list.contours[0].imgYMax]) #max_y:Y座標上端、サテライト液滴y座標 + mirgin値、または画像上端Y座標の最小値 min_y = max([sat_slope_params[2] * cnt_list.delay + sat_slope_params[3] - pix_mirgin,\ 0]) #吐出輪郭の検証 #ノズル輪郭は除く(ゆえにレンジは1からスタート) for i in range(1, len(cnt_list.contours)): cnt = cnt_list.contours[i] if self.__DEBUG: calculation_log( '{} th cnt with delay at {} is called'.format( i, cnt_list.delay)) #各輪郭の重心座標が上記4点で定義される矩形範囲に入るか否かを判定する。 flag_exotic_droplet_detected = (cnt.center_X < min_x) or ( cnt.center_X > max_x) or (cnt.center_Y < min_y) or (cnt.center_Y > max_y) if flag_exotic_droplet_detected: if self.__DEBUG: calculation_log( 'exotic droplet occured at {} us, X : {}, Y : {} at min_x : {}, max_x : {}, min_y : {}, max_y : {}' .format(cnt_list.delay, cnt.center_X, cnt.center_Y, min_x, max_x, min_y, max_y)) flag_exotic_droplet_exists = True cnt_exotic_areas.append(cnt.area) else: if self.__DEBUG: calculation_log( 'cnt at delay{} does not contain exotic droplets'. format(cnt_list.delay)) ret_max_areas = max( cnt_exotic_areas) if len(cnt_exotic_areas) != 0 else 0 return flag_exotic_droplet_exists, ret_max_areas
def __set_main_Y_of_nozzle(self): if self.__DEBUG: calculation_log('set nozzle_main_Y') self.main_Y_of_nozzle = self.contours[0].main_Y return None
def __remove_noise(self): ''' 画像ノイズ除去関数 輪郭画像から固定位置に決まって出現する小さい輪郭(=カメラに映ったごみ)を削除。 ノズルを除く各輪郭に対して、輪郭近似度を定義し計算。 輪郭近似度がthresh以下のものに対して、削除判定。 削除判定時、面積がself.noise_remove_area_thresh以上のものは削除しない。 コンストラクタより呼び出し。 Parameters ---------- なし Return ---------- なし ''' if self.__DEBUG: calculation_log('noise_remove method is called') removeIndexList = [] flagAllRemoveIsSucceed = True #以下、削除先データの削除。 #i,jのアサインが変わるのでこの段階では削除元のデータは削除しない。 #検索順はi, j昇順なので、削除元のデータのindexは削除後に再度別の輪郭の削除が生じても変化はしない。 for i in range(len(self.analysisResults)): # print('{}'.format(i)) for j in range(1, len(self.analysisResults[i].contours)): # print('{}'.format(j)) flagDelDone = False for k in range(i + 1, len(self.analysisResults)): # print('{}'.format(k)) for l in range(1, len(self.analysisResults[k].contours)): # print('{}'.format(l)) if self.__get_CntDist_is_closer( self.analysisResults[i].contours[j], self.analysisResults[k].contours[l], self.__noise_remove_topological_dist_thresh): area = self.analysisResults[k].contours[l].area if area < self.__noise_remove_area_thresh: # print('{}, {}, will be deled'.format(k, l)) if self.__DEBUG: calculation_log( 'contour with X,Y = {}, {} and area = {} was deleted as noise' .format( self.analysisResults[k]. contours[l].main_X, self.analysisResults[k]. contours[l].main_Y, self.analysisResults[k]. contours[l].area)) lists = self.analysisResults[k].contours.pop(l) # print('{}, {}, del done'.format(k, l)) flagDelDone = True break if flagDelDone == True: removeIndexList.append( [i, j, self.analysisResults[i].contours[j]]) # print('first_remove was done') #以下、削除元データの削除。 flagAllRemoveIsSucceed = False for removeElem in removeIndexList: testList = [ cnt for cnt in self.analysisResults[removeElem[0]].contours if not removeElem[2].is_equal(cnt) ] if len(testList) != 0: self.analysisResults[removeElem[0]].contours = testList flagAllRemoveIsSucceed = True return flagAllRemoveIsSucceed
def analyse_Image(delay, path, min_area_thresh, binarize_thresh, auto_binarize, draw_contour, draw_convexhull, draw_coords, exportImage, mkdir, flag_export_fillImg, DEBUG): ''' 画像読み込み→輪郭抽出→データ格納関数 Parameters ---------------------- delay : float ディレイ時間[ux] path : str ファイル名 min_area_thresh : float 輪郭面積最小値、この値以下はノイズと見做す。 binarize_thresh : int 二値化時閾値、auto_binarize = Falseで本値を利用。 auto_binarize : bool 自動二値化実行。大津の方法で実行する。 draw_contour : bool 輪郭描画フラグ draw_convexhull : bool 凸包輪郭描画フラグ draw_coords : bool 各座標描画フラグ exportImage : bool 画像出力フラグ mkdir : bool ディレクトリ生成フラグ flag_export_fillImg : bool 輪郭穴埋め結果描画フラグ DEBUG : bool デバッグモード起動 Returns ---------------------- cntResults : Analysis_Resultクラス 輪郭抽出結果。画像内にある結果を一括で出力。 ''' if DEBUG: calculation_log( 'import file is {} with the fill img flag is {}'.format( path, flag_export_fillImg)) flag_image_modify_deeply = False #BGR画像の読み込み img = cv2.imread(path) if DEBUG: calculation_log('image file {} was imported'.format(path)) #ガウシアンによるぼかし。バックグラウンドノイズの除去 # img = cv2.GaussianBlur(img,(9, 9),3) #ガンマ関数 # img = gamma_function(img) #画像のグレイスケール化 im = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #エッジ強調フィルタのテスト。余計な計算コストとノイズを拾いやすくなることから様子見。 # kernel = np.array([[-1,-1,-1], # [-1,9,-1], # [-1,-1,-1]]) # im = cv2.filter2D(im, -1, kernel) #二値化、オートバイナライズか否かで挙動違う ret, im_bin = cv2.threshold(im, binarize_thresh, 255, (cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) if auto_binarize else (cv2.THRESH_BINARY_INV)) ret = ret - 1 #輪郭抽出 contours, hierarchy = cv2.findContours(im_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #閾値でフィルタ contours = [ cnt for cnt in contours if cv2.contourArea(cnt) > min_area_thresh ] #インデックス値宣言、輪郭X座標インデックス、Y座標インデックスを指定。 indX, indY = 0, 1 imgYMax, _ = im.shape yMax_at_largest_contour = max(contours[0], key=lambda pt2: pt2[0, 1])[0, 1] calculation_log( 'ymax_at_largest_contour is {}'.format(yMax_at_largest_contour)) if yMax_at_largest_contour == imgYMax - 1: contours.pop(0) calculation_log('delete bottom noise') #以下、ノズル輪郭補正 #ターゲットとなる輪郭を抽出(ノズル輪郭は必ず画像上端にあるため、輪郭のうち少なくとも1つはY = 0を含む) targetCnts = [ cnt for cnt in contours if any([pt[0, indY] == 0 for pt in cnt]) ] if DEBUG: calculation_log('the length of contour with Y = 0 point is {}'.format( len(targetCnts))) #ターゲット輪郭が存在する場合 #targetCntがただ1つ→それはノズルがただ1つのブロブとして輪郭検出されていることを示す。 if len(targetCnts) == 1: #ターゲット輪郭内部のヴォイドを検出 #Y = 0なる輪郭点を抽出 ptZeroList = [Pt for Pt in targetCnts[0] if Pt[0, indY] == 0] #Y = 0なる輪郭点のうちの最大値と最小値を検出→ノズル両端の座標 leftX, rightX = min([pt[0, indX] for pt in ptZeroList ]), max([pt[0, indX] for pt in ptZeroList]) #理想的な輪郭抽出が実行されている場合、ノズル両端座標間の輪郭は必ず直線であるため、cv2.CHAIN_APPROX_SIMPLEでの検出では #ノズル両端を結ぶ輪郭内部にY = 0となる別の点が含まれることは無い。逆に、そのような点が存在する場合はノズル輪郭内部にて #輪郭が分割されない程度のヴォイドが発生していることを示す。 #以下はそのようなヴォイドの有無を抽出するコード、すなわち輪郭両端座標内部(両端座標を除く)にてY == 0なる輪郭を抽出している。 ptZeroListInnerVoid = [ Pt for Pt in targetCnts[0] if Pt[0][indY] == 0 and Pt[0][indX] > leftX and Pt[0][indX] < rightX ] if DEBUG: calculation_log('length of voided contour at nozzle is {}'.format( len(ptZeroListInnerVoid))) #ヴォイドが存在する場合 if len(ptZeroListInnerVoid) != 0: #ヴォイド構成点の最も左端の座標を取得 inner_leftX = min([pt[0, indX] for pt in ptZeroListInnerVoid]) inner_leftPt = [ Pt for Pt in ptZeroListInnerVoid if Pt[0][indX] == inner_leftX ][0] #ヴォイド構成点の最も右端の座標を取得 inner_rightX = max([pt[0, indX] for pt in ptZeroListInnerVoid]) inner_rigntPt = [ Pt for Pt in ptZeroListInnerVoid if Pt[0][indX] == inner_rightX ][0] #targetCnts[0]輪郭構成点群における、ヴォイド最左端、最右端点のインデックスを取得。 #以下は、targetCnts[0]内部にinner_leftPtと一致する座標を抽出する。 #ただし、以下の関数ではnumpyの仕様から、X座標の一致とY座標の一致を別に検出してしまうため、 #一旦ことごとく検出し、unique関数を用いて一致座標を座標一致回数とともに抽出する。 u_left, counts_left = np.unique( np.where(targetCnts[0] == inner_leftPt)[0], return_counts=True) #X、Y座標ともに一致する場合は抽出回数が2であり、これはただ1つ存在するため #そのような座標を抽出した後にインデックスを取得する。 inner_left_index = u_left[counts_left > 1][0] #最右端座標に関しても同様の処理をする。 u_right, counts_right = np.unique( np.where(targetCnts[0] == inner_rigntPt)[0], return_counts=True) inner_right_index = u_right[counts_right > 1][0] #OpenCVの輪郭抽出においては、閉輪郭抽出の場合、必ずそのインデックス順序は #最も左上の座標を基点に反時計回りに振られる。 #従い、ノズル輪郭上部に存在するヴォイドは、上記アルゴリズムで取得したヴォイドの最右端および最左端部インデックスの間の点である。 voidContour = targetCnts[0][inner_right_index:inner_left_index] #ヴォイド構成点要素数が存在する場合(これしかありえないが、例外除け) if len(voidContour) != 0: #ヴォイド輪郭を完全に覆う最小の長方形の最小X、最大X、最大Y座標を取得する。(最小Yは必ず0である。) left_X_min = min([vCnt[0][0] for vCnt in voidContour]) right_X_Max = max([vCnt[0][0] for vCnt in voidContour]) Y = max([vCnt[0][1] for vCnt in voidContour]) img = cv2.fillConvexPoly(img, voidContour, color=(ret, ret, ret)) #img = cv2.rectangle(img, (left_X_min, 0), (right_X_Max, Y), (0,0,0), -1) if DEBUG: calculation_log( 'img is filled with rectangle Xleft = {}, Xright = {}, Y = {}' .format(left_X_min, right_X_Max, Y)) #塗りつぶし画像出力する処理 if flag_export_fillImg: if not os.path.exists(os.path.dirname(path) + "/fillCnts"): os.makedirs(os.path.dirname(path) + "/fillCnts", exist_ok=True) savePath = (os.path.dirname(path) + '/fillCnts/'+ os.path.splitext(os.path.basename(path))[0] +\ '_fillCnts.jpg') if mkdir else (os.path.splitext(path)[0] + "_fillCnts.jpg") cv2.imwrite(savePath, img) #以下、塗りつぶした画像に対して、グレイスケール化→二値化→輪郭抽出やり直し im = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, im_bin = cv2.threshold( im, binarize_thresh, 255, (cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) if auto_binarize else (cv2.THRESH_BINARY_INV)) #輪郭抽出 contours, hierarchy = cv2.findContours(im_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #閾値でフィルタ contours = [ cnt for cnt in contours if cv2.contourArea(cnt) > min_area_thresh ] #ターゲット輪郭要素数が2つ以上の場合:これは、輪郭がスプリットするくらいにノズル内部輪郭が白くなっているため #上記戦略が取れない。従い、分割された輪郭全てを覆うような長方形を生成し塗りつぶす。 if len(targetCnts) > 1: #各ターゲット輪郭のY = 0なる点を取得 ptZeroListList = [[Pt for Pt in tgt if Pt[0, indY] == 0] for tgt in targetCnts] if DEBUG: calculation_log( 'nozzle contour is completely separated, filling processing is now called.' ) #各ターゲット輪郭の最大X座標の最大値、および最小X座標の最小値を取得(それぞれ、最左端、最右端座標となる) leftX = min([min([p[0, indX] for p in pts]) for pts in ptZeroListList]) rightX = max( [max([p[0, indX] for p in pts]) for pts in ptZeroListList]) #輪郭抽出近似を外し、輪郭を構成する全ての座標を抽出。 #Y座標決定にて、直線部は近似されているため最頻出Y座標とノズルY座標が一致しない可能性が高い。 #近似を外し、全ての構成点を取得することで、実際のY座標と最頻出Y座標を一致させる。 #黒塗りをするY座標を、分割輪郭の面積にて重み付けした期待値として取得する。 #最頻出Y座標は、極小面積のノイズの影響を小さくするため面積にて重み付けした。 contours, hierarchy = cv2.findContours(im_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) #閾値でフィルタ contours = [ cnt for cnt in contours if cv2.contourArea(cnt) > min_area_thresh ] #再度ターゲットY座標を取得 targetCnts = [ cnt for cnt in contours if any([pt[0, indY] == 0 for pt in cnt]) ] #以下、最頻出Yと対象輪郭面積を取得 freqNum_YList = [] for tgtCnt in targetCnts: freqNum_PtList = [] for key, ptGroup in groupby(tgtCnt, key=lambda pt: pt[0][1]): listPtGroup = list(ptGroup) freqNum_PtList.append([len(listPtGroup), key]) freqNum_PtList = [[pt[0], pt[1]] for pt in freqNum_PtList if pt[1] != 0] freqNum_PtList.sort(key=lambda elem: elem[0]) freqNum_YList.append([ freqNum_PtList[-1][0], freqNum_PtList[-1][1], cv2.contourArea(tgtCnt) ]) #重みとY座標の積リストを取得 YAreas = sum([lst[1] * lst[2] for lst in freqNum_YList]) #面積リストを取得 Areas = sum([lst[2] for lst in freqNum_YList]) #Y座標の期待値を算出 Y_ = (int)(YAreas / Areas) #長方形を黒で塗りつぶす。 img = cv2.rectangle(img, (leftX, 0), (rightX, Y_), (ret, ret, ret), -1) flag_image_modify_deeply = True if DEBUG: calculation_log( 'img is filled with rectangle Xleft = {}, Xright = {}, Y = {}'. format(leftX, rightX, Y_)) #塗りつぶし画像出力する処理 if flag_export_fillImg: if not os.path.exists(os.path.dirname(path) + "/fillCnts"): os.makedirs(os.path.dirname(path) + "/fillCnts", exist_ok=True) savePath = (os.path.dirname(path) + '/fillCnts/'+ os.path.splitext(os.path.basename(path))[0] +\ '_fillCnts.jpg') if mkdir else (os.path.splitext(path)[0] + "_fillCnts.jpg") cv2.imwrite(savePath, img) #以下、二値化→輪郭抽出やり直し im = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ret, im_bin = cv2.threshold(im, binarize_thresh, 255, (cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU) if auto_binarize else (cv2.THRESH_BINARY_INV)) #輪郭抽出 contours, hierarchy = cv2.findContours(im_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) #閾値でフィルタ contours = [ cnt for cnt in contours if cv2.contourArea(cnt) > min_area_thresh ] #輪郭面積でソート contours.sort(key=lambda cnt: cv2.contourArea(cnt), reverse=True) if len(contours) > num_evaluate_contour_max: contours = contours[:num_evaluate_contour_max] yMax_at_largest_contour = max(contours[0], key=lambda pt2: pt2[0, 1])[0, 1] ymin_at_largest_contour = min(contours[0], key=lambda pt2: pt2[0, 1])[0, 1] calculation_log('ymax_at_largest_contour is {} after modified'.format( yMax_at_largest_contour)) if yMax_at_largest_contour == imgYMax - 1: contours.pop(0) imgYMax = ymin_at_largest_contour calculation_log('delete bottom noise') if DEBUG: calculation_log('the length of contours is {}'.format(len(contours))) #輪郭結果格納リストの宣言 cntResults = [] #サテライトY順に降順ソート contours.sort(key=lambda cnt: min(cnt, key=lambda pt2: pt2[0, 1])[0, 1]) #各輪郭に対する処理 for cnt in contours: #輪郭面積 area = cv2.contourArea(cnt) #周囲長 perimeter = cv2.arcLength(cnt, True) #凸包輪郭計算 hull = cv2.convexHull(cnt) #凸包面積 convArea = cv2.contourArea(hull) #凸包周囲長さ convPerimeter = cv2.arcLength(hull, True) #モーメント計算 M = cv2.moments(cnt) #重心X cx = int(M['m10'] / M['m00']) #重心Y cy = int(M['m01'] / M['m00']) #Y座標最大のpt左側にて yMax = max(cnt, key=lambda pt2: pt2[0, 1])[0, 1] pt_yMax_xLeft = [pt for pt in cnt if pt[0, 1] == yMax][0][0] pt_yMax_xRight = [pt for pt in cnt if pt[0, 1] == yMax][-1][0] main_X = (pt_yMax_xLeft[0] + pt_yMax_xRight[0]) / 2 main_Y = pt_yMax_xRight[1] #Y座標最小のpt左側にて ymin = min(cnt, key=lambda pt2: pt2[0, 1])[0, 1] pt_yMin_xLeft = [pt for pt in cnt if pt[0, 1] == ymin][0][0] pt_yMin_xRight = [pt for pt in cnt if pt[0, 1] == ymin][-1][0] satellite_X = (pt_yMin_xLeft[0] + pt_yMin_xRight[0]) / 2 satellite_Y = pt_yMin_xLeft[1] if DEBUG: calculation_log( 'contour was analysed with main_y : {}'.format(main_Y)) #体積と最頻Y座標を取得 cntList = cnt.tolist() cntList.sort(key=lambda pt: pt[0][1]) volume = 0.0 freqNum_PtList = [] for key, ptGroup in groupby(cntList, key=lambda pt: pt[0][1]): listPtGroup = list(ptGroup) freqNum_PtList.append([len(listPtGroup), key]) if len(listPtGroup) > 0: x_min = min(listPtGroup, key=lambda pt2: pt2[0][0])[0][0] x_max = max(listPtGroup, key=lambda pt2: pt2[0][0])[0][0] volume = volume + ((x_max - x_min) / 2.0)**2 * math.pi freqNum_PtList.sort(key=lambda freqnum_pt: freqnum_pt[0]) freq_num, freq_Y = freqNum_PtList[-1][0], freqNum_PtList[-1][1] if DEBUG: calculation_log( 'contour was analysed with freq_Y : {}'.format(freq_Y)) #解析結果の格納 retResultTmp = Contour_Elem.Analysis_Result( delay=delay, main_X=main_X, main_Y=main_Y, satellite_X=satellite_X, satellite_Y=satellite_Y, area=area, arclength=perimeter, center_X=cx, center_Y=cy, convex_hull_contour_area=convArea, convex_hull_contour_arclength=convPerimeter, imgYMax=imgYMax, volume=volume, freq_num=freq_num, freq_Y=freq_Y, DEBUG=DEBUG) if DEBUG: calculation_log('cnt_class with main_Y is {} is generated'.format( retResultTmp.main_Y)) #解析結果のリストへの追加 cntResults.append(retResultTmp) if DEBUG: calculation_log('cnt with main_Y is {} is appended'.format( cntResults[-1].main_Y)) cntResults = [cnt for cnt in cntResults if cnt.main_Y <= imgYMax] cntResults.sort(key=lambda res: res.satellite_Y) #面積で降順ソート analysis_contours = Analysis_Results_Class.Analysis_Results( delay, cntResults, DEBUG) if DEBUG: calculation_log('length of cntResults is {}'.format(len(cntResults))) #以下、画像出力対応 if exportImage: #ディレクトリ作製 if mkdir: if not os.path.exists(os.path.dirname(path) + "/drawRsts"): os.makedirs(os.path.dirname(path) + "/drawRsts", exist_ok=True) if DEBUG: calculation_log('mkdir at {}/drawRsts'.format( os.path.dirname(path))) #輪郭描画 if draw_contour: #面積最大の輪郭のみ太線で描画 img = cv2.drawContours(img, [contours[0]], -1, (0, 255, 0), 2) if len(contours) > 1: img = cv2.drawContours(img, contours[1:], -1, (0, 255, 0), 1) #凸包輪郭描画 if draw_convexhull: #凸包輪郭取得 hulls = [cv2.convexHull(cnt) for cnt in contours] #描画、面積最大のみ太線 img = cv2.drawContours(img, [hulls[0]], -1, (255, 255, 0), 2) if len(hulls) > 1: img = cv2.drawContours(img, hulls[1:], -1, (255, 255, 0), 1) #座標描画 if draw_coords: for i in range(len(cntResults)): main_X = cntResults[i].main_X main_Y = cntResults[i].main_Y img = cv2.rectangle(img, ((int)(main_X - 5), (int)(main_Y - 5)), ((int)(main_X + 5), (int)(main_Y + 5)), (0, 0, 255), 2 if i == 0 else 1) satellite_X = cntResults[i].satellite_X satellite_Y = cntResults[i].satellite_Y img = cv2.rectangle(img, ((int)(satellite_X - 5), (int)(satellite_Y - 5)), ((int)(satellite_X + 5), (int)(satellite_Y + 5)), (0, 255, 255), 2 if i == 0 else 1) center_X = cntResults[i].center_X center_Y = cntResults[i].center_Y img = cv2.rectangle(img, ((int)(center_X - 5), (int)(center_Y - 5)), ((int)(center_X + 5), (int)(center_Y + 5)), (255, 255, 255), 2 if i == 0 else 1) #ファイルパス生成 savePath = (os.path.dirname(path) + '/drawRsts/'+ os.path.splitext(os.path.basename(path))[0] + \ '_drawResult.jpg') if mkdir else (os.path.splitext(path)[0] + "_drawResult.jpg") #ファイル生成 cv2.imwrite(savePath, img) if DEBUG: calculation_log('export image at {}'.format(savePath)) #メモリ解放 del img del im del contours gc.collect() #輪郭解析結果リストを返す return analysis_contours, flag_image_modify_deeply
def __init__(self, analysis_results_list, area_mirgin_detect_faced, area_mirgin_detect_separation, arc_length_mirgin_detect_separation, solidity_mirgin_detect_separation, noise_remove_topological_dist_thresh, noise_remove_area_thresh, DEBUG): ''' コンストラクタ 1:単純な輪郭データ群をディレイ時間でgroupByの後にリストとして格納 2:ノイズを除去 3:特徴量計算しクラス変数に格納 Parameters ---------- analysis_results_list : [Analysis_Result] 輪郭解析結果群 area_mirgin_detect_faced : float 液滴吐出開始検知閾値面積 [pix] area_mirgin_detect_separation : float 液滴分離検知閾値面積[pix] arc_length_mirgin_detect_separation : float 液滴分離検知閾値輪郭長[pix] solidity_mirgin_detect_separation : float 液滴分離検知閾値solidity [U] noise_remove_topological_dist_thresh : float ノイズ除去時輪郭類似判定用の位相空間距離 [U] nosie_remove_area_thresh : int ノイズ除去時輪郭面積上限[pix] DEBUG : bool デバッグモード判定 ''' if DEBUG: calculation_log('constructor was called.') if DEBUG: calculation_log('set params to class_field parameters.') analysis_results_list = [ rsts for rsts in analysis_results_list if len(rsts.contours) != 0 ] #ディレイ時間にて昇順ソートしanalysisResultsに格納 analysis_results_list.sort(key=lambda rst: rst.delay) self.analysisResults = analysis_results_list #以下、プロパティのセット self.__DEBUG = DEBUG self.__area_mirgin_detect_faced = area_mirgin_detect_faced self.__area_mirgin_detect_separation = area_mirgin_detect_separation self.__arc_length_mirgin_detect_separation = arc_length_mirgin_detect_separation self.__solidity_mirgin_detect_separation = solidity_mirgin_detect_separation self.__noise_remove_topological_dist_thresh = noise_remove_topological_dist_thresh self.__noise_remove_area_thresh = noise_remove_area_thresh if DEBUG: calculation_log( 'set params to class_field parameters was completed.') #ノイズ除去関数によるノイズ除去 self.__remove_noise() if DEBUG: calculation_log('noises was removed.') #パラメータセット関数によるパラメータセット self.__set_solidity() self.__set_droplet_faced() self.__set_droplet_separated() self.__set_regament_max() self.__set_arc_solidity() self.__set_volume() self.__set_freq_Y() self.__set_num_initial_contour() self.__set_magnitude_of_doublet_droplet() if DEBUG: calculation_log('set feature params was completed.') return None
def auto_Tracking( dirPath, #フォルダパス, str rsts, #解析する輪郭群、analysis_result_list class draw_Tracking_Results, #追尾結果の出力 draw_Fitting_Line, #フィッティング結果の描画, DEBUG #デバッグモード指定 ): """ 輪郭群抽出結果から液滴追尾結果を生成する関数 Parameters ---------- dirPath : str 入力画像を格納するディレクトリパス。 rsts : FindContourAnalysis.Analysis_Results_Listクラス 解析対象の輪郭抽出結果群。 draw_Tracking_Results : bool 追尾結果の出力の有無、初期値False draw_Fitting_Line : bool フィッティング結果の描画、初期値False Returns ------- tracking_Results : Tracking_Resultsクラス 追尾結果。 """ if DEBUG: calculation_log('Auto_Tracking module was called.') #結果格納クラス宣言 tracking_Results = Tracking_Results_Class.Tracking_Results() #輪郭格納データ配列のインデックス宣言 #analysisResultsリストの2つめにて指定。 index_delay = 0 #ディレイのインデックス index_Cnt = 1 #輪郭リストのインデックス #メイン液滴の追尾 if rsts.flag_faced_is_detected == True: #追尾対象の抽出 rstsMain = [ rst for rst in rsts.analysisResults if rst.delay >= rsts.delay_faced ] #ディレイ順に昇順ソート rstsMain.sort(key=lambda rst: rst.delay) #検出開始時のメイン液滴座標のディレイと座標格納、面積最大の輪郭にて tracking_Results.Set_MainXY(rstsMain[0].delay, rstsMain[0].contours[0].main_X, rstsMain[0].contours[0].main_Y) #追尾対象のディレイ写真が2枚以上の場合 if len(rstsMain) > 1: #追尾検出2枚目の検出 if len(rstsMain[1].contours) > 1: #対象輪郭が2つ以上の場合、初回の結果との距離順にソート。ソート後、最近傍のメイン液滴を格納。 rstsMain[1].contours.sort( key=lambda rst: (rst.main_X - tracking_Results.results[0].main_X)**2 + (rst.main_Y - tracking_Results.results[0].main_Y)**2) #追尾検出2枚目のディレイと座標格納 tracking_Results.Set_MainXY(rstsMain[1].delay, rstsMain[1].contours[0].main_X, rstsMain[1].contours[0].main_Y) #追尾検出3枚目以降 for i in range(2, len(rstsMain)): #ソート基準座標の計算 #ディレイ比計算 delayRatio = (rstsMain[i].delay - rstsMain[i - 2].delay) / ( rstsMain[i - 1].delay - rstsMain[i - 2].delay) #予想基準座標算出 ptEval_X = tracking_Results.results[-2].main_X + delayRatio * ( tracking_Results.results[-1].main_X - tracking_Results.results[-2].main_X) ptEval_Y = tracking_Results.results[-2].main_Y + delayRatio * ( tracking_Results.results[-1].main_Y - tracking_Results.results[-2].main_Y) #予想Y座標が画像Y座標最大値より大きい場合は追尾打ち切り if ptEval_Y >= rstsMain[i].contours[0].imgYMax: if DEBUG: calculation_log( 'main_tracking is stopped caused by the imgY_limitation at delay {}' .format(rstsMain[i].delay)) break #評価輪郭数0の場合は打ち切り if len(rstsMain[i].contours) == 0: if DEBUG: calculation_log( 'main_tracking is stopped caused by zero evaluatable contours at delay {}' .format(rstsMain[i].delay)) break #評価点が2点以上の場合の処理 if len(rstsMain[i].contours) > 1: #評価基準点と各輪郭のメイン液滴座標距離順に輪郭群をソート。ソート後、最近傍のメイン液滴を格納。 rstsMain[i].contours.sort(key=lambda rst: ( rst.main_X - ptEval_X)**2 + (rst.main_Y - ptEval_Y)**2) #最近傍座標が画像際下端より下に来た場合は打ち切り if rstsMain[i].contours[0].main_Y > rstsMain[i].contours[ 0].imgYMax: if DEBUG: calculation_log( 'main_tracking is stopped caused by most_plausible main_Y over imgYMax at delay {}' .format(rstsMain[i].delay)) break #最近傍座標が一つ前の結果より上に来た場合は打ち切り if rstsMain[i].contours[0].main_Y < tracking_Results.results[ -1].main_Y: if DEBUG: calculation_log( 'main_tracking is stopped caused by inverse_direction_main_Y at delay {}' .format(rstsMain[i].delay)) break #検出結果の格納 tracking_Results.Set_MainXY(rstsMain[i].delay, rstsMain[i].contours[0].main_X, rstsMain[i].contours[0].main_Y) if DEBUG: calculation_log('main_tracking was completed.') #サテライト液滴の追尾 flag_sat_is_trackable = True if rsts.flag_separated_is_detected == True: #追尾対象の抽出 rstsSatellite = [ rst for rst in rsts.analysisResults if rst.delay >= rsts.delay_separated ] #ディレイ順に昇順ソート rstsSatellite.sort(key=lambda rst: rst.delay) #1枚目の輪郭数カウント、2以上でソート if len(rstsSatellite[0].contours) > 1: #面積順で輪郭リストをソート、降順 rstsSatellite[0].contours.sort(key=lambda cnt: cnt.area, reverse=True) #対象輪郭の抽出、面積最大→ノズルの検出 rstBase = rstsSatellite[0].contours[0] #satelliteのY座標がノズルのY座標より下に来るもののみ抽出 rstAdd = [ rst for rst in rstsSatellite[0].contours if rst.satellite_Y >= rstBase.main_Y ] if len(rstAdd) == 0: flag_sat_is_trackable = False if len(rstAdd) == 1: rstAdd else: #一つ前の結果からの距離順にて昇順ソート。 rstAdd.sort( key=lambda rst: (rst.satellite_Y - rstBase.main_Y)**2) if flag_sat_is_trackable: #1枚目輪郭の結果格納 tracking_Results.Set_SatelliteXY(rstsSatellite[0].delay, rstAdd[0].satellite_X, rstAdd[0].satellite_Y) #追尾対象のディレイ写真が2枚以上の場合 if len(rstsSatellite) > 1: #追尾検出2枚目の検出 #2枚目に格納されている輪郭情報が2以上の場合 if len(rstsSatellite[1].contours) > 1: #サテライト液滴X座標がnanではないものを抽出。 lstSat = list( filter(lambda rst: not math.isnan(rst.satellite_X), tracking_Results.results)) #satelliteのY座標が一つ前のY座標より下に来るもののみ抽出 rstAdd = [ rst for rst in rstsSatellite[1].contours if rst.satellite_Y >= lstSat[-1].satellite_Y ] print(len(rstAdd)) if len(rstAdd) > 0: #一つ前の結果からの距離順にて昇順ソート。 rstAdd.sort( key=lambda rst: (rst.satellite_X - lstSat[-1].satellite_X)**2 + (rst.satellite_Y - lstSat[-1].satellite_Y)**2) else: rstAdd = sorted( lstSat, key=lambda rst: (rst.satellite_X - lstSat[-1].satellite_X)**2 + (rst.satellite_Y - lstSat[-1].satellite_Y)**2) else: #対象の輪郭が1つの場合、そのまま結果の格納用オブジェクトをコピー rstAdd = rstsSatellite[1].contours #サテライト液滴追尾結果の格納 tracking_Results.Set_SatelliteXY(rstsSatellite[1].delay, rstAdd[0].satellite_X, rstAdd[0].satellite_Y) print('2nd added') #追尾検出3枚目以降 for i in range(2, len(rstsSatellite)): #i枚目の輪郭格納結果数が0であれば打ち切り if len(rstsSatellite[i].contours) == 0: break #すでに格納されている結果から、satellite_X座標がnanではないものを抽出。 lstSat = list( filter(lambda rst: not math.isnan(rst.satellite_X), tracking_Results.results)) #ひとつ前の結果のサテライトY座標より下にサテライトY座標がくるもののみを抽出 rstAdd = [ rst for rst in rstsSatellite[i].contours if rst.satellite_Y >= lstSat[-1].satellite_Y ] #抽出結果数が0であれば打ち切り if len(rstAdd) == 0: break #抽出結果を、ひとつ前のサテライト座標からの距離順に昇順ソート→最も近いものをサテライト液滴として採用。 rstAdd.sort(key=lambda rst: (rst.satellite_X - lstSat[-1].satellite_X)**2 + (rst.satellite_Y - lstSat[-1].satellite_Y)**2) #サテライト検出結果を格納 tracking_Results.Set_SatelliteXY(rstsSatellite[i].delay, rstAdd[0].satellite_X, rstAdd[0].satellite_Y) if DEBUG: calculation_log('satellite_tracking was completed.') for elem in tracking_Results.results: calculation_log( 'delay : {}us, main_X : {}, main_Y : {}, sat_X : {}, sat_Y : {}' .format(elem.delay, elem.main_X, elem.main_Y, elem.satellite_X, elem.satellite_Y)) #格納結果をディレイ時間に対して昇順でソート tracking_Results.results.sort(key=lambda rst: rst.delay) if DEBUG: calculation_log('results objects were sorted with rst.delay.') #追尾結果の描画指定の場合 if draw_Tracking_Results: #追尾結果描画関数の呼び出し try: drawTrackingResult(dirPath=dirPath, trackingRsts=tracking_Results, draw_Fitting_Line=draw_Fitting_Line, DEBUG=DEBUG) except: if DEBUG: calculation_log('auto_tracking_export_failure.') #指定したディレクトリパスをprint(!!!後ほどコメントアウト!!!) print(dirPath) #追尾結果を返す return tracking_Results
def analyse_Images_List(directoryPath, min_area_thresh, binarize_thresh, auto_binarize, area_mirgin_detect_faced, area_mirgin_detect_separation, arc_length_mirgin_detect_separation, solidity_mirgin_detect_separation, noise_remove_topological_dist_thresh, noise_remove_area_thresh, mkdir, draw_contour, draw_convexhull, draw_coords, exportImage, draw_reg_Detected, DEBUG): ''' 画像ディレクトリ→連続輪郭解析関数 Parameters ---------------------- directoryPath : str 解析ディレクトリ名 min_area_thresh : float 最小面積閾値[pix] binarize_thresh : int 二値化閾値 auto_binarize : bool 自動二値化(大津の方法)実行 area_mirgin_detect_faced : float 液滴吐出開始検知閾値[pix] area_mirgin_detect_separation : float 液滴分離検知面積閾値[pix] arc_length_mirgin_detect_separation : float 液滴分離検知輪郭長閾値[pix] solidity_mirgin_detect_separation : float 液滴分離検知solidity比閾値[U] noise_remove_topological_dist_thresh : float ノイズ除去時輪郭類似判定位相空間距離閾値 noise_remove_area_thresh : float ノイズ除去時輪郭面積上限[pix] mkdir : bool ディレクトリ作製フラグ draw_contour : bool 輪郭描画フラグ draw_convexhull : bool 凸包輪郭描画フラグ draw_coords : bool 各座標描画フラグ exportImage : bool 解析結果画像出力フラグ draw_reg_Detected : bool 最大輪郭検出結果画像出力フラグ DEBUG : bool デバッグモードフラグ Returns ---------------------- retAnalysisResults : Analysis_Results_Listクラス 輪郭抽出結果群 ''' #ファイルリストの取得 extension = '.jpg' files = glob.glob(directoryPath + "/*" + extension) if len(files) < 2: calculation_log('num_files are 0 or 1') return None if DEBUG: calculation_log('files are imported, {}'.format(len(files))) calculation_log('min_area_thresh is {}'.format(min_area_thresh)) #解析結果集計用リスト analysisResultsList = [] flag_image_modified_deeply = False #ファイル名末尾よりディレイ時間取得 for filePath in files: #ファイル名前よりディレイ時間の取得 delay = 0.0 max_description_field_length = 10 i = max_description_field_length flag_delay_is_get = False while i > len(extension): try: delay = float(filePath[-i:-len(extension)]) flag_delay_is_get = True break except: i = i - 1 if not flag_delay_is_get: delay = -1.0 #輪郭抽出結果の格納 if DEBUG: calculation_log('analyse_image method is calling for the delay {} with file {}'.format(delay, filePath)) #画像→輪郭解析実行 appendResults = analyse_Image( delay, filePath, min_area_thresh, binarize_thresh, auto_binarize, draw_contour, draw_convexhull, draw_coords, exportImage, mkdir, flag_export_fillImg = False, DEBUG = DEBUG) analysisResultsList.append(appendResults[0]) if appendResults[1]: flag_image_modified_deeply = True if DEBUG: calculation_log('analysis image results were appended for the delay {} with file {}'.format(delay, filePath)) #全画像輪郭解析実施後処理 if DEBUG: calculation_log('contour_list was completed with length {}'.format(len(analysisResultsList))) #返り値格納用リストに再集計、コンストラクタにてデータ整理 retAnalysisResults = Analysis_Contours_List_Class.Analysis_Results_List( analysis_results_list = analysisResultsList, area_mirgin_detect_faced = area_mirgin_detect_faced, area_mirgin_detect_separation = area_mirgin_detect_separation, arc_length_mirgin_detect_separation = arc_length_mirgin_detect_separation, solidity_mirgin_detect_separation = solidity_mirgin_detect_separation, noise_remove_topological_dist_thresh = noise_remove_topological_dist_thresh, noise_remove_area_thresh = noise_remove_area_thresh, DEBUG = DEBUG ) #解析結果群格納クラス取得後処理 if DEBUG: calculation_log('retAnalysisResults object were generated, length is {}'.format(len(retAnalysisResults.analysisResults))) #最大リガメント長さの描画、フラグにて有無を制御 if draw_reg_Detected: regamentResults = retAnalysisResults.max_regament_length, retAnalysisResults.delay_max_regament_detected if DEBUG: calculation_log('detected delay is {} us, and detected length is {} pix'.format(regamentResults[1], regamentResults[0])) if not math.isnan(regamentResults[1]): #当該輪郭の検出 drawResultCnts = list(filter(lambda data: data.delay == regamentResults[1], retAnalysisResults.analysisResults))[0] drawResultCnt = list(filter(lambda cnt: cnt.get_regament_length() == regamentResults[0], drawResultCnts.contours))[0] #ディレクトリ生成 os.makedirs(directoryPath+'/rgResult', exist_ok=True) #当該ディレイの画像ファイルパス取得 if DEBUG: calculation_log('mkdir at {}/rgResult'.format(directoryPath)) try: filePath = glob.glob(directoryPath+'/*{0}.jpg'.format(str(drawResultCnts.delay)))[0] except: filePath = glob.glob(directoryPath+'/*{0}.jpg'.format(str((int)(drawResultCnts.delay))))[0] #当該画像データ取得 im = cv2.imread(filePath) #リガメント描画 im = cv2.line(im, ((int)(drawResultCnt.main_X),(int)(drawResultCnt.main_Y)), ((int)(drawResultCnt.satellite_X),(int)(drawResultCnt.satellite_Y)), (255, 255, 128), 3) #ファイル出力 savePath = directoryPath+'/rgResult/' + os.path.basename(filePath) + '_drawRegament.jpg' cv2.imwrite(savePath, im) if DEBUG: calculation_log('export regament result image, {}'.format(savePath)) else: calculation_log('reg_detection is not succeed, so rgResult was not drawn.') #成功処理 if DEBUG: calculation_log('cnt selection was completed.') #関数終了 return retAnalysisResults, flag_image_modified_deeply
def gamma_function(img): calculation_log('gamma_function is calling.') return cv2.LUT(img, lookUpTable)