Cara Menyimpan Hasil Deteksi Objek ke Database SQLite

Menyimpan hasil deteksi objek ke database SQLite berarti menulis setiap baris deteksi (label, koordinat kotak, skor keyakinan, timestamp) ke dalam satu file database tunggal yang bisa kamu query kapan saja. SQLite cocok untuk proyek computer vision skala kecil sampai menengah karena tidak butuh server, tidak butuh instalasi layanan, dan file databasenya bisa ikut dipindahkan bersama kode. Kalau kamu sudah pernah menyimpan hasil ke CSV, pindah ke SQLite memberi satu keuntungan utama: kamu bisa memfilter dan menggabungkan data tanpa memuat seluruh isi file ke memori.

Kapan SQLite lebih masuk akal daripada CSV

CSV bagus untuk data yang jarang diubah dan langsung dibaca spreadsheet. Masalahnya muncul saat jumlah baris lewat puluhan ribu dan kamu ingin menjawab pertanyaan seperti "berapa rata-rata skor keyakinan untuk label person hari ini". Dengan CSV, jawaban itu biasanya berarti memuat seluruh file lalu memprosesnya dengan pandas. Dengan SQLite, satu query sudah cukup.

SQLite juga menjaga tipe data. Kolom skor keyakinan tetap float, timestamp tetap tercatat sebagai teks berformat baku, dan kamu tidak perlu khawatir ada sel yang bergeser karena satu label mengandung koma. Untuk proyek yang terus menambah data seiring waktu, kemampuan menambahkan baris tanpa menulis ulang seluruh file membuat perbedaan besar.

SQLite menulis ke disk. Kalau kamera memproses 30 frame per detik dan setiap frame menghasilkan beberapa deteksi, kamu tidak mau membuka koneksi dan commit per baris. Kelola koneksi sekali di awal, kumpulkan baris dalam batch, lalu commit setiap beberapa ratus baris.

Menyiapkan skema tabel deteksi

Sebelum menulis kode, tentukan kolom apa saja yang dibutuhkan. Skema minimal untuk hasil deteksi objek biasanya mencakup identitas frame, label kelas, koordinat kotak pembatas, dan skor keyakinan.

  • id: primary key autoincrement, berguna untuk merujuk baris tertentu.
  • session_id: penanda satu sesi perekaman, misalnya nama file video atau waktu mulai.
  • frame_index: nomor frame dalam sesi tersebut.
  • timestamp: waktu deteksi dalam format ISO 8601.
  • label: nama kelas hasil model, misalnya person atau car.
  • confidence: skor keyakinan sebagai angka desimal.
  • x1, y1, x2, y2: sudut kotak pembatas dalam piksel.

Kalau modelmu menghasilkan mask segmentasi, tambahkan kolom teks untuk menyimpan poligon dalam format JSON. Menyimpan koordinat sebagai JSON di satu kolom membuat query berbasis area jadi lebih sulit, jadi simpan juga bounding box-nya secara terpisah.

Membuat database dan tabel dengan Python

Modul sqlite3 sudah ada di instalasi Python standar, jadi tidak ada paket tambahan yang perlu dipasang. Kode berikut membuat file database dan tabel deteksi.

import sqlite3

