41
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Python + Pillow で英文かぎ針編みパターンから編み図を自動生成するツールを作ってみた

Last updated at Posted at 2025-12-14

はじめに

こんにちは:sunny:
any 株式会社のエンジニア @n__aki です:santa_tone1:
この記事は、any Product Team Advent Calendar2025 15日目の記事になります!


数年前から趣味で続けている、かぎ針編み🧶
1本のかぎ針で毛糸を編んでいく手芸で、例えば下記のような小さなモチーフから、
鞄・マフラー・洋服のような大きなものまで作ることができます。

最近は海外のサイトでパターン(編み方の手順書)を購入することも増えてきました。
ただ、海外のパターンは英文の文章で指示が書かれている一方、
日本では記号(○、●、T など)で構造を示した「編み図」 が一般的。
文章と記号という違いがあるため、慣れないうちは理解にかなり時間がかかります。

普段はChatGPTに英文パターンを日本語訳してもらったりしているのですが、
「これが編み図だったらな...」と思うようになりました。

そこで今回、英文パターンをもとに
Pythonで自動的に編み図を生成するツールを作ってみました!

最終的には、英文パターンをそのまま読み込んで
編み図として可視化するところまで全部自動化することを目指しています:muscle:

🎯 作ったもの

今回実装したツールでは、以下のようなことができるようになっています。

  • JSONのパターンから編み図(PNG画像)を自動生成
  • Round1までは円形、Round2以降は正方形…などといったハイブリッド配置
  • 3種類のステッチ記号(dc, ch, slst)に対応
  • 立ち上がりの目を縦に配置
  • 正方形周囲上の距離ベースで均等に記号を配置
  • start / sequence / end 構造を理解し、繰り返し部分を自動展開

🛠 技術スタック

  • Python 3.x
  • Pillow (PIL)
    • 画像生成・描画
  • 編み図らしい見た目を再現するための配置ロジック
    • 段ごとに「丸 → 四角」へ形を切り替えて並べる
    • 正方形の外周に一定間隔で記号を配置する
    • 立ち上がり目(ch1〜ch3など)をスタート地点として他のステッチを並べる

🚀 使い方

インストール

pip install Pillow

基本的な使用方法

# JSONファイルから編み図を生成
python crochet_chart_v2.py -j pattern.json

# Round 1から正方形配置
python crochet_chart_v2.py -j pattern.json --square-from 1

# 出力ファイル名を指定
python crochet_chart_v2.py -j pattern.json -o my_chart.png

JSONのパターン例

今回のツールでは、以下のようなJSONを読み込みます。
英文パターンからの変換にはChatGPTを使用しました。

英文パターン(例)

Round 1: Magic ring, ch 3 (counts as dc), 2 dc, ch 2, *3 dc, ch 2; repeat from * 2 more times, join with slst to top of ch-3.

Round 2: Ch 3 (counts as dc), 2 dc in same space, ch 1, *(3 dc, ch 2, 3 dc) in next ch-2 space, ch 1; repeat from * 2 more times, (3 dc, ch 2) in last ch-2 space, join with slst to top of ch-3.

JSON(例)

{
  "rounds": [
    {
      "round": "start",
      "repeat": 0,
      "sequence": [
        {"stitch": "ch", "count": 5},
        {"stitch": "slst", "count": 1}
      ]
    },
    {
      "round": 1,
      "repeat": 3,
      "start": [
        {"stitch": "ch", "count": 3},
        {"stitch": "dc", "count": 2},
        {"stitch": "ch", "count": 2}
      ],
      "sequence": [
        {"stitch": "dc", "count": 3},
        {"stitch": "ch", "count": 2}
      ],
      "end": [
        {"stitch": "slst", "count": 1}
      ]
    }
  ]
}

🔧 実装のポイント

1. 正方形での記号配置は「角度」ではなく「距離」を使う

