IC timer 555 adalah sirkuit terpadu (chip) yang digunakan dalam berbagai pembangkit timer, pulsa dan aplikasi osilator. Komponen ini digunakan secara luas, berkat kemudahan dalam penggunaan, harga rendah dan stabilitas yang baik
Jika anda pencinta IC TTL datau CMOS maka project jam digital ini akan menunjukkan bahwa tidak ada salahnya balik kembali ke dasar elektronika digital , sebab semuanya BISA dibuat dengan teknologi jadul
Di awal tahun 2025 ini terasa sedikit telat menulis blog ini kembali, entah karena umur sudah terasa bertambah banyak ? Entahlah ....namun alasan yang tidak mengenakkan ini menjadi pengingat penting bagi saya. Semangat saya menulis blog ini dikarenakan memori otak buatan era tahun 80an ini lumayan gampang pelupa. Jadi seharusnya bulan yang agak sibuk januari-februari 2025 ini harus saya simpan di blog ini agar suatu saat saya membutuhkannya dapat dengan mudah melakukan search kembali di google.
Memang kesibukan kali ini ditahun 2025 dimulai dari 1 bulan sebelumnya dimana saya diminta menyelesaikan project penelitian di FIKK-UNESA (akan saya ceritakan jika sudah kelar), dan yang sangat menjadi perhatian ketika diundang oleh Prodi D4 Transportasi Fakultas Vokasi - Unesa untuk membagi ilmu saya mengenai deteksi objek via YOLO mulai sering di bicarakan oleh prodi D4 Teknik Listrik, dimana saya 4 tahun mengajar sebagai program praktisi mengajar. Kini saya diminta untuk menjajal membagi ilmu koding kepada mahasiswa yang nol putul terhadap coding.
Gambar diatas ini merupakan demo saya pertama kali ketika diminta untuk membuktikan kemampuan YOLO V8 dalam mendeteksi golongan kendaraan sesuai kelas yang ditentukan oleh Kemenhub. Jadi dapat dikatakan demo ini menjadi pembuka ke keseruan lainnya dimana saya diberikan beberapa mahasiswa untuk saya 'ubah' tugas akhirnya menjadi lebih kekinian terutama dengan bantuan koding terkhusus yang berhubungan dengan machine vision di transportasi. Jadi harapannya adalah kemampuan saya di bidang machine vision dapat ditularkan ke mereka.
Kelanjutan dari pertemuan tak terduga ini adalah ketika semester genap 2025 dimulai pada bulan februari, saya dipercayai oleh kepala prodi d4 transportasi Ibu Dr. Anita Susanti Spd. MT. untuk memberikan tambahan kelas di mata kuliah Metodologi Penelitian dan Aplikasi Komputer. Semangangatnya adalah untuk menjadikan tugas akhir dan penelitian para mahasiswa/i lebih berorientasi ke produk dan terhindar dari analisa yang lebih mirip penelitian di prodi asli sebelum dipecah yaitu Teknik Sipil S1. Jadi 'ROH' fakultas VOKASI yang dulu selama 4 tahun sempat saya sisipkan di D4 Teknik Listrik, kini akan saya lakukan metode yang serupa di D4 Transportasi.
LALU BAGAIMANA BISA PRODI TANPA KULIAH KODING DIJEJALI OPENCV-YOLO ?
Bukan aisi555 kalau tanpa ide nyeleneh, teringat saat awal kuliah 25 tahun yang lalu yang sangat membekas ketika disodorkan tugas pemrograman C++ tanpa sempat diberikan penjelasan oleh dosen. Bagaimana paniknya seorang anak kampung yang hanya tau komputer untuk mengetik, kini diminta mengerjakan tugas koding kalender abadi ? Analogi kejadian di tahun reformasi ini menjadikan sebuah acuan bahwa saya ini tidak sehebat teman-teman dari sma di surabaya yang rata-rata sudah mengenal minimal bahasa BASIC, namun waktu itu saya tetap berusaha agar mengerti dengan cepat. Kalau dulu kuncinya "copy paste " punya teman, kini anak jaman sekarang dimudahkan dengan mesin pencari sumber-sumber kodingan siap pakai yang bertebaran di internet. Bahkan dengan ChatGpt pun kalau dilakukan dengan tepat "kelar ini barang" !
Yang saya ingin tanamkan adalah agar mahasiswa tidak menyerah diawal apalagi setelah ketemu kata-kata asing sepert syntax, python env, library, variabel, IF THEN, Loop dan sebagainya. Logika mengajar bahasa pemrograman saya balik dengan memberikan contoh yang siap pakai pada google colab ( buka koding lengkap disini ), lalu saya demokan dikelas bersama-sama 120++ mahasiswa. Lumayan banyak penuh di auditorium K10 dan dapat dibayangkan bagaimana kehebohannya. Gambar diatas adalah pengenalan opencv untuk mendeteksi bentuk lingkaran pada sebuah gambar.
Metode ini kemudian saya lanjutkan pada koding kedua berupa pengenalan object karakter pelat nomer menggunakan inference dan API roboflow (koding lengkap disini). Sekali lagi saya berusaha memperkenalkan bahwa di internet sana ada pemodelan AI dari berbagai object yang dapat diambil dengan gratis salah satunya adalah ROBOFLOW. Mahasiswa cukup hanya tahu bagian mana yang harus diubah agar gambar plat nomer yang mereka ambil sebelum kuliah dapat dideteksi sesuai harapan.
Masih banyak keseruan kedepannya terutama tawaran-tawaran untuk mempelajari berbagai metode-metode algoritma di dunia transportasi - jalan raya -logistik - kereta api - pelabuhan dan banyak lainnya yang akan saya bagikan ke pembaca setia blog ini. Yang seperti ini nih ....
Mikrokontroler merupakan ujung tombak dari implementasi IOT diberbagai bidang, dimana dengan kemampuan pengolahan sensor yang semakin baik dapat dimanfaatkan untuk membantu kehidupan manusia sehari-hari . Seperti halnya ilustrasi gambar paling atas merupakan pemanfaatan ESP32 untuk membantu pembacaan meter PDAM secara digital dan kemudian saya bersama mahasiswa Teknik Listrik - Vokasi Unesa Surabaya, yang kebetulan lagi Ujian Tengah Semester (UTS), ingin meng-upgrade ilmu jaman sekarang, sehingga dapat memiliki pemahaman "digitalisasi" yang benar dan tepat guna. Ayo ikuti keseruan UTS kali ini dan pembaca bisa juga mencobanya dirumah !
Ada 5 proses penting dalam kerangka berpikir untuk perancangan sistem pembacaan meteran pdam seperti gambar diatas, walau ada keterbatasan di sisi pengambilan foto (hanya simulasi file gambar meter dalam spiffs) yang akan kita lakukan, perancangan sistem digitalisasi meter pdam idealnya seperti ini :
ESP32 / ESP32 CAM mengambil gambar dari meter pdam dan merubahnya menjadi teks ter-encoded base64
ESP32 mengirimkan gambar dalam bentuk base64 tadi secara MQTT ke sebuah topik
Cloud computing dalam hal ini google colab, melakukan subscribe ke topic dan kemudian menerima data gambar base64, melakukan decoding menjadi gambar jpg kemudian dengan bantuan model yolo/roboflow melakukan deteksi angka meter melalui proses Artificial Inteligence, dan kemudian pembacaan angka meter di publish ke topic reply.
ESP32 yang sebelumnya sudah subscribe ke topic reply akan menerima angka pembacaan meter dan diolah ke serial monitor atau display LCD/OLED sesuai kreatifitas.
Database pelanggan di pusat billing center dapat di update secara otomatis dan tagihan dicetak sesuai penggunaan air di pelanggan.
Perangkat minimum yang kalian gunakan adalah ESP32, resistor 10Kohm dan Push button / tactile switch. Cukup hanya itu saja bisa kalian rangkai dengan atau tanpa projectboard/breadboard.
FLOWCHART :
Catatan : "GUNAKAN ARDUINO IDE 1.8.XX (VERSI LAMA) JIKA KALIAN INGIN MENGIKUTI LANGKAH DIBAWAH INI YANG BERBASIS SPIFFS , JIKA KALIAN SUDAH PAHAM MENGENAI LITTLE FS SILAHKAN GUNAKAN SAJA ARDUINO IDE 2.X.X (BARU) "
SPIFFS merupakan file system layaknya di komputer untuk menyimpan data-data gambar, teks, audio dll didalam memori flash nya ESP32. Untuk melakukan seting arduino ide 1.8.xx kalian, ikuti langkah berikut :
Catatan : gambar diatas hanya untuk menunjukkan dimana file dan folder arduino kalian, tidak perlu dibuka atau browse. Cuman di copy nama foldernya lalu dibuka melalui explorer dan pindahkan file jar ke directorynya.
3. Restart arduino ide kalian dan jika berhasil pada menu tools muncul menu baru "ESP32 sketch data upload". Buat file sketch/ino baru dan save terlebih dahulu.
4. Untuk seting jenis board yg dipakai pilih "ESP32 Dev Module" dan seting lainnya berupa pilihan "Huge App" seperti pada gambar berikut:
5. Fotokan meter pdam yg ada di sekitar kalian (gunakan hp) kemudian kecilkan dan compress sampai file JPG nya berukuran dibawah 30Kb namun masih dapat terbaca dengan jelas. Gunakan tools kompresi online yang saya rekomendasikan adalah : https://www.imgonline.com.ua/eng/compress-image-size.php
6. Pindahkan file gambar tadi (rename dulu dengan pdam.jpg) ke folder baru bernama "data" yg lokasinya satu tingkat dibawah folder dimana kalian menyimpan sketch atau file .ino, seperti pada ilustrasi berikut:
7. Untuk memindahkan file ke ESP32, maka setelah file gambar pdam.jpg tersimpan di folder /data, cukup lanjutkan dengan pilih tools => ESP32 sketch upload, sampai sukses seperti gambar berikut:
Selanjutnya kita akan melakukan coding ke ESP32 kita yang akan bertujuan untuk mengirimkan data secara mqtt, sehingga dibutuhkan library "pubsubclient" yang bisa kalian install seperti biasanya. Namun karena ada keterbatasan maksimum teks yg bisa dikirim, maka kita butuh melakukan "tweak" terhadap librarynya dan ikuti saja langkah berikut:
1. Masuk ke folder arduino kamu lalu menuju libraries/pubsubclient/src dan cari file bernama pubsubclient.h lalu edit menggunakan teks editor. Temukan item bernama #define MQTT_MAX_PACKET_SIZE 256 , lalu ganti menjadi 50000 seperti gambar dibawah:
2. Setelah library disimpan, maka dapat melakukan editing coding sebagai acuan dibawah ini, sesuaikan dengan yg kamu pakai. Saya menggunakan broker : mqtt.telkomiot.id karena masih gratis dan kecepatan serta quotanya dapat digunakan untuk data mqtt yg lumayan panjang. Jadi jika belum punya akunnya silahkan daftar dulu di www.telkomiot.id
//UTS MIKROKONTROLER 2024
//d4 teknik listrik vokasi unesa surabaya
//by: nyoman yudi kurniawan ST
#include <WiFi.h>
#include <SPIFFS.h>
#include <PubSubClient.h>
#include <Base64.h>
#define tombol 19 //sesuaikan pin tombol yg digunakan
//sesaikan wifi yang kamu pake
const char* ssid = "Nama Wifi";
const char* password = "password";
//Kita gunakan telkomiot sebagai broker, perhatikan baik-baik
const char* mqtt_server = "mqtt.telkomiot.id"; // jangan pernah ubah ini
const char* mqtt_key = "18f8e70xxxxxxxx"; // access key akun
const char* mqtt_token = "18f8e70xxxxxxx"; // token key akun
// topic dan reply silahkan ditambah no kelompok kamu di akhir,
// semisal "/tlunesa/pdam-12" , jangan sampai sama kelompok lain
const char* topic = "/tlunesa/pdam";
const char* reply = "/tlunesa/pdam/reply";
WiFiClient espClient;
PubSubClient client(espClient);
// Function untuk terhubung ke wifi
void setup_wifi() {
delay(10);
Serial.println();
Serial.print(F("UTS Mikrokontroler 2024 - Menghubungkan ke "));
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println(F("WiFi Terhubung.."));
}
// Function untuk koneksi MQTT
void reconnect() {
while (!client.connected()) {
Serial.print(F("Mencoba koneksi MQTT ..."));
String clientId = "Unesa-d4-";
clientId += String(random(0xffff), HEX);
// menghubungkan..
if (client.connect(clientId.c_str(),mqtt_key,mqtt_token)) {
Serial.println(F("Terhubung ! dan Subscribe"));
client.subscribe(reply);
} else {
Serial.print(F("failed, rc="));
Serial.print(client.state());
delay(5000);
}
}
}
void setup() {
pinMode(tombol, INPUT);
Serial.begin(9600);
// Inisialisasi SPIFFS
if (!SPIFFS.begin()) {
Serial.println(F("SPIFFS Mount gagal"));
return;
}
// Inisialisasi WiFi and MQTT
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
//jika tombol ditekan (aktif low)
if (!digitalRead(tombol))
{
Serial.println("");
Serial.println(F("Tombol Ditekan.."));
// buka gambar di binary mode, catatan : maksimal 30kb
File file = SPIFFS.open("/pdam.jpg", "rb");
if (!file) {
Serial.println(F("Gagal membuka file di spiffs"));
return;
}
// Read the file size
size_t fileSize = file.size();
Serial.print("File size: ");
Serial.println(fileSize);
// memesan alamat memory
uint8_t* buffer = (uint8_t*)malloc(fileSize);
if (buffer == nullptr) {
Serial.println(F("Kesalahan mengalokasi buffer memori"));
file.close();
return;
}
// Baca data binarry ke buffer
file.read(buffer, fileSize);
file.close();
// Encode gambar dalam Base64
String encodedImage = base64::encode(buffer, fileSize);
// bersihkan buffer
free(buffer);
// Publish ke topik MQTT
if (client.publish(topic, encodedImage.c_str())) {
Serial.println(F("Gambar berhasil di publish"));
} else {
Serial.println(F("Gagal mengirim gambar"));
}
// Biar brokernya gak tewas
delay(1000);
}
}
//callback untuk membaca hasil subscribe/reply
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print(F("Pesan masuk ["));
Serial.print(topic);
Serial.print(F("] Pembacaan Meter :"));
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
}
3. Setelah sukses melakukan upload coding, kalian bisa menggunakan aplikasi MQTT seperti mqtt.fx untuk mengetest apakah data berhasil terkirim atau tidak (tentunya setelah tombol dipencet) dengan bantuan aplikasi online base64 decoding : https://base64.guru/converter/decode/image
Google colab merupakan fasilitas gratis dari google untuk meng-explore dunia cloud computing. Kali ini kita akan manfaatkan google cloud untuk mengolah data gambar kemudian melakukan komputasi AI melalui API yolo-roboflow untuk menterjemahkan data gambar meter pdam menjadi data pembacaan meter pdam. Lakukan langkah berikut untuk membuat cloud server pembaca meter pdam di google colab :
1. Buka google colab ( https://colab.research.google.com/ ) dan login menggunakan akun google kalian. Buatlah notebook baru lalu beri nama sepantasnya. Koneksikan dengan runtime dan lakukan langkah pertama memasukkan perintah intalasi library seperti berikut :
#instal dependecies dulu biar gak salah paham
!pip install paho-mqtt==1.6.0
!pip install inference
Proses mungkin agak lama dan ada warning untuk Mulai Ulang sesi, lakukan saja seperti gambar:
2. Lanjutkan dengan menambahkan coding python sesuai contoh berikut, lalu jalankan dengan panah di kiri atas:
#UTS MIKROKONTROLER 2024
#d4 teknik listrik vokasi unesa surabaya
#by: nyoman yudi kurniawan ST
import cv2
from inference_sdk import InferenceHTTPClient
from google.colab.patches import cv2_imshow
from random import randrange
import base64
import numpy as np
import time
from paho.mqtt import client as mqtt_client
# Inisialisasi broker , samakan dengan script di esp32
broker_address="mqtt.telkomiot.id"
broker_port=1883
mqtt_key = "18f8e70xxxxxxxxxx"
mqtt_token = "18f8e70xxxxxxxxx"
topic = "/tlunesa/pdam"
reply = "/tlunesa/pdam/reply"
#koneksi ke broker
def connect_mqtt() -> mqtt_client:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Berhasil Terhubung MQTT Broker!")
else:
print("Gagal koneksi mqtt, return code %d\n", rc)
def on_publish(client,userdata,result):
print("data reply terkirim ke broker")
client= mqtt_client.Client(f'unesa-client-{randrange(0,1000)}')
client.on_connect = on_connect
client.on_publish = on_publish
client.username_pw_set(mqtt_key,mqtt_token)
client.connect(broker_address,broker_port, 60 )
return client
#subscribe ke mqtt broker
def subscribe(client: mqtt_client):
client.subscribe(topic)
client.on_message = on_message
def on_message(client, userdata, message):
print("Data foto masuk...")
# Get the payload (Base64-encoded image)
base64_image = message.payload.decode('utf-8')
# Decode the Base64 string to binary image data
image_data = base64.b64decode(base64_image)
# Convert the binary data to a NumPy array
np_arr = np.frombuffer(image_data, np.uint8)
# Decode the image from the NumPy array
image = cv2.imdecode(np_arr, cv2.IMREAD_COLOR)
#terhubung dengan server Yolo / roboflow
#jika API key nya penuh, kalian bisa daftar gratis sendiri
CLIENT = InferenceHTTPClient(
api_url="https://detect.roboflow.com",
api_key="fuOy83MqlC1LtKZ25J0p"
)
#lakukan pendeteksi object dengan model yolo
results = CLIENT.infer(image, model_id="water-meter-dataset/1")
# mendapatkan prediksi object dari result
predictions = results['predictions']
# Mengecek prediksis dan mengambar boxes
for prediction in predictions:
# Get the bounding box coordinates
x = int(prediction['x'])
y = int(prediction['y'])
width = int(prediction['width'])
height = int(prediction['height'])
# Menggambar bounding box pada gambar meter
cv2.rectangle(image, (x-int(width/2), y-int(height/2)), (x + int(width/2), y + int(height/2)), (0, 0, 255), 2)
# Ambil class ID dari angka meter
class_id = prediction['class']
# Tambahkan nomer meter pada box
cv2.putText(image, class_id, (x-int(width/2), y+height+5), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 0), 2)
#tampilin gambar hasil pengolahan yolo
cv2_imshow(image)
# Sorting the predictions list by 'x'
sorted_predictions = sorted(results["predictions"], key=lambda d: d["x"])
# penggabungan class dari nomer menjadi teks
class_order_numbers = [int(item["class"]) for item in sorted_predictions]
combined_number = str("".join(map(str, class_order_numbers)))
# Jadi deh angka pembacaan meter, lalu publish kembali ke topic reply
print( f'pembacaan meter pdam:{combined_number}')
client.publish(reply, combined_number)
try:
client = connect_mqtt()
subscribe(client)
# Start the MQTT loop
client.loop_start()
time.sleep(600) #biargak kelamaan
except KeyboardInterrupt:
print("KeyboardInterrupt terdeteksi, stop mqtt loop...")
finally:
client.loop_stop()
client.disconnect()
print("MQTT loop selesai dan client terputus")
3. Hasilnya sebagai berikut , dan pada serial monitor / debug arduino ide juga terkirim angka pembacaan meter
4. Kreatifitas kalian bisa tambahkan LCD / OLED untuk menampilkan data pembacaan meter di display yang kalian pilih. Bisa juga LED berkedip jika ada reply yg masuk, sesuaikan dengan kemampuan kalian saja.
Hasil paling baik dari UTS mahasiswa saya dapat dilihat pada video berikut :
Wah ternyata yolov5 sangat cocok digunakan pada raspberry pi 3 (baca disini dulu), jadi semangat nihh berbagi kegembiraan bersama pembaca. Jadi seperti yang dulu saat saya belajar yolo v3, ujungnya adalah deteksi orang pada cctv yang bisa dibaca disini. Langsung aja kita akan buat script untuk mengetestnya melalui cctv yang ada di kota malang yang lebih ringan daripada di jogja, alamat untuk memilih titiknya di: http://cctv.malangkota.go.id/
Dan script gabungan dari beberapa tulisan sebelumnya saya bagikan seperti berikut :
import sys
import time
import json
import torch
import cv2
import os
import contextlib
from pathlib import Path
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = '/usr/lib/x86_64-linux-gnu/qt5/plugins'
def draw_boxes(frame, results):
# Get the bounding boxes, labels, and confidence scores
bboxes = results.xyxyn[0][:, :-1].numpy()
labels = results.xyxyn[0][:, -1].numpy()
confidences = results.xyxyn[0][:, -2].numpy()
# Define the COCO class label for 'person'
PERSON_LABEL = 0
# Draw boxes for persons only
for bbox, label, confidence in zip(bboxes, labels, confidences):
if label == PERSON_LABEL:
x1, y1, x2, y2 = bbox[:4]
x1 = int(x1 * frame.shape[1])
y1 = int(y1 * frame.shape[0])
x2 = int(x2 * frame.shape[1])
y2 = int(y2 * frame.shape[0])
cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv2.putText(frame, f'Orang {confidence:.2f}', (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 255, 0), 2)
def main(stream_source):
start_time = time.time()
# Load YOLOv5 model
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)
# Open the video stream
cap = cv2.VideoCapture(stream_source)
if not cap.isOpened():
print(f"Error: Could not open video stream {stream_source}")
return
# start_time = time.time()
ret, frame = cap.read()
if not ret:
print("Error: Could not read frame")
cap.release()
return
# Perform inference
results = model(frame)
# Extract bounding boxes and labels
labels = results.xyxyn[0][:, -1].numpy()
n_persons = sum(1 for label in labels if label == 0) # label '0' typically corresponds to 'person' in COCO dataset
# Calculate processing time
processing_time = time.time() - start_time
# Output results as JSON
output = {
"orang": n_persons,
"time": round(processing_time, 2)
}
print(json.dumps(output))
# Save the frame with bounding boxes as JPEG
draw_boxes(frame, results)
output_image_path = "/home/lampuku/yolov5/output.jpg"
#results.render() # This function draws bounding boxes on the frame
cv2.imwrite(output_image_path, frame)
cap.release()
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python single_detect.py <stream_source>")
else:
stream_source = sys.argv[1]
main(stream_source)
Hasilnya seperti berikut :
Waktu processing memang terlihat lama 23 detik, namun ini adalah waktu yg menunjukkan proses awal fusing layer dari yolov5. Namun jika melakukan deteksi selanjutnya cukup cepat ketika saya mencoba loop detect seperti berikut ini :
Wow dibawah 5 detik, cukup cepat deteksinya lhooo...Kalau ada yg berminat bisa menggabungkannya dengan node-red untuk membuat webui seperti gambar paling atas.
Setelah memanfaatkan kekuatan cloud computing untuk pengolahan gambar yolo v3, karena raspberry pi zero w resource nya terbatas (baca dulu disini), maka kini saatnya melakukan upgrade ke seri raspberry pi yang lebih tinggi yaitu raspi 3B yang memang support komputasi 64bit. Jadi berdasarkan bantuan chatGPT disarankan untuk mencoba yolo v5 dimana berbasis engine TORCH sehingga pas dijalankan di arm 64 bit. Jadi jangan lupa instal versi raspbbery pi melalui imagernya yaitu OS lite legacy (bullseye) 64 bit tanpa desktop. Jadi jangan sampai salah install OS karena memang sangat terbatas resource raspi 3B yang quad core CPU 64bit 1.2 Ghz dengan ram 1GB saja.
Jika sudah sukses instalasi OS maka bisa lanjut menghubungkan ke wifi dan gunakan putty untuk ssh ke ip raspi kamu dan jalankan urutan perintah berikut :
Kemudian jika instalasi selesai maka dapat menjalankan script contoh detect.py dan usahakan ukuran gambarnya tidak besar.
python detect.py --source nolkm.jpg
Hasilnya sebagai berikut, sangat memuaskan :
Hasil diatas mungkin bisa berbeda jika ada dependencies atau library yang gagal instal atau bahkan salah instal. Saya sangat mengandalkan chatGPT setiap ada kesalahan yang saya temukan dan agak lupa apa saja error yg muncul itu. Dan yang paling penting adalah menggunakan CPU untuk pengolahan gambar karena raspberry pi tidak punya GPU sekelas Nvidia untuk menjalankan torch.
Salah satu error yang saya ingat adalah, karena OS saya tanpa desktop maka runtime QT untuk menampilkan gambar akan selalu dianggap error :
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "/home/lampuku/.local/lib/python3.9/site-packages/cv2/qt/plugins" even though it was found.
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
Jadi hal ini disolusikan oleh chatGPT dengan melakukan instalasi manual "headless" sebagai berikut :
1. Install QT dan Xwindows environment. Ini mungkin tidak di perlukan jika kamu menggunakan desktop pada raspberry pi 3 kamu
2. Jangan lupa menambahkan ini jika ingin menjalankan yolov5 pada script python
export QT_QPA_PLATFORM_PLUGIN_PATH=/usr/lib/x86_64-linux-gnu/qt5/plugins # Adjust path as necessary
3. Jika diperlukan install open cv dengan headless environment
pip install opencv-python-headless
4. Lakukan pengecekan instalasi dengan script testing dibawah ini :
import torch
from PIL import Image
# Load YOLOv5 model
model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True)
# Set image path
image_path = 'path/to/your/image.jpg'# Perform inference
results = model(image_path)
# Display results
results.show() # Displays the image with bounding boxes# Optionally, save the results
results.save(save_dir='results/') # Saves results in the 'results' directory
Dan jika hasilnya muncul seperti dibawah ini berarti instalasi sudah benar
Cloud computing adalah hal yang cukup lumrah kita temui untuk membantu semua pekerjaan komputasi kita secara jarak jauh dan dimanapun. Saya sering menggunakan vps - google cloud - aws untuk membatu banyak pekerjaan saya dan kali ini saya akan gunakan google colab yang memiliki kemampuan menjalankan script python pada cloud. Permasalahannya adalah jika kita ingin mengakses google colab secara http API /Post /Get maka tidak akan ada IP public yang diberikan oleh google. Sehingga kita membutuhkan fasilitas tunneling "Gratis" bernama NGROK
Ngrok adalah alat yang memungkinkan pengembang untuk mengekspos server lokal ke internet dengan cara yang aman. Ini sangat berguna untuk pengembangan dan pengujian aplikasi web, terutama ketika perlu memeriksa bagaimana aplikasi tersebut berinteraksi dengan layanan eksternal atau perangkat lain yang tidak berada di jaringan lokal.
Silahkan daftar dengan akun google kamu dan jangan lupa dapatkan authtoken tunneling untuk praktek yang aakan saya contohkan dibawah.
Pada google colab, setelah terkoneksi dengan benar, maka dibutuhkan mengunduh file konfigurasi yolo v3 seperti berikut ini
Brikut ini adalah script python untuk mengolah gambar via flask yang mirip dengan tulisan sebelumnya disini . Jangan lupa mengambil authtoken tunnel di dashbor ngrok
from flask import Flask, request, jsonify
import cv2
import numpy as np
import time
from pyngrok import ngrok
import threading
# Replace 'your_authtoken' with your actual authtoken from ngrok dashboard
result['processing_time'] = float(processing_time) # Ensure it's a float
return jsonify(result)
# Function to run Flask server
defrun_flask():
app.run(port=5000)
# Start Flask server in a separate thread
flask_thread = threading.Thread(target=run_flask)
flask_thread.start()
# Set up ngrok tunnel
public_url = ngrok.connect(5000)
print("Flask server is running at:", public_url)
Sedangkan script pada raspberry pi zero tetap sama dengan tulisan sebelumnya. Jalankan script pada google colab sampai muncul alamat public dari ngrok tunneling.
* Serving Flask app '__main__'
* Debug mode: off
INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
INFO:werkzeug:Press CTRL+C to quit
Dikarenakan alamat publik dari tunneling ngrok berubah setiap kali script dijalankan pada google colab, maka saya sudah berhasil mengakalinya dengan memanfaatkan MQTT sebagai pengirim alamat tunnel nya dan dapat digunakan oleh banyak pengguna semisal banyak raspberry pi zero w + cam di beberapa titik lampu. Ini akan saya bahas jika ada yang tertarik dengan tulisan saya ini (by request).
Judulnya sedikit membuat ambigu, ngapain sih pake raspberry segala kalau juga digunakan PC lain untuk mengolah yolo ? Eiittsss ..saya pingin mensimulasikan raspberry pi zero w saya sebagai pengambil gambar melalui camera raspi ov5647, lalu alat saya ini akan dipasang pada banyak titik untuk medeteksi jumlah orang di bawah lampu jalan. Jadi harga raspi zero w yg cukup murah ditambah camera yg terjangkau menjadi pilihan yang cukup bagus dibanding meng-upgrade ke versi raspi 4 yang jauh harganya walau dapat mengolah gambar dengan lebih bagus (akan di bahas belakangan). Cukup 1 komputer yang processor kelas i5 sudah bisa menjadi server pengolah gambar.
Kali ini saya akan membahas membuat "server" pengolah gambar pada pc saya yang terhubung dengan wifi yang sama dengan raspi zero w yang saya gunakan sebagai simulator pengambil gambar. Untuk itu sebaiknya baca penjelasan sebelumnya untuk memahami yolo-python untuk mendeteksi objek disini:
Yolo dan python untuk deteksi objek : Videonya dilihat disini
Deteksi object pada cctv menggunakan python pada node-red : Klik disini
Yang kita gunakan sebagai server lokal adalah flask yang merupakan pilihan favorit untuk mengetest sistem server berbasis python. Flask adalah sebuah mikroframework web untuk Python yang dikembangkan oleh Armin Ronacher sebagai bagian dari proyek Pocoo. Flask sangat populer karena kesederhanaannya dan fleksibilitasnya, sehingga memungkinkan pengembang untuk membuat aplikasi web dengan cepat dan efisien.
Fitur Utama Flask
Ringan dan Fleksibel: Flask tidak memiliki lapisan abstraksi database atau validasi form bawaan, tetapi memungkinkan integrasi dengan banyak pustaka pihak ketiga.
WSGI: Flask berbasis pada Werkzeug WSGI toolkit dan Jinja2 templating engine.
Routing: Flask menyediakan sistem routing yang mudah digunakan untuk mengarahkan URL ke fungsi Python.
Templating: Dengan menggunakan Jinja2, Flask memungkinkan penggunaan template untuk memisahkan logika aplikasi dari tampilan.
Blueprints: Flask mendukung modularisasi aplikasi melalui blueprints, yang memungkinkan pengembangan aplikasi besar menjadi lebih terstruktur.
Ekstensi: Banyak ekstensi yang tersedia untuk Flask, seperti Flask-SQLAlchemy untuk ORM, Flask-WTF untuk validasi form, dan Flask-Login untuk otentikasi pengguna.
Route and View Functions: @app.route('/') mendefinisikan route untuk halaman utama. Fungsi home akan mengembalikan string "Hello, Flask!".
Dynamic Route: @app.route('/hello/<name>') mendefinisikan route dinamis yang menerima parameter name.
Form Handling: Route /form menerima metode GET dan POST. Jika metode POST, data dari form akan diambil dan pengguna akan diarahkan ke halaman hello.
Kelebihan Flask
Kesederhanaan: Mudah dipelajari dan digunakan, cocok untuk pemula maupun pengembang berpengalaman.
Fleksibilitas: Dapat dengan mudah disesuaikan sesuai kebutuhan aplikasi.
Komunitas: Komunitas yang besar dan aktif, menyediakan banyak tutorial dan dukungan.
Kelemahan Flask
Kurangnya Fitur Bawaan: Tidak memiliki banyak fitur bawaan seperti framework web lain yang lebih besar (misalnya, Django).
Pengaturan Manual: Banyak fitur yang harus diatur dan diintegrasikan secara manual.
Flask sangat cocok untuk aplikasi web kecil hingga menengah, API, dan proyek yang membutuhkan fleksibilitas tinggi.
Selanjutnya pada raspi zero w akan saya buat script python untuk mengirimkan gambar ke server saya :
import sys
import requests
import cv2
import time
def send_image(image_path, server_url):
# Read image from file
image = cv2.imread(image_path)
if image is None:
print(f"Failed to load image {image_path}")
return
# Encode image as JPEG
_, img_encoded = cv2.imencode('.jpg', image)
# Measure the start time for the network request
start_time = time.time()
# Send the image to the Flask server
response = requests.post(f"{server_url}/detect", files={"image": img_encoded.tobytes()})
# Measure the end time for the network request
end_time = time.time()
# Calculate network time
network_time = end_time - start_time
# Check and parse the response
response_data = response.json()
server_processing_time_str = response_data.get('processing_time', None)
if server_processing_time_str is not None:
try:
server_processing_time = float(server_processing_time_str)
print(f"Server processing time: {server_processing_time:.2f} seconds")
except ValueError:
print("Error: Server processing time is not a valid float.")
server_processing_time = None
else:
print("Server processing time not found in response.")
server_processing_time = None
print(response_data)
print(f"Network time: {network_time:.2f} seconds")
if __name__ == "__main__":
if len(sys.argv) != 3:
print("Usage: python myscript.py <image_path> <server_url>")
else:
image_path = sys.argv[1]
server_url = sys.argv[2]
send_image(image_path, server_url)
Sedangkan pada sisi server, seperti yang sudah saya bahas pada cara pengolahan yolo sebelumnya disini, maka script yang saya buat sebagai berikut :
from flask import Flask, request, jsonify
import cv2
import numpy as np
import time
app = Flask(__name__)
yolo = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
classes = []
with open("coco.names", "r") as file:
classes = [line.strip() for line in file.readlines()]
layer_names = yolo.getLayerNames()
output_layers = [layer_names[i - 1] for i in yolo.getUnconnectedOutLayers()]
colorRed = (0,0,255)
colorGreen = (0,255,0)
# #Loading Images
def detect_objects(img):
starting_time = time.time()
height, width, channels = img.shape
# # Detecting objects
blob = cv2.dnn.blobFromImage(img, 0.00392, (255, 255), (0, 0, 0), True, crop=False)
yolo.setInput(blob)
outputs = yolo.forward(output_layers)
class_ids = []
confidences = []
boxes = []
for output in outputs:
for detection in output:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.4 and ( class_id == 0 or class_id == 2 or class_id == 3 ): # 0 = orang, 2 = motor , 3 = mobil
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
org = 0
mob = 0
mot = 0
for i in range(len(boxes)):
if i in indexes:
if class_ids[i] == 0:
org = org + 1
label = 'orang : ' + repr(org)
elif class_ids[i] == 2:
mob = mob + 1
label = 'mobil : ' + repr(mob)
elif class_ids[i] == 3:
mot = mot + 1
label = 'motor : ' + repr(mot)
x, y, w, h = boxes[i]
#label = str(classes[class_ids[i]]) + ', x=' +repr(x) + ',y=' +repr(y)
#label = str(classes[class_ids[i]]) + '- no: ' + repr(i+1)
cv2.rectangle(img, (x, y), (x + w, y + h), colorGreen, 3)
cv2.putText(img, label, (x, y -5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255) )
print("{")
print(f"\"Jumlah Orang\": {org},")
print(f"\"Jumlah Mobil\": {mob},")
print(f"\"Jumlah Motor\": {mot},")
elapsed_time = time.time() - starting_time
print("\"processing time\":" + repr(elapsed_time) )
print("}")
cv2.imwrite("output.jpg",img)
return {"Orang": org, "Mobil": mob, "Motor": mot, "time": elapsed_time }
@app.route("/detect", methods=["POST"])
def detect():
file = request.files["image"]
npimg = np.fromfile(file, np.uint8)
image = cv2.imdecode(npimg, cv2.IMREAD_COLOR)
result = detect_objects(image)
return jsonify(result)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000)
Dan hasilnya sebagai berikut :
Nah...bisa dan cepat bukan ? Jadi file gambar yang saya tampilkan output.jpg diatas merupakan hasil pengolahan gambar pada pc saya sebagai sever dan kemudian dikembalikan ke raspberry pi zero w sebagai json hasil perhitungan jumlah orang. Jadi cukup 1 server bisa melayani banyak alat pengambil gambar yang sama menggunakan raspberry pi zero w yang harganya lumayan murah.
Bagaimana jika PC nya tidak tersedia dan hanya ada jaringan wifi dilokasi ? Kita kan bahas selanjutnya memanfaatkan komputasi cloud dari google lanjut disini.
Wah gak kerasa sudah lama sekali saya tidak menyentuh raspberry pi zero saya hampir 4 tahun setelahnya baru sempat menyentuhnya lagi. Jadi pembaca yang ingin mengetahui bagaimana mengenal seri raspberry pi paling minim dapat kembali ke : https://www.aisi555.com/2020/07/solder-pi-bermain-dengan-gpio-dan.html dan bisa mengenal dasar-dasar raspberry pi dalam konteks GPIO dan padanannya ketika dimanfaatkan layaknya mikrokontroller.
Kali ini saya yang sedang berkutat dengan dunia image processing berbasis yolo ingin menge-test apakah dengan processor dual core 1Ghz dan ram 512 Kb dapat menjalankan yolo ? Dari beberapa literatur di internet (dan chatgpt tentunya) kita akan menggunakan opencv dan yolo v3 tiny. Tidak lupa saya memformat ulang raspberry pi zero w saya dengan OS terbaru mengunakan software windows - Raspberry Pi Imager dan saya pilihkan Os lite-32 tanpa desktop agar menghemat space. Jadi saya mengandalkan putty untuk meng-edit semua raspberry saya.
Raspberry Pi Zero W, dengan kekuatan pemrosesan dan memorinya yang terbatas, paling cocok untuk versi ringan YOLO (You Only Look Once) yang dioptimalkan untuk lingkungan dengan sumber daya rendah. Model YOLO umumnya intensif secara komputasi, jadi untuk Raspberry Pi Zero W, Anda harus fokus pada versi yang lebih ringkas yang dirancang untuk efisiensi. Berikut adalah versi yang lebih mungkin kompatibel:
YOLOv3 Tiny: Ini adalah versi sederhana dari YOLOv3 yang dirancang agar lebih cepat dan memerlukan lebih sedikit daya komputasi. Ini adalah pilihan bagus untuk perangkat dengan sumber daya terbatas.
YOLOv4 Tiny: Mirip dengan YOLOv3 Tiny, ini adalah versi YOLOv4 yang dioptimalkan dan dirancang untuk berjalan pada perangkat dengan kemampuan komputasi lebih rendah.
YOLO-Nano: Ini adalah model ringan lainnya yang bertujuan untuk memberikan keseimbangan yang baik antara kinerja dan penggunaan sumber daya.
Tiny YOLOv2: Versi ini juga terkenal dengan efisiensinya dan dapat menjadi pilihan yang cocok untuk Raspberry Pi Zero W.
Instalasi dan Pengaturan:
Berikut panduan umum tentang cara menjalankan salah satu model ini di Raspberry Pi Zero W Anda:
1. Instal dependencies:
Pastikan Anda telah menginstal Python (disarankan Python 3).
Instal perpustakaan yang diperlukan seperti NumPy, OpenCV, dan TensorFlow Lite atau PyTorch bergantung pada model dan kerangka kerja yang Anda pilih.
Unduh file konfigurasi Tiny YOLO dan file bobot. Misalnya, Anda bisa mendapatkan bobot dan konfigurasi YOLOv3 Tiny dari situs web resmi YOLO atau repositori GitHub.
3.Jika menggunakan TensorFlow Lite, konversikan model ke format TensorFlow Lite, yang lebih dioptimalkan untuk perangkat tersemat.
pip3 install tensorflow
Lanjutkan instalasi converter tensorflow lite, jika ini terasa susah skip saja karena saya tidak menggunakannya
4.Jalankan Modelnya:
Tulis skrip untuk memuat model dan menjalankan inferensi. Berikut ini contoh sederhana menggunakan OpenCV dan model YOLOv3 Tiny:
import cv2
import numpy as np
net = cv2.dnn.readNet("yolov3-tiny.weights", "yolov3-tiny.cfg")
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
def load_image(img_path):
image = cv2.imread(img_path)
blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
return image
def get_outputs():
layer_names = net.getLayerNames()
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
return output_layers
def detect_objects(image):
detections = net.forward(get_outputs())
for detection in detections:
for obj in detection:
scores = obj[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
center_x = int(obj[0] * image.shape[1])
center_y = int(obj[1] * image.shape[0])
w = int(obj[2] * image.shape[1])
h = int(obj[3] * image.shape[0])
x = int(center_x - w / 2)
y = int(center_y - h / 2)
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
return image
image = load_image("your_image.jpg")
output_image = detect_objects(image)
#cv2.imshow("Output", output_image)
#cv2.waitKey(0)
#cv2.destroyAllWindows()
Hasilnya ?
Gagal bokk...ternyata hasil nya sangat tergantung pada kecerahan gambar dan sangat lambat jika menggunakan gamabr yang lebih besar resolusinya.
wah saya padahal punya proyek untuk mengatur nyala lampu dengan perbandingan jumlah orang dibawah lampu... lalu bagaimana ? Pada bagian selanjutnya saya akan memanfaatkan "komputer lain " yang akan dipinjam kekuatan komputasinya. Apakah google cloud bisa? Silahkan lanjut baca disini..