5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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ストア]
(https://www.amazon.co.jp/dp/B014KS0WGY)

#5.その他

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

5
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
5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?