非IT企業に勤める中年サラリーマンのIT日記

非IT企業でしかもITとは全く関係ない部署にいる中年エンジニア。唯一の趣味がプログラミングという”自称”プログラマー。

Python: OpenCVを使って画像に集中線を入れる

   

OpenCVを使うと画像編集ができます。いろいろな編集ができるみたいですが、今回はよくブログで使われるような集中線が入った画像を作ってみたいと思います。

PythonにOpenCVを導入する方法は以下を見てください。

広告

実行例

今回紹介するプログラムは、以下のように画像に集中線を入れるものです。

以下がカスタマイズ可能です。

  • ラインの太さ
  • ラインの色
  • 画像の中に描く内円の半径
  • ラインを何°ごと描くか
  • 乱れのレベル

ソースコード

以下がソースコード全文です。5行目から16行目までがパラメータの設定なので必要に応じて修正してください。

import cv2
import math
import random

#画像ファイル名
img_filename = "test.jpg"
#ラインの太さ
border_width = 2
#ラインの色
border_color = (0, 0, 0)
#画像の中に描く内円の半径
r1 =200
#ラインを何°ごと描くか
step = 2
#乱れレベル(0:乱れなし)
sc = 10

#画像を取得
pic = cv2.imread(img_filename)

#画像の高さと幅
h, w = pic.shape[:2]
#中央座標
center_x = int(w * 0.5)
center_y = int(h * 0.5)
#画像の角を接する円の半径
r0 = int(math.sqrt(h ** 2 + w ** 2)) + 1

for theta in range(360):
  if theta % step != 0:
    continue
  #線の乱れ係数
  scattering = random.uniform(0, sc*10)
  #中央を軸にした円の円周座標
  x0 = int(r0 * math.sin(theta * math.pi/180)) + center_x
  y0 = int(r0 * math.cos(theta * math.pi/180)) + center_y
  #描く線の先の座標
  r1a = r1 + scattering
  x1 = int(r1a * math.sin(theta * math.pi/180)) + center_x
  y1 = int(r1a * math.cos(theta * math.pi/180)) + center_y
  #集中線を描く
  cv2.line(pic, (x0, y0), (x1, y1), border_color, border_width)

cv2.imshow('test', pic)

key = cv2.waitKey(0)
if key == 27: #ESCで終了
  cv2.destroyAllWindows()
  exit()
if key == 115: #「s」で保存して終了
  cv2.imwrite('out.jpg',pic)
  cv2.destroyAllWindows()
  exit()
 

 

解説

どのように集中線を入れているか解説します。基本的な考え方なので他のプログラミング言語でも参考になるかと思います。

まず、集中線の開始位置は画像の端ではなく画像の角に接する円から線が伸びています。その半径は以下の数式で求められます。

内円の半径r1は任意です。今回のプログラムではカスタマイズできます。

次に集中線の開始位置(x0, y0)と終了位置(x1, y1)の座標の計算方法ですが、以下のような三角関数で求められます。(円中心=画像中央の座標が(0, 0)だった場合)

 

実際は円中心の座標(=画像中心の座標)は(0, 0)ではなく、画像の左上端が(0, 0)なので、そのズレ分を加算してあげる必要があります。

 

あとはθを1〜360まで変えて上げれば、画像にぐるっとラインが形成されます。

但し、この計算式で集中線を描くと以下のように中央部がまん丸く描かれてしまいます。

 

中央部を髪をすくように乱してあげる必要があります。

ライン長をランダムに変えてあげれば良いので、以下のようにrにランダム係数を加算してあげればOKです。

そうして出来たのが以下の画像です。

 

あとは内円の径を変えたり、ラインの太さを変えることで好みの集中線に仕上げればOKです。

 

広告

 - Python