Python Pillow(PIL)で画像を読み込んでNumPyの配列に変換してRGBの要素ごとに編集する

下記の画像を使用しました。
Biljana JovanovicによるPixabayからの画像

from PIL import Image
import numpy as np

pil_img = Image.open('eggs-gbd58ab03b_640.png')
print('モード', pil_img.mode)

np_img = np.array(pil_img)   #PILからnumpyへ変換
np_img[:, :, 0] = 0   #赤の要素を削除
np_img[:, :, 1] = 0   #緑の要素を削除
new_pil_img = Image.fromarray(np_img)   #numpyからPILへ変換

new_pil_img.show()
new_pil_img.save('out.png')
元の画像
編集後の画像

Pythonのglobモジュールで複数の拡張子を指定してファイル一覧を取得する

カレントディレクトリの「画像」ディレクトリの中のファイルの中から
拡張子が「jpg」と「png」のファイルの一覧を取得する。

方法1
import glob

types = ('jpg', 'png')
files = []
for t in types:
    files += glob.glob('./画像/*.' + t)

for file in files:
    print(file)
方法2
import glob

for file in glob.glob('./画像/*'):
    type = file[-3:]
    if type in ('jpg', 'png'):
        print(file)
方法3
import glob
import re

for file in glob.glob('./画像/*'):
    if re.match('.+\.(png|jpg)$', file):
        print(file)

Pygame入門 ブロック崩しゲームを作る(途中) ボールと衝突したブロックを消す しかし、ボールはブロックに当たっても跳ね返らない

マウスの左クリックで開始します
f:id:collatz:20220407104507g:plain

import pygame
import sys

SCREEN = pygame.Rect(0, 0, 400, 400)
FPS = 30

WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

BALL_SIZE = 20

PADDLE_WIDTH = 60
PADDLE_HEIGHT = 5
PADDLE_POS_Y = SCREEN.bottom - 30

BLOCK_ROW = 5
BLOCK_COLUMN = 6
BLOCK_MARGIN = 10
BLOCK_WIDTH = ((SCREEN.width - BLOCK_MARGIN) / BLOCK_COLUMN) - BLOCK_MARGIN
BLOCK_HEIGHT = 20

class Ball(pygame.sprite.Sprite):
    def __init__(self, pos, speed):
        pygame.sprite.Sprite.__init__(self, self.containers)
        x, y = pos
        vx, vy = speed
        self.image = pygame.Surface((BALL_SIZE, BALL_SIZE))
        self.image.fill(WHITE)
        pygame.draw.circle(self.image, RED, self.image.get_rect().center, BALL_SIZE / 2)
        self.rect = pygame.Rect(x, y, BALL_SIZE, BALL_SIZE)
        self.vx = vx
        self.vy = vy
        self.update = self.start #これにより、updateメソッドが実行されるとstartメソッドが実行される

    def start(self):
        #Ballの初期X座標をPaddleのX座標にする
        self.rect.centerx = paddle.rect.centerx

        #マウスの左クリックによりBallを動かし始める
        if pygame.mouse.get_pressed()[0]:
            self.update = self.move #これにより、updateメソッドが実行されるとstartメソッドが実行される

    def move(self):
        #Ballを移動させる
        self.rect.move_ip(self.vx, self.vy)
        #Paddleに当たったら跳ね返る
        if self.rect.colliderect(paddle.rect):
            self.vy = -self.vy
            self.rect.bottom = paddle.rect.top
        #画面の左端か右端に当たったら跳ね返る
        if self.rect.left < SCREEN.left or SCREEN.right < self.rect.right:
            self.vx = -self.vx
        #画面の上端に当たったら跳ね返る
        if self.rect.top < SCREEN.top:
            self.vy = -self.vy
        #画面の下端に当たったら止まる
        if SCREEN.bottom < self.rect.bottom:
            self.vx = 0
            self.vy = 0

        self.rect = self.rect.clamp(SCREEN) #SCREENから出ないようにする

class Paddle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.Surface((PADDLE_WIDTH, PADDLE_HEIGHT))
        self.image.fill(GREEN)
        self.rect = pygame.Rect(0, PADDLE_POS_Y, PADDLE_WIDTH, PADDLE_HEIGHT)

    def update(self):
        self.rect.centerx = pygame.mouse.get_pos()[0] #Paddleの真ん中のX座標をマウスのX座標にする
        self.rect = self.rect.clamp(SCREEN) #SCREENから出ないようにする

