Python+OpenCVでイラストを描く

#1.はじめに

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

#2.実行結果

![20191127.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534247/73b3ecae-1ace-3c16-b839-ab490c0b4b9e.png)

#3.スクリプト全体

```Python: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](https://note.nkmk.me/python-opencv-draw-function/)
[Amazon.co.jp： 萌えキャラクターの描き方　顔・からだ編 (マンガの技法書) eBook: 伊原達矢, 角丸つぶら: Kindleストア]
(https://www.amazon.co.jp/dp/B014KS0WGY)

#5.その他

OpenCVだと曲線は円弧(楕円含む)しかなく、曲線を書きづらいので、続きはGIMP Python-Fuに移行しています。
→[GIMP Python-Fuでイラストを描く その1 - Qiita](https://qiita.com/mayo00/items/27380386566136f03813)