label-studio-converter 1.1.0 → 1.3.0

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.
package/README.md CHANGED
@@ -16,15 +16,19 @@
16
16
 
17
17
  - [Getting Started](#toolbox-getting-started)
18
18
  - [Prerequisites](#bangbang-prerequisites)
19
+ - [Installation](#package-installation)
19
20
  - [Run Locally](#running-run-locally)
20
21
  - [Usage](#eyes-usage)
21
- - [Basic Usage](#basic-usage)
22
+ - [Library Usage](#library-usage)
22
23
  - [CLI Usage](#cli-usage)
24
+ - [Examples](#examples)
25
+ - [Enhancement Features](#enhancement-features)
23
26
  - [Using generated files with Label Studio](#using-generated-files-with-label-studio)
24
27
  - [Interface setup](#interface-setup)
25
28
  - [Serving annotation files locally](#serving-annotation-files-locally)
26
29
  - [Using generated files with PPOCRLabelv2](#using-generated-files-with-ppocrlabelv2)
27
30
  - [Conversion Margin of Error](#conversion-margin-of-error)
31
+ - [Delete Generated Files](#delete-generated-files)
28
32
  - [Roadmap](#compass-roadmap)
29
33
  - [Contributing](#wave-contributing)
30
34
  - [Code of Conduct](#scroll-code-of-conduct)
@@ -54,6 +58,27 @@
54
58
  [04928bf](https://github.com/PFCCLab/PPOCRLabel/tree/04928bf015656e41ba5569877df9b0666ca90f89)
55
59
 
56
60
  - [Node.js](https://nodejs.org/): Tested with version `22.x` and above.
61
+
62
+ <!-- Installation -->
63
+
64
+ ### :package: Installation
65
+
66
+ **As a CLI tool:**
67
+
68
+ ```bash
69
+ npm install -g label-studio-converter
70
+ ```
71
+
72
+ **As a library:**
73
+
74
+ ```bash
75
+ npm install label-studio-converter
76
+ # or
77
+ pnpm add label-studio-converter
78
+ # or
79
+ yarn add label-studio-converter
80
+ ```
81
+
57
82
  <!-- Run Locally -->
58
83
 
59
84
  ### :running: Run Locally
@@ -87,50 +112,123 @@ pnpm install
87
112
  > setting up Label Studio for OCR tasks, please refer to the [Using generated
88
113
  > files with Label Studio](#using-generated-files-with-label-studio) section.
89
114
 
90
- ### Basic Usage
115
+ > [!NOTE]
116
+ > **This package can be used both as a CLI tool and as a library.**
117
+ >
118
+ > - **CLI**: Run commands directly from the terminal
119
+ > - **Library**: Import and use functions in your TypeScript/JavaScript code
120
+
121
+ ### Library Usage
122
+
123
+ **Conversion Functions:**
91
124
 
92
125
  ```ts
93
- import { toLabelStudio, toPPOCR } from 'label-studio-converter';
126
+ import {
127
+ labelStudioToPPOCR,
128
+ minLabelStudioToPPOCR,
129
+ ppocrToLabelStudio
130
+ } from 'label-studio-converter';
131
+
132
+ // Convert Label Studio Full Format to PPOCRLabel
133
+ const fullData = [...]; // FullOCRLabelStudio type
134
+ const ppocrMap = await labelStudioToPPOCR(fullData, {
135
+ baseImageDir: 'images/ch',
136
+ normalizeShape: 'rectangle',
137
+ widthIncrement: 5,
138
+ heightIncrement: 5,
139
+ precision: 0 // integers
140
+ });
94
141
 
95
- // Convert PPOCRLabel files to Label Studio format
96
- await toLabelStudio({
97
- inputDirs: ['./input-ppocr'],
98
- outDir: './output-label-studio',
99
- defaultLabelName: 'Text',
100
- toFullJson: true,
101
- createFilePerImage: false,
102
- createFileListForServing: true,
103
- fileListName: 'files.txt',
142
+ // Convert Label Studio Min Format to PPOCRLabel
143
+ const minData = [...]; // MinOCRLabelStudio type
144
+ const ppocrMap2 = await minLabelStudioToPPOCR(minData, {
145
+ baseImageDir: 'images/ch',
146
+ precision: 0
147
+ });
148
+
149
+ // Convert PPOCRLabel to Label Studio
150
+ const ppocrData = [...]; // PPOCRLabel type
151
+ const labelStudioData = await ppocrToLabelStudio(ppocrData, {
152
+ imagePath: 'example.jpg',
104
153
  baseServerUrl: 'http://localhost:8081',
105
- sortVertical: 'none',
106
- sortHorizontal: 'none',
107
- normalizeShape: 'none', // Options: 'none', 'rectangle'
108
- widthIncrement: 0, // Increase width in pixels (can be negative)
109
- heightIncrement: 0, // Increase height in pixels (can be negative)
110
- precision: -1, // Number precision: -1 = full precision (default for Label Studio)
154
+ inputDir: './images',
155
+ toFullJson: true,
156
+ labelName: 'Text',
157
+ precision: -1 // full precision
111
158
  });
159
+ ```
112
160
 
113
- // Convert Label Studio files to PPOCRLabel format
114
- await toPPOCR({
115
- inputDirs: ['./input-label-studio'],
116
- outDir: './output-ppocr',
117
- fileName: 'Label.txt',
118
- baseImageDir: 'images/ch',
119
- sortVertical: 'none',
120
- sortHorizontal: 'none',
121
- normalizeShape: 'none', // Options: 'none', 'rectangle'
122
- widthIncrement: 0, // Increase width in pixels (can be negative)
123
- heightIncrement: 0, // Increase height in pixels (can be negative)
124
- precision: 0, // Number precision: 0 = integers (default for PPOCR)
161
+ **Enhancement Functions:**
162
+
163
+ ```ts
164
+ import {
165
+ enhancePPOCRLabel,
166
+ enhanceLabelStudioData,
167
+ } from 'label-studio-converter';
168
+
169
+ // Enhance PPOCRLabel data
170
+ const enhanced = enhancePPOCRLabel(ppocrData, {
171
+ sortVertical: 'top-bottom',
172
+ sortHorizontal: 'ltr',
173
+ normalizeShape: 'rectangle',
174
+ widthIncrement: 10,
175
+ heightIncrement: 5,
176
+ precision: 0,
177
+ });
178
+
179
+ // Enhance Label Studio data (Full or Min format)
180
+ const enhancedLS = await enhanceLabelStudioData(
181
+ labelStudioData,
182
+ true, // isFull: true for Full format, false for Min format
183
+ {
184
+ sortVertical: 'top-bottom',
185
+ normalizeShape: 'rectangle',
186
+ precision: 2,
187
+ },
188
+ );
189
+ ```
190
+
191
+ **Utility Functions:**
192
+
193
+ ```ts
194
+ import {
195
+ transformPoints,
196
+ normalizeShape,
197
+ resizeBoundingBox,
198
+ sortBoundingBoxes,
199
+ } from 'label-studio-converter';
200
+
201
+ // Transform points (normalize + resize)
202
+ const transformed = transformPoints(points, {
203
+ normalizeShape: 'rectangle',
204
+ widthIncrement: 10,
205
+ heightIncrement: 5,
125
206
  });
207
+
208
+ // Normalize diamond shapes to rectangles
209
+ const normalized = normalizeShape(points);
210
+
211
+ // Resize bounding box
212
+ const resized = resizeBoundingBox(points, 10, 5);
213
+
214
+ // Sort bounding boxes
215
+ const sorted = sortBoundingBoxes(annotations, 'top-bottom', 'ltr');
126
216
  ```
127
217
 
128
218
  ### CLI Usage
129
219
 
220
+ **Available Commands:**
221
+
222
+ ```bash
223
+ label-studio-converter --help
224
+ ```
225
+
130
226
  ```bash
131
227
  USAGE
132
- label-studio-converter toLabelStudio [--outDir value] [--defaultLabelName value] [--toFullJson] [--createFilePerImage] [--createFileListForServing] [--fileListName value] [--baseServerUrl value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] <args>...
133
- label-studio-converter toPPOCR [--outDir value] [--fileName value] [--baseImageDir value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] <args>...
228
+ label-studio-converter toLabelStudio [--outDir value] [--fileName value] [--backup] [--defaultLabelName value] [--toFullJson] [--createFilePerImage] [--createFileListForServing] [--fileListName value] [--baseServerUrl value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] [--outputMode value] <args>...
229
+ label-studio-converter toPPOCR [--outDir value] [--fileName value] [--backup] [--baseImageDir value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] <args>...
230
+ label-studio-converter enhance-labelstudio [--outDir value] [--fileName value] [--backup] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] [--outputMode value] <args>...
231
+ label-studio-converter enhance-ppocr [--outDir value] [--fileName value] [--backup] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] <args>...
134
232
  label-studio-converter --help
135
233
  label-studio-converter --version
136
234
 
@@ -141,81 +239,402 @@ FLAGS
141
239
  -v --version Print version information and exit
142
240
 
143
241
  COMMANDS
144
- toLabelStudio Convert PPOCRLabel files to Label Studio format
145
- toPPOCR Convert Label Studio files to PPOCRLabel format
242
+ toLabelStudio Convert PPOCRLabel files to Label Studio format
243
+ toPPOCR Convert Label Studio files to PPOCRLabel format
244
+ enhance-labelstudio Enhance Label Studio files with sorting, normalization, and resizing
245
+ enhance-ppocr Enhance PPOCRLabel files with sorting, normalization, and resizing
146
246
  ```
147
247
 
148
- Subcommands:
248
+ **Commands:**
149
249
 
150
- **toLabelStudio**:
250
+ - `toLabelStudio` - Convert PPOCRLabel files to Label Studio format
151
251
 
152
252
  ```bash
153
253
  USAGE
154
- label-studio-converter toLabelStudio [--outDir value] [--defaultLabelName value] [--toFullJson] [--createFilePerImage] [--createFileListForServing] [--fileListName value] [--baseServerUrl value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] <args>...
254
+ label-studio-converter toLabelStudio [--outDir value] [--fileName value] [--backup] [--defaultLabelName value] [--toFullJson] [--createFilePerImage] [--createFileListForServing] [--fileListName value] [--baseServerUrl value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] [--outputMode value] <args>...
155
255
  label-studio-converter toLabelStudio --help
156
256
 
157
257
  Convert PPOCRLabel files to Label Studio format
158
258
 
159
259
  FLAGS
160
- [--outDir] Output directory. Default to "./output"
161
- [--defaultLabelName] Default label name for text annotations. Default to "Text"
162
- [--toFullJson/--noToFullJson] Convert to Full OCR Label Studio format. Default to "true"
163
- [--createFilePerImage/--noCreateFilePerImage] Create a separate Label Studio JSON file for each image. Default to "false"
164
- [--createFileListForServing/--noCreateFileListForServing] Create a file list for serving in Label Studio. Default to "true"
165
- [--fileListName] Name of the file list for serving. Default to "files.txt"
166
- [--baseServerUrl] Base server URL for constructing image URLs in the file list. Default to "http://localhost:8081"
167
- [--sortVertical] Sort bounding boxes vertically. Options: "none" (default), "top-bottom", "bottom-top"
168
- [--sortHorizontal] Sort bounding boxes horizontally. Options: "none" (default), "ltr", "rtl"
169
- [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none" (default), "rectangle"
260
+ [--outDir] Output directory. If not specified, files are saved in the same directory as the source files
261
+ [--fileName] Custom output filename (without extension). If not specified, uses source filename with format suffix
262
+ [--backup/--noBackup] Create backup of existing files before overwriting. Default: false
263
+ [--defaultLabelName] Default label name for text annotations. Default: "Text"
264
+ [--toFullJson/--noToFullJson] Convert to Full OCR Label Studio format. Default: "true"
265
+ [--createFilePerImage/--noCreateFilePerImage] Create a separate Label Studio JSON file for each image. Default: "false"
266
+ [--createFileListForServing/--noCreateFileListForServing] Create a file list for serving in Label Studio. Default: "true"
267
+ [--fileListName] Name of the file list for serving. Default: "files.txt"
268
+ [--baseServerUrl] Base server URL for constructing image URLs in the file list. Default: "http://localhost:8081"
269
+ [--sortVertical] Sort bounding boxes vertically. Options: "none", "top-bottom", "bottom-top". Default: "none"
270
+ [--sortHorizontal] Sort bounding boxes horizontally. Options: "none", "ltr", "rtl". Default: "none"
271
+ [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none", "rectangle". Default: "none"
170
272
  [--widthIncrement] Increase bounding box width by this amount (in pixels). Can be negative to decrease. Default: 0
171
273
  [--heightIncrement] Increase bounding box height by this amount (in pixels). Can be negative to decrease. Default: 0
172
274
  [--precision] Number of decimal places for coordinates. Use -1 for full precision (no rounding). Default: -1
275
+ [--recursive/--noRecursive] Recursively search directories for files. Default: false
276
+ [--filePattern] Regex pattern to match PPOCRLabel files (should match .txt files). Default: ".*\.txt$"
277
+ [--outputMode] Output mode: "annotations" for editable annotations (ground truth) or "predictions" for read-only predictions (pre-annotations). Default: "annotations"
173
278
  -h --help Print help information and exit
174
279
 
175
280
  ARGUMENTS
176
281
  args... Input directories containing PPOCRLabel files
177
282
  ```
178
283
 
179
- **toPPOCR**:
284
+ - `toPPOCR` - Convert Label Studio files to PPOCRLabel format
180
285
 
181
286
  ```bash
182
287
  USAGE
183
- label-studio-converter toPPOCR [--outDir value] [--fileName value] [--baseImageDir value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] <args>...
288
+ label-studio-converter toPPOCR [--outDir value] [--fileName value] [--backup] [--baseImageDir value] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] <args>...
184
289
  label-studio-converter toPPOCR --help
185
290
 
186
291
  Convert Label Studio files to PPOCRLabel format
187
292
 
188
293
  FLAGS
189
- [--outDir] Output directory. Default to "./output"
190
- [--fileName] Output PPOCR file name. Default to "Label.txt"
191
- [--baseImageDir] Base directory path to prepend to image filenames in output (e.g., "ch" or "images/ch")
192
- [--sortVertical] Sort bounding boxes vertically. Options: "none" (default), "top-bottom", "bottom-top"
193
- [--sortHorizontal] Sort bounding boxes horizontally. Options: "none" (default), "ltr", "rtl"
194
- [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none" (default), "rectangle"
195
- [--widthIncrement] Increase bounding box width by this amount (in pixels). Can be negative to decrease. Default: 0
196
- [--heightIncrement] Increase bounding box height by this amount (in pixels). Can be negative to decrease. Default: 0
197
- [--precision] Number of decimal places for coordinates. Use -1 for full precision (no rounding). Default: 0 (integers)
198
- -h --help Print help information and exit
294
+ [--outDir] Output directory. If not specified, files are saved in the same directory as the source files
295
+ [--fileName] Output PPOCR file name. Default: "Label.txt"
296
+ [--backup/--noBackup] Create backup of existing files before overwriting. Default: false
297
+ [--baseImageDir] Base directory path to prepend to image filenames in output (e.g., "ch" or "images/ch")
298
+ [--sortVertical] Sort bounding boxes vertically. Options: "none", "top-bottom", "bottom-top". Default: "none"
299
+ [--sortHorizontal] Sort bounding boxes horizontally. Options: "none", "ltr", "rtl". Default: "none"
300
+ [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none", "rectangle". Default: "none"
301
+ [--widthIncrement] Increase bounding box width by this amount (in pixels). Can be negative to decrease. Default: 0
302
+ [--heightIncrement] Increase bounding box height by this amount (in pixels). Can be negative to decrease. Default: 0
303
+ [--precision] Number of decimal places for coordinates. Use -1 for full precision (no rounding). Default: 0 (integers)
304
+ [--recursive/--noRecursive] Recursively search directories for files. Default: false
305
+ [--filePattern] Regex pattern to match Label Studio files (should match .json files). Default: ".*\.json$"
306
+ -h --help Print help information and exit
199
307
 
200
308
  ARGUMENTS
201
309
  args... Input directories containing Label Studio files
202
310
  ```
203
311
 
312
+ - `enhance-labelstudio` - Enhance Label Studio files with sorting,
313
+ normalization, and resizing
314
+
315
+ ```bash
316
+ USAGE
317
+ label-studio-converter enhance-labelstudio [--outDir value] [--fileName value] [--backup] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] [--outputMode value] <args>...
318
+ label-studio-converter enhance-labelstudio --help
319
+
320
+ Enhance Label Studio files with sorting, normalization, and resizing
321
+
322
+ FLAGS
323
+ [--outDir] Output directory. If not specified, files are saved in the same directory as the source files
324
+ [--fileName] Custom output filename. If not specified, uses the same name as the source file
325
+ [--backup/--noBackup] Create backup of existing files before overwriting. Default: false
326
+ [--sortVertical] Sort bounding boxes vertically. Options: "none", "top-bottom", "bottom-top". Default: "none"
327
+ [--sortHorizontal] Sort bounding boxes horizontally. Options: "none", "ltr", "rtl". Default: "none"
328
+ [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none", "rectangle". Default: "none"
329
+ [--widthIncrement] Increase bounding box width by this amount (in pixels). Can be negative to decrease. Default: 0
330
+ [--heightIncrement] Increase bounding box height by this amount (in pixels). Can be negative to decrease. Default: 0
331
+ [--precision] Number of decimal places for coordinates. Use -1 for full precision (no rounding). Default: -1
332
+ [--recursive/--noRecursive] Recursively search directories for files. Default: false
333
+ [--filePattern] Regex pattern to match Label Studio files (should match .json files). Default: ".*\.json$"
334
+ [--outputMode] Output mode: "annotations" for editable annotations (ground truth) or "predictions" for read-only predictions (pre-annotations). Default: "annotations"
335
+ -h --help Print help information and exit
336
+
337
+ ARGUMENTS
338
+ args... Input directories containing Label Studio JSON files
339
+ ```
340
+
341
+ - `enhance-ppocr` - Enhance PPOCRLabel files with sorting, normalization, and resizing
342
+
343
+ ```bash
344
+ USAGE
345
+ label-studio-converter enhance-ppocr [--outDir value] [--fileName value] [--backup] [--sortVertical value] [--sortHorizontal value] [--normalizeShape value] [--widthIncrement value] [--heightIncrement value] [--precision value] [--recursive] [--filePattern value] <args>...
346
+ label-studio-converter enhance-ppocr --help
347
+
348
+ Enhance PPOCRLabel files with sorting, normalization, and resizing
349
+
350
+ FLAGS
351
+ [--outDir] Output directory. If not specified, files are saved in the same directory as the source files
352
+ [--fileName] Custom output filename. If not specified, uses the same name as the source file
353
+ [--backup/--noBackup] Create backup of existing files before overwriting. Default: false
354
+ [--sortVertical] Sort bounding boxes vertically. Options: "none", "top-bottom", "bottom-top". Default: "none"
355
+ [--sortHorizontal] Sort bounding boxes horizontally. Options: "none", "ltr", "rtl". Default: "none"
356
+ [--normalizeShape] Normalize diamond-like shapes to axis-aligned rectangles. Options: "none", "rectangle". Default: "none"
357
+ [--widthIncrement] Increase bounding box width by this amount (in pixels). Can be negative to decrease. Default: 0
358
+ [--heightIncrement] Increase bounding box height by this amount (in pixels). Can be negative to decrease. Default: 0
359
+ [--precision] Number of decimal places for coordinates. Use -1 for full precision (no rounding). Default: 0 (integers)
360
+ [--recursive/--noRecursive] Recursively search directories for files. Default: false
361
+ [--filePattern] Regex pattern to match PPOCRLabel files (should match .txt files). Default: ".*\.txt$"
362
+ -h --help Print help information and exit
363
+
364
+ ARGUMENTS
365
+ args... Input directories containing PPOCRLabel files
366
+ ```
367
+
368
+ **Error Handling:**
369
+
370
+ The `toLabelStudio` command handles missing or unreadable image files gracefully:
371
+
372
+ - If an image file referenced in PPOCRLabel cannot be found or read, a warning is logged
373
+ - Default dimensions of **1920×1080** are used as fallback
374
+ - Conversion continues for remaining images without interruption
375
+
376
+ This allows the conversion process to complete even when some image files are missing from the dataset.
377
+
204
378
  #### Examples
205
379
 
206
- **Convert PPOCRLabel files to full Label Studio format:**
380
+ **Basic Conversions:**
207
381
 
208
382
  ```bash
209
- label-studio-converter toLabelStudio ./input-ppocr --outDir ./output-label-studio --defaultLabelName Text --toFullJson --createFileListForServing --fileListName files.txt --baseServerUrl http://localhost:8081 --sortVertical none --sortHorizontal none
383
+ # Convert PPOCRLabel files to full Label Studio format
384
+ label-studio-converter toLabelStudio ./input-ppocr --outDir ./output-label-studio
385
+
386
+ # Convert Label Studio files to PPOCRLabel format
387
+ label-studio-converter toPPOCR ./input-label-studio --outDir ./output-ppocr
388
+
389
+ # Convert with custom output filename for PPOCR
390
+ label-studio-converter toPPOCR ./input-label-studio --outDir ./output-ppocr --fileName MyLabels.txt
391
+
392
+ # Convert with base image directory path
393
+ label-studio-converter toPPOCR ./input-label-studio --baseImageDir images/ch
210
394
  ```
211
395
 
212
396
  > [!NOTE]
213
397
  > By default, all PPOCRLabel positions are treated as **polygons** in Label Studio.
214
398
 
215
- **Convert Label Studio files to PPOCRLabel format:**
399
+ **toLabelStudio Options:**
400
+
401
+ ```bash
402
+ # Create separate JSON file for each image
403
+ label-studio-converter toLabelStudio ./input-ppocr \
404
+ --outDir ./output \
405
+ --createFilePerImage
406
+
407
+ # Specify custom label name (default is "Text")
408
+ label-studio-converter toLabelStudio ./input-ppocr \
409
+ --outDir ./output \
410
+ --defaultLabelName Handwriting
411
+
412
+ # Convert to minimal format (without serving support)
413
+ label-studio-converter toLabelStudio ./input-ppocr \
414
+ --outDir ./output \
415
+ --noToFullJson
416
+
417
+ # Disable file list creation for serving
418
+ label-studio-converter toLabelStudio ./input-ppocr \
419
+ --outDir ./output \
420
+ --noCreateFileListForServing
421
+
422
+ # Custom file list name and server URL
423
+ label-studio-converter toLabelStudio ./input-ppocr \
424
+ --outDir ./output \
425
+ --fileListName my-images.txt \
426
+ --baseServerUrl http://192.168.1.100:8080
427
+
428
+ # Convert to predictions format (pre-annotations) instead of annotations
429
+ # Predictions are read-only and useful for pre-annotated data
430
+ label-studio-converter toLabelStudio ./input-ppocr \
431
+ --outDir ./output \
432
+ --outputMode predictions
433
+
434
+ # Convert to annotations format (default, editable ground truth)
435
+ label-studio-converter toLabelStudio ./input-ppocr \
436
+ --outDir ./output \
437
+ --outputMode annotations
438
+ ```
439
+
440
+ > [!IMPORTANT]
441
+ > **Output Mode Restrictions:**
442
+ >
443
+ > - The `--outputMode` flag is only available for:
444
+ > - `toLabelStudio` command (when using `--toFullJson`)
445
+ > - `enhance-labelstudio` command (for Full JSON format files only)
446
+ > - **Not available** for:
447
+ > - `toPPOCR` command (PPOCR format doesn't distinguish annotations/predictions)
448
+ > - `enhance-ppocr` command (PPOCR format doesn't distinguish annotations/predictions)
449
+ > - Min JSON Label Studio format (doesn't support annotations/predictions)
450
+ >
451
+ > **Prediction Scores:**
452
+ >
453
+ > - When converting from PPOCRLabel to Label Studio with `--outputMode predictions`, the `dt_score` field from PPOCRLabel is automatically mapped to the prediction `score` field in Label Studio
454
+ > - This allows pre-annotation confidence scores to be preserved and displayed in Label Studio
455
+ > - Score values should be between 0.0 and 1.0 (confidence percentage)
456
+
457
+ **toPPOCR Options:**
458
+
459
+ ```bash
460
+ # Basic conversion with output directory
461
+ label-studio-converter toPPOCR ./input-label-studio \
462
+ --outDir ./output
463
+
464
+ # Custom output filename
465
+ label-studio-converter toPPOCR ./input-label-studio \
466
+ --outDir ./output \
467
+ --fileName CustomLabel.txt
468
+
469
+ # Add base image directory to paths
470
+ label-studio-converter toPPOCR ./input-label-studio \
471
+ --outDir ./output \
472
+ --baseImageDir dataset/images
473
+ ```
474
+
475
+ **Recursive Search and Pattern Matching:**
476
+
477
+ ```bash
478
+ # Recursively search all subdirectories for .txt files
479
+ label-studio-converter toLabelStudio ./data --recursive
480
+
481
+ # Search with custom pattern (only files starting with "Label")
482
+ label-studio-converter toLabelStudio ./data \
483
+ --recursive \
484
+ --filePattern "Label.*\.txt$"
485
+
486
+ # Convert only specific JSON files (e.g., final annotations)
487
+ label-studio-converter toPPOCR ./annotations \
488
+ --recursive \
489
+ --filePattern ".*_final\.json$"
490
+
491
+ # Enhance only specific files matching pattern
492
+ label-studio-converter enhance-ppocr ./dataset \
493
+ --recursive \
494
+ --filePattern "train_.*\.txt$"
495
+ ```
496
+
497
+ > [!NOTE]
498
+ >
499
+ > - `--recursive`: Searches all subdirectories for matching files
500
+ > - `--filePattern`: Regex pattern to filter files (default: `.*\.txt$` for PPOCR, `.*\.json$` for Label Studio)
501
+ > - Patterns are flexible - use any regex, but ensure they match appropriate file types (.txt for PPOCR, .json for Label Studio)
502
+
503
+ ### Enhancement Features
504
+
505
+ The tool provides powerful enhancement capabilities that can be used standalone or integrated with conversion:
506
+
507
+ **Enhance PPOCRLabel files:**
508
+
509
+ ```bash
510
+ # Sort annotations from top to bottom, left to right
511
+ label-studio-converter enhance-ppocr ./data --sortVertical top-bottom --sortHorizontal ltr
512
+
513
+ # Normalize diamond shapes to rectangles and resize
514
+ label-studio-converter enhance-ppocr ./data --normalizeShape rectangle --widthIncrement 10 --heightIncrement 5
515
+
516
+ # Apply all enhancements
517
+ label-studio-converter enhance-ppocr ./data \
518
+ --sortVertical top-bottom \
519
+ --sortHorizontal ltr \
520
+ --normalizeShape rectangle \
521
+ --widthIncrement 5 \
522
+ --heightIncrement 5 \
523
+ --precision 0
524
+ ```
525
+
526
+ **Enhance Label Studio files:**
527
+
528
+ ```bash
529
+ # Sort and normalize Label Studio annotations
530
+ label-studio-converter enhance-labelstudio ./data \
531
+ --sortVertical top-bottom \
532
+ --normalizeShape rectangle \
533
+ --precision 2
534
+
535
+ # Works with both Full and Min formats automatically
536
+ label-studio-converter enhance-labelstudio ./label-studio-files --outDir ./enhanced
537
+ ```
538
+
539
+ **Enhancement Options:**
540
+
541
+ - `--sortVertical`: Sort bounding boxes vertically
542
+ - `none` (default): No sorting
543
+ - `top-bottom`: Sort from top to bottom
544
+ - `bottom-top`: Sort from bottom to top
545
+ - Example:
546
+ ```bash
547
+ # Sort annotations from top to bottom
548
+ label-studio-converter enhance-ppocr ./data --sortVertical top-bottom
549
+ ```
550
+
551
+ - `--sortHorizontal`: Sort bounding boxes horizontally
552
+ - `none` (default): No sorting
553
+ - `ltr`: Sort left to right (useful for English, most European languages)
554
+ - `rtl`: Sort right to left (useful for Arabic, Hebrew)
555
+ - Example:
556
+
557
+ ```bash
558
+ # Sort annotations left to right
559
+ label-studio-converter enhance-ppocr ./data --sortHorizontal ltr
560
+
561
+ # Sort annotations right to left
562
+ label-studio-converter enhance-ppocr ./data --sortHorizontal rtl
563
+ ```
564
+
565
+ - `--normalizeShape`: Normalize shapes
566
+ - `none` (default): Keep original shape
567
+ - `rectangle`: Convert diamond-like or rotated shapes to axis-aligned rectangles
568
+ - Example:
569
+ ```bash
570
+ # Convert irregular shapes to clean rectangles
571
+ label-studio-converter enhance-ppocr ./data --normalizeShape rectangle
572
+ ```
573
+
574
+ - `--widthIncrement`: Increase/decrease width (pixels, can be negative)
575
+ - Default: `0`
576
+ - Examples:
577
+
578
+ ```bash
579
+ # Increase width by 10 pixels
580
+ label-studio-converter enhance-ppocr ./data --widthIncrement 10
581
+
582
+ # Decrease width by 5 pixels
583
+ label-studio-converter enhance-ppocr ./data --widthIncrement -5
584
+ ```
585
+
586
+ - `--heightIncrement`: Increase/decrease height (pixels, can be negative)
587
+ - Default: `0`
588
+ - Examples:
589
+
590
+ ```bash
591
+ # Increase height by 15 pixels
592
+ label-studio-converter enhance-ppocr ./data --heightIncrement 15
593
+
594
+ # Decrease height by 3 pixels
595
+ label-studio-converter enhance-ppocr ./data --heightIncrement -3
596
+ ```
597
+
598
+ - `--precision`: Control the number of decimal places for coordinate values
599
+ - `-1`: Full precision - no rounding, keeps all decimal places (default for Label Studio output)
600
+ - Example output: `27.44656917885264`
601
+ - `0`: Round to integers (default for PPOCR output)
602
+ - Example output: `27`
603
+ - `1`: Round to 1 decimal place
604
+ - Example output: `27.4`
605
+ - `2`: Round to 2 decimal places
606
+ - Example output: `27.45`
607
+ - Any positive integer for that many decimal places
608
+ - Examples:
609
+
610
+ ```bash
611
+ # Use full precision
612
+ label-studio-converter toLabelStudio ./data --precision -1
613
+
614
+ # Use integer coordinates
615
+ label-studio-converter toPPOCR ./data --precision 0
616
+
617
+ # Use 2 decimal places
618
+ label-studio-converter enhance-labelstudio ./data --precision 2
619
+ ```
620
+
621
+ **Conversion with Enhancement:**
622
+
623
+ All enhancement options are available in conversion commands:
216
624
 
217
625
  ```bash
218
- label-studio-converter toPPOCR ./input-label-studio --outDir ./output-ppocr --fileName Label.txt --baseImageDir images/ch --sortVertical none --sortHorizontal none
626
+ # Convert with enhancements applied during conversion
627
+ label-studio-converter toLabelStudio ./input-ppocr \
628
+ --outDir ./output \
629
+ --sortVertical top-bottom \
630
+ --normalizeShape rectangle \
631
+ --widthIncrement 10
632
+
633
+ label-studio-converter toPPOCR ./input-label-studio \
634
+ --outDir ./output \
635
+ --sortVertical top-bottom \
636
+ --sortHorizontal ltr \
637
+ --normalizeShape rectangle
219
638
  ```
220
639
 
221
640
  **Convert PPOCRLabel files to Label Studio format with one file per image:**
@@ -254,7 +673,7 @@ label-studio-converter toPPOCR ./input-label-studio --outDir ./output --normaliz
254
673
  <b>Before normalization</b> (diamond-like shapes):
255
674
  </summary>
256
675
 
257
- ![Before normalization](./docs/images/LabelStudio_original_diamond.png)
676
+ ![Before normalization](./docs/images/label-studio-original-diamond.png)
258
677
 
259
678
  </details>
260
679
 
@@ -269,7 +688,7 @@ Command:
269
688
  ./dist/cli.js toPPOCR ./tmp --baseImageDir output --normalizeShape rectangle
270
689
  ```
271
690
 
272
- ![After normalization](./docs/images/LabelStudio_converted_diamond.png)
691
+ ![After normalization](./docs/images/label-studio-converted-diamond.png)
273
692
 
274
693
  </details>
275
694
 
@@ -278,7 +697,7 @@ Command:
278
697
  <b>Before normalization</b> (diamond-like vertical shapes):
279
698
  </summary>
280
699
 
281
- ![Before normalization (vert)](./docs/images/LabelStudio_original_diamond_vert.png)
700
+ ![Before normalization (vert)](./docs/images/label-studio-original-diamond-vert.png)
282
701
 
283
702
  </details>
284
703
 
@@ -293,7 +712,7 @@ Command:
293
712
  ./dist/cli.js toPPOCR ./tmp --baseImageDir output --normalizeShape rectangle
294
713
  ```
295
714
 
296
- ![After normalization (vert)](./docs/images/LabelStudio_converted_diamond_vert.png)
715
+ ![After normalization (vert)](./docs/images/label-studio-converted-diamond-vert.png)
297
716
 
298
717
  </details>
299
718
 
@@ -470,19 +889,19 @@ aspects of the data.
470
889
 
471
890
  Label Studio annotation:
472
891
 
473
- ![Label Studio annotation](./docs/images/LabelStudio_original_example.png)
892
+ ![Label Studio annotation](./docs/images/label-studio-original-example.png)
474
893
 
475
894
  Generated PPOCRLabelv2 annotation:
476
895
 
477
- ![PPOCRLabelv2 annotation](./docs/images/PPOCRLabel_converted_example.png)
896
+ ![PPOCRLabelv2 annotation](./docs/images/ppocr-label-converted-example.png)
478
897
 
479
898
  Converted back to Label Studio annotation:
480
899
 
481
- ![Converted back to Label Studio annotation](./docs/images/LabelStudio_converted_back_example.png)
900
+ ![Converted back to Label Studio annotation](./docs/images/label-studio-converted-back-example.png)
482
901
 
483
902
  <details>
484
903
  <summary>
485
- <b>Original data</b> (<code>full_label_studio.json</code>):
904
+ <b>Original data</b>:
486
905
  </summary>
487
906
 
488
907
  ```json
@@ -499,13 +918,13 @@ Converted back to Label Studio annotation:
499
918
  "original_height": 520,
500
919
  "image_rotation": 0,
501
920
  "value": {
502
- "x": 27.44656917885264,
503
- "y": 58.07692307692308,
504
- "width": 42.63217097862767,
505
- "height": 5.961538461538453,
921
+ "x": 27.691012033297714,
922
+ "y": 58.08133472367049,
923
+ "width": 42.14645223570203,
924
+ "height": 5.4223149113660085,
506
925
  "rotation": 0
507
926
  },
508
- "id": "JQAipC-2LH",
927
+ "id": "pa6F68vZpa",
509
928
  "from_name": "bbox",
510
929
  "to_name": "image",
511
930
  "type": "rectangle",
@@ -516,14 +935,14 @@ Converted back to Label Studio annotation:
516
935
  "original_height": 520,
517
936
  "image_rotation": 0,
518
937
  "value": {
519
- "x": 27.44656917885264,
520
- "y": 58.07692307692308,
521
- "width": 42.63217097862767,
522
- "height": 5.961538461538453,
938
+ "x": 27.691012033297714,
939
+ "y": 58.08133472367049,
940
+ "width": 42.14645223570203,
941
+ "height": 5.4223149113660085,
523
942
  "rotation": 0,
524
943
  "labels": ["Text"]
525
944
  },
526
- "id": "JQAipC-2LH",
945
+ "id": "pa6F68vZpa",
527
946
  "from_name": "label",
528
947
  "to_name": "image",
529
948
  "type": "labels",
@@ -534,14 +953,14 @@ Converted back to Label Studio annotation:
534
953
  "original_height": 520,
535
954
  "image_rotation": 0,
536
955
  "value": {
537
- "x": 27.44656917885264,
538
- "y": 58.07692307692308,
539
- "width": 42.63217097862767,
540
- "height": 5.961538461538453,
956
+ "x": 27.691012033297714,
957
+ "y": 58.08133472367049,
958
+ "width": 42.14645223570203,
959
+ "height": 5.4223149113660085,
541
960
  "rotation": 0,
542
961
  "text": ["ACUTE CORONARY SYNDROME"]
543
962
  },
544
- "id": "JQAipC-2LH",
963
+ "id": "pa6F68vZpa",
545
964
  "from_name": "transcription",
546
965
  "to_name": "image",
547
966
  "type": "textarea",
@@ -552,13 +971,13 @@ Converted back to Label Studio annotation:
552
971
  "original_height": 520,
553
972
  "image_rotation": 0,
554
973
  "value": {
555
- "x": 27.559055118110237,
556
- "y": 64.8076923076923,
557
- "width": 26.884374807767497,
558
- "height": 4.423038206853052,
559
- "rotation": 359.76027010391914
974
+ "x": 27.569025196146622,
975
+ "y": 70.38581856100105,
976
+ "width": 49.03965680633165,
977
+ "height": 4.788140385599174,
978
+ "rotation": 359.64368755661553
560
979
  },
561
- "id": "gydCl1Q9Nt",
980
+ "id": "iIfXbvxhFx",
562
981
  "from_name": "bbox",
563
982
  "to_name": "image",
564
983
  "type": "rectangle",
@@ -569,14 +988,71 @@ Converted back to Label Studio annotation:
569
988
  "original_height": 520,
570
989
  "image_rotation": 0,
571
990
  "value": {
572
- "x": 27.559055118110237,
573
- "y": 64.8076923076923,
574
- "width": 26.884374807767497,
575
- "height": 4.423038206853052,
576
- "rotation": 359.76027010391914,
991
+ "x": 27.569025196146622,
992
+ "y": 70.38581856100105,
993
+ "width": 49.03965680633165,
994
+ "height": 4.788140385599174,
995
+ "rotation": 359.64368755661553,
996
+ "labels": ["Text"]
997
+ },
998
+ "id": "iIfXbvxhFx",
999
+ "from_name": "label",
1000
+ "to_name": "image",
1001
+ "type": "labels",
1002
+ "origin": "manual"
1003
+ },
1004
+ {
1005
+ "original_width": 889,
1006
+ "original_height": 520,
1007
+ "image_rotation": 0,
1008
+ "value": {
1009
+ "x": 27.569025196146622,
1010
+ "y": 70.38581856100105,
1011
+ "width": 49.03965680633165,
1012
+ "height": 4.788140385599174,
1013
+ "rotation": 359.64368755661553,
1014
+ "text": ["MILD CORONARY ARTERY DISEASE"]
1015
+ },
1016
+ "id": "iIfXbvxhFx",
1017
+ "from_name": "transcription",
1018
+ "to_name": "image",
1019
+ "type": "textarea",
1020
+ "origin": "manual"
1021
+ },
1022
+ {
1023
+ "original_width": 889,
1024
+ "original_height": 520,
1025
+ "image_rotation": 0,
1026
+ "value": {
1027
+ "points": [
1028
+ [27.630018614722168, 81.85610010427528],
1029
+ [61.66434617987663, 80.8133472367049],
1030
+ [61.969313272754356, 85.71428571428571],
1031
+ [28.239952800477624, 86.44421272158499]
1032
+ ],
1033
+ "closed": true
1034
+ },
1035
+ "id": "mpqixNR8uh",
1036
+ "from_name": "poly",
1037
+ "to_name": "image",
1038
+ "type": "polygon",
1039
+ "origin": "manual"
1040
+ },
1041
+ {
1042
+ "original_width": 889,
1043
+ "original_height": 520,
1044
+ "image_rotation": 0,
1045
+ "value": {
1046
+ "points": [
1047
+ [27.630018614722168, 81.85610010427528],
1048
+ [61.66434617987663, 80.8133472367049],
1049
+ [61.969313272754356, 85.71428571428571],
1050
+ [28.239952800477624, 86.44421272158499]
1051
+ ],
1052
+ "closed": true,
577
1053
  "labels": ["Handwriting"]
578
1054
  },
579
- "id": "gydCl1Q9Nt",
1055
+ "id": "mpqixNR8uh",
580
1056
  "from_name": "label",
581
1057
  "to_name": "image",
582
1058
  "type": "labels",
@@ -587,14 +1063,16 @@ Converted back to Label Studio annotation:
587
1063
  "original_height": 520,
588
1064
  "image_rotation": 0,
589
1065
  "value": {
590
- "x": 27.559055118110237,
591
- "y": 64.8076923076923,
592
- "width": 26.884374807767497,
593
- "height": 4.423038206853052,
594
- "rotation": 359.76027010391914,
595
- "text": ["UNSTABLE ANGINA"]
1066
+ "points": [
1067
+ [27.630018614722168, 81.85610010427528],
1068
+ [61.66434617987663, 80.8133472367049],
1069
+ [61.969313272754356, 85.71428571428571],
1070
+ [28.239952800477624, 86.44421272158499]
1071
+ ],
1072
+ "closed": true,
1073
+ "text": ["MEDICAL MANAGEMENT"]
596
1074
  },
597
- "id": "gydCl1Q9Nt",
1075
+ "id": "mpqixNR8uh",
598
1076
  "from_name": "transcription",
599
1077
  "to_name": "image",
600
1078
  "type": "textarea",
@@ -604,11 +1082,11 @@ Converted back to Label Studio annotation:
604
1082
  "was_cancelled": false,
605
1083
  "ground_truth": false,
606
1084
  "created_at": "2026-01-07T03:14:39.424067Z",
607
- "updated_at": "2026-01-07T03:14:39.424096Z",
1085
+ "updated_at": "2026-01-10T03:21:09.833576Z",
608
1086
  "draft_created_at": "2026-01-07T03:14:04.596361Z",
609
- "lead_time": 56.087,
1087
+ "lead_time": 2686.9700000000003,
610
1088
  "prediction": {},
611
- "result_count": 2,
1089
+ "result_count": 3,
612
1090
  "unique_id": "7e8c79f1-49ce-471c-8b26-8b8c6f9c3401",
613
1091
  "import_id": null,
614
1092
  "last_action": null,
@@ -627,7 +1105,7 @@ Converted back to Label Studio annotation:
627
1105
  "data": { "ocr": "\/data\/upload\/2\/5b1e3483-example.jpg" },
628
1106
  "meta": {},
629
1107
  "created_at": "2026-01-07T03:13:41.175183Z",
630
- "updated_at": "2026-01-07T03:14:39.478016Z",
1108
+ "updated_at": "2026-01-10T03:21:09.923449Z",
631
1109
  "allow_skip": true,
632
1110
  "inner_id": 1,
633
1111
  "total_annotations": 1,
@@ -647,7 +1125,7 @@ Converted back to Label Studio annotation:
647
1125
 
648
1126
  <details>
649
1127
  <summary>
650
- <b>Converted data</b> (<code>output/Label.txt</code>):
1128
+ <b>Converted data</b>:
651
1129
  </summary>
652
1130
 
653
1131
  Command:
@@ -659,14 +1137,14 @@ Command:
659
1137
  Output:
660
1138
 
661
1139
  ```
662
- output/5b1e3483-example.jpg [{"transcription":"ACUTE CORONARY SYNDROME","points":[[243.99999999999997,302],[623,302],[623,332.99999999999994],[243.99999999999997,332.99999999999994]],"dt_score":1},{"transcription":"UNSTABLE ANGINA","points":[[245,337],[484.00209204105306,337],[484.00209204105306,359.9997986756359],[245,359.9997986756359]],"dt_score":1}]
1140
+ output/example.jpg [{"transcription":"ACUTE CORONARY SYNDROME","points":[[246,302],[621,302],[621,330],[246,330]],"dt_score":1},{"transcription":"MILD CORONARY ARTERY DISEASE","points":[[245,366],[681,366],[681,391],[245,391]],"dt_score":1},{"transcription":"MEDICAL MANAGEMENT","points":[[246,426],[548,420],[551,446],[251,450]],"dt_score":1}]
663
1141
  ```
664
1142
 
665
1143
  </details>
666
1144
 
667
1145
  <details>
668
1146
  <summary>
669
- <b>Convert back to Label Studio</b> (<code>output/Label_full.json</code>):
1147
+ <b>Convert back to Label Studio</b>:
670
1148
  </summary>
671
1149
 
672
1150
  Command:
@@ -679,178 +1157,248 @@ Output:
679
1157
 
680
1158
  ```json
681
1159
  [
682
- {
683
- "id": 1,
684
- "annotations": [
685
- {
686
- "id": 1,
687
- "completed_by": 1,
688
- "result": [
689
- {
690
- "original_width": 889,
691
- "original_height": 520,
692
- "image_rotation": 0,
693
- "value": {
694
- "points": [
695
- [27.44656917885264, 58.07692307692308],
696
- [70.07874015748031, 58.07692307692308],
697
- [70.07874015748031, 64.03846153846153],
698
- [27.44656917885264, 64.03846153846153]
699
- ],
700
- "closed": true
1160
+ [
1161
+ {
1162
+ "id": 1,
1163
+ "annotations": [
1164
+ {
1165
+ "id": 1,
1166
+ "completed_by": 1,
1167
+ "result": [
1168
+ {
1169
+ "original_width": 889,
1170
+ "original_height": 520,
1171
+ "image_rotation": 0,
1172
+ "value": {
1173
+ "points": [
1174
+ [27.671541057367826, 58.07692307692308],
1175
+ [69.85376827896513, 58.07692307692308],
1176
+ [69.85376827896513, 63.46153846153846],
1177
+ [27.671541057367826, 63.46153846153846]
1178
+ ],
1179
+ "closed": true
1180
+ },
1181
+ "id": "fce62949-7",
1182
+ "from_name": "poly",
1183
+ "to_name": "image",
1184
+ "type": "polygon",
1185
+ "origin": "manual"
701
1186
  },
702
- "id": "4ebb52a4-d",
703
- "from_name": "poly",
704
- "to_name": "image",
705
- "type": "polygon",
706
- "origin": "manual"
707
- },
708
- {
709
- "original_width": 889,
710
- "original_height": 520,
711
- "image_rotation": 0,
712
- "value": {
713
- "points": [
714
- [27.44656917885264, 58.07692307692308],
715
- [70.07874015748031, 58.07692307692308],
716
- [70.07874015748031, 64.03846153846153],
717
- [27.44656917885264, 64.03846153846153]
718
- ],
719
- "closed": true,
720
- "labels": ["Text"]
1187
+ {
1188
+ "original_width": 889,
1189
+ "original_height": 520,
1190
+ "image_rotation": 0,
1191
+ "value": {
1192
+ "points": [
1193
+ [27.671541057367826, 58.07692307692308],
1194
+ [69.85376827896513, 58.07692307692308],
1195
+ [69.85376827896513, 63.46153846153846],
1196
+ [27.671541057367826, 63.46153846153846]
1197
+ ],
1198
+ "closed": true,
1199
+ "labels": ["Text"]
1200
+ },
1201
+ "id": "fce62949-7",
1202
+ "from_name": "label",
1203
+ "to_name": "image",
1204
+ "type": "labels",
1205
+ "origin": "manual"
721
1206
  },
722
- "id": "4ebb52a4-d",
723
- "from_name": "label",
724
- "to_name": "image",
725
- "type": "labels",
726
- "origin": "manual"
727
- },
728
- {
729
- "original_width": 889,
730
- "original_height": 520,
731
- "image_rotation": 0,
732
- "value": {
733
- "points": [
734
- [27.44656917885264, 58.07692307692308],
735
- [70.07874015748031, 58.07692307692308],
736
- [70.07874015748031, 64.03846153846153],
737
- [27.44656917885264, 64.03846153846153]
738
- ],
739
- "closed": true,
740
- "text": ["ACUTE CORONARY SYNDROME"]
1207
+ {
1208
+ "original_width": 889,
1209
+ "original_height": 520,
1210
+ "image_rotation": 0,
1211
+ "value": {
1212
+ "points": [
1213
+ [27.671541057367826, 58.07692307692308],
1214
+ [69.85376827896513, 58.07692307692308],
1215
+ [69.85376827896513, 63.46153846153846],
1216
+ [27.671541057367826, 63.46153846153846]
1217
+ ],
1218
+ "closed": true,
1219
+ "text": ["ACUTE CORONARY SYNDROME"]
1220
+ },
1221
+ "id": "fce62949-7",
1222
+ "from_name": "transcription",
1223
+ "to_name": "image",
1224
+ "type": "textarea",
1225
+ "origin": "manual"
741
1226
  },
742
- "id": "4ebb52a4-d",
743
- "from_name": "transcription",
744
- "to_name": "image",
745
- "type": "textarea",
746
- "origin": "manual"
747
- },
748
- {
749
- "original_width": 889,
750
- "original_height": 520,
751
- "image_rotation": 0,
752
- "value": {
753
- "points": [
754
- [27.559055118110237, 64.8076923076923],
755
- [54.44342992587774, 64.8076923076923],
756
- [54.44342992587774, 69.23073051454536],
757
- [27.559055118110237, 69.23073051454536]
758
- ],
759
- "closed": true
1227
+ {
1228
+ "original_width": 889,
1229
+ "original_height": 520,
1230
+ "image_rotation": 0,
1231
+ "value": {
1232
+ "points": [
1233
+ [27.559055118110237, 70.38461538461539],
1234
+ [76.6029246344207, 70.38461538461539],
1235
+ [76.6029246344207, 75.1923076923077],
1236
+ [27.559055118110237, 75.1923076923077]
1237
+ ],
1238
+ "closed": true
1239
+ },
1240
+ "id": "9d9389a6-f",
1241
+ "from_name": "poly",
1242
+ "to_name": "image",
1243
+ "type": "polygon",
1244
+ "origin": "manual"
760
1245
  },
761
- "id": "06aa0669-d",
762
- "from_name": "poly",
763
- "to_name": "image",
764
- "type": "polygon",
765
- "origin": "manual"
766
- },
767
- {
768
- "original_width": 889,
769
- "original_height": 520,
770
- "image_rotation": 0,
771
- "value": {
772
- "points": [
773
- [27.559055118110237, 64.8076923076923],
774
- [54.44342992587774, 64.8076923076923],
775
- [54.44342992587774, 69.23073051454536],
776
- [27.559055118110237, 69.23073051454536]
777
- ],
778
- "closed": true,
779
- "labels": ["Text"]
1246
+ {
1247
+ "original_width": 889,
1248
+ "original_height": 520,
1249
+ "image_rotation": 0,
1250
+ "value": {
1251
+ "points": [
1252
+ [27.559055118110237, 70.38461538461539],
1253
+ [76.6029246344207, 70.38461538461539],
1254
+ [76.6029246344207, 75.1923076923077],
1255
+ [27.559055118110237, 75.1923076923077]
1256
+ ],
1257
+ "closed": true,
1258
+ "labels": ["Text"]
1259
+ },
1260
+ "id": "9d9389a6-f",
1261
+ "from_name": "label",
1262
+ "to_name": "image",
1263
+ "type": "labels",
1264
+ "origin": "manual"
780
1265
  },
781
- "id": "06aa0669-d",
782
- "from_name": "label",
783
- "to_name": "image",
784
- "type": "labels",
785
- "origin": "manual"
786
- },
787
- {
788
- "original_width": 889,
789
- "original_height": 520,
790
- "image_rotation": 0,
791
- "value": {
792
- "points": [
793
- [27.559055118110237, 64.8076923076923],
794
- [54.44342992587774, 64.8076923076923],
795
- [54.44342992587774, 69.23073051454536],
796
- [27.559055118110237, 69.23073051454536]
797
- ],
798
- "closed": true,
799
- "text": ["UNSTABLE ANGINA"]
1266
+ {
1267
+ "original_width": 889,
1268
+ "original_height": 520,
1269
+ "image_rotation": 0,
1270
+ "value": {
1271
+ "points": [
1272
+ [27.559055118110237, 70.38461538461539],
1273
+ [76.6029246344207, 70.38461538461539],
1274
+ [76.6029246344207, 75.1923076923077],
1275
+ [27.559055118110237, 75.1923076923077]
1276
+ ],
1277
+ "closed": true,
1278
+ "text": ["MILD CORONARY ARTERY DISEASE"]
1279
+ },
1280
+ "id": "9d9389a6-f",
1281
+ "from_name": "transcription",
1282
+ "to_name": "image",
1283
+ "type": "textarea",
1284
+ "origin": "manual"
800
1285
  },
801
- "id": "06aa0669-d",
802
- "from_name": "transcription",
803
- "to_name": "image",
804
- "type": "textarea",
805
- "origin": "manual"
806
- }
807
- ],
808
- "was_cancelled": false,
809
- "ground_truth": false,
810
- "created_at": "2026-01-07T04:16:31.329Z",
811
- "updated_at": "2026-01-07T04:16:31.329Z",
812
- "draft_created_at": "2026-01-07T04:16:31.329Z",
813
- "lead_time": 0,
814
- "prediction": {},
815
- "result_count": 6,
816
- "unique_id": "b471a896-b002-4b52-b3a4-36f810c3ca16",
817
- "import_id": null,
818
- "last_action": null,
819
- "bulk_created": false,
820
- "task": 1,
821
- "project": 1,
822
- "updated_by": 1,
823
- "parent_prediction": null,
824
- "parent_annotation": null,
825
- "last_created_by": null
826
- }
827
- ],
828
- "file_upload": "5b1e3483-example.jpg",
829
- "drafts": [],
830
- "predictions": [],
831
- "data": {
832
- "ocr": "http://localhost:8081/output/5b1e3483-example.jpg"
833
- },
834
- "meta": {},
835
- "created_at": "2026-01-07T04:16:31.329Z",
836
- "updated_at": "2026-01-07T04:16:31.329Z",
837
- "allow_skip": false,
838
- "inner_id": 1,
839
- "total_annotations": 1,
840
- "cancelled_annotations": 0,
841
- "total_predictions": 0,
842
- "comment_count": 0,
843
- "unresolved_comment_count": 0,
844
- "last_comment_updated_at": null,
845
- "project": 1,
846
- "updated_by": 1,
847
- "comment_authors": []
848
- }
1286
+ {
1287
+ "original_width": 889,
1288
+ "original_height": 520,
1289
+ "image_rotation": 0,
1290
+ "value": {
1291
+ "points": [
1292
+ [27.671541057367826, 81.92307692307692],
1293
+ [61.64229471316085, 80.76923076923077],
1294
+ [61.97975253093363, 85.76923076923076],
1295
+ [28.23397075365579, 86.53846153846155]
1296
+ ],
1297
+ "closed": true
1298
+ },
1299
+ "id": "4f2e63fc-b",
1300
+ "from_name": "poly",
1301
+ "to_name": "image",
1302
+ "type": "polygon",
1303
+ "origin": "manual"
1304
+ },
1305
+ {
1306
+ "original_width": 889,
1307
+ "original_height": 520,
1308
+ "image_rotation": 0,
1309
+ "value": {
1310
+ "points": [
1311
+ [27.671541057367826, 81.92307692307692],
1312
+ [61.64229471316085, 80.76923076923077],
1313
+ [61.97975253093363, 85.76923076923076],
1314
+ [28.23397075365579, 86.53846153846155]
1315
+ ],
1316
+ "closed": true,
1317
+ "labels": ["Text"]
1318
+ },
1319
+ "id": "4f2e63fc-b",
1320
+ "from_name": "label",
1321
+ "to_name": "image",
1322
+ "type": "labels",
1323
+ "origin": "manual"
1324
+ },
1325
+ {
1326
+ "original_width": 889,
1327
+ "original_height": 520,
1328
+ "image_rotation": 0,
1329
+ "value": {
1330
+ "points": [
1331
+ [27.671541057367826, 81.92307692307692],
1332
+ [61.64229471316085, 80.76923076923077],
1333
+ [61.97975253093363, 85.76923076923076],
1334
+ [28.23397075365579, 86.53846153846155]
1335
+ ],
1336
+ "closed": true,
1337
+ "text": ["MEDICAL MANAGEMENT"]
1338
+ },
1339
+ "id": "4f2e63fc-b",
1340
+ "from_name": "transcription",
1341
+ "to_name": "image",
1342
+ "type": "textarea",
1343
+ "origin": "manual"
1344
+ }
1345
+ ],
1346
+ "was_cancelled": false,
1347
+ "ground_truth": false,
1348
+ "created_at": "2026-01-10T03:25:05.530Z",
1349
+ "updated_at": "2026-01-10T03:25:05.530Z",
1350
+ "draft_created_at": "2026-01-10T03:25:05.530Z",
1351
+ "lead_time": 0,
1352
+ "prediction": {},
1353
+ "result_count": 9,
1354
+ "unique_id": "e17b1920-022b-4e48-9207-f9904a42e840",
1355
+ "import_id": null,
1356
+ "last_action": null,
1357
+ "bulk_created": false,
1358
+ "task": 1,
1359
+ "project": 1,
1360
+ "updated_by": 1,
1361
+ "parent_prediction": null,
1362
+ "parent_annotation": null,
1363
+ "last_created_by": null
1364
+ }
1365
+ ],
1366
+ "file_upload": "5b1e3483-example.jpg",
1367
+ "drafts": [],
1368
+ "predictions": [],
1369
+ "data": {
1370
+ "ocr": "http://localhost:8081/output/5b1e3483-example.jpg"
1371
+ },
1372
+ "meta": {},
1373
+ "created_at": "2026-01-10T03:25:05.530Z",
1374
+ "updated_at": "2026-01-10T03:25:05.530Z",
1375
+ "allow_skip": false,
1376
+ "inner_id": 1,
1377
+ "total_annotations": 1,
1378
+ "cancelled_annotations": 0,
1379
+ "total_predictions": 0,
1380
+ "comment_count": 0,
1381
+ "unresolved_comment_count": 0,
1382
+ "last_comment_updated_at": null,
1383
+ "project": 1,
1384
+ "updated_by": 1,
1385
+ "comment_authors": []
1386
+ }
1387
+ ]
849
1388
  ]
850
1389
  ```
851
1390
 
852
1391
  </details>
853
1392
 
1393
+ **Comparison of bounding box positions:**
1394
+
1395
+ | Original Label Studio (polygon) | Label Studio to PPOCRLabel | PPOCRLabel -> Label Studio (polygon) | Margin (Converted Back − Original) |
1396
+ | :--------------------------------------: | -------------------------- | ---------------------------------------- | --------------------------------------- |
1397
+ | \[27.630018614722168, 81.85610010427528] | \[246,426] | \[27.671541057367826, 81.92307692307692] | \[0.04152244264566, 0.06697681880164] |
1398
+ | \[61.66434617987663, 80.8133472367049] | \[548,420] | \[61.64229471316085, 80.76923076923077] | \[-0.02205146671578, -0.04411646747413] |
1399
+ | \[61.969313272754356, 85.71428571428571] | \[551,446] | \[61.97975253093363, 85.76923076923076] | \[0.01043925817927, 0.05494505494505] |
1400
+ | \[28.239952800477624, 86.44421272158499] | \[251,450] | \[28.23397075365579, 86.53846153846155] | \[-0.00598204682183, 0.09424881687656] |
1401
+
854
1402
  > [!IMPORTANT]
855
1403
  > So as you can see, after converting from Label Studio to PPOCRLabelv2 and then
856
1404
  > back to Label Studio, the positions of the bounding boxes have slight
@@ -858,6 +1406,83 @@ Output:
858
1406
  > annotations, especially if precise bounding box locations are critical for your
859
1407
  > application.
860
1408
 
1409
+ ### Delete generated files
1410
+
1411
+ To delete the generated files after conversion, you can use the following
1412
+ commands:
1413
+
1414
+ **Linux/macOS**:
1415
+
1416
+ - When you specified a custom output directory using `--outDir` option:
1417
+
1418
+ ```bash
1419
+ rm -rf ./output-label-studio
1420
+ ```
1421
+
1422
+ - When you did not specify an output directory (default: files are saved in the same directory as the source files):
1423
+
1424
+ **For default output file names:**
1425
+
1426
+ ```bash
1427
+ # Delete Label Studio files generated by toLabelStudio command
1428
+ find ./input-dir -type f \( -name "*_full.json" -o -name "*_min.json" \) -delete
1429
+
1430
+ # Delete PPOCRLabel files generated by toPPOCR command
1431
+ find ./input-dir -type f -name "*_Label.txt" -delete
1432
+
1433
+ # Delete file list for serving
1434
+ find ./input-dir -type f -name "files.txt" -delete
1435
+ ```
1436
+
1437
+ **For custom output file names or patterns:**
1438
+
1439
+ ```bash
1440
+ # Delete files with custom pattern (e.g., files ending with _converted.json)
1441
+ find ./input-dir -type f -name "*_converted.json" -delete
1442
+
1443
+ # Delete files with custom PPOCRLabel filename (e.g., CustomLabel.txt)
1444
+ find ./input-dir -type f -name "*_CustomLabel.txt" -delete
1445
+ ```
1446
+
1447
+ **Windows (PowerShell)**:
1448
+
1449
+ - When you specified a custom output directory using `--outDir` option:
1450
+
1451
+ ```powershell
1452
+ Remove-Item -Path ".\output-label-studio" -Recurse -Force
1453
+ ```
1454
+
1455
+ - When you did not specify an output directory (default: files are saved in the same directory as the source files):
1456
+
1457
+ **For default output file names:**
1458
+
1459
+ ```powershell
1460
+ # Delete Label Studio files generated by toLabelStudio command
1461
+ Get-ChildItem -Path ".\input-dir" -Recurse -Include "*_full.json","*_min.json" | Remove-Item -Force
1462
+
1463
+ # Delete PPOCRLabel files generated by toPPOCR command
1464
+ Get-ChildItem -Path ".\input-dir" -Recurse -Filter "*_Label.txt" | Remove-Item -Force
1465
+
1466
+ # Delete file list for serving
1467
+ Get-ChildItem -Path ".\input-dir" -Recurse -Filter "files.txt" | Remove-Item -Force
1468
+ ```
1469
+
1470
+ **For custom output file names or patterns:**
1471
+
1472
+ ```powershell
1473
+ # Delete files with custom pattern (e.g., files ending with _converted.json)
1474
+ Get-ChildItem -Path ".\input-dir" -Recurse -Filter "*_converted.json" | Remove-Item -Force
1475
+
1476
+ # Delete files with custom PPOCRLabel filename (e.g., CustomLabel.txt)
1477
+ Get-ChildItem -Path ".\input-dir" -Recurse -Filter "*_CustomLabel.txt" | Remove-Item -Force
1478
+ ```
1479
+
1480
+ > [!WARNING]
1481
+ > These commands will permanently delete files. Make sure to review the file
1482
+ > patterns and paths before executing. You can preview files that would be
1483
+ > deleted by removing the `-delete` flag (Linux/macOS) or `| Remove-Item-Force`
1484
+ > (Windows) from the commands.
1485
+
861
1486
  <!-- Roadmap -->
862
1487
 
863
1488
  ## :compass: Roadmap