031_py_pillow - kotaproj/study_zenpan GitHub Wiki
from PIL import Image, ImageDraw, ImageFont
image = Image.new("1", (128, 64))
image
# ドットを配置(2点)
draw.point([(10, 10), (20, 20)], fill='white')
image
# ライン描画
draw.line([(30, 30), (40, 40)], fill='white', width=2)
image
pillow使い方
画像読み込み
https://note.nkmk.me/python-pillow-basic/
from PIL import Image, ImageFilter
im = Image.open('data/src/lenna_square.png')
画像保存
https://note.nkmk.me/python-pillow-basic/
new_im.save('data/dst/lenna_square_pillow.jpg', quality=95)
二値化 - 1
gray = img.convert("L") # グレイスケールに変換
gray.point(lambda x: 0 if x < 230 else x) # 値が230以下は0になる
二値化 - 2
https://qiita.com/kikuchiTakuya/items/9c1da0aaaf88f231d2e3
import numpy as np
from PIL import Image
from matplotlib import pylab as plt
img = np.array(Image.open('lena.jpg').convert('L'), 'f')
img = (img > 128) * 255
plt.imshow(img)
plt.show()
pillow <-> numpy変換
https://white-wheels.hatenadiary.org/entry/20100322/p1
pillow -> numpy
NumpyのarrayからPILへの変換 PILのfromarrayメソッドによって、配列の各値を1byte整数型(0〜255)として画像のpixel値に変換することができます。
pilImg = Image.fromarray(numpy.uint8(imgArray))
numpy -> pillow
import numpy
import Image
PILからNumpyのarrayへの変換 numpyで用意されているasarray関数を使うと、PILのImageオブジェクトを配列に変換することができます。
imgArray = numpy.asarray(pilImg)
さらに配列の値を書き変えられるようにするためには、writeableフラグをTrueにする必要があるようです。
imgArray.flags.writeable = True
直線、多角形、点
https://note.nkmk.me/python-pillow-imagedraw/
- 直線 : line(xy, fill, width)
- xy
- ((x1, y1), (x2, y2), (x3, y3)...)のように2点以上の複数の座標を指定する。
- 各点を結んだ直線が描画される。
- width : 線幅(線の太さ)
- widthで線幅を太くした場合、xyで3点以上指定すると接続部が不格好になる。
- xy
- 多角形 : polygon(xy, fill, outline)
- xy
- ((x1, y1), (x2, y2), (x3, y3)...)のように3点以上の複数の座標を指定する。
- 各点と最初と最後の点が結ばれた多角形が描画される。
- xy
- 点 : point(xy, fill)
- xy
- ((x1, y1), (x2, y2), (x3, y3)...)のように1点以上の複数の座標を指定する。
- 各点に1ピクセルの点が描画される。
- xy
直線(line())、多角形(polygon())、点(point())の例。点は1ピクセルなので見づらいが右側に描画されている。
im = Image.new('RGB', (500, 250), (128, 128, 128))
draw = ImageDraw.Draw(im)
draw.line(((30, 200), (130, 100), (80, 50)), fill=(255, 255, 0))
draw.line(((80, 200), (180, 100), (130, 50)), fill=(255, 255, 0), width=10)
draw.polygon(((200, 200), (300, 100), (250, 50)), fill=(255, 255, 0), outline=(0, 0, 0))
draw.point(((350, 200), (450, 100), (400, 50)), fill=(255, 255, 0))
楕円
draw.ellipse((100, 100, 150, 200), fill=(255, 0, 0), outline=(0, 0, 0))
四角
draw.rectangle((200, 100, 300, 200), fill=(0, 192, 192), outline=(255, 255, 255))
直線
draw.line((350, 200, 450, 100), fill=(255, 255, 0), width=10)
一時データ
import PIL.Image
import PIL.ImageDraw
import PIL.ImageFont
import webcolors
# 使うフォント,サイズ,描くテキストの設定
ttfontname = "ipaexg.ttf"
fontsize = 28
rain_colors = ["red", "green", "blue", "cyan", "white", "magenta", "yellow"]
def create_msgpng(msg, color):
# 画像サイズ,背景色を設定
canvasSize = (32*(len(msg)+2), 32)
backgroundRGB = webcolors.name_to_rgb("black")
# 文字を描く画像の作成
img = PIL.Image.new('RGB', canvasSize, backgroundRGB)
draw = PIL.ImageDraw.Draw(img)
# 用意した画像に文字列を描く
x_off, y_off = 28, 0
font = PIL.ImageFont.truetype(ttfontname, 28)
for cnt, moji in enumerate(msg):
textWidth, textHeight = draw.textsize(moji, font=font)
textTopLeft = (x_off, 28 - 28)
if "rainbow" in color:
rgb = webcolors.name_to_rgb(rain_colors[cnt%len(rain_colors)])
else:
rgb = webcolors.name_to_rgb(color)
draw.text(textTopLeft, moji, fill=rgb, font=font)
x_off += textWidth
img = img.crop((0, 0, x_off+28, 32))
img.save("image_moku2.png")
create_msgpng("〇×xxxfaklfaj ", color="rainbow")
import board
import neopixel
import time
import numpy as np
import cv2
IMG_PATH = "image_moku.png"
# IMG_PATH = "heart_dokidoki.gif"
# シリアルLEDの初期化
pixel_pin = board.D18
num_pixels = 32*32
ORDER = neopixel.GRB
pixels = neopixel.NeoPixel(
pixel_pin, num_pixels, brightness=0.010, auto_write=False, pixel_order=ORDER
)
def show32x32_pixel(np_rgb):
global pixels
for cnt in range(32):
if cnt%2 == 0:
# [D],[C]エリア - 偶数行の並べ替え
for scnt, val in enumerate(np_rgb[cnt,:16,]):
pixels[1023 - cnt*16 - scnt] = (val[0], val[1], val[2])
# [A],[B]エリア - 偶数行の並べ替え
for scnt, val in enumerate(np_rgb[cnt,16:,]):
pixels[cnt*16 + 16 - 1 - scnt] = (val[0], val[1], val[2])
else:
# [D],[C]エリア - 奇数行の並べ替え
for scnt, val in enumerate(np_rgb[cnt,:16:,]):
pixels[1024 - (cnt+1)*16 + scnt] = (val[0], val[1], val[2])
# [A],[B]エリア - 奇数行の並べ替え
for scnt, val in enumerate(np_rgb[cnt,16:,]):
pixels[cnt*16 + scnt] = (val[0], val[1], val[2])
pixels.show()
return
def main():
# 消灯
pixels.fill((0, 0, 0))
pixels.show()
cap = cv2.VideoCapture(IMG_PATH)
while True:
ret, frame = cap.read()
if ret == False:
break
h, w, _ = frame.shape
# スクロール表示
for srt in range(w-32):
show32x32_pixel(cv2.cvtColor(frame[:,srt:srt+32,:], cv2.COLOR_BGR2RGB))
time.sleep(0.1)
# LED消灯
pixels.fill((0, 0, 0))
pixels.show()
if __name__ == "__main__":
main()