Mac って何?それって美味しいの?

マイコンと呼ばれた時代から現在まで、使用記から何から何でも。

画像生成AIでレース。

競馬場で人間を走らせようとすると、どうしてもウマが生成されてしまう。

プロンプトを試行錯誤して、やっと実現できるようになった。

アイドル 牝 競走

4枚目、唯一生成されたメガネっ娘を推したい。

 

女子高生レース

混戦のため同じ高校でチームを組んでたりします。

汚れ具合がレースの激しさを物語っています。

 

大人女子レース

大人女子のレースは色気がでますね。

 

楽しくって、調子に乗りすぎた。

最後は普通にアニメ風に。

アニメ風

 

Re: らーめんチャレンジ

だめだ。画像生成AI、楽しすぎる。

前回に引き続き「ゆるふわギャル」でラーメンチャレンジ。

 

yummac.hatenablog.jp

Stable Diffusionでチャレンジしてみる。

使用マシンは iMac 2011 core i7 なので気長に待ちます。

ゆるふわギャル eating ramen

chilled_remix_V2, step:25, upscale Latent 2x

これは生成に指定しているモデルにも影響されるよね。

箸を持つ指も苦手なのがわかります。これでも頑張っているほう。

ラーメンをすするゆるふわギャル(学生)

もう、箸を持たずにすすっています。ゆび多め。

ラーメンを食べない

オシャレな感じだけど、もはや食べない。映えればいいの。

 

Bing Image Creatorでも、プロンプトに本気出してみる。

ラーメンを食べるゆるふわギャル(ノスタルジック)

ラーメンを食べるゆるふわギャル(誤生成)

 

プロンプトのちょっとの加減でネコになります。

それにしても、箸を持つ手(指)が上手に描けています。前足か。

 

それから、パステルなゆるふわにしてみる。

ラーメンを食べるゆるふわギャル(ぱすてる)

こちらはまた、ちょっとした加減で「安全でない画像コンテンツが検出されました」扱いでブロックされてしまいます。

ラーメンを食べるゆるふわギャルは「不適切」なのか。

いやいや、「性的」なものを思わせるプロンプトがまずいんだろうね。

らーめんチャレンジ

今週のお題「こぼしたもの」

 

最近、Stable DiffusionをiMacで使って遊んでいるが、なんと、Microsoft Edgeで画像生成できるという記事を見た。

DALL-E3を無料で使え、Stable Diffusionよりも上手く描けるという?!

そして、さっそく試してみた。

Gooole Chrome使いの私なので、ときどき勝手に起動するEdgeは嫌いなヤツだったが、ひさしぶりにダブルクリックした。

Microsoft Bing の Image Creator」のページを表示する。

Edge関係なかった。chromeでもできるやん。

そして、最近お気に入りの「ゆるふわギャル」でラーメンチャレンジ。

プロンプトは日本語でOK。生成したい画像の説明を文章で入力すればいい。

「ラーメンを食べているゆるふわギャル」

ラーメンを食べているゆるふわギャル

かわいいイラストが生成された。

イラストではなくリアルにするには「写真」を指示するのか。

3画像生成された。

ラーメンを食べている「ゆるふわ美少女」の写真

なぜか、ネコが生成されるんだよねぇ。

イラストの時もネコが最初だった。

「ゆるふわ」がふさふさなネコを想像させる?

でもすごいな!楽しい。

 

追加)

Bing AIチャットを使うと勝手に画像生成してくれる!

ただ、AIでプロンプト変換してから画像生成するので期待しているのと出来が異なることが多い。

「ゆるふわギャル」の特徴をチャットでAI自身が説明しているにも関わらず、ネコイラストが生成される。

やっぱりImage Creatorのページでプロンプトに記述したほうが期待していいる画像に近づけると思います。

「写真、ラーメンを食べている「ゆるふわギャル」、髪型:長くて、ウェーブがかかっていることが多いです。 メイク:ナチュラルメイクが多く、ピンクやベージュなどの淡い色を使います。 ファッション:ゆるいシルエットの服を好みます。」

