File size: 3,166 Bytes
c8716b4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# -*- coding: utf-8 -*-
"""
data.py
์ด๋ฏธ ํฌ๋กญ๋œ ์Šฌ๋ผ์ด์Šค(cropped/ + labels.jsonl)์—์„œ ๋ฐฐํ„ฐ๋ฆฌ๋ฅผ ์ฝ์–ด์˜จ๋‹ค.

์ด ํŒŸ์˜ ๋ฐ์ดํ„ฐ๋Š” ์›๋ณธ์ด ์•„๋‹ˆ๋ผ '๋‚ด ์ „์ฒ˜๋ฆฌ ์ถœ๋ ฅ'์ด๋‹ค:
  data/cropped/<battery_key>/<slice>.jpg   (๋ฐฐํ„ฐ๋ฆฌ outline+์—ฌ์œ ๋กœ ํฌ๋กญ๋œ ํšŒ์ƒ‰ ์Šฌ๋ผ์ด์Šค)
  data/labels.jsonl   (์Šฌ๋ผ์ด์Šค๋ณ„: set/path/battery_key/type(cell|module)/swelling_flag/boxes(ํฌ๋กญ์ขŒํ‘œ GT))
โ†’ ์ด๋ฏธ ํฌ๋กญ๋ผ ์žˆ์œผ๋ฏ€๋กœ ์ถ”๋ก ์€ outline ํฌ๋กญ ์—†์ด 'ํฌ๋กญ ์ด๋ฏธ์ง€ ๊ทธ๋Œ€๋กœ' ํƒ€์ผ๋ง/letterbox ํ•œ๋‹ค.

๋ฃจํŠธ ์ง€์ •(์šฐ์„ ์ˆœ์œ„): GLUE_DATA_ROOT > /workspace/battery-ct-security/data > d:/CT DATA
"""
import json
import os
from collections import defaultdict
from pathlib import Path

from PIL import Image

# ๋ฐฐํ„ฐ๋ฆฌ๋‹น ์Šฌ๋ผ์ด์Šค ์ƒํ•œ(๋ฐ๋ชจ ์†๋„; ์ถ•๋‹น ๊ท ๋“ฑ ์ƒ˜ํ”Œ). 0 ์ด๋ฉด ์ „๋Ÿ‰. env GLUE_MAX_SLICES.
MAX_SLICES = int(os.environ.get("GLUE_MAX_SLICES", "0"))

_ROOT = None
_INDEX = None     # {battery_key: {"type": str, "slices": [(name, rel_path)]}}


def _candidates():
    env = os.environ.get("GLUE_DATA_ROOT")
    if env:
        yield Path(env)
    yield Path("/workspace/battery-ct-security/data")
    yield Path("d:/CT DATA")


def data_root():
    global _ROOT
    if _ROOT is not None:
        return _ROOT
    for c in _candidates():
        if c and (c / "labels.jsonl").exists():
            _ROOT = c
            return _ROOT
    raise FileNotFoundError(
        "labels.jsonl ์„ ๋ชป ์ฐพ์Œ. GLUE_DATA_ROOT ๋กœ data ํด๋”๋ฅผ ์ง€์ •ํ•˜์„ธ์š”.")


def _build_index():
    global _INDEX
    if _INDEX is not None:
        return _INDEX
    root = data_root()
    idx = defaultdict(lambda: {"type": None, "slices": []})
    with open(root / "labels.jsonl", encoding="utf-8") as f:
        for line in f:
            r = json.loads(line)
            bk = r["battery_key"]
            idx[bk]["type"] = r.get("type")
            idx[bk]["slices"].append((Path(r["path"]).stem, r["path"]))
    for bk in idx:
        idx[bk]["slices"].sort(key=lambda s: s[0])
    _INDEX = idx
    return idx


def list_batteries():
    return sorted(_build_index().keys())


def cell_type_of(bid):
    t = _build_index().get(bid, {}).get("type")
    return t if t in ("cell", "module") else ("cell" if "cell" in bid else "module")


def _subsample(records, k):
    if k <= 0 or len(records) <= k:
        return records
    return [records[round(t * (len(records) - 1) / (k - 1))] for t in range(k)]


def load_battery(bid):
    """๋ฐฐํ„ฐ๋ฆฌ ํ•˜๋‚˜ โ†’ (slices, cell_type).
    slices = [{"idx", "name", "img_path"(ํฌ๋กญ ์ด๋ฏธ์ง€ ์ ˆ๋Œ€๊ฒฝ๋กœ)}]  (์ด๋ฏธ ํฌ๋กญ๋จ โ†’ outline ๋ถˆํ•„์š”)."""
    idx = _build_index()
    if bid not in idx:
        raise KeyError(f"๋ฐฐํ„ฐ๋ฆฌ ์—†์Œ: {bid}")
    root = data_root()
    recs = _subsample(idx[bid]["slices"], MAX_SLICES)
    slices = [{"idx": i, "name": name, "img_path": str(root / "cropped" / rel)}
              for i, (name, rel) in enumerate(recs)]
    return slices, cell_type_of(bid)


def open_slice(sl):
    """ํฌ๋กญ ์Šฌ๋ผ์ด์Šค โ†’ ํšŒ์ƒ‰ ์ด๋ฏธ์ง€(PIL 'L'). (์ด๋ฏธ ํฌ๋กญ๋œ ์ด๋ฏธ์ง€ ๊ทธ๋Œ€๋กœ)."""
    return Image.open(sl["img_path"]).convert("L")