ESP32 Cam Deteksi Object / Benda
Pada kesempatan kali ini saya akan menjelaskan mengenai bagaimana cara membuat sebuah ESP32 Cam dapat mendeteksi object yang berada di epannya. untuk contoh pada video kali ini objectnya yaitu bola, lampu dan spidol yang mana masihng2 memiliki size yang berbeda. untuk detailnya berikut kodingnya.
1. Interface
2. Program ESP32 Cam
#include "esp_camera.h"
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
//================ WIFI =================
const char* ssid = "ESP32-OBJECT";
const char* password = "12345678";
WebServer server(80);
Preferences memory;
//================ AI THINKER CAMERA =================
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
//================ DATA OBJECT =================
struct ObjectData
{
bool aktif;
float area;
float ratio;
float red;
float green;
float blue;
};
ObjectData data[4];
String namaObject[4]=
{
"BOLA",
"SPIDOL",
"LAMPU",
"UNKNOWN"
};
String hasil="BELUM ADA";
float areaNow=0;
float ratioNow=0;
float rNow=0;
float gNow=0;
float bNow=0;
int confidence=0;
unsigned long timer=0;
//================ SIMPAN =================
void saveData(int id)
{
memory.begin("object",false);
String key="d"+String(id);
memory.putBytes(
key.c_str(),
&data[id],
sizeof(ObjectData)
);
memory.end();
}
//================ LOAD =================
void loadData()
{
memory.begin("object",true);
for(int i=0;i<4;i++)
{
String key="d"+String(i);
memory.getBytes(
key.c_str(),
&data[i],
sizeof(ObjectData)
);
}
memory.end();
}
//================ RESET =================
void resetData()
{
for(int i=0;i<4;i++)
{
data[i].aktif=false;
}
memory.begin("object",false);
memory.clear();
memory.end();
}
//================ BACA OBJECT =================
void bacaObject()
{
camera_fb_t *fb =
esp_camera_fb_get();
if(!fb)
return;
int total=0;
long R=0;
long G=0;
long B=0;
int minX=320;
int maxX=0;
int minY=240;
int maxY=0;
for(int y=0;y<fb->height;y+=2)
{
for(int x=0;x<fb->width;x+=2)
{
int index=(y*fb->width+x)*2;
uint16_t pixel =
(fb->buf[index]<<8)
|
fb->buf[index+1];
int r =
((pixel>>11)&31)*255/31;
int g =
((pixel>>5)&63)*255/63;
int b =
(pixel&31)*255/31;
// object beda warna dari background
if(
abs(r-g)>20 ||
abs(g-b)>20 ||
abs(r-b)>20
)
{
total++;
R+=r;
G+=g;
B+=b;
if(x<minX) minX=x;
if(x>maxX) maxX=x;
if(y<minY) minY=y;
if(y>maxY) maxY=y;
}
}
}
if(total>20)
{
areaNow=total;
rNow=R/total;
gNow=G/total;
bNow=B/total;
float w=maxX-minX;
float h=maxY-minY;
if(h>0)
ratioNow=w/h;
klasifikasi();
}
else
{
hasil="TIDAK ADA";
confidence=0;
}
esp_camera_fb_return(fb);
}
//================ KLASIFIKASI =================
void klasifikasi()
{
float best=99999;
int index=-1;
for(int i=0;i<4;i++)
{
if(!data[i].aktif)
continue;
float nilai=0;
nilai += abs(areaNow-data[i].area)/100;
nilai += abs(ratioNow-data[i].ratio)*20;
nilai += abs(rNow-data[i].red)/20;
nilai += abs(gNow-data[i].green)/20;
nilai += abs(bNow-data[i].blue)/20;
if(nilai<best)
{
best=nilai;
index=i;
}
}
if(index>=0)
{
confidence=
100-(best*5);
if(confidence<0)
confidence=0;
if(confidence>100)
confidence=100;
hasil=namaObject[index];
}
else
{
hasil="UNKNOWN";
confidence=0;
}
}
//================ KALIBRASI =================
void kalibrasi()
{
if(!server.hasArg("objek"))
return;
String obj=
server.arg("objek");
int id=-1;
if(obj=="BOLA") id=0;
if(obj=="SPIDOL") id=1;
if(obj=="LAMPU") id=2;
if(obj=="UNKNOWN") id=3;
if(id>=0)
{
data[id].aktif=true;
data[id].area=areaNow;
data[id].ratio=ratioNow;
data[id].red=rNow;
data[id].green=gNow;
data[id].blue=bNow;
saveData(id);
}
server.send(
200,
"text/plain",
"KALIBRASI OK "+obj
);
}
//================ DATA JSON =================
void dataJSON()
{
String json="{";
json+="\"hasil\":\""+hasil+"\",";
json+="\"confidence\":"+String(confidence)+",";
json+="\"area\":"+String(areaNow);
json+="}";
server.send(
200,
"application/json",
json
);
}
//================ WEB =================
void home()
{
String html=R"rawliteral(
<html>
<body style="text-align:center;font-family:Arial">
<h2>
ESP32 OBJECT DETECTOR
</h2>
<h1 id="hasil">
-
</h1>
<h3>
Confidence:
<span id="conf">
0
</span>%
</h3>
<h3>
Area:
<span id="area">
0
</span>
</h3>
<hr>
<h3>
KALIBRASI
</h3>
<button onclick="kal('BOLA')">
⚽ BOLA
</button>
<button onclick="kal('SPIDOL')">
🖊️ SPIDOL
</button>
<button onclick="kal('LAMPU')">
💡 LAMPU
</button>
<button onclick="kal('UNKNOWN')">
UNKNOWN
</button>
<br><br>
<button onclick="reset()">
RESET
</button>
<script>
setInterval(()=>{
fetch('/data')
.then(r=>r.json())
.then(d=>{
hasil.innerHTML=d.hasil;
conf.innerHTML=d.confidence;
area.innerHTML=d.area;
});
},500);
function kal(x)
{
fetch('/kal?objek='+x);
}
function reset()
{
fetch('/reset');
}
</script>
</body>
</html>
)rawliteral";
server.send(
200,
"text/html",
html
);
}
//================ SETUP =================
void setup()
{
Serial.begin(115200);
camera_config_t config;
config.ledc_channel=LEDC_CHANNEL_0;
config.ledc_timer=LEDC_TIMER_0;
config.pin_d0=Y2_GPIO_NUM;
config.pin_d1=Y3_GPIO_NUM;
config.pin_d2=Y4_GPIO_NUM;
config.pin_d3=Y5_GPIO_NUM;
config.pin_d4=Y6_GPIO_NUM;
config.pin_d5=Y7_GPIO_NUM;
config.pin_d6=Y8_GPIO_NUM;
config.pin_d7=Y9_GPIO_NUM;
config.pin_xclk=XCLK_GPIO_NUM;
config.pin_pclk=PCLK_GPIO_NUM;
config.pin_vsync=VSYNC_GPIO_NUM;
config.pin_href=HREF_GPIO_NUM;
config.pin_sscb_sda=SIOD_GPIO_NUM;
config.pin_sscb_scl=SIOC_GPIO_NUM;
config.pin_pwdn=PWDN_GPIO_NUM;
config.pin_reset=RESET_GPIO_NUM;
config.xclk_freq_hz=20000000;
config.pixel_format=PIXFORMAT_RGB565;
config.frame_size=FRAMESIZE_QQVGA;
config.fb_count=1;
esp_camera_init(&config);
loadData();
WiFi.mode(WIFI_AP);
WiFi.softAP(
ssid,
password
);
Serial.println(
WiFi.softAPIP()
);
server.on("/",home);
server.on("/data",dataJSON);
server.on("/kal",kalibrasi);
server.on("/reset",[](){
resetData();
server.send(
200,
"text/plain",
"RESET"
);
});
server.begin();
}
//================ LOOP =================
void loop()
{
server.handleClient();
if(millis()-timer>700)
{
bacaObject();
timer=millis();
}
}
#include <WiFi.h>
#include <WebServer.h>
#include <Preferences.h>
//================ WIFI =================
const char* ssid = "ESP32-OBJECT";
const char* password = "12345678";
WebServer server(80);
Preferences memory;
//================ AI THINKER CAMERA =================
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
//================ DATA OBJECT =================
struct ObjectData
{
bool aktif;
float area;
float ratio;
float red;
float green;
float blue;
};
ObjectData data[4];
String namaObject[4]=
{
"BOLA",
"SPIDOL",
"LAMPU",
"UNKNOWN"
};
String hasil="BELUM ADA";
float areaNow=0;
float ratioNow=0;
float rNow=0;
float gNow=0;
float bNow=0;
int confidence=0;
unsigned long timer=0;
//================ SIMPAN =================
void saveData(int id)
{
memory.begin("object",false);
String key="d"+String(id);
memory.putBytes(
key.c_str(),
&data[id],
sizeof(ObjectData)
);
memory.end();
}
//================ LOAD =================
void loadData()
{
memory.begin("object",true);
for(int i=0;i<4;i++)
{
String key="d"+String(i);
memory.getBytes(
key.c_str(),
&data[i],
sizeof(ObjectData)
);
}
memory.end();
}
//================ RESET =================
void resetData()
{
for(int i=0;i<4;i++)
{
data[i].aktif=false;
}
memory.begin("object",false);
memory.clear();
memory.end();
}
//================ BACA OBJECT =================
void bacaObject()
{
camera_fb_t *fb =
esp_camera_fb_get();
if(!fb)
return;
int total=0;
long R=0;
long G=0;
long B=0;
int minX=320;
int maxX=0;
int minY=240;
int maxY=0;
for(int y=0;y<fb->height;y+=2)
{
for(int x=0;x<fb->width;x+=2)
{
int index=(y*fb->width+x)*2;
uint16_t pixel =
(fb->buf[index]<<8)
|
fb->buf[index+1];
int r =
((pixel>>11)&31)*255/31;
int g =
((pixel>>5)&63)*255/63;
int b =
(pixel&31)*255/31;
// object beda warna dari background
if(
abs(r-g)>20 ||
abs(g-b)>20 ||
abs(r-b)>20
)
{
total++;
R+=r;
G+=g;
B+=b;
if(x<minX) minX=x;
if(x>maxX) maxX=x;
if(y<minY) minY=y;
if(y>maxY) maxY=y;
}
}
}
if(total>20)
{
areaNow=total;
rNow=R/total;
gNow=G/total;
bNow=B/total;
float w=maxX-minX;
float h=maxY-minY;
if(h>0)
ratioNow=w/h;
klasifikasi();
}
else
{
hasil="TIDAK ADA";
confidence=0;
}
esp_camera_fb_return(fb);
}
//================ KLASIFIKASI =================
void klasifikasi()
{
float best=99999;
int index=-1;
for(int i=0;i<4;i++)
{
if(!data[i].aktif)
continue;
float nilai=0;
nilai += abs(areaNow-data[i].area)/100;
nilai += abs(ratioNow-data[i].ratio)*20;
nilai += abs(rNow-data[i].red)/20;
nilai += abs(gNow-data[i].green)/20;
nilai += abs(bNow-data[i].blue)/20;
if(nilai<best)
{
best=nilai;
index=i;
}
}
if(index>=0)
{
confidence=
100-(best*5);
if(confidence<0)
confidence=0;
if(confidence>100)
confidence=100;
hasil=namaObject[index];
}
else
{
hasil="UNKNOWN";
confidence=0;
}
}
//================ KALIBRASI =================
void kalibrasi()
{
if(!server.hasArg("objek"))
return;
String obj=
server.arg("objek");
int id=-1;
if(obj=="BOLA") id=0;
if(obj=="SPIDOL") id=1;
if(obj=="LAMPU") id=2;
if(obj=="UNKNOWN") id=3;
if(id>=0)
{
data[id].aktif=true;
data[id].area=areaNow;
data[id].ratio=ratioNow;
data[id].red=rNow;
data[id].green=gNow;
data[id].blue=bNow;
saveData(id);
}
server.send(
200,
"text/plain",
"KALIBRASI OK "+obj
);
}
//================ DATA JSON =================
void dataJSON()
{
String json="{";
json+="\"hasil\":\""+hasil+"\",";
json+="\"confidence\":"+String(confidence)+",";
json+="\"area\":"+String(areaNow);
json+="}";
server.send(
200,
"application/json",
json
);
}
//================ WEB =================
void home()
{
String html=R"rawliteral(
<html>
<body style="text-align:center;font-family:Arial">
<h2>
ESP32 OBJECT DETECTOR
</h2>
<h1 id="hasil">
-
</h1>
<h3>
Confidence:
<span id="conf">
0
</span>%
</h3>
<h3>
Area:
<span id="area">
0
</span>
</h3>
<hr>
<h3>
KALIBRASI
</h3>
<button onclick="kal('BOLA')">
⚽ BOLA
</button>
<button onclick="kal('SPIDOL')">
🖊️ SPIDOL
</button>
<button onclick="kal('LAMPU')">
💡 LAMPU
</button>
<button onclick="kal('UNKNOWN')">
UNKNOWN
</button>
<br><br>
<button onclick="reset()">
RESET
</button>
<script>
setInterval(()=>{
fetch('/data')
.then(r=>r.json())
.then(d=>{
hasil.innerHTML=d.hasil;
conf.innerHTML=d.confidence;
area.innerHTML=d.area;
});
},500);
function kal(x)
{
fetch('/kal?objek='+x);
}
function reset()
{
fetch('/reset');
}
</script>
</body>
</html>
)rawliteral";
server.send(
200,
"text/html",
html
);
}
//================ SETUP =================
void setup()
{
Serial.begin(115200);
camera_config_t config;
config.ledc_channel=LEDC_CHANNEL_0;
config.ledc_timer=LEDC_TIMER_0;
config.pin_d0=Y2_GPIO_NUM;
config.pin_d1=Y3_GPIO_NUM;
config.pin_d2=Y4_GPIO_NUM;
config.pin_d3=Y5_GPIO_NUM;
config.pin_d4=Y6_GPIO_NUM;
config.pin_d5=Y7_GPIO_NUM;
config.pin_d6=Y8_GPIO_NUM;
config.pin_d7=Y9_GPIO_NUM;
config.pin_xclk=XCLK_GPIO_NUM;
config.pin_pclk=PCLK_GPIO_NUM;
config.pin_vsync=VSYNC_GPIO_NUM;
config.pin_href=HREF_GPIO_NUM;
config.pin_sscb_sda=SIOD_GPIO_NUM;
config.pin_sscb_scl=SIOC_GPIO_NUM;
config.pin_pwdn=PWDN_GPIO_NUM;
config.pin_reset=RESET_GPIO_NUM;
config.xclk_freq_hz=20000000;
config.pixel_format=PIXFORMAT_RGB565;
config.frame_size=FRAMESIZE_QQVGA;
config.fb_count=1;
esp_camera_init(&config);
loadData();
WiFi.mode(WIFI_AP);
WiFi.softAP(
ssid,
password
);
Serial.println(
WiFi.softAPIP()
);
server.on("/",home);
server.on("/data",dataJSON);
server.on("/kal",kalibrasi);
server.on("/reset",[](){
resetData();
server.send(
200,
"text/plain",
"RESET"
);
});
server.begin();
}
//================ LOOP =================
void loop()
{
server.handleClient();
if(millis()-timer>700)
{
bacaObject();
timer=millis();
}
}
3. VIDEO HASILNYA


No comments:
Post a Comment