Avtomatska obdelava tileset slik - 3877 ločenih objektov in TSX datotek
- Ustvarjen skript za ločevanje objektov iz tileset slik (obdelaj_tilesete.py) - Odstranjevanje zelenega ozadja (#00FF00) iz vseh slik - Ločevanje posameznih objektov iz multi-object slik - Pomanjševanje na 50% originalne velikosti - Obdelanih 234 slik 3877 ločenih objektov - Ustvarjen skript za generiranje TSX datotek (generiraj_tsx_datoteke.py) - Avtomatsko generiranje 3877 TSX datotek za Tiled Map Editor - Pravilna XML struktura za vsak tileset - Avtomatska detekcija velikosti objektov - Relativne poti do slik Rezultati: - assets/narezano_loceno/ - 3877 ločenih PNG objektov - assets/tilesets_auto/ - 3877 TSX datotek za Tiled - Dokumentacija in navodila za uporabo Vse pripravljeno za uporabo v Tiled Map Editor!
This commit is contained in:
107
tools/generiraj_tsx_datoteke.py
Normal file
107
tools/generiraj_tsx_datoteke.py
Normal file
@@ -0,0 +1,107 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
|
||||
# ===== NASTAVITVE =====
|
||||
vhodna_mapa = r"c:\novafarma\assets\narezano_loceno"
|
||||
izhodna_mapa_tsx = r"c:\novafarma\assets\tilesets_auto"
|
||||
|
||||
# Ustvari izhodno mapo
|
||||
if not os.path.exists(izhodna_mapa_tsx):
|
||||
os.makedirs(izhodna_mapa_tsx)
|
||||
|
||||
def generiraj_tsx(pot_slike, ime_slike, relativna_pot_do_slike):
|
||||
"""
|
||||
Generiraj TSX datoteko za eno sliko.
|
||||
"""
|
||||
try:
|
||||
# Preberi velikost slike
|
||||
img = Image.open(pot_slike)
|
||||
width, height = img.size
|
||||
|
||||
# Generiraj ime tileseta (brez _obj01, _obj02, itd.)
|
||||
ime_brez_ext = os.path.splitext(ime_slike)[0]
|
||||
|
||||
# Odstrani _obj01, _obj02 iz imena za lepše ime tileseta
|
||||
if "_obj" in ime_brez_ext:
|
||||
base_name = ime_brez_ext.rsplit("_obj", 1)[0]
|
||||
obj_num = ime_brez_ext.rsplit("_obj", 1)[1]
|
||||
tileset_name = f"{base_name} - Object {obj_num}"
|
||||
else:
|
||||
tileset_name = ime_brez_ext
|
||||
|
||||
# Ustvari TSX vsebino
|
||||
tsx_content = f'''<?xml version="1.0" encoding="UTF-8"?>
|
||||
<tileset version="1.10" tiledversion="1.11.1" name="{tileset_name}" tilewidth="{width}" tileheight="{height}" tilecount="1" columns="1">
|
||||
<image source="{relativna_pot_do_slike}" width="{width}" height="{height}"/>
|
||||
</tileset>
|
||||
'''
|
||||
|
||||
# Generiraj ime TSX datoteke
|
||||
tsx_ime = f"{ime_brez_ext}.tsx"
|
||||
tsx_pot = os.path.join(izhodna_mapa_tsx, tsx_ime)
|
||||
|
||||
# Shrani TSX datoteko
|
||||
with open(tsx_pot, 'w', encoding='utf-8') as f:
|
||||
f.write(tsx_content)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Napaka pri {ime_slike}: {str(e)}")
|
||||
return False
|
||||
|
||||
def generiraj_vse_tsx():
|
||||
"""
|
||||
Generiraj TSX datoteke za vse PNG slike v narezano_loceno mapi.
|
||||
"""
|
||||
print("🚀 Začenjam generiranje TSX datotek za Tiled...\n")
|
||||
print(f"📂 Vhodna mapa: {vhodna_mapa}")
|
||||
print(f"📦 Izhodna mapa: {izhodna_mapa_tsx}\n")
|
||||
print("=" * 70)
|
||||
|
||||
skupaj_tsx = 0
|
||||
skupaj_napak = 0
|
||||
|
||||
# Preglej vse podmape
|
||||
for podmapa in os.listdir(vhodna_mapa):
|
||||
pot_podmape = os.path.join(vhodna_mapa, podmapa)
|
||||
|
||||
if not os.path.isdir(pot_podmape):
|
||||
continue
|
||||
|
||||
print(f"\n📁 Obdelujem: {podmapa}")
|
||||
print("-" * 70)
|
||||
|
||||
# Najdi vse PNG slike v podmapi
|
||||
slike = [f for f in os.listdir(pot_podmape) if f.endswith(".png")]
|
||||
print(f" Najdenih {len(slike)} slik\n")
|
||||
|
||||
for ime_slike in slike:
|
||||
pot_slike = os.path.join(pot_podmape, ime_slike)
|
||||
|
||||
# Relativna pot od tilesets_auto/ do slike
|
||||
# tilesets_auto/ je v assets/
|
||||
# slika je v assets/narezano_loceno/[podmapa]/[ime_slike]
|
||||
relativna_pot = f"../narezano_loceno/{podmapa}/{ime_slike}"
|
||||
|
||||
if generiraj_tsx(pot_slike, ime_slike, relativna_pot):
|
||||
skupaj_tsx += 1
|
||||
if skupaj_tsx % 100 == 0:
|
||||
print(f" ✅ Generirano {skupaj_tsx} TSX datotek...")
|
||||
else:
|
||||
skupaj_napak += 1
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print(f"✨ KONČANO!")
|
||||
print(f" ✅ Uspešno generirano: {skupaj_tsx} TSX datotek")
|
||||
if skupaj_napak > 0:
|
||||
print(f" ❌ Napake: {skupaj_napak}")
|
||||
print(f"\n📂 TSX datoteke so v: {izhodna_mapa_tsx}")
|
||||
print(f"\n🎮 Zdaj lahko dodaš te tilesete v Tiled:")
|
||||
print(f" 1. Odpri svojo mapo v Tiled")
|
||||
print(f" 2. Map → Add External Tileset...")
|
||||
print(f" 3. Izberi TSX datoteko iz {izhodna_mapa_tsx}")
|
||||
print(f" 4. Uporabi na mapi!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
generiraj_vse_tsx()
|
||||
193
tools/obdelaj_tilesete.py
Normal file
193
tools/obdelaj_tilesete.py
Normal file
@@ -0,0 +1,193 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
import numpy as np
|
||||
|
||||
# ===== NASTAVITVE =====
|
||||
vhodne_mape = [
|
||||
r"c:\novafarma\assets\topdown_objects",
|
||||
r"c:\novafarma\assets\krvava_zetev_sprites",
|
||||
r"c:\novafarma\assets\tiled_sprites"
|
||||
]
|
||||
|
||||
izhodna_mapa = r"c:\novafarma\assets\narezano_loceno"
|
||||
nova_velikost_faktor = 0.5 # Pomanjša na 50% (lahko spremeniš)
|
||||
min_velikost_objekta = 20 # Minimalna velikost objekta v pikslih (ignorira majhne artefakte)
|
||||
|
||||
# Barve za odstranjevanje (zeleno ozadje)
|
||||
ZELENA_BARVA_RGB = [0, 255, 0] # Svetlo zelena (#00FF00)
|
||||
BARVA_TOLERANCA = 30 # Toleranca za odstranjevanje zelene
|
||||
|
||||
# Ustvari izhodno mapo
|
||||
if not os.path.exists(izhodna_mapa):
|
||||
os.makedirs(izhodna_mapa)
|
||||
|
||||
def odstrani_zeleno_ozadje(img):
|
||||
"""
|
||||
Odstrani zeleno ozadje in naredi prosojno.
|
||||
"""
|
||||
img_array = np.array(img)
|
||||
|
||||
# Če slika nima alpha kanala, dodaj ga
|
||||
if len(img_array.shape) == 2 or img_array.shape[2] == 3:
|
||||
# Ustvari alpha kanal
|
||||
if len(img_array.shape) == 2:
|
||||
# Grayscale
|
||||
rgb = np.stack([img_array, img_array, img_array], axis=2)
|
||||
else:
|
||||
rgb = img_array[:, :, :3]
|
||||
|
||||
alpha = np.ones((img_array.shape[0], img_array.shape[1]), dtype=np.uint8) * 255
|
||||
img_array = np.concatenate([rgb, alpha[:, :, np.newaxis]], axis=2)
|
||||
|
||||
# Najdi zelene piksle
|
||||
r, g, b = img_array[:, :, 0], img_array[:, :, 1], img_array[:, :, 2]
|
||||
|
||||
# Maska za zeleno barvo (kjer je zelena dominantna)
|
||||
je_zelena = (
|
||||
(g > r + BARVA_TOLERANCA) & # Zelena je večja od rdeče
|
||||
(g > b + BARVA_TOLERANCA) & # Zelena je večja od modre
|
||||
(g > 200) # Zelena je dovolj svetla
|
||||
)
|
||||
|
||||
# Nastavi alpha na 0 za zelene piksle
|
||||
img_array[:, :, 3][je_zelena] = 0
|
||||
|
||||
return Image.fromarray(img_array, 'RGBA')
|
||||
|
||||
def najdi_objekte(img):
|
||||
"""
|
||||
Najde vse ločene objekte na sliki glede na prosojnost.
|
||||
Vrne seznam bounding box-ov (x, y, width, height).
|
||||
"""
|
||||
from scipy import ndimage
|
||||
|
||||
# Pretvori v numpy array
|
||||
img_array = np.array(img)
|
||||
|
||||
# Ustvari masko prosojnosti (kjer alpha > 50)
|
||||
alpha_channel = img_array[:, :, 3]
|
||||
maska = alpha_channel > 50
|
||||
|
||||
# Najdi povezane komponente (objekte)
|
||||
labeled, num_features = ndimage.label(maska)
|
||||
|
||||
objekti = []
|
||||
for i in range(1, num_features + 1):
|
||||
# Najdi koordinate tega objekta
|
||||
pozicije = np.where(labeled == i)
|
||||
if len(pozicije[0]) == 0:
|
||||
continue
|
||||
|
||||
y_min, y_max = pozicije[0].min(), pozicije[0].max()
|
||||
x_min, x_max = pozicije[1].min(), pozicije[1].max()
|
||||
|
||||
width = x_max - x_min + 1
|
||||
height = y_max - y_min + 1
|
||||
|
||||
# Ignoriraj premajhne objekte (artefakti)
|
||||
if width >= min_velikost_objekta and height >= min_velikost_objekta:
|
||||
objekti.append((x_min, y_min, width, height))
|
||||
|
||||
return objekti
|
||||
|
||||
def procesiraj_sliko(pot_slike, ime_slike, mapa_izvora):
|
||||
"""
|
||||
Procesiraj eno sliko - odstrani zeleno ozadje, najdi vse objekte in jih shrani LOČENO.
|
||||
"""
|
||||
try:
|
||||
img = Image.open(pot_slike).convert("RGBA")
|
||||
print(f"\n📸 Obdelujem: {ime_slike}")
|
||||
|
||||
# 1. ODSTRANI ZELENO OZADJE
|
||||
img_brez_zelene = odstrani_zeleno_ozadje(img)
|
||||
print(f" 🟢 Odstranil zeleno ozadje")
|
||||
|
||||
# 2. NAJDI VSE OBJEKTE
|
||||
objekti = najdi_objekte(img_brez_zelene)
|
||||
|
||||
if len(objekti) == 0:
|
||||
print(f" ⚠️ Nisem našel objektov")
|
||||
return
|
||||
|
||||
print(f" ✅ Našel {len(objekti)} objekt(ov)")
|
||||
|
||||
# 3. SHRANI VSAK OBJEKT LOČENO
|
||||
for idx, (x, y, w, h) in enumerate(objekti):
|
||||
# Izreži objekt
|
||||
objekt = img_brez_zelene.crop((x, y, x + w, y + h))
|
||||
|
||||
# Pomanjšaj
|
||||
nova_w = int(w * nova_velikost_faktor)
|
||||
nova_h = int(h * nova_velikost_faktor)
|
||||
|
||||
if nova_w > 0 and nova_h > 0:
|
||||
objekt = objekt.resize((nova_w, nova_h), Image.Resampling.LANCZOS)
|
||||
|
||||
# Generiraj ime datoteke
|
||||
ime_brez_ext = os.path.splitext(ime_slike)[0]
|
||||
if len(objekti) == 1:
|
||||
# Če je samo en objekt, ne dodaj številke
|
||||
novo_ime = f"{ime_brez_ext}.png"
|
||||
else:
|
||||
# Če je več objektov, dodaj številko (npr. drevo_1, drevo_2, ...)
|
||||
novo_ime = f"{ime_brez_ext}_obj{idx+1:02d}.png"
|
||||
|
||||
# Ustvari podmapo za izvorno mapo
|
||||
podinhodna_mapa = os.path.join(izhodna_mapa, os.path.basename(mapa_izvora))
|
||||
if not os.path.exists(podinhodna_mapa):
|
||||
os.makedirs(podinhodna_mapa)
|
||||
|
||||
# Shrani
|
||||
pot_shranjevanja = os.path.join(podinhodna_mapa, novo_ime)
|
||||
objekt.save(pot_shranjevanja)
|
||||
print(f" 💾 Shranil: {novo_ime} ({nova_w}x{nova_h}px)")
|
||||
|
||||
except Exception as e:
|
||||
print(f" ❌ Napaka pri {ime_slike}: {str(e)}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
def procesiraj_vse_mape():
|
||||
"""
|
||||
Glavna funkcija - procesiraj vse mape.
|
||||
"""
|
||||
print("🚀 Začenjam ločevanje objektov in odstranjevanje zelenega ozadja...\n")
|
||||
print(f"📂 Vhodne mape: {len(vhodne_mape)}")
|
||||
print(f"📦 Izhodna mapa: {izhodna_mapa}")
|
||||
print(f"📏 Faktor pomanjševanja: {nova_velikost_faktor} ({int(nova_velikost_faktor*100)}%)")
|
||||
print(f"🔍 Minimalna velikost objekta: {min_velikost_objekta}px")
|
||||
print(f"🟢 Odstranjujem zeleno ozadje: RGB{ZELENA_BARVA_RGB} ±{BARVA_TOLERANCA}\n")
|
||||
print("=" * 70)
|
||||
|
||||
skupaj_slik = 0
|
||||
skupaj_objektov = 0
|
||||
|
||||
for mapa in vhodne_mape:
|
||||
if not os.path.exists(mapa):
|
||||
print(f"⚠️ Mapa ne obstaja: {mapa}")
|
||||
continue
|
||||
|
||||
print(f"\n📁 Obdelujem mapo: {os.path.basename(mapa)}")
|
||||
print("-" * 70)
|
||||
|
||||
slike = [f for f in os.listdir(mapa) if f.endswith((".png", ".jpg", ".jpeg"))]
|
||||
print(f" Najdenih {len(slike)} slik\n")
|
||||
|
||||
for ime in slike:
|
||||
pot = os.path.join(mapa, ime)
|
||||
procesiraj_sliko(pot, ime, mapa)
|
||||
skupaj_slik += 1
|
||||
|
||||
print("\n" + "=" * 70)
|
||||
print(f"✨ KONČANO! Obdelal {skupaj_slik} slik")
|
||||
print(f"📂 Rezultati so v: {izhodna_mapa}")
|
||||
print(f" Vsak objekt je shranjen v LOČENI datoteki!")
|
||||
|
||||
# Preveri, če imamo scipy (potreben za najdi_objekte)
|
||||
try:
|
||||
from scipy import ndimage
|
||||
procesiraj_vse_mape()
|
||||
except ImportError:
|
||||
print("❌ NAPAKA: Potrebuješ scipy knjižnico!")
|
||||
print(" Namesti z: pip install scipy numpy pillow")
|
||||
print("\n Zaženi: pip install scipy")
|
||||
Reference in New Issue
Block a user