写真、ラーメンを食べている「ゆるふわギャル」、髪型:長くて、ウェーブがかかっていることが多いです。 メイク:ナチュラルメイクが多く、ピンクやベージュなどの淡い色を使います。 ファッション:ゆるいシルエットの服を好みます。

 

iMac 2011 i7 で AUTOMATIC1111 / stable-diffusion-webui が動作するなんて!

google Colab を利用させていただき(無料プランなので低姿勢で)

Stable Diffusionによる画像生成を楽しんでましたが、いよいよ

有料でなければ使えなくなってしまいました。

あの、楽しい画像生成をどうにか無料でできないか。

このiMacでは動かないの?

えっ?動くの?!10年以上前のGPUだよ?

生成時間は目を瞑れる。寝て待つのは苦じゃ無い。

それじゃ、まあ、動くかどうかやってみよー

 

マシン

iMac Core i7 2.8 21.5-Inch mid-2011

CPU : Intel Core I7 2600S Quad Core 2.8 GHz 

GPU : AMD Radeon HD 6770M 512MB

RAM : 16GB

 

インストール

こちらのサイトを参考にさせていただきました。ありがとうございます。

M1/Intel MacにStable DiffusinをインストールAUTOMATIC1111編 | Gift by Gifted

 

私が引っかかったところだけ記述します。

Pythonのバージョンは3.10推奨、3.11はエラーで起動しない

Pythonバージョンは既にインストールしてある3.11の方が新しいし、このままでいいだろうと思い実行したが起動途中エラーで止まってしまう。

3.10をインストールしたら起動できた。

GPUが半精度浮動小数点数計算できないエラー

Generateボタンをクリックするとエラーが出る。

RuntimeError: "LayerNormKernelImpl" not implemented for 'Half'

グラフィックカードが半精度浮動小数点数の計算に対応していないからのようで、

webui-macos-env.shのCOMMANDLINE_ARGSを変更した。

export COMMANDLINE_ARGS="--skip-torch-cuda-test --upcast-sampling --no-half-vae --use-cpu all --precision full --no-half"

GPUは使わずCPUで演算するようになる?

 

そして生成してみた!

stable diffusion on iMac

”cat” step:10 512x512で所要時間は3分30秒くらい

”girl” step:20 512x512で所要時間は7分くらい

step10だとナニコレ画像になるかと思ったけど、悪く無い。普通にネコだ。

step20でおおよそ倍の時間かかったけど、7分くらい全然待てるよ。

プロンプトのウェイトや拡張機能で長くなるだろうけど、

google Colabで、エラーで止まるのを恐れながら使うのを考えたら

使い慣れたiMacで安心してできちゃうのが素敵。

これからも遊ばせていただきます。

Python知識ゼロから始めるchatGPTを利用した超簡単ゲームプログラミング(応用編)

 

yummac.hatenablog.jp

 

前回作成?生成?した、CUIで遊べるカードゲームをGUI画面で遊べるようにする。

Pythonの知識がない私が頼るのはchatGPT様だ。

とりあえずわがまま言ってみる。

「このゲームをGUI画面で遊べるようにコードを作成してください」

回答:

以下は、Tkinterを使用して作成したカードバトルゲームのGUIの一部です。このコードを基にして、GUI画面で遊べるカードバトルゲームを構築することができます。

import tkinter as tk
import random

# カードデッキを作成
suits = ['ハート', 'ダイヤ', 'スペード', 'クラブ']
ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'ジャック', 'クイーン', 'キング', 'エース']
deck = [{'スート': suit, 'ランク': rank} for suit in suits for rank in ranks]

# プレイヤーを作成
player1 = {'名前': 'プレイヤー1', '手札': []}
player2 = {'名前': 'コンピュータ', '手札': []}

