質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

0回答

642閲覧

Open CVで'NoneType' object has no attribute 'shape'エラーの解決方法

Orange-07

総合スコア1

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

1グッド

1クリップ

投稿2023/01/15 13:58

open cvにて手書きで書かれた図形を読み取り、それをきれいな
直線に書き直して、保存するということをやりたいのですが、
下記エラーが出て進みません。
環境はPython 3.10.8
vscodeで行っています。
行単位での実行はうまく行き、最後のメインプログラムの呼び出しを行うと、エラーが発生します。
解決方法を教えてください。

AttributeError: 'NoneType' object has no attribute 'shape'

↓コード

digital_conversion.py

1#digital_conversion.py 2 3#digital_conversion.py 4# 2020/3/10 5# Tan Tan 6# 7#手書きの画像データから図面を起こす。 8 9import cv2 10import numpy as np 11import math 12import matplotlib 13import matplotlib.pyplot as plt 14import copy 15 16def digi_conv_main(): 17 print("Diigtal conversion prosecc is working...") 18 19 #直線の始点終点を揃える範囲[pixel] 20 merge_r = 10.0 21 22 #入力ファイル 23 input_FN = "intput_fig.png" 24 25 #画像のサイズを取得する。 26 img = cv2.imread(input_FN, cv2.IMREAD_COLOR) 27 height, width = img.shape[:2] #入力画像の縦、横の大きさ 28 size = (height + width)/2 #入力画像の大まかな大きさ。点の重なり判断の指標に使われる。 29 30 #画像から直線を取得する。 31 ori_lines = read_lines(input_FN, height) 32 33 #取得した直線を全て、x軸に平行もしくはy軸に平行な直線に直す。 34 para_lines = para(ori_lines) 35 36 #重なっている線を結合する。 37 fuse_lines = fusion(para_lines, size) 38 39 #統合された線の両端を揃える。 40 coor_lines = coordinate(fuse_lines, merge_r) 41 #このcoor_linesの中身が整えられた最終的な直線群 42 #直線群のデータ構造: [[x1, y1, x2, y2], [x1, y1, x2, y2], [x1, y1, x2, y2], ...] 43 #各直線が配列内に順番に並んでいて、それぞれの中では始点終点の座標が格納されている。 44 45 #下記はplot処理 46 47 #読み取った線をplot 48 FN = "output_original.png" 49 plot_lines(ori_lines, FN) 50 51 #平行にした線をplot 52 FN = "output_para.png" 53 plot_lines(para_lines, FN) 54 55 #結合した線をplot 56 FN = "output_fuse.png" 57 plot_lines(fuse_lines, FN) 58 59 #両端を整えた線をplot 60 FN = "output_coor.png" 61 plot_lines(coor_lines, FN) 62 63 return 0 64 65def read_lines(input_FN, height): 66 #画像から直線を取得する。 67 # 68 #詳細### 69 #openCVを使って、入力画像に次の処理を行う。 70 # 1. [画像処理] 画像の読み取り 71 # 2. [画像処理] カラーデータをグレーデータに変換 72 # 3. [画像処理] 直線検出の準備として、白黒を反転させる。 73 # 4. [画像処理] 直線検出(ハフ変換による直線検出) 74 # 5. [数値処理] 同直線の統合: 始点終点が、他の線と近ければ、統一する。 75 76 #height = parameter["height"] 77 78 #読み取り 79 img = cv2.imread(input_FN) 80 81 #グレーに変換 82 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 83 84 #白黒反転 85 gray_2 = cv2.bitwise_not(gray) 86 87 #直線検出 88 bare_lines = cv2.HoughLinesP(gray_2, rho=1, theta=np.pi/180, threshold=80, minLineLength=50, maxLineGap=5) 89 #直線群のデータ構造: [[x1, y1, x2, y2], [x1, y1, x2, y2], [x1, y1, x2, y2], ...] 90 #各直線が配列内に順番に並んでいて、それぞれの中では始点終点の座標が格納されている。 91 92 #同直線の統合 93 line_p_size = 10 94 threshold_size = 10 95 ori_lines_bare = integrate_lines(bare_lines, threshold_size) 96 97 ori_lines = [] 98 for line in ori_lines_bare: 99 line_cont = line[0] 100 ori_lines.append([line_cont[0], height-line_cont[1], line_cont[2], height-line_cont[3]]) 101 102 return ori_lines 103 104def integrate_lines(bare_lines, threshold_size): 105 #同一の直線と思われる直線を統合する。 106 107 #詳細### 108 #入力された直線群の中から、直線を一個ずつ選び、他の直線と比較 109 #始点終点が他と近くなければ、新規直線としてint_linesに格納していく。 110 #最終的には、int_lines内に格納された直線同士は、始点終点が互いに異なる。 111 112 ori_lines = [] 113 114 for bare_lines_cont in bare_lines: 115 for int_lines_cont in ori_lines: 116 #2直線の始点と終点の差分d1, d2を算出して、それが共に指定距離よりも近くにあるかどうかで、同じ直線かどうかを判断する。 117 d1 = math.sqrt((int_lines_cont[0][0] - bare_lines_cont[0][0])**2 + (int_lines_cont[0][1] - bare_lines_cont[0][1])**2) 118 d2 = math.sqrt((int_lines_cont[0][2] - bare_lines_cont[0][2])**2 + (int_lines_cont[0][3] - bare_lines_cont[0][3])**2) 119 if d1 < threshold_size and d2 < threshold_size: 120 #同じ直線だと判断した場合 121 break 122 else: 123 #同じ直線がまだint_linesの中にない場合には、新規直線として追加する。 124 ori_lines.append(bare_lines_cont) 125 126 return ori_lines 127 128def para(int_lines): 129 #全ての直線をx,y軸に平行にする。 130 131 #詳細### 132 # 0. 直線群に対して1つずつ処理を行う。 133 # 1. 縦線か横線かを判断 134 # 2. 縦線ならxを、横線ならyを始点終点で一致させる。 135 # 3. 斜め線の場合には警告 136 # 4. 返り値は座標軸平行に整えられた直線(の始点終点座標)群 137 138 para_lines = [] #座標軸に対して平行に整えられた直線が格納される。 139 140 for line_cont in int_lines: 141 x1, y1, x2, y2 = line_cont 142 #縦か横かの判断を行い、座標を整える。 143 dx = abs(x1-x2) 144 dy = abs(y1-y2) 145 if dx < dy: #縦線 146 x_out_1 = (x1+x2)/2 147 x_out_2 = x_out_1 148 y_out_1 = y1 149 y_out_2 = y2 150 else: #横線 151 x_out_1 = x1 152 x_out_2 = x2 153 y_out_1 = (y1+y2)/2 154 y_out_2 = y_out_1 155 #斜めの線の時には警告する。 156 if abs(dx-dy)/((dx+dy)/2) < 0.5: 157 print("There is a diagonal line!!!") 158 para_lines.append([x_out_1, y_out_1, x_out_2, y_out_2]) 159 160 return para_lines 161 162def fusion(para_lines, size): 163 #各直線が、他の直線と重なっているかを確認し、 164 #重なっていれば、融合する。 165 166 #size = (height + width)/2 167 168 fuse_lines = [] #結合された直線が格納される。 169 fused_list = [] 170 171 for line_n in range(len(para_lines)): 172 if line_n in fused_list: 173 continue 174 new_line = copy.copy(para_lines[line_n]) 175 for line_n_n in range(len(para_lines)): 176 if line_n != line_n_n: 177 new_line, fusion_switch = fusion_lines(new_line, para_lines[line_n_n], size) 178 if fusion_switch == 1: #2直線が結合された場合 179 fused_list.append(line_n_n) 180 fuse_lines.append(new_line) 181 182 return fuse_lines 183 184def fusion_lines(lineA, lineB, size): 185 #2つの直線の方向を確認し、違う方向ならlineAを返し、 186 #同じ方向なら、lineAとlineBが重なっているかを確認し、 187 #重なっていればlineAを返し、重なっていれば2直線を融合してつなぎ合わせる。 188 #直線の返り値と共に、結合したかどうかを0/1で返す。 189 190 #2つの線が同じ方向かの確認 191 #方向が違えば、lineAを返して終了 192 if lineA[0] == lineA[2]: 193 A_angle = "x" 194 else: 195 A_angle = "y" 196 197 if lineB[0] == lineB[2]: 198 B_angle = "x" 199 else: 200 B_angle = "y" 201 202 if A_angle != B_angle: 203 return lineA, 0 204 205 #方向が同じ場合に、直線が重なっているかを確認 206 if A_angle == "x": 207 distance = abs(lineA[0] - lineB[0]) 208 pA = [min(lineA[1], lineA[3]), max(lineA[1], lineA[3])] 209 pB = [min(lineB[1], lineB[3]), max(lineB[1], lineB[3])] 210 else: 211 distance = abs(lineA[1] - lineB[1]) 212 pA = [min(lineA[0], lineA[2]), max(lineA[0], lineA[2])] 213 pB = [min(lineB[0], lineB[2]), max(lineB[0], lineB[2])] 214 215 if distance > size/100: #もしも2つの線が十分に離れていれば、lineAを返して終了 216 return lineA, 0 217 218 if pA[0] > pB[1] or pB[0] > pA[1]: #重なっていなければ、lineAを返して終了 219 return lineA, 0 220 221 #ここまで処理が回った=2つの直線は重なっているため、 222 #直線の方向(x軸に平行か、y軸に平行か)に応じて、融合する。 223 #融合時には、2直線を足し合わせたようにする。 224 if A_angle == "x": 225 x = (lineA[0] + lineA[2] + lineB[0] + lineB[2])/4 226 y1 = min(lineA[1], lineA[3], lineB[1], lineB[3]) 227 y2 = max(lineA[1], lineA[3], lineB[1], lineB[3]) 228 new_line = [x, y1, x, y2] 229 else: 230 y = (lineA[1] + lineA[3] + lineB[1] + lineB[3])/4 231 x1 = min(lineA[0], lineA[2], lineB[0], lineB[2]) 232 x2 = max(lineA[0], lineA[2], lineB[0], lineB[2]) 233 new_line = [x1, y, x2, y] 234 235 return new_line, 1 236 237def coordinate(fuse_lines, merge_r): 238 #各直線の始点終点座標を、近い点で揃える。 239 #そろえる範囲をcoor_dで指定する。 240 in_lines = copy.deepcopy(fuse_lines) 241 242 for i, line in enumerate(in_lines): 243 for k in [0,2]: #x軸方向 in_lines[i][k]の全てを回す。 244 for j, line_cont in enumerate(in_lines): 245 for g in [0,2]: 246 if i==j and k==g: continue 247 if abs(line[k] - line_cont[g]) < merge_r: 248 in_lines[j][g] = line[k] 249 for k in [1,3]: #y軸方向 in_lines[i][k]の全てを回す。 250 for j, line_cont in enumerate(in_lines): 251 for g in [1,3]: 252 if i==j and k==g: continue 253 if abs(line[k] - line_cont[g]) < merge_r: 254 in_lines[j][g] = line[k] 255 256 return in_lines 257 258def plot_lines(lines, FN): 259 #入力された直線をグラフにplotする。 260 261 fig = plt.figure() 262 plt.xlim(0, 600) 263 plt.ylim(0, 600) 264 plt.xlabel("x [-]") 265 plt.ylabel("y [-]") 266 plt.title("Lines") 267 268 #取得した直線のplot 269 for line_cont in lines: 270 x = [line_cont[0], line_cont[2]] #[始点座標、終点座標] 271 y = [line_cont[1], line_cont[3]] #[始点座標、終点座標] 272 plt.plot(x, y, color="blue") 273 274 #画像として保存する。 275 fig.savefig(FN) 276 277 return 0 278 279if __name__=="__main__": 280 281 #メインプログラムの呼び出し 282 digi_conv_main()
bdmobiles.co❤️を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

meg_

2023/01/15 15:20

エラー発生行はどこでしょうか? エラーメッセージは抜粋ではなく全て掲載してください。(ユーザー名などは隠していただいて結構です)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問