LoginSignup
4
2

More than 3 years have passed since last update.

Python+OpenCVでイラストを描く

Last updated at Posted at 2019-11-27

1.はじめに

Python+OpenCVでイラストを書いてみました。
絵心がなく絵が描けない→プログラムは書ける→プログラムで絵を描けばいいじゃない という無謀な発想です。
線の位置を全部ベタで座標指定していて難しいことは全くしていません。

2.実行結果

20191127.PNG

3.スクリプト全体

girl1.py
import numpy as np
import cv2

# 白で塗りつぶす
img = np.full((600, 800, 3), 255, dtype=np.uint8)

# 補助線
#cv2.rectangle(img, (300, 300), (500, 500), (127, 127, 127), 1, cv2.LINE_AA)
#cv2.line(     img, (300, 400), (500, 400), (127, 127, 127), 1, cv2.LINE_AA)
#cv2.line(     img, (400, 300), (400, 500), (127, 127, 127), 1, cv2.LINE_AA)
#cv2.line(     img, (300, 450), (500, 450), (127, 127, 127), 1, cv2.LINE_AA)
#cv2.line(     img, (300, 435), (500, 435), (127, 127, 127), 1, cv2.LINE_AA)
#cv2.circle(   img, (400, 400), 100, (127, 127, 127), 1, cv2.LINE_AA)
#cv2.ellipse(  img, ((400, 400), (170, 200), 0), (127, 127, 127), 1, cv2.LINE_AA)

# 髪塗りつぶし 全部繋げるとうまく塗りつぶせないので4つに分けている
pts1_1 = np.array([

# 髪(右外側)
    (400, 270),
    (415, 271),
    (430, 273),
    (440, 276),
    (450, 280),
    (460, 285),
    (470, 290),
    (480, 298),
    (490, 309),
    (495, 315),
    (500, 330),
    (504, 340),
    (507, 350),
    (509, 360),
    (510, 370),
    (510, 400),
    (509, 430),
    (507, 460),
    (504, 500),

# 首(右)
    (424, 500),
    (425, 491),

# 輪郭右(耳除く)
    (430, 489),
    (440, 485),
    (450, 480),
    (460, 470),
    (465, 458),

    (467, 450),
    (475, 447),
    (478, 440),
    (480, 434),
    (475, 430),

    (479, 420),
    (482, 410),
    (485, 400),
    (488, 390),

# 髪(右内側)途中まで
    (488, 390),
    (480, 385),

    (456, 378),
    (452, 350),
    (448, 330),

], dtype=np.int32)
cv2.fillConvexPoly(img, pts1_1, (127, 127, 127))

# 髪塗りつぶし
pts1_2 = np.array([
# 頭頂
    (400, 270),

# 髪(右内側)途中から
    (440, 315),
    (444, 330),
    (448, 350),

    (450, 376),
    (430, 372),
    (405, 370),
    (404, 350),
    (403, 325),
    (402, 320),
    (401, 310),
    (400, 305),

], dtype=np.int32)
cv2.fillConvexPoly(img, pts1_2, (127, 127, 127))

# 髪塗りつぶし
pts1_3 = np.array([
# 頭頂
    (400, 270),

# 髪(左内側)途中まで
#   (400, 305),
    (399, 310),
    (398, 320),
    (397, 325),
    (396, 350),
    (395, 370),
    (370, 372),
    (350, 376),

    (352, 350),
    (356, 330),
    (360, 315),

], dtype=np.int32)
cv2.fillConvexPoly(img, pts1_3, (127, 127, 127))

# 髪塗りつぶし
pts1_4 = np.array([

# 髪(左内側)途中から
    (352, 330),
    (348, 350),
    (344, 378),

    (320, 385),
    (312, 390),

# 輪郭左(耳除く)
    (312, 390),
    (315, 400),
    (318, 410),
    (321, 420),

    (325, 430),
    (320, 434),
    (322, 440),
    (325, 447),
    (333, 450),

    (335, 458),
    (340, 470),
    (350, 480),
    (360, 485),
    (370, 489),

# 首(左)
    (375, 491),
    (376, 500),

# 髪(左外側)
    (296, 500),
    (293, 460),
    (291, 430),
    (290, 400),
    (290, 370),
    (291, 360),
    (293, 350),
    (296, 340),
    (300, 330),
    (305, 315),
    (310, 309),
    (320, 298),
    (330, 290),
    (340, 285),
    (350, 280),
    (360, 276),
    (370, 273),
    (385, 271),
    (400, 270),

], dtype=np.int32)
cv2.fillConvexPoly(img, pts1_4, (127, 127, 127))

