Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ expo-env.d.ts
npm-debug.*
yarn-debug.*
yarn-error.*
metro.log
metro-error.log

# macOS
.DS_Store
Expand All @@ -49,6 +51,7 @@ yarn-error.*

# AI model binaries require independently verified redistribution rights.
/assets/models/*.tflite
!/assets/models/efficientdet-lite0-int8-v1.tflite
/.local-models/

# typescript
Expand Down
13 changes: 11 additions & 2 deletions App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,15 @@ function VehicleAnalysisSheet({ session, onClose, onRequestAnalysis }: { session
<Text style={styles.modelNoticeTitle}>{analysis.status === 'completed' ? 'Lokalna analiza je dovršena' : 'Lokalna analiza nije dostupna'}</Text>
<Text style={styles.modelNoticeText}>
{analysis.status === 'ready-for-model'
? 'Model detekcije nije uključen u ovu javnu verziju. Snimka ostaje spremljena i spremna za buduću lokalnu analizu.'
? 'Lokalni model detekcije nije se mogao pokrenuti u ovom buildu. Snimka ostaje spremljena; tehnički detalj prikazan je u ograničenjima izvještaja.'
: 'Analiza koristi lokalni model vozila i OCR. Rezultati oznake ostaju kandidati dok se ne potvrde kroz više kadrova.'}
</Text>
<Text style={styles.modelNoticeText}>Dokazni kadrovi: {analysis.evidenceFrames.length} · tragovi vozila: {analysis.vehicleTracks.length}</Text>
{analysis.audioSummary && (
<Text style={styles.modelNoticeText}>
Zvuk videa: prosjek {formatDbfs(analysis.audioSummary.averageDbfs)} · vrh {formatDbfs(analysis.audioSummary.peakDbfs)} · {analysis.audioSummary.sampleCount} očitanja
</Text>
)}
{analysis.vehicleTracks.map(track => (
<View key={`${track.id}-evidence`} style={styles.trackEvidence}>
{track.evidenceCropUri
Expand Down Expand Up @@ -175,7 +180,10 @@ function ReportSheet({ session, onClose, onExport }: { session: Session; onClose
<View style={styles.reportSummary}>
<Text style={styles.reportSummaryText}>Trajanje: {formatDuration(session.durationSeconds)}</Text>
<Text style={styles.reportSummaryText}>Lokacija: {formatLocation(session.location)}</Text>
<Text style={styles.reportSummaryText}>Buka: prosjek {formatDbfs(session.noiseAverageDbfs)} · vrh {formatDbfs(session.noisePeakDbfs)}</Text>
<Text style={styles.reportSummaryText}>
Zvuk: prosjek {formatDbfs(report?.audioSummary?.averageDbfs ?? session.noiseAverageDbfs)} · vrh {formatDbfs(report?.audioSummary?.peakDbfs ?? session.noisePeakDbfs)}
</Text>
{report?.audioSummary && <Text style={styles.reportSummaryText}>Dekodirano: {report.audioSummary.sampleCount} očitanja po {report.audioSummary.windowMs} ms</Text>}
<Text style={styles.reportSummaryText}>{analysisLabel(session.analysis)}</Text>
</View>
{report ? (
Expand All @@ -188,6 +196,7 @@ function ReportSheet({ session, onClose, onExport }: { session: Session; onClose
{track.plateCandidates.some(candidate => candidate.confirmationCount >= 2) ? track.plateCandidates.filter(candidate => candidate.confirmationCount >= 2).map(candidate => (
<Text key={candidate.normalizedText} style={styles.reportPlateText}>{candidate.normalizedText} · {candidate.confirmationCount} kadar(a) · {candidate.confidenceLevel}</Text>
)) : <Text style={styles.reportMuted}>Nema potvrđenog kandidata oznake.</Text>}
{track.noise && <Text style={styles.reportMuted}>Zvuk uz prolazak: prosjek {formatDbfs(track.noise.averageDbfs)} · vrh {formatDbfs(track.noise.peakDbfs)}</Text>}
</View>
)) : <Text style={styles.reportMuted}>U dokaznim kadrovima nisu pronađena vozila.</Text>}
{report.unassignedPlateCandidates.length > 0 && (
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

Mobilni istraživačko-razvojni projekt za snimanje i kasniju analizu prometnih scena pomoću kamere, mikrofona i umjetne inteligencije na pametnom telefonu.

> Trenutačna verzija: **v0.2.0 razvojna**. Aplikacija lokalno snima videosesije sa zvukom i priprema dokazne kadrove za eksperimentalnu analizu. Javni izvor ne distribuira AI model. Aplikacija ne mjeri niti potvrđuje stvarnu brzinu vozila ili razinu buke.
> Trenutačna verzija: **v0.2.0 razvojna**. Aplikacija lokalno snima videosesije sa zvukom, izdvaja dokazne kadrove i koristi licencirani lokalni EfficientDet-Lite0 model za eksperimentalnu detekciju vozila. Aplikacija ne mjeri niti potvrđuje stvarnu brzinu vozila ili razinu buke.

## Cilj

Expand Down Expand Up @@ -46,7 +46,7 @@ flowchart TB
- Lokalni dnevnik sesija s vremenom snimanja, trajanjem i veličinom datoteke.
- Pregled snimljenog videa unutar aplikacije i trajno brisanje odabrane sesije.
- Sučelje prilagođeno radu na terenu: status, mjerač vremena i brzo zaustavljanje snimanja.
- Eksperimentalna lokalna obrada: izdvajanje i rangiranje kadrova, osnovno praćenje, OCR kandidati oznaka i korelacija audio uzoraka. Detektor vozila zahtijeva zaseban pravilno licenciran model.
- Eksperimentalna lokalna obrada: EfficientDet-Lite0 detekcija vozila, izdvajanje i rangiranje kadrova, osnovno praćenje, OCR kandidati oznaka te dekodiranje i vremenska korelacija zvuka iz uvezenog videa.
- Razvojna dijagnostika prikazuje confidence, vrijeme i okvir svake detekcije po tragu vozila.
- Automatizirane provjere obuhvaćaju lint, TypeScript i testove čistih analitičkih modula.

Expand Down Expand Up @@ -81,7 +81,7 @@ Pokrenite razvojni poslužitelj i otvorite ga development buildom. Za rad kamere

## Android development build i terensko testiranje

Za lokalni AI model aplikacija će koristiti vlastiti Android development build, a ne Expo Go. Konfiguracija je pripremljena u `eas.json` pod profilom `development` i proizvodi interni `.apk` paket.
Za lokalni AI model aplikacija koristi vlastiti Android development build, a ne Expo Go. Konfiguracija je pripremljena u `eas.json` pod profilom `development` i proizvodi interni `.apk` paket.

Nakon prijave u Expo račun, build se stvara naredbom:

Expand All @@ -107,21 +107,22 @@ Prije početka snimanja potvrdite dozvole za kameru, mikrofon i lokaciju. Snimit

## Tehnologije

- Expo SDK 54
- React Native 0.81.5
- Expo SDK 57
- React Native 0.86.3
- TypeScript
- `expo-camera`
- `expo-file-system`
- `expo-video`
- `react-native-audio-api`
- AsyncStorage

## AI model

Javni repozitorij ne uključuje binarni AI model. Zašto je prethodni razvojni artefakt uklonjen i koji su uvjeti za doprinos novog modela opisano je u [modelskoj kartici](docs/MODEL.md).
Javni repozitorij uključuje službeni EfficientDet-Lite0 int8 v1 pod Apache-2.0 licencom. Izvor, SHA-256, ulazno-izlazni ugovor i ograničenja opisani su u [modelskoj kartici](docs/MODEL.md).

## Smjer projekta

JEKA AOPS je otvoreni istraživačko-razvojni projekt pod licencom Apache-2.0. Sljedeći korak je integracija provjerljivo licenciranog lokalnog modela i terenska provjera u Android development buildu. Bez kalibracije scene rezultati se ne smiju predstavljati kao mjerenje.
JEKA AOPS je otvoreni istraživačko-razvojni projekt pod licencom Apache-2.0. Sljedeći korak je terenska provjera lokalnog modela, OCR-a i praćenja u Android development buildu. Bez kalibracije scene rezultati se ne smiju predstavljati kao mjerenje.

## Doprinos i sigurnost

Expand Down
4 changes: 3 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
],
"expo-asset",
"expo-sharing",
"expo-status-bar"
"expo-status-bar",
"react-native-fast-tflite",
"react-native-audio-api"
],
"ios": {
"supportsTablet": true
Expand Down
Binary file added assets/models/efficientdet-lite0-int8-v1.tflite
Binary file not shown.
54 changes: 34 additions & 20 deletions docs/MODEL.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
# Model detekcije vozila

## Status javne distribucije
JEKA AOPS uključuje lokalni **EfficientDet-Lite0 int8, verzija 1** za početnu detekciju cestovnih vozila. Model radi na uređaju; snimke i kadrovi ne šalju se vanjskom AI servisu.

Javni repozitorij namjerno **ne sadrži binarni AI model**. Raniji razvojni artefakt identificirao se kao EfficientDet Lite0 V1, ali nije postojao izvorni zapis preuzimanja ni upstream checksum kojim bi se nedvojbeno potvrdili porijeklo i pravo redistribucije. Zbog toga je uklonjen prije javne objave.
## Podrijetlo i licenca

`detectVehiclesInFrames` trenutačno je stabilna neutralna implementacija koja vraća prazan skup detekcija. Snimanje, lokalna pohrana, audio uzorkovanje, izdvajanje kadrova i izvještaji mogu se razvijati neovisno o odabiru modela.
- Izdavač: Google / TensorFlow
- Arhitektura: EfficientDet-Lite0
- Skup podataka: COCO 2017, 80 klasa
- Fiksni izvor: <https://storage.googleapis.com/mediapipe-models/object_detector/efficientdet_lite0/int8/1/efficientdet_lite0.tflite>
- Službena kartica: <https://www.kaggle.com/models/tensorflow/efficientdet/tfLite/lite0-detection-metadata/1>
- Službeni vodič: <https://developers.google.com/edge/mediapipe/solutions/vision/object_detector>
- Licenca modela: Apache License 2.0
- Datum preuzimanja: 2026-09-01
- Veličina: 4.602.795 bajtova
- SHA-256: `0720bf247bd76e6594ea28fa9c6f7c5242be774818997dbbeffc4da460c723bb`

## Uvjeti za novi model
Model je spremljen kao `assets/models/efficientdet-lite0-int8-v1.tflite`. Runtime `react-native-fast-tflite` distribuira se pod MIT licencom.

Prije dodavanja ili automatskog preuzimanja modela pull request mora sadržavati:
## Ulaz i izlaz

1. naziv modela, izdavača, verziju, izvorni URL i datum preuzimanja;
2. SHA-256 preuzete datoteke i reproducibilan postupak provjere;
3. licencu modela, obavezne obavijesti i licencu skupa podataka;
4. dopušta li licenca redistribuciju binarnog artefakta i komercijalnu uporabu;
5. ulazni tip, oblik, RGB raspored i normalizaciju;
6. redoslijed, tipove i oblike izlaznih tenzora;
7. mapu klasa, confidence/NMS pragove i poznata ograničenja;
8. testove na sintetičkim ili pravilno licenciranim snimkama bez osobnih podataka.
- Ulaz: RGB `uint8`, `[1, 320, 320, 3]`
- Predobrada: očuvanje omjera slike uz letterbox rubove vrijednosti 114
- Izlazi: okviri `[top, left, bottom, right]`, COCO klase, confidence i broj detekcija
- Prag: 0,32
- Prihvaćene klase: bicycle, car, motorcycle, bus i truck
- Koordinate: nakon izvođenja vraćaju se u normalizirane koordinate izvornog kadra

## Integracijska granica
Kadrovi se izdvajaju lokalno iz videozapisa. Model se izvršava CPU delegatom radi predvidljive kompatibilnosti; kasnije se može zasebno provjeriti GPU delegat.

Adapter se implementira u `src/analysis/vehicleDetectionModel.ts` i mora zadržati potpis:
## OCR fallback

```ts
detectVehiclesInFrames(frames: EvidenceFrame[]): Promise<VehicleDetection[]>
```
Ako detektor ne pronađe vozilo, aplikacija ipak zadržava do tri najkvalitetnija cijela kadra i na njima pokreće OCR. Takvi kandidati nisu prostorno pridruženi vozilu i moraju biti jasno označeni kao nepouzdani. Registracijska oznaka ne prikazuje se kao potvrđena bez ponavljanja kroz više različitih kadrova.

Native biblioteka i config plugin dodaju se tek kada je odabrani model odobren. Model ne treba commitati ako se može reproducibilno preuzeti tijekom lokalne pripreme ili builda uz provjeru očekivanog SHA-256.
## Poznata ograničenja

## Ograničenja rezultata
- COCO model prepoznaje opće klase vozila; ne prepoznaje marku, model, identitet ni prometni prekršaj.
- Mala, zamućena, zaklonjena i noćna vozila mogu biti propuštena.
- Confidence nije dokaz točnosti niti certificirana mjera.
- OCR može zamijeniti slične znakove; rezultat ostaje kandidat dok se ne potvrdi kroz više kadrova.
- Zvuk u videozapisu uvezenom iz galerije lokalno se dekodira i svodi na RMS dBFS očitanja u prozorima od 250 ms. To omogućuje vremensku korelaciju s vizualnim tragom vozila, ali nije kalibrirano mjerenje razine zvučnog tlaka u dB(A) niti dokaz da je baš opaženo vozilo izvor zvuka.
- Bez kalibracije scene aplikacija ne mjeri stvarnu brzinu vozila.

Detekcija, OCR i korelacija buke eksperimentalne su procjene. Ne smiju se predstavljati kao identifikacija osobe, certificirano mjerenje, forenzički dokaz ili automatski zaključak o prometnom prekršaju.

## Promjena modela

Pull request koji mijenja model mora navesti izvorni URL, verziju, licencu, SHA-256, skup podataka, ulazno-izlazni ugovor, mapu klasa, pragove i rezultate provjere na stvarnom Android uređaju. Nova binarna datoteka ne prihvaća se bez provjerljivog podrijetla i prava redistribucije.
Loading