正方形の場合、角度で均等に分割しても記号が均等に並びませんでした。
そこで、角度ではなく正方形の周囲長に沿った距離を基準に配置する方式としました。

def calculate_square_point_from_perimeter(self, perimeter_pos: float, radius: float):
    """
    正方形の周囲上の位置(距離)からxy座標を計算する
    """
    side_length = radius * 2
    half_side = side_length / 2
    perimeter = side_length * 4
    
    # 周囲上の位置を正規化
    perimeter_pos = perimeter_pos % perimeter
    
    if perimeter_pos <= side_length:
        # 上辺 (左から右)
        x = -half_side + perimeter_pos
        y = -half_side
        angle = 0
    elif perimeter_pos <= side_length * 2:
        # 右辺 (上から下)
        x = half_side
        y = -half_side + (perimeter_pos - side_length)
        angle = math.pi / 2
    # ... 下辺、左辺も同様
    
    return x, y, angle

→ これにより「角で記号が詰まってしまう」問題を解消しました!

2. ch3基準の相対配置

かぎ針編みでは、各ラウンドの最初に「立ち上がりの目(今回はch3)」が入ります。
この ch3 は 「次の段のスタート位置」 にあたるため、
編み図でも ch3 の位置を基準点として他の記号を並べる必要があります。

そのため今回のツールでは、

  • まず前段の slst の位置から ch3 の正確な位置を計算し
  • ch3 を次の段の基準点(ゼロ地点)として
  • そこから反時計回りに dc や ch などのステッチを等間隔に配置する

というch3基準の相対配置を採用しました。
これにより、自然な記号の並び方が再現できたと思います。

# ch3の実際のxy座標から正方形周囲上の位置(距離)を計算
if prev_slst_position is not None:
    ch3_x, ch3_y = prev_slst_position
    rel_x = ch3_x - self.center[0]
    rel_y = ch3_y - self.center[1]
    
    # 正方形のどの辺にあるかを判定
    if abs(rel_y + half_side) < abs(half_side / 10):  # 上辺
        ch3_perimeter_pos = rel_x + half_side
    elif abs(rel_x - half_side) < abs(half_side / 10):  # 右辺
        ch3_perimeter_pos = side_length + (rel_y + half_side)
    # ... 他の辺も同様

# 1ステッチあたりの周囲上の距離
distance_per_stitch = perimeter / remaining_count

# ch3の左隣から反時計回りに配置
current_perimeter_pos = ch3_perimeter_pos - distance_per_stitch * (adjusted_idx + 1)

3. start / sequence / end 構造に対応

多くの英文パターンは「スタート → 繰り返し → 終わり」で構成されています。
そのため、これを反映した繰り返しロジックを展開しました。

def expand_to_tokens_v2(pattern_json: Dict[str, Any]) -> List[List[str]]:
    rounds_tokens = []
    
    for round_data in pattern_json["rounds"]:
        round_tokens = []
        round_num = round_data["round"]
        repeat_count = round_data.get("repeat", 1)
        
        # startラウンドの場合(repeat=0)
        if round_num == "start" or repeat_count == 0:
            sequence = round_data.get("sequence", [])
            for item in sequence:
                stitch = item["stitch"]
                count = item["count"]
                round_tokens.extend([stitch] * count)
        else:
            # 通常のラウンド
            # 1. start部分(1回のみ)
            start_sequence = round_data.get("start", [])
            for item in start_sequence:
                stitch = item["stitch"]
                count = item["count"]
                round_tokens.extend([stitch] * count)
            
            # 2. sequence部分(repeat回繰り返す)
            sequence = round_data.get("sequence", [])
            for _ in range(repeat_count):
                for item in sequence:
                    stitch = item["stitch"]
                    count = item["count"]
                    round_tokens.extend([stitch] * count)
            
            # 3. end部分(1回のみ)
            end_sequence = round_data.get("end", [])
            for item in end_sequence:
                stitch = item["stitch"]
                count = item["count"]
                round_tokens.extend([stitch] * count)
        
        rounds_tokens.append(round_tokens)
    
    return rounds_tokens