class Block(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self, self.containers)
        x, y = pos
        self.image = pygame.Surface((BLOCK_WIDTH, BLOCK_HEIGHT))
        self.image.fill(BLUE)
        self.rect = pygame.Rect(x, y, BLOCK_WIDTH, BLOCK_HEIGHT)

#main
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode(SCREEN.size)

sprite_group = pygame.sprite.Group() #すべてのスプライトの更新と描画を行うためのグループ
block_group = pygame.sprite.Group() #BallとBlockの衝突判定とBlockの削除を行うためのグループ
Ball.containers = sprite_group #これにより、Ballインスタンスが自動でsprite_groupに追加される
Paddle.containers = sprite_group #これにより、Paddleインスタンスが自動でsprite_groupに追加される
Block.containers = sprite_group, block_group #これにより、Blockインスタンスが自動でsprite_groupとblock_groupに追加される

ball = Ball((200, 150), (6, 6))
paddle = Paddle()
#Blockの作成
for r in range(BLOCK_ROW):
    for c in range(BLOCK_COLUMN):
        block_x =  BLOCK_MARGIN + (BLOCK_WIDTH + BLOCK_MARGIN) * c
        block_y = BLOCK_MARGIN + (BLOCK_HEIGHT + BLOCK_MARGIN) * r
        Block((block_x, block_y))

while True:
    #Ballと衝突したBlockを削除する
    #ballスプライトとblock_groupに属している各Blockスプライトの衝突を判定してくれる
    #3つ目の引数をTrueにするとballと衝突したBlockがblock_groupから削除される
    #それによりballと衝突したBlockは画面から消える。(画面描画はsprite_group.draw(screen)により行われているため。)
    pygame.sprite.spritecollide(ball, block_group, True)

    sprite_group.update()
    screen.fill(WHITE)
    sprite_group.draw(screen)
    pygame.display.update()
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

PythonのSympyを使って2点を結ぶ2本の線分の交点の座標をベクトルを使って計算する

import numpy
import sympy

#点p1と点p2を結ぶ線分と点p3と点p4を結ぶ線分の交点を求める
def intersection(p1, p2, p3, p4):
    #各点をベクトルで表す
    a1 = numpy.array(p1)
    a2 = numpy.array(p2)
    a3 = numpy.array(p3)
    a4 = numpy.array(p4)

    #方程式で使う変数の準備
    k = sympy.Symbol('k')
    t = sympy.Symbol('t')

    #点p1と点p2を通るベクトル方程式
    vec1 = a1 + k * (a2 - a1)
    #点p3と点p4を通るベクトル方程式
    vec2 = a3 + t * (a4 - a3)

    eq1 = sympy.Eq(vec1[0], vec2[0])
    eq2 = sympy.Eq(vec1[1], vec2[1])

    s = sympy.solve((eq1, eq2))

    return (a1 + s[k] * (a2 - a1))

print(intersection((2,7),(6,1),(2,3),(6,5)))

forth入門

gforthのインストール
Debian系のLinuxの場合
$ sudo apt install gforth

gforthの起動
$ gforth

gforthの終了
byeと入力するかCtrl+Dを押す

1 + 2 を計算する
1 2 + .s

1 + 2 * 3 を計算する
1 2 3 * + .s

(1 + 2) * (3 + 4)を計算する
1 2 + 3 4 + * .s

スタックの一番上の要素をコピーしてスタックに積む
1 2 3 ok
.s <3> 1 2 3 ok
dup ok
.s <4> 1 2 3 3 ok

スタックの1番目と2番目を交換する
1 2 3 ok
.s <3> 1 2 3 ok
swap ok
.s <3> 1 3 2 ok

スタックの3番目の要素を取り出し1番上に積む
1 2 3 ok
.s <3> 1 2 3 ok
rot ok
.s <3> 2 3 1 ok

ワードの定義
1を足すワード「inc」の定義
: inc 1 + ;
使用例
2 inc
2乗するワードの定義
: square dup * ;

Pygame入門 Sprite同士の衝突を検知して、そのSpriteを削除する

f:id:collatz:20220405170715g:plain
pygame.sprite.spritecollideでSprite同士の衝突を検知できる。
また、引数の指定によって、衝突したSpriteを削除できる。

pygame.sprite.spritecollide(sprite, group, dokill)
2番めの引数のgroupに属するSpriteのうち、
1番目の引数のspriteと衝突しているもののリストを返す。
3番めの引数のdokillをTrueにすると、衝突しているSpriteがgroupから削除される。
Spriteの衝突判定は、Spriteのrectプロパティによって行っている。