# ゲームを初期化
def initialize_game():
    player1['手札'] = []
    player2['手札'] = []
    for _ in range(5):
        player1['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))
        player2['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))
    update_display()

# ゲームの進行
def play_round():
    player1_card = player1['手札'].pop(random.randint(0, len(player1['手札']) - 1))
    player2_card = player2['手札'].pop(random.randint(0, len(player2['手札']) - 1))
    winner = battle(player1_card, player2_card)
    if winner == player1:
        result_label.config(text=f"{player1['名前']}の勝利!")
    elif winner == player2:
        result_label.config(text=f"{player2['名前']}の勝利!")
    else:
        result_label.config(text="引き分け")
    update_display()

# カードのバトル
def battle(player1_card, player2_card):
    rank_order = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'ジャック', 'クイーン', 'キング', 'エース']
    if rank_order.index(player1_card['ランク']) > rank_order.index(player2_card['ランク']):
        return player1
    elif rank_order.index(player1_card['ランク']) < rank_order.index(player2_card['ランク']):
        return player2
    else:
        return None

# 画面の更新
def update_display():
    player1_label.config(text=f"{player1['名前']}の手札: {', '.join([card['ランク'] for card in player1['手札']])}")
    player2_label.config(text=f"{player2['名前']}の手札: {', '.join([card['ランク'] for card in player2['手札']])}")

# Tkinterウィンドウを作成
root = tk.Tk()
root.title("カードバトルゲーム")

# ボタンとラベルを配置
start_button = tk.Button(root, text="ゲームを始める", command=initialize_game)
start_button.pack()
play_button = tk.Button(root, text="ラウンドをプレイ", command=play_round)
play_button.pack()
result_label = tk.Label(root, text="")
result_label.pack()
player1_label = tk.Label(root, text="")
player1_label.pack()
player2_label = tk.Label(root, text="")
player2_label.pack()

# ゲームを初期化
initialize_game()

# Tkinterウィンドウを表示
root.mainloop()

こりゃ楽ちんだぜ!と喜んだのも束の間、実行してみるとコレジャナイ感が。

でも、これをベースにカスタマイズして作り上げるってことだね。

どんどんchatGPTに要望や質問を投げてコードをカスタマイズしていく。

「手札のカードを横に並べて表示し、その中からプレイヤーが選んでバトルするようにしたい」

「プレイヤー1のカードをマウスでクリックして選択できるようにしたい」

「カードに画像を表示したい」

カード画像はStableDiffusionで生成しますが、サイズが小さいとコレジャナイ画像が生成されてしまうので、512 x 768で生成しました。

ゲームで表示するにはデカすぎるので縮小します。

画像変形ツールを使って縮小しておくのが常套手段ですが、

ここはあえてPythonでやります。

「カードの画像サイズを幅128、高さ192にしたい」

回答:

〜 Pillow(PIL)ライブラリを使用して画像をリサイズすることができます。

ここで、生成されたコードの動作には、追加のライブラリをインストールする作業が必要となりました。

Windowsならコマンドプロンプトから、Macならターミナルから、Pillowライブラリをインストールします。

pip install Pillow

うまくいかないときはググってみましょう。

まだまだchatGPT様のお世話になります。

canvasの背景色を深緑にしたい」

「カード画像5枚横に並べて表示し、クリックされたカード画像に外枠を表示、前にクリックし表示していた枠は消すようにしてください」

「それぞれのカード画像の下にランクを表示したい」

・・・

そんなこんなで出来上がった「ドラゴンカードゲーム」

ドラゴンカードゲーム
import tkinter as tk
from tkinter import messagebox
from tkinter import PhotoImage
from PIL import Image, ImageTk  # Pillowライブラリをインポート
import random

# カードデッキを作成
suits = ['ハート', 'ダイヤ', 'スペード', 'クラブ']
ranks = ['ドラコ', 'リザードマン', 'ドレイク', 'ヒドラ', 'サーペント', 'ワイバーン', 'アジュールドラゴン', 'クリムゾンドラゴン', '西洋ドラゴン', '東洋ドラゴン']
deck = [{'スート': suit, 'ランク': rank} for suit in suits for rank in ranks]
card_width = 128
card_height = 192
card_interval = 20
card_p1_y = 310
card_p2_y = 40

# プレイヤーを作成
player1 = {'名前': 'あなた', '手札': []}
player2 = {'名前': 'コンピュータ', '手札': []}

#プレイヤー1カード(表示用)
player1_cards = {}

# 選択されたカードを格納する変数
selected_card = None

# 外枠の色を指定
frame_color = "red"

# 選択されたカードのインデックスを保持する変数
selected_card_index = None

# ゲームの設定
rounds = 5  # ラウンド数を指定
round_num = 0
player1_score = 0
player2_score = 0

# 各ランクに対応する画像ファイルを辞書に格納
original_images = {}
card_images = {}
text_objects = []

# ゲームを初期化
def initialize_game():
    global round_num
    global player1_score
    global player2_score
    global player1_cards
    round_num = 0
    player1_score = 0
    player2_score = 0
    player1_cards = []
    player1['手札'] = []
    player2['手札'] = []
    deck = []
    deck = [{'スート': suit, 'ランク': rank} for suit in suits for rank in ranks]
    for _ in range(5):
        player1['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))
        player2['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))

    # 選択されたカードをクリア
    global selected_card
    selected_card = None
    global selected_card_index
    canvas.delete(selected_card_index)
    selected_card_index = None
    global text_objects
    for text_object in text_objects:
        canvas.delete(text_object)
    text_objects = []

    #update_display()
    # プレイヤー1の手札を描画
    canvas.delete("player1_hand")
    x = card_interval
    for card in player1['手札']:
        draw_card(canvas, x, card_p1_y, card, 1)
        x += (card_width + card_interval)

    # プレイヤー2(コンピュータ)の手札を描画
    canvas.delete("player2_hand")
    x = card_interval
    for card in player2['手札']:
        draw_card(canvas, x, card_p2_y, card, 0)
        x += (card_width + card_interval)
    
    result_label1.config(text="")
    result_label2.config(text="")
    result_label3.config(text="")

# ゲームの進行
def play_round():
    global player1_score
    global player2_score
    global round_num

    if round_num > rounds:
        messagebox.showinfo("エラー", "「ゲームを始める」をクリックしてください")
        return

    # プレイヤー1(人間)がカードを選ぶ
    global selected_card  # グローバル変数として選択されたカードを保持
    if selected_card is None:
        messagebox.showinfo("エラー", "カードを選択してください。")
        return
    player1_card = selected_card

    round_num += 1

    # プレイヤー2(コンピュータ)が一番強いカードを選ぶ
    player2_card = select_strongest_card(player2['手札'])

    result_label1.config(text=f"{player2['名前']}のカード : {player2_card['ランク']} " + "★" * (ranks.index(player2_card['ランク']) + 1))
    result_label2.config(text=f"{player1['名前']}のカード : {player1_card['ランク']} " + "★" * (ranks.index(player1_card['ランク']) + 1))
    winner = battle(player1_card, player2_card)
    if winner == player1:
        player1_score += 1
        result_label3.config(text=f"{player1['名前']}の勝利!")
    elif winner == player2:
        player2_score += 1
        result_label3.config(text=f"{player2['名前']}の勝利!")
    else:
        result_label3.config(text="引き分け")

    if round_num >= rounds:
        round_num += 1
        # 最終結果を表示
        if player1_score > player2_score:
            messagebox.showinfo("ゲーム終了",f"結果発表\n{player1['名前']} : {player1_score}勝\n{player2['名前']} : {player2_score}勝\n{player1['名前']}の勝利!")
        elif player1_score < player2_score:
            messagebox.showinfo("ゲーム終了",f"結果発表\n{player1['名前']} : {player1_score}勝\n{player2['名前']} : {player2_score}勝\n{player2['名前']}の勝利!")
        else:
            messagebox.showinfo("ゲーム終了",f"結果発表\n{player1['名前']} : {player1_score}勝\n{player2['名前']} : {player2_score}勝\n引き分け!")
        return
    
    # プレイヤー1の手札から選択されたカードを削除
    player1['手札'].remove(selected_card)
    
    # プレイヤー2の手札から選択されたカードを削除
    player2['手札'].remove(player2_card)

    # カードをデッキからランダムに選び、手札に加える
    player1['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))
    player2['手札'].append(deck.pop(random.randint(0, len(deck) - 1)))

    # 選択されたカードをクリア
    selected_card = None
    global selected_card_index
    canvas.delete(selected_card_index)
    selected_card_index = None
    global text_objects
    for text_object in text_objects:
        canvas.delete(text_object)
    text_objects = []

    # プレイヤー1の手札を描画
    canvas.delete("player1_hand")
    x = card_interval
    for card in player1['手札']:
        draw_card(canvas, x, card_p1_y, card, 1)
        x += (card_width + card_interval)

    # プレイヤー2(コンピュータ)の手札を描画
    canvas.delete("player2_hand")
    x = card_interval
    for card in player2['手札']:
        draw_card(canvas, x, card_p2_y, card, 0)
        x += (card_width + card_interval)

def battle(player1_card, player2_card):
    global ranks
    if ranks.index(player1_card['ランク']) > ranks.index(player2_card['ランク']):
        return player1
    elif ranks.index(player1_card['ランク']) < ranks.index(player2_card['ランク']):
        return player2
    else:
        return None

def select_strongest_card(player_hand):
    global ranks
    strongest_card = None
    for card in player_hand:
        if not strongest_card or ranks.index(card['ランク']) > ranks.index(strongest_card['ランク']):
            strongest_card = card
    return strongest_card

def draw_card(canvas, x, y, card, sw):
    suit = card['スート']
    rank = card['ランク']
    rank_i = "★" * (ranks.index(rank) + 1)
    card_text = f"{rank}\n{rank_i}"

    # カード画像を配置
    card_object = canvas.create_image(x, y, anchor=tk.NW, image=card_images[rank])
    if sw > 0:
        canvas.tag_bind(card_object, "", select_card)

    # カードテキストを配置
    text_object = canvas.create_text(x, (y + card_height + 5), text=card_text, anchor="nw", fill="white", font=("Helvetica", 12))
    text_objects.append(text_object)

# クリックされたカードの処理
def select_card(event):
    global selected_card_index
    # 前に選択されたカードの外枠を削除
    if selected_card_index is not None:
        canvas.delete(selected_card_index)
    
    global selected_card
    x, y = event.x, event.y  # クリックされた位置のx座標とy座標を取得
    for card in player1['手札']:
        card_x, card_y = get_card_position(player1['手札'].index(card))
        if card_x <= x <= card_x + card_width and card_y <= y <= card_y + card_height:
            selected_card = card
            break

    # クリックされたカードの外枠を表示
    selected_card_index = canvas.create_rectangle((card_x - 2), (card_y - 2), (card_x + card_width + 2), (card_y + card_height + 2), outline=frame_color, width=2)

def get_card_position(index):
    x = card_interval + index * (card_width + card_interval)
    return x, card_p1_y

# Tkinterウィンドウを作成
root = tk.Tk()
root.title("カードバトルゲーム")

# Canvasを作成
canvas = tk.Canvas(root, width=800, height=550, bg="dark green")
canvas.pack()

# デフォルトカードに対応する画像ファイルを読み込む
default_card_image = Image.open('default.png')

# Stable Diffusion で生成した画像のサイズが大きいため縮小します
# 幅と高さ比2:3で512*768とかで生成(サイズ小さいとコレジャナイ画像になるため)
# 各ランクの画像ファイルを読み込み、Tkinter PhotoImageオブジェクトに変換して格納
for rank in ranks:
    image_file = f"{rank}.png"  # ランクごとの画像ファイル名を生成
    original_images[rank] = Image.open(image_file)

    # 対応するランクの画像を辞書から取得
    original_image = original_images.get(rank)
    
    if original_image:
        # 画像を指定のサイズにリサイズ
        resized_image = original_image.resize((card_width, card_height), Image.LANCZOS)

        # リサイズした画像をTkinter PhotoImageオブジェクトに変換
        card_images[rank] = ImageTk.PhotoImage(resized_image)
    else:
        # デフォルト画像を指定のサイズにリサイズ
        resized_image = default_card_image.resize((card_width, card_height), Image.LANCZOS)

        # リサイズした画像をTkinter PhotoImageオブジェクトに変換
        card_images[rank] = ImageTk.PhotoImage(resized_image)

#テキスト配置
canvas.create_text(card_interval, card_p1_y - 20, text=f"{player1['名前']}のカード", anchor="w", fill="white", font=("Helvetica", 14))
canvas.create_text(card_interval, card_p2_y - 20, text=f"{player2['名前']}のカード", anchor="w", fill="white", font=("Helvetica", 14))

# ボタンとラベルを配置
play_button = tk.Button(root, text="選んだカードで対決!", command=play_round)
play_button.pack()
start_button = tk.Button(root, text="ゲームを始める", command=initialize_game)
start_button.pack()
result_label1 = tk.Label(root, text="")
result_label1.pack()
result_label2 = tk.Label(root, text="")
result_label2.pack()
result_label3 = tk.Label(root, text="")
result_label3.pack()

# ゲームを初期化
initialize_game()

# Tkinterウィンドウを表示
root.mainloop()

生成されたコードを付け加えたり変更したりで大変だった感じはあるが

これを知識が無いところから作成することを考えたら

もう、素晴らしいね。

出来上がったコードは、まだ変なところとかあったり、

コンピュータのカードを隠せるようにするなど、改良の余地はあるけど、

なんか、標題の目的を達成できた感がある。

今回はドラゴンで男の子向けだが、女の子向けの画像も用意したいなと思っている。

オトナ向けは・・・やめておこう。

Fusion DriveのMacにOSがインストールできない問題の解決

Mac mini Late 2014 ジャンクを手に入れた。

なんでも、macOSのインストールができないらしい。

実機を起動してみる。

macOS 復旧 は問題なく起動した。

でも、いざインストールしようとすると「復旧サーバに接続できません」となる。

じゃUSBインストーラで、と電源押すと禁止マーク(丸に斜線)が表示され 、

macOS 復旧も起動しない。High sierra でも Catalina でも。

もちろんPROMクリアはやってる。それでダメってことはEFIくさい。

Fusion Drive ってのもなんかあやしい。

OCLPのUSBインストーラでVenturaの復旧メニュー起動できた。

ターミナルのdiskutilでFusion Driveを再作成してみる。

Fusion Drive が分割された場合の修復方法 - Apple サポート (日本)

diskutil resetFusion

なんだか、いい感じに再作成された気がする。

が、やはりUSBインストーラは禁止マークで止まる。

再度、OCLPのUSBインストーラでVenturaの復旧メニュー起動し、

今度はFusion Driveを解除してSSDとHDDに分離、初期化をする。

diskutil list
diskutil apfs deleteContainer disk2

disk2の部分は環境によって異なる場合があります。

diskutil list の結果から適切な値を指定してください。

 

分離したSSD、HDDそれぞれHFS+で初期化する。

SSD128GBのやつだ。ここで初めてSSDの容量がはっきりした。

今度はUSBインストーラのCatalina復旧メニュー起動。

分離したまま128GBのSSDにインストールしてみる。

 

インストール完了後、やはり「このMacについて」を確認。

同型の i7 をちょっと期待してたけど i5 だった。

2.8GHzだからi5でも上位機種だね。

不具合も解消し、スペック的にも悪くないし、どうしようかな。