4. ステッチ記号の描画

各ステッチに応じた記号を角度を考慮して描画します。

def draw_stitch_symbol(self, draw: ImageDraw.Draw, x: float, y: float, 
                      stitch: str, angle: float = 0, vertical_ch: bool = False):
    # 角度に応じた回転を考慮
    def rotate_point(px, py, angle):
        cos_a = math.cos(angle)
        sin_a = math.sin(angle)
        return (px * cos_a - py * sin_a, px * sin_a + py * cos_a)
    
    if stitch == "dc":  # double crochet
        # 縦線 + 上部横線 + 中央斜め線
        # 各点を回転して描画
    elif stitch == "ch":  # chain
        if vertical_ch:
            # 縦長の楕円(立ち上がりチェーン用)
            width = half_size // 2
            height = half_size
        else:
            # 横長の楕円(通常のチェーン)
            width = half_size
            height = half_size // 2

📊 処理の流れ

JSON入力
  ↓
トークン列展開(start/sequence/end構造を処理)
  ↓
各ラウンドの形状判定(円形 or 正方形)
  ↓
ch3検出 & 縦配置
  ↓
ch3基準の相対配置計算
  ↓
周囲距離ベースで座標計算
  ↓
ステッチ記号描画
  ↓
PNG画像出力

📘 実際に生成してみる

まず、参考として実際に使用されている編み図の例を紹介します。

出典: https://www.felissimo.co.jp/couturier/blog/event/knitting-festival/post-31433/

続いて、今回のツールで生成した編み図がこちらです。
(上記の参考例とは異なるモチーフのものになります)

基本的な形は再現できているものの、
実際の編み図と比べると、まだ改善したい部分もいくつか見えてきました。

🔍 現時点の課題

1. 「どこに編み入れるか」がわかりづらい

英文パターンでは

  • ch2-space
  • next space
  • top of ch-3

といった「編み入れ位置」が指定されていますが、
現在の描画ではこれらの位置が視覚的に分かりにくいという問題があります。

2. 編み図の角とモチーフの角がずれている

正方形の周囲に均等配置しているため、

  • 描画された編み図の角
  • モチーフの実際の角

が一致しないケースがあります。

✨ 今後の改善点

今回のツールは「編み図の自動生成」としては大きな一歩ですが、
さらに実際の編み図に近づけるための改善点も多くあります。

具体的な改善案として考えているのがこちらです👇


1. 英文パターン → JSONの完全自動化(ChatGPT API組み込み)

英文パターンをそのまま貼るだけで編み図が作成できるように、

  • ラウンド解析
  • repeat展開
  • stitch数抽出
  • 編み入れ位置(in next space、ch2-space など)の解釈
  • JSON生成

まで全自動化したいです:muscle:

2. 編み入れ位置の明確化

現状の編み図では「どこに編み入れるのか」がわかりづらい状態になっています。

  • 記号に角度をつける
  • その記号が「どのスペースに属するか」をJSONに含める

などの対応をすることで読みやすい編み図に近づけたいです:muscle:

3. 角位置の明確化

生成された編み図の角と、実際のモチーフの角がずれてしまう問題があります。

  • Corner cluster(例: 3dc, ch2, 3dc)の中央を角として指定
  • 角はステッチの数に応じて左右へ微調整

などを試してみることで編み図と実際のモチーフの角が合うようにしたいです:muscle:

🎉 まとめ

今回、英文パターンから編み図を描画するツールを作ってみました。
記号の並べ方や回転、段ごとの形状など試行錯誤しながらの開発でしたが、
ひとまず動くものになり達成感がありました!

まだまだ改善ポイントは残っているので、 これからも調整を重ねて
より読みやすい編み図を作れるツールに育てていきたいと思います!

41
3
0

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
41
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?