sprite / NOTES.md
Cnass's picture
Upload 11 files
2414b69 verified
|
Raw History Blame Contribute Delete
8.24 kB

Session notes

Oturumlar arası bağlam aktarımı için tutuluyor. Silinebilir.


Bölüm 1 — ÇÖZÜLDÜ: segmentasyon (animasyon strip'leri + tileset)

Önceki oturumdan kalan iki problem de kapandı. Detay README.md §2'de; burada neyin neden değiştiği özetleniyor.

Problem 1 — animasyon strip'leri parçalanıyordu

spritesheet.png gibi sheet'lerde her kare tek sprite yerine düzinelerce parçaya bölünüyordu. İki ayrı sebep vardı:

  1. Bir karenin parçaları gap-tabanlı birleştirme yarıçapından uzakta.
  2. Daha kötüsü: bu parçacıkların çoğu 1-2px olduğu için find_components onları MIN_SPRITE_SIZE_PX altı speckle sayıp ATIYORDU. Kareler sadece bölünmüyor, KAYBOLUYORDU (8 karenin 2'si hiç görünmüyordu). "Klon" sorunu da buradan geliyordu — kalan özdeş küçük parçaları duplicate detector haklı olarak klon işaretliyordu.

Çözüm: detect_separator_grid() — her kesim çizgisinin tamamen arka plan olduğu bir periyot+faz arıyor. Böyle bir çizgi hiçbir piksel bloğunu kesemez. Önceki oturumda takılınan nokta buydu: _grid_candidate_divisors hücre boyutunun sheet boyutunu tam bölmesini şart koşuyordu ve skorlama iki gerçek sheet arasında çelişiyordu. Yeni dedektör ikisine de ihtiyaç duymuyor; kesimin doğruluğu içerik istatistiğinden ÇIKARILMIYOR, doğrudan DOĞRULANIYOR.

İki incelik: faz da aranmalı (11px adımlı kafeste boşluklar 8, 19, 30... konumlarında), ve "en küçük yasal periyot" yetmiyor (parçacıklı bir karenin içindeki tesadüfi boş satırdan geçen kesim yasal ama kareyi ikiye böler; adaylar hücre sayısı × en dar boşluk ile puanlanıyor).

regroup_by_grid() gap sonucunu bu hücrelere topluyor ve sadece birleştirme yapıyor: gap aşamasının zaten birleştirdiği bir sprite (yaprak+sap) hücreleri union'lıyor, asla bölünmüyor.

Problem 2 — Dungeon_Tileset.png tek dev blok oluyordu

Grid fallback devreye girmiyordu (eski koşul "en fazla 6 bölge" istiyordu, sheet'te 21 bölge vardı).

Çözüm: aşırı-birleşme koşuluna alan tabanlı dal (bir ekseni baştan sona kaplayan VE alanın ≥%25'ini yutan bölge) + detect_tile_grid() — hücre adımını sheet'in kendi kenar periyodikliğinden okuyor. Kritik nokta: gerçek adımın her KATI da gerçek tile sınırlarına denk gelir, o yüzden en yüksek puanı hep en büyük kat alır (16px tileset 32/80 okunur); bu yüzden "en iyi puana yakın EN KÜÇÜK adım" seçiliyor. İki eksenin aynı kare hücrede anlaşması da şart — bu, tek eksende periyodik animasyon sheet'lerini bu yoldan uzak tutuyor.

Sonuçlar

sheet önce sonra doğrusu
spritesheet.png 128×128 7 (2 kare kayıp) 8 8 kare
spritesheet (1).png 512×256 54 27 27 kare
spritesheet (2).png 256×256 71 24 24 kare
Dungeon_Tileset.png 160×160 21 (dev blok) 100 100 tile
Dungeon_Tiles.png 400×400 300 297 300 tile*

* 297 = 300 tile, biri 4 hücrelik kompozit obje olarak birleştirildi (aşağıya bak). Beş sheet'te de kutular tüm ön plan piksellerini kapsıyor (coverage 1.000).

Ayrıca: O(n²) ölçeklenme

merge_related_components ve güven skorundaki en-yakın-komşu taraması her çifti karşılaştırıyordu. İkisi de uzamsal indekse alındı; aday kümeleri kesin testlerin dikkate alacağı çiftlerin üst kümesi olduğu için sonuçlar birebir aynı (brute-force referansa karşı doğrulandı). 2048×2048'lik, ~16k sprite'a bölünen bir sheet: dakikalar → ~2s.


Bölüm 2 — Kompozit objeler (çok hücreye yayılan tek obje)

Grid kesimi karolar için doğru, çok hücreye yayılan objeler için yanlış. Üç hücreye inen bir merdiven tek şeydir; hücre hücre kesilince tek başlarına anlamsız üç parça olur ve tekrar eden orta bölümü kendi diğer yarısının duplicate'i sayılır.

_composite_cell_groups() grid kesiminden sonra tek bir bağlı çizim parçasına ait hücreleri tekrar birleştiriyor. İki incelik:

  • Test bağlı-bileşen kimliği, "iki komşu hücre sınırda değiyor mu" DEĞİL. Bunlar eşdeğer görünür ama değildir: iki düz dolgu karosu tüm ortak kenarları boyunca değer ve saçma bir sprite'a kaynaşır. (Önce bunu denedim, Dungeon_Tileset.png'de tam olarak bunu yaptı.)
  • Kimlik de tek başına yetmiyor: zindanın zemini ve duvarları da tek devasa bağlı bölge. Ayıran şey büyüklük — kompozit obje birkaç hücre (GRID_COMPOSITE_MAX_CELLS, varsayılan 6), arazi düzinelerce.

Bilinen sınır (açıkça yazıyorum): bu sadece obje kendi başına bir çizim adasıysa çalışıyor. Dungeon_Tileset.png'de sütunlar ve kapı çevredeki araziye DEĞECEK şekilde çizilmiş — üst bölge tamamı 17.399 piksellik tek opak ada, sheet'in %68'i — yani hiçbir yerel kural bunları zemini de kaynaştırmadan ayıramaz. Onlar için elle Merge aracı var. Kendi arka planı üzerinde duran objeler (yaygın durum) otomatik hallediliyor.


Bölüm 3 — Dataset kalitesi (yeni)

Sprite'ları doğru kesmek işin yarısı. Diğer yarısı sonucun eğitilmeye değer olup olmadığı — farklı bir soru, farklı hata biçimleri. Detay README.md §3'te.

  • auto_tagger.py — kategori/style/tag önerisi. En güçlü sinyal provenans: tile grid'den çıkan sprite tileset karosudur, separator grid'den çıkan animasyon karesidir. Bunlar içerik tahmini değil, nasıl üretildiğine dair gerçek. AUTO_TAG_MIN_CONFIDENCE altında KATEGORİ "unknown"a düşer (yanlış kategori boş kategoriden kötüdür); style iddiaları piksellerin destekleyebileceğiyle sınırlı (4 renk = Game Boy DEĞİL; gameboy sadece gerçek 4-tonlu monokrom rampa için, NES tahmini yok). Her otomatik satır insan dokunana kadar auto_tagged=1 taşıyor.
  • Toplu atama (POST /api/batch/assign) — kapsam: aktif sheet / tüm pending / hepsi. Etiketler varsayılan olarak eklemeli, böylece toplu geçiş auto-tagger'ın sprite başına bulduklarını ezmiyor.
  • POST /api/batch/dedupe-keep-one — duplicate zincirini geçişli takip edip (#40 → #12 → #3 tek kümedir) her kümeden en iyi puanlıyı tutuyor, gerisini reddediyor. "Reject Duplicates"tan farkı: bir tileset aynı zemin karosunu meşru olarak onlarca kez tekrar eder.
  • Train/val/test (dataset_manager.assign_split) — deterministik (hash, shuffle değil) ve sheet bazlı gruplu. Animasyonun 24 karesi neredeyse aynı görüntüler; sprite bazlı bölmek kare 7'yi train'e kare 8'i test'e koyar ve skor ezberi ölçer. Az sayıda sheet varken bir bölüm boş kalabilir — split önizlemesi bunu saklamak yerine söylüyor.
  • dataset_report.py — kompozisyon uyarıları (bir sınıf >%60, çok ince sınıflar, çoğu metadata denetlenmemiş, tek kaynak sheet, tek çözünürlük) + kalite skoru kalibrasyonu. Kalibrasyon çoğunluk taban çizgisini de raporluyor: en iyi eşik "hep büyük sınıfı tahmin et"i ancak geçiyorsa, uydurma bir öneri yerine "bu skor senin kararlarını ayırmıyor, elle incelemeye devam et" diyor.
  • Animasyon önizleme (GET /api/animation/frames) — kareler orijinal sheet konumlarına göre ortak bir tuvale yerleştiriliyor. Sıkı kırpılmış crop'ları arka arkaya oynatmak animasyonu titretir.

Test durumu

100/100 geçiyor: segmentation 26, dataset 20, api 14, auto_tagger 12, extraction 10, duplicates 10, background 8.

test_dataset.py ve test_api.py config.DB_PATH'i geçici bir dosyaya yönlendirip database'i reload ediyor, yani Space'in gerçek verisine dokunmuyorlar (doğrulandı).

Hâlâ yapılmadı

  • Arayüzde segmentasyon modu seçici / "Force grid size" alanı yok. segment_sheet(mode=...) üç modu da destekliyor ("auto", "gap", "grid") ama analyzer.process_sheet her zaman "auto" çağırıyor; bunu bir API parametresi olarak dışarı açmak küçük bir iş.
  • Kompozit birleştirme, objenin araziye değdiği durumları çözemiyor (yukarıda "bilinen sınır"). Bunun için semantik bir model gerekir.