nuizu 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nuizu-0.1.0/PKG-INFO +220 -0
- nuizu-0.1.0/README.md +204 -0
- nuizu-0.1.0/pyproject.toml +23 -0
- nuizu-0.1.0/src/nuizu/__init__.py +2 -0
- nuizu-0.1.0/src/nuizu/__main__.py +232 -0
- nuizu-0.1.0/src/nuizu/auto_angle.py +146 -0
- nuizu-0.1.0/src/nuizu/compensate.py +274 -0
- nuizu-0.1.0/src/nuizu/fill.py +397 -0
- nuizu-0.1.0/src/nuizu/formats/__init__.py +1 -0
- nuizu-0.1.0/src/nuizu/formats/common.py +98 -0
- nuizu-0.1.0/src/nuizu/formats/dst.py +257 -0
- nuizu-0.1.0/src/nuizu/formats/jef.py +234 -0
- nuizu-0.1.0/src/nuizu/formats/pes.py +289 -0
- nuizu-0.1.0/src/nuizu/optimize.py +88 -0
- nuizu-0.1.0/src/nuizu/palettes.py +158 -0
- nuizu-0.1.0/src/nuizu/pipeline.py +605 -0
- nuizu-0.1.0/src/nuizu/preprocess.py +258 -0
- nuizu-0.1.0/src/nuizu/quantize.py +416 -0
- nuizu-0.1.0/src/nuizu/segment.py +298 -0
- nuizu-0.1.0/src/nuizu/svg_preview.py +212 -0
nuizu-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nuizu
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Convert photos to embroidery data files (DST / PES / JEF)
|
|
5
|
+
Author: mokuichi147
|
|
6
|
+
License-Expression: MIT OR Apache-2.0
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Requires-Dist: opencv-python
|
|
9
|
+
Requires-Dist: pillow
|
|
10
|
+
Requires-Dist: scikit-learn
|
|
11
|
+
Requires-Dist: typer
|
|
12
|
+
Requires-Python: >=3.12.10
|
|
13
|
+
Project-URL: Homepage, https://github.com/Mokuichi147/Nuizu
|
|
14
|
+
Project-URL: Repository, https://github.com/Mokuichi147/Nuizu
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# Nuizu
|
|
18
|
+
|
|
19
|
+
写真・イラスト・漫画など、あらゆる画像を刺繍用データファイルに変換するPython CLIツール。
|
|
20
|
+
JANOME、Brother、その他主要刺繍機向けの出力形式に対応。
|
|
21
|
+
|
|
22
|
+
## 対応出力形式
|
|
23
|
+
|
|
24
|
+
| 形式 | 拡張子 | 対応機種 |
|
|
25
|
+
|------|--------|----------|
|
|
26
|
+
| Tajima DST | `.dst` | ほぼ全機種対応(最も互換性が高い) |
|
|
27
|
+
| Brother PES | `.pes` | Brother / Babylock |
|
|
28
|
+
| JANOME JEF | `.jef` | JANOME |
|
|
29
|
+
|
|
30
|
+
## 必要環境
|
|
31
|
+
|
|
32
|
+
- `uv`
|
|
33
|
+
- Python 3.12+
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uv sync
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## クイックスタート
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# 基本変換(JEF形式、出力パス省略)
|
|
43
|
+
uv run nuizu jef photo.jpg
|
|
44
|
+
|
|
45
|
+
# 12色、最長辺150mmで変換(プレビューはSVG形式に変更)
|
|
46
|
+
uv run nuizu jef photo.png design.jef --colors 12 --size 150 --preview svg
|
|
47
|
+
|
|
48
|
+
# フル機能(最大色数指定、自動角度、プルコンペンセーション、背景あり)
|
|
49
|
+
uv run nuizu dst photo.jpg design.dst \
|
|
50
|
+
--max-colors 10 \
|
|
51
|
+
--auto-angle --pull-comp 0.3 -b
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
基本構文:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
uv run nuizu <dst|pes|jef> 入力画像 [出力ファイル]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `出力ファイル`を省略すると、入力画像と同名で拡張子だけが各形式に変わります(例: `photo.jpg` → `photo.dst`)。
|
|
61
|
+
|
|
62
|
+
## 全オプション一覧(`dst` / `pes` / `jef` 共通)
|
|
63
|
+
|
|
64
|
+
### サイズ
|
|
65
|
+
|
|
66
|
+
| オプション | デフォルト | 説明 |
|
|
67
|
+
|-----------|-----------|------|
|
|
68
|
+
| `-s, --size` | 100 | 最長辺の目標サイズ (mm) |
|
|
69
|
+
|
|
70
|
+
### カラー
|
|
71
|
+
|
|
72
|
+
| オプション | デフォルト | 説明 |
|
|
73
|
+
|-----------|-----------|------|
|
|
74
|
+
| `-c, --colors` | - | 使用する糸色数(厳密に維持) |
|
|
75
|
+
| `-m, --max-colors` | 8 | 最大糸色数(指定数以下に自動調整) |
|
|
76
|
+
| `-p, --palette` | auto | 糸パレット (`auto`, `janome`, `brother`, `madeira`, `generic`) |
|
|
77
|
+
|
|
78
|
+
### ステッチ
|
|
79
|
+
|
|
80
|
+
| オプション | デフォルト | 説明 |
|
|
81
|
+
|-----------|-----------|------|
|
|
82
|
+
| `-t, --thread-width` | 0.4 | 糸幅 (mm) |
|
|
83
|
+
| `-d, --density` | 糸幅と同値 | フィル行間隔 mm(小さい=密) |
|
|
84
|
+
| `-l, --stitch-length` | 3.0 | 最大ステッチ長 mm |
|
|
85
|
+
| `-a, --angle` | 45 | フィルステッチ角度(度) |
|
|
86
|
+
| `--auto-angle` | - | 領域ごとに最適フィル角度を自動決定 |
|
|
87
|
+
| `--no-underlay` | - | アンダーレイ(下縫い)無効 |
|
|
88
|
+
| `--no-outline` | - | アウトライン無効 |
|
|
89
|
+
| `--satin-outline` | - | アウトラインをサテンステッチに |
|
|
90
|
+
| `--pull-comp MM` | 0 | プルコンペンセーション mm(推奨: 0.2-0.5) |
|
|
91
|
+
|
|
92
|
+
### 画像処理
|
|
93
|
+
|
|
94
|
+
| オプション | デフォルト | 説明 |
|
|
95
|
+
|-----------|-----------|------|
|
|
96
|
+
| `--blur` | 3 | ぼかし半径(0=無効) |
|
|
97
|
+
| `--min-region` | 0.001 | 最小領域サイズ(画像全体に対する比率) |
|
|
98
|
+
| `--auto-crop` | - | 被写体を自動検出してクロップ |
|
|
99
|
+
| `-b, --background` | - | 背景色もステッチに含める(デフォルトはスキップ) |
|
|
100
|
+
|
|
101
|
+
### 出力
|
|
102
|
+
|
|
103
|
+
| オプション | デフォルト | 説明 |
|
|
104
|
+
|-----------|-----------|------|
|
|
105
|
+
| `--preview` | png | プレビュー生成 (`png`, `svg`, `none`) |
|
|
106
|
+
| `-q, --quiet` | - | 進行状況メッセージを抑制 |
|
|
107
|
+
|
|
108
|
+
## 処理パイプライン
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
[入力画像]
|
|
112
|
+
│
|
|
113
|
+
▼
|
|
114
|
+
[1] 前処理
|
|
115
|
+
├── リサイズ(最大800px)
|
|
116
|
+
├── Gaussianぼかし(ノイズ軽減)
|
|
117
|
+
└── Medianフィルタ(アンチエイリアス・JPEG圧縮ノイズ除去)
|
|
118
|
+
│
|
|
119
|
+
▼
|
|
120
|
+
[2] 色量子化
|
|
121
|
+
├── LAB色空間でK-meansクラスタリング
|
|
122
|
+
├── 刺繍糸パレットへスナップ(JANOME/Brother/Madeira)
|
|
123
|
+
├── 近似色クラスタの自動マージ(ΔE閾値)
|
|
124
|
+
└── 明るい背景の自動検出(前景比率チェック)
|
|
125
|
+
│
|
|
126
|
+
▼
|
|
127
|
+
[3] 領域分割
|
|
128
|
+
├── ラベルマップ平滑化(多数決投票)
|
|
129
|
+
├── 暗色ピクセルの復元(輪郭・ストローク保護)
|
|
130
|
+
├── OpenCV輪郭抽出(RETR_CCOMP: 穴あり対応)
|
|
131
|
+
├── モルフォロジー処理(小ギャップの閉鎖)
|
|
132
|
+
└── ピクセル座標 → mm座標変換
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
[4] ステッチ順序最適化
|
|
136
|
+
├── 色グループ化(色変更最小化)
|
|
137
|
+
└── グループ内で最近傍法(ジャンプ最小化)
|
|
138
|
+
│
|
|
139
|
+
▼
|
|
140
|
+
[5] ステッチ生成
|
|
141
|
+
├── プルコンペンセーション(輪郭拡張)
|
|
142
|
+
├── 自動フィル角度決定(PCA / minAreaRect)
|
|
143
|
+
├── 細幅領域のフィルスキップ(アウトラインのみ)
|
|
144
|
+
├── アンダーレイ(垂直方向・疎)
|
|
145
|
+
├── メインフィル(スキャンライン走査)
|
|
146
|
+
├── フィルコンペンセーション(行端延長)
|
|
147
|
+
├── アウトライン(ランニング or サテン)
|
|
148
|
+
└── ロングステッチ分割(最大7mm)
|
|
149
|
+
│
|
|
150
|
+
▼
|
|
151
|
+
[6] ファイル出力(DST / PES / JEF)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## アーキテクチャ
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
src/nuizu/
|
|
158
|
+
├── __main__.py # CLI エントリーポイント(Typer)
|
|
159
|
+
├── pipeline.py # メイン変換パイプライン
|
|
160
|
+
├── preprocess.py # 画像前処理(背景検出、自動クロップ)
|
|
161
|
+
├── quantize.py # 色量子化(K-means / LAB色空間 / クラスタマージ)
|
|
162
|
+
├── palettes.py # 実メーカー糸パレット(JANOME / Brother / Madeira)
|
|
163
|
+
├── segment.py # 領域分割(OpenCV contour / 穴あり階層抽出)
|
|
164
|
+
├── auto_angle.py # フィル角度自動最適化(PCA / minAreaRect)
|
|
165
|
+
├── fill.py # フィルステッチ生成(ラスタスキャンライン方式)
|
|
166
|
+
├── compensate.py # プルコンペンセーション(布引き攣り補正)
|
|
167
|
+
├── optimize.py # ステッチ順序最適化
|
|
168
|
+
├── svg_preview.py # SVGプレビュー生成
|
|
169
|
+
└── formats/
|
|
170
|
+
├── common.py # 共通データ構造(Stitch, Pattern, ThreadColor)
|
|
171
|
+
├── dst.py # Tajima DST ライター
|
|
172
|
+
├── pes.py # Brother PES ライター
|
|
173
|
+
└── jef.py # JANOME JEF ライター
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 使用例
|
|
177
|
+
|
|
178
|
+
### 写真をJANOMEで刺繍する
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
uv run nuizu jef portrait.jpg portrait.jef \
|
|
182
|
+
--palette janome --colors 8 --size 100 \
|
|
183
|
+
--auto-angle --pull-comp 0.3
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### 被写体を自動クロップして刺繍
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
uv run nuizu dst flower.jpg flower.dst \
|
|
190
|
+
--auto-crop --colors 6
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### 密度の高い高品質仕上げ
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
uv run nuizu pes logo.png logo.pes \
|
|
197
|
+
--density 0.25 --stitch-length 2.5 --satin-outline \
|
|
198
|
+
--pull-comp 0.4 --max-colors 10
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### シンプルな変換
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
uv run nuizu dst photo.jpg \
|
|
205
|
+
--no-underlay --no-outline --colors 4
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## プルコンペンセーションの目安
|
|
209
|
+
|
|
210
|
+
| 生地タイプ | 推奨値 (mm) |
|
|
211
|
+
|-----------|-------------|
|
|
212
|
+
| 薄い生地(オーガンジー、シルク) | 0.2 - 0.3 |
|
|
213
|
+
| 中厚生地(コットン、リネン) | 0.3 - 0.4 |
|
|
214
|
+
| 厚い生地(デニム、キャンバス) | 0.4 - 0.6 |
|
|
215
|
+
|
|
216
|
+
## 制限事項
|
|
217
|
+
|
|
218
|
+
- 出力ファイルのバイナリ形式はリバースエンジニアリングに基づいています。実機での動作は糸・生地・テンションなど多くの要因に依存します。
|
|
219
|
+
- 写真の変換品質は元画像のコントラストと色の明確さに大きく左右されます。
|
|
220
|
+
- 非常に大きな刺繍(200mm超)ではステッチ数が数万を超え、実機での刺繍時間が長くなります。
|
nuizu-0.1.0/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Nuizu
|
|
2
|
+
|
|
3
|
+
写真・イラスト・漫画など、あらゆる画像を刺繍用データファイルに変換するPython CLIツール。
|
|
4
|
+
JANOME、Brother、その他主要刺繍機向けの出力形式に対応。
|
|
5
|
+
|
|
6
|
+
## 対応出力形式
|
|
7
|
+
|
|
8
|
+
| 形式 | 拡張子 | 対応機種 |
|
|
9
|
+
|------|--------|----------|
|
|
10
|
+
| Tajima DST | `.dst` | ほぼ全機種対応(最も互換性が高い) |
|
|
11
|
+
| Brother PES | `.pes` | Brother / Babylock |
|
|
12
|
+
| JANOME JEF | `.jef` | JANOME |
|
|
13
|
+
|
|
14
|
+
## 必要環境
|
|
15
|
+
|
|
16
|
+
- `uv`
|
|
17
|
+
- Python 3.12+
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
uv sync
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## クイックスタート
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# 基本変換(JEF形式、出力パス省略)
|
|
27
|
+
uv run nuizu jef photo.jpg
|
|
28
|
+
|
|
29
|
+
# 12色、最長辺150mmで変換(プレビューはSVG形式に変更)
|
|
30
|
+
uv run nuizu jef photo.png design.jef --colors 12 --size 150 --preview svg
|
|
31
|
+
|
|
32
|
+
# フル機能(最大色数指定、自動角度、プルコンペンセーション、背景あり)
|
|
33
|
+
uv run nuizu dst photo.jpg design.dst \
|
|
34
|
+
--max-colors 10 \
|
|
35
|
+
--auto-angle --pull-comp 0.3 -b
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
基本構文:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv run nuizu <dst|pes|jef> 入力画像 [出力ファイル]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- `出力ファイル`を省略すると、入力画像と同名で拡張子だけが各形式に変わります(例: `photo.jpg` → `photo.dst`)。
|
|
45
|
+
|
|
46
|
+
## 全オプション一覧(`dst` / `pes` / `jef` 共通)
|
|
47
|
+
|
|
48
|
+
### サイズ
|
|
49
|
+
|
|
50
|
+
| オプション | デフォルト | 説明 |
|
|
51
|
+
|-----------|-----------|------|
|
|
52
|
+
| `-s, --size` | 100 | 最長辺の目標サイズ (mm) |
|
|
53
|
+
|
|
54
|
+
### カラー
|
|
55
|
+
|
|
56
|
+
| オプション | デフォルト | 説明 |
|
|
57
|
+
|-----------|-----------|------|
|
|
58
|
+
| `-c, --colors` | - | 使用する糸色数(厳密に維持) |
|
|
59
|
+
| `-m, --max-colors` | 8 | 最大糸色数(指定数以下に自動調整) |
|
|
60
|
+
| `-p, --palette` | auto | 糸パレット (`auto`, `janome`, `brother`, `madeira`, `generic`) |
|
|
61
|
+
|
|
62
|
+
### ステッチ
|
|
63
|
+
|
|
64
|
+
| オプション | デフォルト | 説明 |
|
|
65
|
+
|-----------|-----------|------|
|
|
66
|
+
| `-t, --thread-width` | 0.4 | 糸幅 (mm) |
|
|
67
|
+
| `-d, --density` | 糸幅と同値 | フィル行間隔 mm(小さい=密) |
|
|
68
|
+
| `-l, --stitch-length` | 3.0 | 最大ステッチ長 mm |
|
|
69
|
+
| `-a, --angle` | 45 | フィルステッチ角度(度) |
|
|
70
|
+
| `--auto-angle` | - | 領域ごとに最適フィル角度を自動決定 |
|
|
71
|
+
| `--no-underlay` | - | アンダーレイ(下縫い)無効 |
|
|
72
|
+
| `--no-outline` | - | アウトライン無効 |
|
|
73
|
+
| `--satin-outline` | - | アウトラインをサテンステッチに |
|
|
74
|
+
| `--pull-comp MM` | 0 | プルコンペンセーション mm(推奨: 0.2-0.5) |
|
|
75
|
+
|
|
76
|
+
### 画像処理
|
|
77
|
+
|
|
78
|
+
| オプション | デフォルト | 説明 |
|
|
79
|
+
|-----------|-----------|------|
|
|
80
|
+
| `--blur` | 3 | ぼかし半径(0=無効) |
|
|
81
|
+
| `--min-region` | 0.001 | 最小領域サイズ(画像全体に対する比率) |
|
|
82
|
+
| `--auto-crop` | - | 被写体を自動検出してクロップ |
|
|
83
|
+
| `-b, --background` | - | 背景色もステッチに含める(デフォルトはスキップ) |
|
|
84
|
+
|
|
85
|
+
### 出力
|
|
86
|
+
|
|
87
|
+
| オプション | デフォルト | 説明 |
|
|
88
|
+
|-----------|-----------|------|
|
|
89
|
+
| `--preview` | png | プレビュー生成 (`png`, `svg`, `none`) |
|
|
90
|
+
| `-q, --quiet` | - | 進行状況メッセージを抑制 |
|
|
91
|
+
|
|
92
|
+
## 処理パイプライン
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
[入力画像]
|
|
96
|
+
│
|
|
97
|
+
▼
|
|
98
|
+
[1] 前処理
|
|
99
|
+
├── リサイズ(最大800px)
|
|
100
|
+
├── Gaussianぼかし(ノイズ軽減)
|
|
101
|
+
└── Medianフィルタ(アンチエイリアス・JPEG圧縮ノイズ除去)
|
|
102
|
+
│
|
|
103
|
+
▼
|
|
104
|
+
[2] 色量子化
|
|
105
|
+
├── LAB色空間でK-meansクラスタリング
|
|
106
|
+
├── 刺繍糸パレットへスナップ(JANOME/Brother/Madeira)
|
|
107
|
+
├── 近似色クラスタの自動マージ(ΔE閾値)
|
|
108
|
+
└── 明るい背景の自動検出(前景比率チェック)
|
|
109
|
+
│
|
|
110
|
+
▼
|
|
111
|
+
[3] 領域分割
|
|
112
|
+
├── ラベルマップ平滑化(多数決投票)
|
|
113
|
+
├── 暗色ピクセルの復元(輪郭・ストローク保護)
|
|
114
|
+
├── OpenCV輪郭抽出(RETR_CCOMP: 穴あり対応)
|
|
115
|
+
├── モルフォロジー処理(小ギャップの閉鎖)
|
|
116
|
+
└── ピクセル座標 → mm座標変換
|
|
117
|
+
│
|
|
118
|
+
▼
|
|
119
|
+
[4] ステッチ順序最適化
|
|
120
|
+
├── 色グループ化(色変更最小化)
|
|
121
|
+
└── グループ内で最近傍法(ジャンプ最小化)
|
|
122
|
+
│
|
|
123
|
+
▼
|
|
124
|
+
[5] ステッチ生成
|
|
125
|
+
├── プルコンペンセーション(輪郭拡張)
|
|
126
|
+
├── 自動フィル角度決定(PCA / minAreaRect)
|
|
127
|
+
├── 細幅領域のフィルスキップ(アウトラインのみ)
|
|
128
|
+
├── アンダーレイ(垂直方向・疎)
|
|
129
|
+
├── メインフィル(スキャンライン走査)
|
|
130
|
+
├── フィルコンペンセーション(行端延長)
|
|
131
|
+
├── アウトライン(ランニング or サテン)
|
|
132
|
+
└── ロングステッチ分割(最大7mm)
|
|
133
|
+
│
|
|
134
|
+
▼
|
|
135
|
+
[6] ファイル出力(DST / PES / JEF)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## アーキテクチャ
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
src/nuizu/
|
|
142
|
+
├── __main__.py # CLI エントリーポイント(Typer)
|
|
143
|
+
├── pipeline.py # メイン変換パイプライン
|
|
144
|
+
├── preprocess.py # 画像前処理(背景検出、自動クロップ)
|
|
145
|
+
├── quantize.py # 色量子化(K-means / LAB色空間 / クラスタマージ)
|
|
146
|
+
├── palettes.py # 実メーカー糸パレット(JANOME / Brother / Madeira)
|
|
147
|
+
├── segment.py # 領域分割(OpenCV contour / 穴あり階層抽出)
|
|
148
|
+
├── auto_angle.py # フィル角度自動最適化(PCA / minAreaRect)
|
|
149
|
+
├── fill.py # フィルステッチ生成(ラスタスキャンライン方式)
|
|
150
|
+
├── compensate.py # プルコンペンセーション(布引き攣り補正)
|
|
151
|
+
├── optimize.py # ステッチ順序最適化
|
|
152
|
+
├── svg_preview.py # SVGプレビュー生成
|
|
153
|
+
└── formats/
|
|
154
|
+
├── common.py # 共通データ構造(Stitch, Pattern, ThreadColor)
|
|
155
|
+
├── dst.py # Tajima DST ライター
|
|
156
|
+
├── pes.py # Brother PES ライター
|
|
157
|
+
└── jef.py # JANOME JEF ライター
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 使用例
|
|
161
|
+
|
|
162
|
+
### 写真をJANOMEで刺繍する
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
uv run nuizu jef portrait.jpg portrait.jef \
|
|
166
|
+
--palette janome --colors 8 --size 100 \
|
|
167
|
+
--auto-angle --pull-comp 0.3
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 被写体を自動クロップして刺繍
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
uv run nuizu dst flower.jpg flower.dst \
|
|
174
|
+
--auto-crop --colors 6
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### 密度の高い高品質仕上げ
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
uv run nuizu pes logo.png logo.pes \
|
|
181
|
+
--density 0.25 --stitch-length 2.5 --satin-outline \
|
|
182
|
+
--pull-comp 0.4 --max-colors 10
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### シンプルな変換
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
uv run nuizu dst photo.jpg \
|
|
189
|
+
--no-underlay --no-outline --colors 4
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## プルコンペンセーションの目安
|
|
193
|
+
|
|
194
|
+
| 生地タイプ | 推奨値 (mm) |
|
|
195
|
+
|-----------|-------------|
|
|
196
|
+
| 薄い生地(オーガンジー、シルク) | 0.2 - 0.3 |
|
|
197
|
+
| 中厚生地(コットン、リネン) | 0.3 - 0.4 |
|
|
198
|
+
| 厚い生地(デニム、キャンバス) | 0.4 - 0.6 |
|
|
199
|
+
|
|
200
|
+
## 制限事項
|
|
201
|
+
|
|
202
|
+
- 出力ファイルのバイナリ形式はリバースエンジニアリングに基づいています。実機での動作は糸・生地・テンションなど多くの要因に依存します。
|
|
203
|
+
- 写真の変換品質は元画像のコントラストと色の明確さに大きく左右されます。
|
|
204
|
+
- 非常に大きな刺繍(200mm超)ではステッチ数が数万を超え、実機での刺繍時間が長くなります。
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nuizu"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Convert photos to embroidery data files (DST / PES / JEF)"
|
|
5
|
+
authors = [{ name = "mokuichi147" }]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
license = "MIT OR Apache-2.0"
|
|
8
|
+
requires-python = ">=3.12.10"
|
|
9
|
+
urls = { Homepage = "https://github.com/Mokuichi147/Nuizu", Repository = "https://github.com/Mokuichi147/Nuizu" }
|
|
10
|
+
dependencies = [
|
|
11
|
+
"numpy",
|
|
12
|
+
"opencv-python",
|
|
13
|
+
"pillow",
|
|
14
|
+
"scikit-learn",
|
|
15
|
+
"typer",
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
nuizu = "nuizu.__main__:main"
|
|
20
|
+
|
|
21
|
+
[build-system]
|
|
22
|
+
requires = ["uv_build>=0.9.17,<0.10.0"]
|
|
23
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""nuizu のCLIエントリーポイント。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import traceback
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import Literal
|
|
9
|
+
|
|
10
|
+
import typer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
PaletteName = Literal["auto", "janome", "brother", "madeira", "generic"]
|
|
14
|
+
PreviewFormat = Literal["png", "svg", "none"]
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(
|
|
17
|
+
no_args_is_help=True,
|
|
18
|
+
add_completion=False,
|
|
19
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
20
|
+
help=(
|
|
21
|
+
"写真を刺繍用データ(DST / PES / JEF)へ変換します。\n\n"
|
|
22
|
+
"使用例:\n"
|
|
23
|
+
" nuizu dst photo.jpg\n"
|
|
24
|
+
" nuizu dst photo.jpg -c 12 -s 150\n"
|
|
25
|
+
" nuizu jef photo.png output.jef --max-colors 10\n"
|
|
26
|
+
" nuizu pes photo.jpg --palette brother -b"
|
|
27
|
+
),
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _run_convert(
|
|
32
|
+
input_path: str,
|
|
33
|
+
output_path: str | None,
|
|
34
|
+
ext: str,
|
|
35
|
+
*,
|
|
36
|
+
size: float,
|
|
37
|
+
colors: int | None,
|
|
38
|
+
max_colors: int,
|
|
39
|
+
palette: str,
|
|
40
|
+
thread_width: float,
|
|
41
|
+
density: float | None,
|
|
42
|
+
stitch_length: float,
|
|
43
|
+
angle: float,
|
|
44
|
+
auto_angle: bool,
|
|
45
|
+
no_underlay: bool,
|
|
46
|
+
no_outline: bool,
|
|
47
|
+
satin_outline: bool,
|
|
48
|
+
pull_comp: float,
|
|
49
|
+
blur: int,
|
|
50
|
+
min_region: float,
|
|
51
|
+
auto_crop: bool,
|
|
52
|
+
skip_bg: bool,
|
|
53
|
+
preview: str | None,
|
|
54
|
+
quiet: bool,
|
|
55
|
+
) -> None:
|
|
56
|
+
in_file = Path(input_path)
|
|
57
|
+
if not in_file.exists() or not in_file.is_file():
|
|
58
|
+
typer.echo(f"エラー: 入力ファイルが見つかりません: {input_path}", err=True)
|
|
59
|
+
raise typer.Exit(code=1)
|
|
60
|
+
|
|
61
|
+
if output_path is None:
|
|
62
|
+
output_path = str(in_file.with_suffix(ext))
|
|
63
|
+
|
|
64
|
+
fill_density = density if density is not None else thread_width
|
|
65
|
+
|
|
66
|
+
if colors is not None:
|
|
67
|
+
n_colors = colors
|
|
68
|
+
strict = True
|
|
69
|
+
else:
|
|
70
|
+
n_colors = max_colors
|
|
71
|
+
strict = False
|
|
72
|
+
|
|
73
|
+
from .pipeline import convert_photo_to_embroidery, generate_preview
|
|
74
|
+
from .svg_preview import generate_svg_preview
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
pattern = convert_photo_to_embroidery(
|
|
78
|
+
image_path=input_path,
|
|
79
|
+
output_path=output_path,
|
|
80
|
+
target_size_mm=size,
|
|
81
|
+
n_colors=n_colors,
|
|
82
|
+
use_thread_palette=palette != "auto",
|
|
83
|
+
thread_brand=palette,
|
|
84
|
+
fill_density=fill_density,
|
|
85
|
+
stitch_length=stitch_length,
|
|
86
|
+
fill_angle=angle,
|
|
87
|
+
auto_angle=auto_angle,
|
|
88
|
+
underlay=not no_underlay,
|
|
89
|
+
outline=not no_outline,
|
|
90
|
+
outline_satin=satin_outline,
|
|
91
|
+
pull_compensation=pull_comp,
|
|
92
|
+
thread_width=thread_width,
|
|
93
|
+
blur_radius=blur,
|
|
94
|
+
min_region_ratio=min_region,
|
|
95
|
+
auto_crop=auto_crop,
|
|
96
|
+
skip_background=skip_bg,
|
|
97
|
+
strict_colors=strict,
|
|
98
|
+
verbose=not quiet,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if preview:
|
|
102
|
+
base = os.path.splitext(output_path)[0]
|
|
103
|
+
|
|
104
|
+
if preview == "png":
|
|
105
|
+
thread_path = f"{base}_preview.png"
|
|
106
|
+
generate_preview(pattern, thread_path, thread_width_mm=thread_width)
|
|
107
|
+
if not quiet:
|
|
108
|
+
typer.echo(f"プレビュー(糸幅): {thread_path}", err=True)
|
|
109
|
+
|
|
110
|
+
stitch_path = f"{base}_stitches.png"
|
|
111
|
+
generate_preview(pattern, stitch_path, thread_width_mm=0)
|
|
112
|
+
if not quiet:
|
|
113
|
+
typer.echo(f"プレビュー(針落ち): {stitch_path}", err=True)
|
|
114
|
+
|
|
115
|
+
elif preview == "svg":
|
|
116
|
+
svg_thread_path = f"{base}_preview.svg"
|
|
117
|
+
generate_svg_preview(pattern, svg_thread_path, thread_width_mm=thread_width)
|
|
118
|
+
if not quiet:
|
|
119
|
+
typer.echo(f"プレビュー(SVG 糸幅): {svg_thread_path}", err=True)
|
|
120
|
+
|
|
121
|
+
svg_stitch_path = f"{base}_stitches.svg"
|
|
122
|
+
generate_svg_preview(pattern, svg_stitch_path, thread_width_mm=0)
|
|
123
|
+
if not quiet:
|
|
124
|
+
typer.echo(f"プレビュー(SVG 針落ち): {svg_stitch_path}", err=True)
|
|
125
|
+
|
|
126
|
+
except Exception as exc:
|
|
127
|
+
typer.echo(f"エラー: {exc}", err=True)
|
|
128
|
+
traceback.print_exc()
|
|
129
|
+
raise typer.Exit(code=1) from exc
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _make_command(ext: str, description: str):
|
|
133
|
+
"""サブコマンド生成ファクトリ。"""
|
|
134
|
+
|
|
135
|
+
def command(
|
|
136
|
+
input_path: str = typer.Argument(
|
|
137
|
+
...,
|
|
138
|
+
metavar="入力画像",
|
|
139
|
+
help="入力画像ファイル(JPG, PNG など)",
|
|
140
|
+
),
|
|
141
|
+
output_path: str | None = typer.Argument(
|
|
142
|
+
None,
|
|
143
|
+
metavar="出力ファイル",
|
|
144
|
+
help=f"出力ファイル(省略時は 入力名{ext})",
|
|
145
|
+
),
|
|
146
|
+
size: float = typer.Option(
|
|
147
|
+
100.0, "--size", "-s", help="最長辺の目標サイズ(mm)",
|
|
148
|
+
),
|
|
149
|
+
colors: int | None = typer.Option(
|
|
150
|
+
None, "--colors", "-c", help="使用する糸色数(厳密に維持)",
|
|
151
|
+
),
|
|
152
|
+
max_colors: int = typer.Option(
|
|
153
|
+
8, "--max-colors", "-m", help="最大糸色数(指定数以下に自動調整)",
|
|
154
|
+
),
|
|
155
|
+
palette: PaletteName = typer.Option(
|
|
156
|
+
"auto", "--palette", "-p", help="糸パレット",
|
|
157
|
+
),
|
|
158
|
+
thread_width: float = typer.Option(
|
|
159
|
+
0.4, "--thread-width", "-t", help="糸幅(mm)",
|
|
160
|
+
),
|
|
161
|
+
density: float | None = typer.Option(
|
|
162
|
+
None, "--density", "-d", help="フィル行間隔(mm)。未指定時は --thread-width と同値",
|
|
163
|
+
),
|
|
164
|
+
stitch_length: float = typer.Option(
|
|
165
|
+
3.0, "--stitch-length", "-l", help="最大ステッチ長(mm)",
|
|
166
|
+
),
|
|
167
|
+
angle: float = typer.Option(
|
|
168
|
+
45.0, "--angle", "-a", help="フィル角度(度)",
|
|
169
|
+
),
|
|
170
|
+
auto_angle: bool = typer.Option(
|
|
171
|
+
False, "--auto-angle", help="領域ごとにフィル角度を自動最適化",
|
|
172
|
+
),
|
|
173
|
+
no_underlay: bool = typer.Option(
|
|
174
|
+
False, "--no-underlay", help="アンダーレイ(下縫い)を無効化",
|
|
175
|
+
),
|
|
176
|
+
no_outline: bool = typer.Option(
|
|
177
|
+
False, "--no-outline", help="アウトライン縫いを無効化",
|
|
178
|
+
),
|
|
179
|
+
satin_outline: bool = typer.Option(
|
|
180
|
+
False, "--satin-outline", help="アウトラインをサテンステッチ化",
|
|
181
|
+
),
|
|
182
|
+
pull_comp: float = typer.Option(
|
|
183
|
+
0.0, "--pull-comp", help="プルコンペンセーション(mm)。推奨: 0.2-0.5",
|
|
184
|
+
),
|
|
185
|
+
blur: int = typer.Option(
|
|
186
|
+
3, "--blur", help="前処理ぼかし半径(0で無効)",
|
|
187
|
+
),
|
|
188
|
+
min_region: float = typer.Option(
|
|
189
|
+
0.001, "--min-region", help="最小領域比率",
|
|
190
|
+
),
|
|
191
|
+
auto_crop: bool = typer.Option(
|
|
192
|
+
False, "--auto-crop", help="主被写体を自動検出してクロップ",
|
|
193
|
+
),
|
|
194
|
+
background: bool = typer.Option(
|
|
195
|
+
False, "--background", "-b", help="背景色もステッチに含める",
|
|
196
|
+
),
|
|
197
|
+
preview: PreviewFormat = typer.Option(
|
|
198
|
+
"png", "--preview", help="プレビュー生成形式",
|
|
199
|
+
),
|
|
200
|
+
quiet: bool = typer.Option(
|
|
201
|
+
False, "--quiet", "-q", help="進行メッセージを抑制",
|
|
202
|
+
),
|
|
203
|
+
) -> None:
|
|
204
|
+
_run_convert(
|
|
205
|
+
input_path, output_path, ext,
|
|
206
|
+
size=size, colors=colors,
|
|
207
|
+
max_colors=max_colors, palette=palette,
|
|
208
|
+
thread_width=thread_width, density=density,
|
|
209
|
+
stitch_length=stitch_length, angle=angle,
|
|
210
|
+
auto_angle=auto_angle, no_underlay=no_underlay,
|
|
211
|
+
no_outline=no_outline, satin_outline=satin_outline,
|
|
212
|
+
pull_comp=pull_comp, blur=blur, min_region=min_region,
|
|
213
|
+
auto_crop=auto_crop, skip_bg=not background,
|
|
214
|
+
preview=preview if preview != "none" else None, quiet=quiet,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
command.__doc__ = description
|
|
218
|
+
return command
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
app.command("dst")(_make_command(".dst", "DST形式(Tajima)で出力"))
|
|
222
|
+
app.command("pes")(_make_command(".pes", "PES形式(Brother / Babylock)で出力"))
|
|
223
|
+
app.command("jef")(_make_command(".jef", "JEF形式(JANOME)で出力"))
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def main() -> None:
|
|
227
|
+
"""pyproject の scripts から呼ばれるエントリーポイント。"""
|
|
228
|
+
app(prog_name="nuizu")
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
if __name__ == "__main__":
|
|
232
|
+
main()
|