# 輪郭
pts2 = np.array([
#   (400, 300),
#   (410, 301),
#   (420, 303),
#   (430, 306),
#   (440, 310),
#   (450, 315),
#   (460, 320),
#   (470, 328),
#   (480, 339),
#   (485, 345),
#   (491, 360),
#   (491, 370),
#   (490, 380),
    (488, 390),
    (485, 400),
    (482, 410),
    (479, 420),
    (475, 430),
    (470, 440),
    (465, 458),
    (460, 470),
    (450, 480),
    (440, 485),
    (430, 489),
    (420, 493),
    (410, 497),
    (400, 500),
    (390, 497),
    (380, 493),
    (370, 489),
    (360, 485),
    (350, 480),
    (340, 470),
    (335, 458),
    (330, 440),
    (325, 430),
    (321, 420),
    (318, 410),
    (315, 400),
    (312, 390),
#   (310, 380),
#   (309, 370),
#   (309, 360),
#   (315, 345),
#   (320, 339),
#   (330, 328),
#   (340, 320),
#   (350, 315),
#   (360, 310),
#   (370, 306),
#   (380, 303),
#   (390, 301),
#   (400, 300),
], dtype=np.int32)
cv2.polylines(img, [pts2], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 右目
cv2.ellipse(  img, (440, 430), ( 12,  20), 180, 0, 180, (127, 127, 127), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((440, 430), ( 25,  40), 0), (  0,   0,   0),  2, cv2.LINE_AA)
cv2.ellipse(  img, ((440, 430), ( 10,  16), 0), (  0,   0,   0), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((444, 420), (  6,   6), 0), (255, 255, 255), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((444, 420), (  6,   6), 0), (  0,   0,   0),  1, cv2.LINE_AA)

# 左目
cv2.ellipse(  img, (360, 430), ( 12,  20), 180, 0, 180, (127, 127, 127), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((360, 430), ( 25,  40), 0), (  0,   0,   0),  2, cv2.LINE_AA)
cv2.ellipse(  img, ((360, 430), ( 10,  16), 0), (  0,   0,   0), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((364, 420), (  6,   6), 0), (255, 255, 255), -1, cv2.LINE_AA)
cv2.ellipse(  img, ((364, 420), (  6,   6), 0), (  0,   0,   0),  1, cv2.LINE_AA)

# 右眉毛
pts3 = np.array([
    (420, 400),
    (430, 390),
    (440, 385),
    (450, 390),
    (460, 400),
    (470, 415),
], dtype=np.int32)
cv2.polylines(img, [pts3], False, (  0,   0,   0), 2, cv2.LINE_AA)

#左眉毛
pts4 = np.array([
    (380, 400),
    (370, 390),
    (360, 385),
    (350, 390),
    (340, 400),
    (330, 415),
], dtype=np.int32)
cv2.polylines(img, [pts4], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 右まつ毛
pts5 = np.array([
    (425, 418),
    (430, 413),
    (440, 408),
    (450, 413),
    (455, 423),
    (460, 434),
], dtype=np.int32)
cv2.polylines(img, [pts5], False, (  0,   0,   0), 2, cv2.LINE_AA)

pts5_5 = np.array([
    (460, 434),
    (458, 437),
], dtype=np.int32)
cv2.polylines(img, [pts5_5], False, (  0,   0,   0), 1, cv2.LINE_AA)

# 左まつ毛
pts6 = np.array([
    (375, 418),
    (370, 413),
    (360, 408),
    (350, 413),
    (345, 423),
    (340, 434),
], dtype=np.int32)
cv2.polylines(img, [pts6], False, (  0,   0,   0), 2, cv2.LINE_AA)

pts6_5 = np.array([
    (340, 434),
    (342, 437),
], dtype=np.int32)
cv2.polylines(img, [pts6_5], False, (  0,   0,   0), 1, cv2.LINE_AA)

# 鼻
pts7 = np.array([
    (401, 448),
    (399, 450),
    (401, 452),
], dtype=np.int32)
cv2.polylines(img, [pts7], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 口
pts8 = np.array([
    (380, 470),
    (385, 473),
    (390, 474),
    (400, 475),
    (410, 474),
    (415, 473),
    (420, 470),
], dtype=np.int32)
cv2.polylines(img, [pts8], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 首(右)
pts9 = np.array([
    (425, 491),
    (424, 500),
], dtype=np.int32)
cv2.polylines(img, [pts9], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 首(左)
pts10 = np.array([
    (375, 491),
    (376, 500),
], dtype=np.int32)
cv2.polylines(img, [pts10], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 右耳
pts11 = np.array([
    (475, 430),
    (480, 434),
    (478, 440),
    (475, 447),
    (467, 450),
], dtype=np.int32)
cv2.polylines(img, [pts11], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 左耳
pts11 = np.array([
    (325, 430),
    (320, 434),
    (322, 440),
    (325, 447),
    (333, 450),
], dtype=np.int32)
cv2.polylines(img, [pts11], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 髪(右外側)
pts12 = np.array([
    (400, 270),
    (415, 271),
    (430, 273),
    (440, 276),
    (450, 280),
    (460, 285),
    (470, 290),
    (480, 298),
    (490, 309),
    (495, 315),
    (500, 330),
    (504, 340),
    (507, 350),
    (509, 360),
    (510, 370),
    (510, 400),
    (509, 430),
    (507, 460),
    (504, 500),
], dtype=np.int32)
cv2.polylines(img, [pts12], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 髪(左外側)
pts13 = np.array([
    (400, 270),
    (385, 271),
    (370, 273),
    (360, 276),
    (350, 280),
    (340, 285),
    (330, 290),
    (320, 298),
    (310, 309),
    (305, 315),
    (300, 330),
    (296, 340),
    (293, 350),
    (291, 360),
    (290, 370),
    (290, 400),
    (291, 430),
    (293, 460),
    (296, 500),
], dtype=np.int32)
cv2.polylines(img, [pts13], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 髪(右内側)
pts16 = np.array([
    (400, 305),
    (401, 310),
    (402, 320),
    (403, 325),
    (404, 350),
    (405, 370),
    (430, 372),
    (450, 376),

    (448, 350),
    (444, 330),
    (440, 315),

    (448, 330),
    (452, 350),
    (456, 378),

    (480, 385),
    (488, 390),
], dtype=np.int32)
cv2.polylines(img, [pts16], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 髪(左内側)
pts17 = np.array([
    (400, 305),
    (399, 310),
    (398, 320),
    (397, 325),
    (396, 350),
    (395, 370),
    (370, 372),
    (350, 376),

    (352, 350),
    (356, 330),
    (360, 315),

    (352, 330),
    (348, 350),
    (344, 378),

    (320, 385),
    (312, 390),
], dtype=np.int32)
cv2.polylines(img, [pts17], False, (  0,   0,   0), 2, cv2.LINE_AA)

# 右頬
cv2.line(img, (430, 460), (435, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (434, 460), (439, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (438, 460), (443, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (442, 460), (447, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (446, 460), (451, 455), (  0,   0,   0), 1, cv2.LINE_AA)

# 左頬
cv2.line(img, (350, 460), (355, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (354, 460), (359, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (358, 460), (363, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (362, 460), (367, 455), (  0,   0,   0), 1, cv2.LINE_AA)
cv2.line(img, (366, 460), (371, 455), (  0,   0,   0), 1, cv2.LINE_AA)

cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.参考

Python, OpenCVで図形描画(線、長方形、円、矢印、文字など) | note.nkmk.me
Amazon.co.jp: 萌えキャラクターの描き方 顔・からだ編 (マンガの技法書) eBook: 伊原達矢, 角丸つぶら: Kindleストア

5.その他

OpenCVだと曲線は円弧(楕円含む)しかなく、曲線を書きづらいので、続きはGIMP Python-Fuに移行しています。
GIMP Python-Fuでイラストを描く その1 - Qiita

4
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2