import pygame
import sys

SCREEN = pygame.Rect(0, 0, 400, 400)
FPS = 30

WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)

BALL_SIZE = 20

PADDLE_WIDTH = 60
PADDLE_HEIGHT = 20
PADDLE_POS_Y = SCREEN.bottom - PADDLE_HEIGHT * 2

class Ball(pygame.sprite.Sprite):
    def __init__(self, pos, speed):
        pygame.sprite.Sprite.__init__(self, self.containers)
        x, y = pos
        vx, vy = speed
        self.image = pygame.Surface((BALL_SIZE, BALL_SIZE))
        self.image.fill(WHITE)
        pygame.draw.circle(self.image, RED, self.image.get_rect().center, BALL_SIZE / 2)
        self.rect = pygame.Rect(x, y, BALL_SIZE, BALL_SIZE)
        self.vx = vx
        self.vy = vy

    def update(self):
        self.rect.move_ip(self.vx, self.vy)
        if self.rect.left < SCREEN.left or SCREEN.right < self.rect.right:
            self.vx = -self.vx
        if self.rect.top < SCREEN.top or SCREEN.bottom < self.rect.bottom:
            self.vy = -self.vy
        self.rect = self.rect.clamp(SCREEN)

class Paddle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self, self.containers)
        self.image = pygame.Surface((PADDLE_WIDTH, PADDLE_HEIGHT))
        self.image.fill(GREEN)
        self.rect = pygame.Rect(0, PADDLE_POS_Y, PADDLE_WIDTH, PADDLE_HEIGHT)

    def update(self):
        self.rect.centerx = pygame.mouse.get_pos()[0] #Paddleの真ん中のX座標をマウスのX座標にする
        self.rect = self.rect.clamp(SCREEN) #SCREENから出ないようにする

#main()
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode(SCREEN.size)

sprite_group = pygame.sprite.Group() #すべてのスプライトの更新と描画を行うためのグループ
ball_group = pygame.sprite.Group() #Paddleとの衝突を調べるためのグループ

Ball.containers = sprite_group, ball_group
Paddle.containers = sprite_group

Ball((200, 200), (2, 3))
Ball((100, 200), (3, 3))
Ball((100, 300), (3, 4))
paddle = Paddle()

while True:
    #paddleと衝突したBallを削除する
    pygame.sprite.spritecollide(paddle, ball_group, True)

    screen.fill(WHITE)
    sprite_group.update()
    sprite_group.draw(screen)

    pygame.display.update()
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

Pygame入門 ブロック崩しのパドルをスプライトで作る

スプライトの使い方

1.「pygame.sprite.Sprite」を継承してスプライトオブジェクトを作る

2.スプライトグループを作る

3.スプライトグループにスプライトオブジェクトを追加する

4.スプライトグループの更新を実行する

グループに追加されているスプライトオブジェクトのupdate()メソッドが実行される。

5.スプライトグループの描画を実行する

グループに追加されているスプライトオブジェクトのself.imageとself.rectの内容を使って描画される。
self.image(pygame.Surface型)によって描画される内容が決まる。
self.rect(pygame.Rect型)によって描画される位置が決まる。

マウスの位置によってパドルが左右に動くプログラム

import pygame
import sys

SCREEN = pygame.Rect(0, 0, 400, 400)
FPS = 30

WHITE = (255, 255, 255)
GREEN = (0, 255, 0)

PADDLE_WIDTH = 60
PADDLE_HEIGHT = 20
PADDLE_POS_Y = SCREEN.bottom - PADDLE_HEIGHT * 2

class Paddle(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((PADDLE_WIDTH, PADDLE_HEIGHT))
        self.image.fill(GREEN)
        self.rect = pygame.Rect(0, PADDLE_POS_Y, PADDLE_WIDTH, PADDLE_HEIGHT)

    def update(self):
        self.rect.left = pygame.mouse.get_pos()[0] #Paddleの左端をマウスのX座標にする
        self.rect = self.rect.clamp(SCREEN) #SCREENから出ないようにする


pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode(SCREEN.size)
paddle = Paddle() #スプライトオブジェクトの作成
sprite_group = pygame.sprite.Group() #スプライトグループの作成
sprite_group.add(paddle) #スプライトグループへスプライトオブジェクトを追加

while True:
    screen.fill(WHITE)
    sprite_group.update() #スプライトグループの更新
    sprite_group.draw(screen) #スプライトグループの描画

    pygame.display.update()
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()