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

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

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

dlibは、機械学習のC++の画像処理ライブラリの一つ。性能の高い顔の器官検出が簡単にでき、Pythonバインドもあります。オープンソースで無料で使用でき、機械学習以外の様々な機能も搭載されています。

OpenCV

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

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3743閲覧

pythonを用いたモーフィング

J-programmer

総合スコア3

dlib

dlibは、機械学習のC++の画像処理ライブラリの一つ。性能の高い顔の器官検出が簡単にでき、Pythonバインドもあります。オープンソースで無料で使用でき、機械学習以外の様々な機能も搭載されています。

OpenCV

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

機械学習

機械学習は、データからパターンを自動的に発見し、そこから知能的な判断を下すためのコンピューターアルゴリズムを指します。人工知能における課題のひとつです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/11/01 00:14

編集2020/11/03 05:32
コード ```### 前提・実現したいこと pythonでのモーフィング ### 発生している問題・エラーメッセージ [INFO] loading facial landmark predictor... C:\Users\Owner\OneDrive\Documents Traceback (most recent call last): File "C:\Users\Owner\OneDrive\Documents\module1101.py", line 64, in <module> points = Face_landmarks(filename) File "C:\Users\Owner\OneDrive\Documents\module1101.py", line 29, in Face_landmarks size = image.shape AttributeError: 'NoneType' object has no attribute 'shape' ### 該当のソースコード ```python import argparse import cv2 import numpy as np import random import os import imutils import dlib def Face_landmarks(image_path): print("[INFO] loading facial landmark predictor...") detector = dlib.get_frontal_face_detector() path = os.getcwd() print(path) predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") image = cv2.imread(image_path) size = image.shape gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) rects = detector(gray, 0) if len(rects) > 2: print("[ERR] too many faces fount...") # print("[Error] {} faces found...".format(len(rect))) sys.exit(1) if len(rects) < 1: print("[ERR] face not found...") # print("[Error] face not found...".format(len(rect)) sys.exit(1) for rect in rects: (bX, bY, bW, bH) = face_utils.rect_to_bb(rect) print("[INFO] face frame {}".format(bX, bY, bW, bH)) shape = predictor(gray, rect) shape = face_utils.shape_to_np(shape) points = shape.tolist() # (0,0),(x,0),(0,y),(x,y) points.append([0, 0]) points.append([int(size[1]-1), 0]) points.append([0, int(size[0]-1)]) points.append([int(size[1]-1), int(size[0]-1)]) # (x/2,0),(0,y/2),(x/2,y),(x,y/2) points.append([int(size[1]/2), 0]) points.append([0, int(size[0]/2)]) points.append([int(size[1]/2), int(size[0]-1)]) points.append([int(size[1]-1), int(size[0]/2)]) cv2.destroyAllWindows() return points if __name__ == '__main__': filename = 'image/MarilynMonroe.jpg' name,ext = os.path.splitext(filename) img = cv2.imread(filename) points = Face_landmarks(failname) stringToWrite = '' for (i, (x, y)) in enumerate(points): print(x, y) stringToWrite += str(x) + " " + str(y) + "n" cv2.circle(img, (x, y), 1, (0, 0, 255), -1) cv2.putText(img, str(i + 1), (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1) cv2.imwrite('%s-points.jpg' %name,img) def Face_delaunay(rect,points1 ,points2 ,alpha ): points = [] for i in range(0, len(points1)): x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0] y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1] points.append((x,y)) triangles, delaunay = calculateDelaunayTriangles(rect, points) cv2.destroyAllWindows() return triangles, delaunay def calculateDelaunayTriangles(rect, points): subdiv = cv2.Subdiv2D(rect) for p in points: subdiv.insert(p) triangleList = subdiv.getTriangleList() delaunayTri = [] pt = [] for t in triangleList: pt.append((t[0], t[1])) pt.append((t[2], t[3])) pt.append((t[4], t[5])) pt1 = (t[0], t[1]) pt2 = (t[2], t[3]) pt3 = (t[4], t[5]) if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3): ind = [] for j in range(0, 3): for k in range(0, len(points)): if(abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0): ind.append(k) if len(ind) == 3: delaunayTri.append((ind[0], ind[1], ind[2])) pt = [] return triangleList,delaunayTri def rectContains(rect, point) : if point[0] < rect[0] : return False elif point[1] < rect[1] : return False elif point[0] > rect[0] + rect[2] : return False elif point[1] > rect[1] + rect[3] : return False return True def Face_morph(img1, img2, img, tri1, tri2, tri, alpha) : """モーフィング画像作成 Args: img1 : 画像1 img2 : 画像2 img : 画像1,2のモーフィング画像(Output用画像) tri1 : 画像1の三角形 tri2 : 画像2の三角形 tri : 画像1,2の間の三角形 alpha: 重み """ # 各三角形の座標を含む最小の矩形領域 (バウンディングボックス)を取得 # (左上のx座標, 左上のy座標, 幅, 高さ) r1 = cv2.boundingRect(np.float32([tri1])) r2 = cv2.boundingRect(np.float32([tri2])) r = cv2.boundingRect(np.float32([tri])) # バウンディングボックスを左上を原点(0, 0)とした座標に変換 t1Rect = [] t2Rect = [] tRect = [] for i in range(0, 3): tRect.append(((tri[i][0] - r[0]),(tri[i][1] - r[1]))) t1Rect.append(((tri1[i][0] - r1[0]),(tri1[i][1] - r1[1]))) t2Rect.append(((tri2[i][0] - r2[0]),(tri2[i][1] - r2[1]))) # 三角形のマスクを生成 # 三角形の領域のピクセル値は1で、残りの領域のピクセル値は0になる mask = np.zeros((r[3], r[2], 3), dtype = np.float32) cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1.0), 16, 0) # アフィン変換の入力画像を用意 img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]] img2Rect = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] # アフィン変換の変換行列を生成 warpMat1 = cv2.getAffineTransform( np.float32(t1Rect), np.float32(tRect) ) warpMat2 = cv2.getAffineTransform( np.float32(t2Rect), np.float32(tRect) ) size = (r[2], r[3]) # アフィン変換の実行 # 1.src:入力画像、2.M:変換行列、3.dsize:出力画像のサイズ、4.flags:変換方法、5.borderMode:境界の対処方法 warpImage1 = cv2.warpAffine( img1Rect, warpMat1, (size[0], size[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 ) warpImage2 = cv2.warpAffine( img2Rect, warpMat2, (size[0], size[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 ) # 2つの画像に重みを付けて、三角形の最終的なピクセル値を見つける imgRect = (1.0 - alpha) * warpImage1 + alpha * warpImage2 # マスクと投影結果を使用して論理AND演算を実行し、 # 三角形領域の投影されたピクセル値を取得しOutput用画像にコピー img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] = img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] * ( 1 - mask ) + imgRect * mask def betweenPoints(point1, point2, alpha) : points = [] for i in range(0, len(points1)): x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0] y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1] points.append((x,y)) return points if __name__ == '__main__' : # モーフィングする画像取得 filename1 = 'image/AudreyHepburn.jpg' filename2 = 'image/MarilynMonroe.jpg' img1 = cv2.imread(filename1) img2 = cv2.imread(filename2) # 画像をfloat型に変換 img1 = np.float32(img1) img2 = np.float32(img2) # 長方形を取得 size = img1.shape rect = (0, 0, size[1], size[0]) # 顔の特徴点を取得 points1 = face_landmarks.Face_landmarks(filename1) points2 = face_landmarks.Face_landmarks(filename2) # 1~99%割合を変えてモーフィング for cnt in range(1, 100): alpha = cnt * 0.01 # 画像1,2の特徴点の間を取得 points = betweenPoints(points1,points2,alpha) # ドロネーの三角形(座標配列とpoints要素番号)を取得 triangles, delaunay = face_delaunay.Face_delaunay(rect,points) # モーフィング画像初期化 imgMorph = np.zeros(img1.shape, dtype = img1.dtype) # ドロネー三角形の配列要素番号を読込 for (i, (x, y, z)) in enumerate(delaunay): # ドロネー三角形のピクセル位置を取得 tri1 = [points1[x], points1[y], points1[z]] tri2 = [points2[x], points2[y], points2[z]] tri = [points[x], points[y], points[z]] # モーフィング画像を作成 Face_morph(img1, img2, imgMorph, tri1, tri2, tri, alpha) # モーフィング画像をint型に変換し出力 imgMorph = np.uint8(imgMorph) cv2.imwrite('output/picture-%s.jpg' % str(cnt).zfill(3),imgMorph)

試したこと

補足情報(FW/ツールのバージョンなど)

こちらを参考にさせていただきました。

https://flat-kids.net/2020/06/30/%E9%A1%94%E3%83%A2%E3%83%BC%E3%83%95%E3%82%A3%E3%83%B3%E3%82%B01-%E9%A1%94%E3%81%AE%E7%89%B9%E5%BE%B4%E7%82%B9%E3%81%AE%E6%A4%9C%E5%87%BA/

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

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

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

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

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

toast-uz

2020/11/01 00:59

コードが正しく表示されていません。「コードの挿入」ボタンを使ってください。
1T2R3M4

2020/11/01 01:12

failnameはどこで定義されてますか。
y_waiwai

2020/11/01 02:32

このままではコードが読めないので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
退会済みユーザー

退会済みユーザー

2020/11/01 04:57 編集

たぶんおかしい箇所が10か所以上あります。相当慣れた人が書いたコードを質問者さんがニコイチしたのか不可解な部分がたくさんあります。
guest

回答1

0

ベストアンサー

GMH
35%
65%
FEA
※画像はwikiより。共にプログラマー界のスーパーおかあちゃんです。

コメントにも書きましたが、細かいエラーがたくさんありましたので個別には書きません。コメントと行間を察する温かい気持ちでコードを読んでください。

なお、fourteenlengthは「技量を証明したくて、むしゃくしゃしてやった、後悔はしていない」などと意味不明なことを供述しており…

Python3

1import argparse 2 3import cv2 4import numpy as np 5import random 6import os 7import imutils 8import dlib 9 10import sys # <--追加 11from imutils import face_utils# <--追加 12def Face_landmarks(image_path): 13 print("[INFO] loading facial landmark predictor...") 14 detector = dlib.get_frontal_face_detector() 15 16 path = os.path.split(__file__)[0]+"\" # <--デバグ用に修正 17 print(path) 18 19 predictor = dlib.shape_predictor(path + "shape_predictor_68_face_landmarks.dat") # <--デバグ用に修正 20 21 image = cv2.imread(path + image_path)# <--デバグ用に修正 22 23 --追加 24 # 画像が読めないとNoneになるため 25 print("File loading error @Face_landmarks(image_path)") 26 sys.exit() 27 28 size = image.shape 29 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) 30 rects = detector(gray, 0) 31 if len(rects) > 2: 32 print("[ERR] too many faces fount...") 33 34 print("[Error] {} faces found...".format(len(rect))) 35 sys.exit(1) 36 37 if len(rects) < 1: 38 print("[ERR] face not found...") 39 40 print("[Error] face not found...".format(len(rect))) 41 sys.exit(1) 42 43 for rect in rects: 44 (bX, bY, bW, bH) = face_utils.rect_to_bb(rect) 45 46 print("[INFO] face frame {}".format(bX, bY, bW, bH)) 47 shape = predictor(gray, rect) 48 49 shape = face_utils.shape_to_np(shape) 50 51 points = shape.tolist() 52 53 # (0,0),(x,0),(0,y),(x,y) 54 points.append([0, 0]) 55 points.append([int(size[1]-1), 0]) 56 points.append([0, int(size[0]-1)]) 57 points.append([int(size[1]-1), int(size[0]-1)]) 58 59 # (x/2,0),(0,y/2),(x/2,y),(x,y/2) 60 points.append([int(size[1]/2), 0]) 61 points.append([0, int(size[0]/2)]) 62 points.append([int(size[1]/2), int(size[0]-1)]) 63 points.append([int(size[1]-1), int(size[0]/2)]) 64 cv2.destroyAllWindows() 65 # return powints 66 return points # <-- 修正 67 68# if name == 'main': <-- 修正 69if __name__ == '__main__': 70 filename = 'image/Grace_Murray_Hopper.jpg' 71 72 name,ext = os.path.splitext(filename) 73 74 path = os.path.split(__file__)[0]+"\" # <--デバグ用に 75 img = cv2.imread(path + filename)# <--デバグ用に修正 76 77 if img is None:# <--追加 78 # 画像が読めないとNoneになるため 79 print("File loading error @ __name__ == '__main__'") 80 sys.exit() 81 82 points = Face_landmarks(filename) # failname --> filename 83 stringToWrite = '' 84 85 for (i, (x, y)) in enumerate(points): 86 print(x, y) 87 stringToWrite += str(x) + " " + str(y) + "n" 88 cv2.circle(img, (x, y), 1, (0, 0, 255), -1) 89 cv2.putText(img, str(i + 1), (x - 10, y - 10), 90 cv2.FONT_HERSHEY_SIMPLEX, 0.35, (0, 0, 255), 1) 91 92 cv2.imwrite('%s-points.jpg' %name,img) 93 94def Face_delaunay(rect,points1 ,points2 ,alpha ): 95 points = [] 96 for i in range(0, len(points1)): 97 x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0] 98 y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1] 99 points.append((x,y)) 100 101 if len(points) < 3:# デバグ用に追加 102 print("FAIL: coordinates should be atleast 3.",len(points)) 103 sys.exit() 104 105 triangles, delaunay = calculateDelaunayTriangles(rect, points) 106 # cv2.destroyAllWindows() # <--削除 107 return triangles, delaunay 108 109def calculateDelaunayTriangles(rect, points): 110 subdiv = cv2.Subdiv2D(rect) 111 112 113 for p in points: 114 p = (int(p[0]), int(p[1])) # <--追加 115 subdiv.insert(p) 116 triangleList = subdiv.getTriangleList() 117 118 119 delaunayTri = [] 120 121 pt = [] 122 # print("triangleList",triangleList) 123 for t in triangleList: 124 pt.append((t[0], t[1])) 125 pt.append((t[2], t[3])) 126 pt.append((t[4], t[5])) 127 128 pt1 = (t[0], t[1]) 129 pt2 = (t[2], t[3]) 130 pt3 = (t[4], t[5]) 131 132 133 if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3): 134 ind = [] 135 for j in range(0, 3): 136 for k in range(0, len(points)): 137 if(abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0): 138 ind.append(k) 139 if len(ind) == 3: 140 delaunayTri.append((ind[0], ind[1], ind[2])) 141 # print(delaunayTri) 142 pt = [] 143 144 return triangleList,delaunayTri 145 146def rectContains(rect, point) : 147 if point[0] < rect[0] : 148 return False 149 elif point[1] < rect[1] : 150 return False 151 elif point[0] > rect[0] + rect[2] : 152 return False 153 elif point[1] > rect[1] + rect[3] : 154 return False 155 return True 156 157def Face_morph(img1, img2, img, tri1, tri2, tri, alpha) : 158 """モーフィング画像作成 159 Args: 160 img1 : 画像1 161 img2 : 画像2 162 img : 画像1,2のモーフィング画像(Output用画像) 163 tri1 : 画像1の三角形 164 tri2 : 画像2の三角形 165 tri : 画像1,2の間の三角形 166 alpha: 重み 167 """ 168 169 # 各三角形の座標を含む最小の矩形領域 (バウンディングボックス)を取得 170 # (左上のx座標, 左上のy座標, 幅, 高さ) 171 r1 = cv2.boundingRect(np.float32([tri1])) 172 r2 = cv2.boundingRect(np.float32([tri2])) 173 r = cv2.boundingRect(np.float32([tri])) 174 175 # バウンディングボックスを左上を原点(0, 0)とした座標に変換 176 t1Rect = [] 177 t2Rect = [] 178 tRect = [] 179 for i in range(0, 3): 180 tRect.append(((tri[i][0] - r[0]),(tri[i][1] - r[1]))) 181 t1Rect.append(((tri1[i][0] - r1[0]),(tri1[i][1] - r1[1]))) 182 t2Rect.append(((tri2[i][0] - r2[0]),(tri2[i][1] - r2[1]))) 183 184 # 三角形のマスクを生成 185 # 三角形の領域のピクセル値は1で、残りの領域のピクセル値は0になる 186 mask = np.zeros((r[3], r[2], 3), dtype = np.float32) 187 cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1.0), 16, 0) 188 189 # アフィン変換の入力画像を用意 190 img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]] 191 img2Rect = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] 192 193 # アフィン変換の変換行列を生成 194 warpMat1 = cv2.getAffineTransform( np.float32(t1Rect), np.float32(tRect) ) 195 warpMat2 = cv2.getAffineTransform( np.float32(t2Rect), np.float32(tRect) ) 196 size = (r[2], r[3]) 197 198 # アフィン変換の実行 199 # 1.src:入力画像、2.M:変換行列、3.dsize:出力画像のサイズ、4.flags:変換方法、5.borderMode:境界の対処方法 200 warpImage1 = cv2.warpAffine( img1Rect, warpMat1, (size[0], size[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 ) 201 warpImage2 = cv2.warpAffine( img2Rect, warpMat2, (size[0], size[1]), flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 ) 202 203 # 2つの画像に重みを付けて、三角形の最終的なピクセル値を見つける 204 imgRect = (1.0 - alpha) * warpImage1 + alpha * warpImage2 205 206 207 # マスクと投影結果を使用して論理AND演算を実行し、 208 # 三角形領域の投影されたピクセル値を取得しOutput用画像にコピー 209 img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] = img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] * ( 1 - mask ) + imgRect * mask 210 return img# <-- 追加 211 212def betweenPoints(point1, point2, alpha) : 213 points = [] 214 for i in range(0, len(points1)): 215 x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0] 216 y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1] 217 points.append((x,y)) 218 return points 219 220if __name__ == '__main__': # <-- 修正 221 os.makedirs("./output",exist_ok=True) # <-- 追加 222 223 path = os.path.split(__file__)[0]+"\" # <--デバグ用に追加 224 225 # モーフィングする画像取得 226 filename1 = 'image/Grace_Murray_Hopper.jpg' 227 filename2 = 'image/Frances_Elizabeth_Allen.jpg' 228 229 img1 = cv2.imread(path + filename1) 230 img2 = cv2.imread(path + filename2) 231 232 if img1 is None:# <--追加 233 # 画像が読めないとNoneになるため 234 print("File loading error @img1") 235 sys.exit() 236 237 238 if img2 is None:# <--追加 239 # 画像が読めないとNoneになるため 240 print("File loading error @img2") 241 sys.exit() 242 243 244 # 画像をfloat型に変換 245 img1 = np.float32(img1) 246 img2 = np.float32(img2) 247 248 # 長方形を取得 249 size = img1.shape 250 rect = (0, 0, size[1], size[0]) 251 252 # 顔の特徴点を取得 253 points1 = Face_landmarks(filename1) # <--修正 254 points2 = Face_landmarks(filename2) # <--修正 255 256 # 1~99%割合を変えてモーフィング 257 for cnt in range(1, 100): 258 alpha = cnt * 0.01 259 260 # 画像1,2の特徴点の間を取得 261 points = betweenPoints(points1,points2,alpha) 262 263 # ドロネーの三角形(座標配列とpoints要素番号)を取得 264 triangles, delaunay = Face_delaunay(rect,points1,points2,alpha)# <--修正 265 266 # モーフィング画像初期化 267 imgMorph = np.zeros(img1.shape, dtype = img1.dtype) 268 269 # ドロネー三角形の配列要素番号を読込 270 for (i, (x, y, z)) in enumerate(delaunay): 271 # ドロネー三角形のピクセル位置を取得 272 tri1 = [points1[x], points1[y], points1[z]] 273 tri2 = [points2[x], points2[y], points2[z]] 274 tri = [points[x], points[y], points[z]] 275 276 # モーフィング画像を作成 277 imgMorph= Face_morph(img1, img2, imgMorph, tri1, tri2, tri, alpha) #<--修正 278 279 # モーフィング画像をint型に変換し出力 280 imgMorph = np.uint8(imgMorph) 281 cv2.imwrite(path +'output/alpha_[%s]_picture-%s.jpg' % (str(cnt).zfill(2),str(cnt).zfill(3)),imgMorph) #<--修正 282 cv2.imshow("imgMorph",imgMorph) # <-- 追加 283 cv2.waitKey(10) # <-- 追加 284

投稿2020/11/01 05:00

編集2020/11/01 06:20
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問