conn = sqlite3.connect("deteksi.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS deteksi (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT NOT NULL,
    frame_index INTEGER NOT NULL,
    timestamp TEXT NOT NULL,
    label TEXT NOT NULL,
    confidence REAL NOT NULL,
    x1 INTEGER, y1 INTEGER, x2 INTEGER, y2 INTEGER
)
""")
conn.execute("CREATE INDEX IF NOT EXISTS idx_label ON deteksi(label)")
conn.execute("CREATE INDEX IF NOT EXISTS idx_session ON deteksi(session_id)")
conn.commit()
conn.close()

Indeks pada kolom label dan session_id mempercepat query filter yang paling sering dipakai. Tanpa indeks, pencarian label pada ratusan ribu baris akan memindai seluruh tabel setiap kali.

Menulis hasil deteksi secara batch

Fungsi di bawah menerima daftar deteksi dari satu frame lalu menyimpannya. Perhatikan penggunaan executemany agar satu frame yang berisi banyak objek hanya butuh satu perjalanan ke database.

from datetime import datetime

def simpan_frame(conn, session_id, frame_index, detections):
    now = datetime.now().isoformat(timespec="seconds")
    rows = [
        (session_id, frame_index, now, d["label"], float(d["confidence"]),
         int(d["x1"]), int(d["y1"]), int(d["x2"]), int(d["y2"]))
        for d in detections
    ]
    conn.executemany("""
        INSERT INTO deteksi
        (session_id, frame_index, timestamp, label, confidence, x1, y1, x2, y2)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    """, rows)

Panggil fungsi ini di dalam loop pemrosesan video, tapi tahan commit sampai kamu mengumpulkan beberapa frame. Commit setiap 200 frame biasanya cukup untuk menjaga data tetap aman tanpa membuat disk sibuk terus-menerus. Kalau kamu memproses video dengan frame rate tinggi, hitung dulu beban I/O-nya seperti saat menghitung FPS kamera untuk proyek computer vision, supaya penulisan database tidak menjadi penghambat.

Query yang sering dibutuhkan setelah data terkumpul

Setelah data masuk, SQLite baru terasa gunanya. Beberapa query berikut menutup sebagian besar kebutuhan analisis awal.

  • Jumlah deteksi per label: SELECT label, COUNT(*) FROM deteksi GROUP BY label ORDER BY 2 DESC;
  • Rata-rata keyakinan per sesi: SELECT session_id, AVG(confidence) FROM deteksi GROUP BY session_id;
  • Deteksi berkeyakinan rendah yang perlu ditinjau: SELECT * FROM deteksi WHERE confidence < 0.4;
  • Objek yang muncul di banyak frame berurutan, untuk melacak pergerakan: SELECT frame_index, label, x1, y1 FROM deteksi WHERE session_id = ? ORDER BY frame_index;

Hasil query bisa langsung diumpankan ke pandas lewat pandas.read_sql_query kalau kamu ingin membuat grafik. Alur ini lebih rapi daripada membaca ulang CSV raksasa, dan cocok dipadukan dengan alat seperti yang dibahas di aplikasi visualisasi data AI gratis untuk pemula.

Kesalahan yang sering terjadi saat menyimpan ke SQLite

Masalah paling umum adalah membuka koneksi baru di setiap frame. Pola itu membuat SQLite melakukan locking berulang dan memperlambat proses secara drastis. Buka koneksi sekali di awal sesi, tutup di akhir.

Kesalahan kedua, menyimpan koordinat sebagai float padahal kamera menghasilkan piksel bulat. Pembulatan ke integer menghemat ruang dan mempercepat perbandingan. Ketiga, lupa menutup koneksi saat program berhenti mendadak, sehingga file database bisa tertinggal dalam kondisi journal yang belum selesai. Gunakan blok try/finally atau context manager agar koneksi selalu ditutup.

Kalau proyekmu melibatkan perangkat keras tambahan seperti mikrokontroler untuk memicu perekaman, pola penyimpanan yang sama bisa dipakai setelah data sensor dikirim ke komputer. Untuk urutan pemasangan perangkatnya, panduan cara memulai proyek Arduino untuk pemula menjelaskan langkah dasarnya. Kalau kamu perlu mendokumentasikan proses pengujian model dalam bentuk video tutorial, memilih metode perekaman layar yang tepat akan menghemat waktu, seperti dibandingkan di perbandingan metode perekam layar untuk tutorial.

Merawat file database seiring pertumbuhan data

File SQLite akan terus membesar selama kamu menambahkan baris. Lakukan VACUUM sesekali untuk memadatkan ruang yang tidak terpakai, terutama setelah menghapus banyak baris. Untuk proyek jangka panjang, pisahkan database per bulan atau per sesi besar agar file tetap mudah dibuka dan dicadangkan.

Backup cukup dilakukan dengan menyalin file .db saat tidak ada proses menulis. Tidak ada layanan yang perlu dihentikan, tidak ada dump yang harus dijalankan. Sifat portabel inilah yang membuat SQLite tetap relevan untuk proyek computer vision rumahan maupun prototipe cepat.

Skema yang rapi, penulisan batch, dan indeks pada kolom yang sering difilter menutup sebagian besar kebutuhan penyimpanan hasil deteksi. Sisanya tinggal disesuaikan dengan pertanyaan yang ingin kamu jawab dari data tersebut.

Pertanyaan yang Sering Diajukan

Apakah SQLite cukup untuk menyimpan jutaan baris deteksi?

Untuk data berukuran beberapa juta baris, SQLite masih bekerja dengan baik asalkan indeksnya tepat. Di atas itu, pertimbangkan database lain yang mendukung penulisan paralel, karena SQLite membatasi satu penulis pada satu waktu.

Bagaimana cara menyimpan hasil deteksi dari beberapa kamera sekaligus?

Tambahkan kolom camera_id pada tabel, lalu isi dengan penanda unik tiap kamera. Satu koneksi database bisa menangani beberapa sumber asal penulisan dilakukan dalam antrean, bukan bersamaan dari banyak proses.

Apakah koordinat kotak sebaiknya disimpan dalam piksel asli atau dinormalisasi?

Simpan keduanya kalau resolusi video bisa berubah antar sesi. Koordinat piksel berguna untuk menggambar ulang kotak pada frame asli, sedangkan koordinat ternormalisasi memudahkan perbandingan antar resolusi berbeda.