画像に集中線を引く
集中線はマンガで用いられる技法で、画面のある点から外側に放射状に線を引き、動きなどを表現するものです。
画像の内側と外側に円を仮定して、内側の円と外側の円の間で三角形を描画することで、画像に集中線を作成しています。
また、集中線の太さ(三角形の鋭角の大きさ)、集中線の頂点の位置にばらつきを与えて自然な感じにしています。
使った関数・メソッド
- cv2.imread() : 画像ファイルの読み出し
- img.shape : 画像の高さ、幅、チャンネル数を取得する
- math.sqrt() : 平方根を求める
- math.pi : 円周率
- math.cos() : cosを求める
- math.sin() : sinを求める
- random.random() : 0.0~1.0の範囲のランダムな浮動小数点を生成
- cv2.fillPoly() : 塗りつぶされた多角形を描画
- cv2.imwrite() : 画像を保存する
環境
準備
画像ファイルはフリー写真素材ぱくたそからダウンロードさせていただき、ファイル名'cat_boss.jpg'で、jupyter notebookファイル(***.ipynb)と同じディレクトリに保存しました。
cat_boss.jpg
コード
import cv2 # OpenCVのインポート import math # Mathのインポート import numpy as np # numpyのインポート import random # randomのインポート fname = 'cat_boss.jpg' # 画像ファイル名 img = cv2.imread(fname) # 画像を読み出しオブジェクトimgに代入 height, width = img.shape[:2] # 画像の高さ、幅を取得 diagonal = math.sqrt(height**2+width**2) # 画像の対角線を計算(外側の円の半径に使用) center_y = int(height/2) # 集中線の中心座標y center_x = int(width/2) # 集中線の中心座標x circle_r_1 = 230 # 内側の円の半径 circle_r_2 = int(diagonal) # 外側の円の半径 line_number = 100 # 集中線の個数 angle_div = 2*math.pi/line_number # 1周をline_numberで分割した際の角度(rad) angle_thickness = 2*math.pi/360*7 # 三角形の鋭角(rad) # 集中線の本数分の三角形を描画する処理 for i in range(line_number): # line_numberだけ繰り返す r_1_variation = (random.random()-1)*30 # 内側の円の半径ばらつき angle_variation = (random.random()-1)/2 # 線の太さのばらつき angle = angle_div * i cos_theta = math.cos(angle) sin_theta = math.sin(angle) cos_theta_2 = math.cos(angle+angle_thickness*angle_variation) sin_theta_2 = math.sin(angle+angle_thickness*angle_variation) x_1 = int(center_x + (circle_r_1+r_1_variation) * cos_theta) y_1 = int(center_y + (circle_r_1+r_1_variation) * sin_theta) x_2 = int(center_x + circle_r_2 * cos_theta) y_2 = int(center_y + circle_r_2 * sin_theta) x_3 = int(center_x + circle_r_2 * cos_theta_2) y_3 = int(center_y + circle_r_2 * sin_theta_2) pts = np.array(((x_1, y_1), (x_2, y_2), (x_3, y_3))) cv2.fillPoly(img, [pts], (0, 0, 0)) # 塗りつぶされた三角形を描画 cv2.imwrite('cat_boss_concentration.png',img) # ファイル名 cat_boss_concentration.png でimgを保存
実行結果
集中線が引かれます。
集中線の中心位置を少し上に、中心円の大きさを大きく、集中線の色を白に変えてみます。
コード
import cv2 # OpenCVのインポート import math # Mathのインポート import numpy as np # numpyのインポート import random # randomのインポート fname = 'cat_boss.jpg' # 画像ファイル名 img = cv2.imread(fname) # 画像を読み出しオブジェクトimgに代入 height, width = img.shape[:2] # 画像の高さ、幅を取得 diagonal = math.sqrt(height**2+width**2) # 画像の対角線を計算(外側の円の半径に使用) center_y = int(height/2-100) # 集中線の中心座標y center_x = int(width/2) # 集中線の中心座標x circle_r_1 = 280 # 内側の円の半径 circle_r_2 = int(diagonal) # 外側の円の半径 line_number = 100 # 集中線の個数 angle_div = 2*math.pi/line_number # 1周をline_numberで分割した際の角度(rad) angle_thickness = 2*math.pi/360*7 # 三角形の鋭角(rad) # 集中線の本数分の三角形を描画する処理 for i in range(line_number): # line_numberだけ繰り返す r_1_variation = (random.random()-1)*30 # 内側の円の半径ばらつき angle_variation = (random.random()-1)/2 # 線の太さのばらつき angle = angle_div * i cos_theta = math.cos(angle) sin_theta = math.sin(angle) cos_theta_2 = math.cos(angle+angle_thickness*angle_variation) sin_theta_2 = math.sin(angle+angle_thickness*angle_variation) x_1 = int(center_x + (circle_r_1+r_1_variation) * cos_theta) y_1 = int(center_y + (circle_r_1+r_1_variation) * sin_theta) x_2 = int(center_x + circle_r_2 * cos_theta) y_2 = int(center_y + circle_r_2 * sin_theta) x_3 = int(center_x + circle_r_2 * cos_theta_2) y_3 = int(center_y + circle_r_2 * sin_theta_2) pts = np.array(((x_1, y_1), (x_2, y_2), (x_3, y_3))) cv2.fillPoly(img, [pts], (255, 255, 255)) # 塗りつぶされた三角形を描画 cv2.imwrite('cat_boss_concentration.png',img) # ファイル名 cat_boss_concentration.png でimgを保存
実行結果
以下のサイトを参考にさせていただきました
Python公式 >> random.random()
note.nkmk.me >> Python, OpenCVで図形描画(線、長方形、円、矢印、文字など)