India Automation Challenge 2021
OR
The coronavirus disease 2019 (COVID-19) pandemic is currently perceived as one of the greatest global threats to public health and well-being and global economic and social stability. COVID-19 spreads mainly from person to person through respiratory droplets. Respiratory droplets travel into the air when you cough, sneeze, talk, shout or sing. These droplets can then land in the mouths or noses of people who are near you or they may breathe these droplets in. Masks are a simple barrier to help prevent your respiratory droplets from reaching others. Studies show that masks reduce the spray of droplets when worn over the nose and mouth.
ESP8266, ESP32-CAM
Arduino IDE, Teachable machine
Developed Face mask detection image classification model using Teachable machine. The link of the model is used in our code. ESP8266 is used for programming ESP32-CAM. Here we can also add a Relay module or Servo motor for Gate.
ESP8266 is used for programming ESP32-CAM.
const char* ssid = "nbsuthar"; //your network SSID
const char* password = "nbsuthar"; //your network password
const char* apssid = "ESP32-CAM";
const char* appassword = "12345678";
#include <WiFi.h>
#include <esp32-hal-ledc.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
#include "esp_http_server.h"
#include "esp_timer.h"
#include "img_converters.h"
#include "fb_gfx.h"
#include "fd_forward.h"
String Feedback="";
String Command="";
String cmd="";
String P1="";
String P2="";
String P3="";
String P4="";
String P5="";
String P6="";
String P7="";
String P8="";
String P9="";
byte ReceiveState=0;
byte cmdState=1;
byte strState=1;
byte questionstate=0;
byte equalstate=0;
byte semicolonstate=0;
typedef struct {
size_t size;
size_t index;
size_t count;
int sum;
int * values;
} ra_filter_t;
typedef struct {
httpd_req_t *req;
size_t len;
} jpg_chunking_t;
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
static ra_filter_t ra_filter;
httpd_handle_t stream_httpd = NULL;
httpd_handle_t camera_httpd = NULL;
static ra_filter_t * ra_filter_init(ra_filter_t * filter, size_t sample_size){
memset(filter, 0, sizeof(ra_filter_t));
filter->values = (int *)malloc(sample_size * sizeof(int));
if(!filter->values){
return NULL;
}
memset(filter->values, 0, sample_size * sizeof(int));
filter->size = sample_size;
return filter;
}
static int ra_filter_run(ra_filter_t * filter, int value){
if(!filter->values){
return value;
}
filter->sum -= filter->values[filter->index];
filter->values[filter->index] = value;
filter->sum += filter->values[filter->index];
filter->index++;
filter->index = filter->index % filter->size;
if (filter->count < filter->size) {
filter->count++;
}
return filter->sum / filter->count;
}
#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
void setup() {
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
Serial.begin(115200);
Serial.setDebugOutput(true);
Serial.println();
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_JPEG;
if(psramFound()){
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10; //0-63 lower number means higher quality
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12; //0-63 lower number means higher quality
config.fb_count = 1;
}
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
delay(1000);
ESP.restart();
}
sensor_t * s = esp_camera_sensor_get();
s->set_framesize(s, FRAMESIZE_QVGA); //UXGA|SXGA|XGA|SVGA|VGA|CIF|QVGA|HQVGA|QQVGA
ledcAttachPin(4, 4);
ledcSetup(4, 5000, 8);
WiFi.mode(WIFI_AP_STA);
//WiFi.config(IPAddress(192, 168, 201, 100), IPAddress(192, 168, 201, 2), IPAddress(255, 255, 255, 0));
WiFi.begin(ssid, password);
delay(1000);
Serial.println("");
Serial.print("Connecting to ");
Serial.println(ssid);
long int StartTime=millis();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
if ((StartTime+10000) < millis()) break;
}
if (WiFi.status() == WL_CONNECTED) {
WiFi.softAP((WiFi.localIP().toString()+"_"+(String)apssid).c_str(), appassword);
Serial.println("");
Serial.println("STAIP address: ");
Serial.println(WiFi.localIP());
for (int i=0;i<5;i++) {
ledcWrite(4,10);
delay(200);
ledcWrite(4,0);
delay(200);
}
}
else {
WiFi.softAP((WiFi.softAPIP().toString()+"_"+(String)apssid).c_str(), appassword);
for (int i=0;i<2;i++) {
ledcWrite(4,10);
delay(1000);
ledcWrite(4,0);
delay(1000);
}
}
//WiFi.softAPConfig(IPAddress(192, 168, 4, 1), IPAddress(192, 168, 4, 1), IPAddress(255, 255, 255, 0));
Serial.println("");
Serial.println("APIP address: ");
Serial.println(WiFi.softAPIP());
startCameraServer();
pinMode(4, OUTPUT);
pinMode(33,OUTPUT);
digitalWrite(4, LOW);
pinMode(16,OUTPUT);
}
void loop() {
if(P1=="helmet"){
Serial.println("wah...");
}
}
static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){
jpg_chunking_t *j = (jpg_chunking_t *)arg;
if(!index){
j->len = 0;
}
if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){
return 0;
}
j->len += len;
return len;
}
static esp_err_t capture_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
int64_t fr_start = esp_timer_get_time();
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
size_t out_len, out_width, out_height;
uint8_t * out_buf;
bool s;
if(fb->width > 400){
size_t fb_len = 0;
if(fb->format == PIXFORMAT_JPEG){
fb_len = fb->len;
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
esp_camera_fb_return(fb);
int64_t fr_end = esp_timer_get_time();
Serial.printf("JPG: %uB %ums\n", (uint32_t)(fb_len), (uint32_t)((fr_end - fr_start)/1000));
return res;
}
dl_matrix3du_t *image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix) {
esp_camera_fb_return(fb);
Serial.println("dl_matrix3du_alloc failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
out_buf = image_matrix->item;
out_len = fb->width * fb->height * 3;
out_width = fb->width;
out_height = fb->height;
s = fmt2rgb888(fb->buf, fb->len, fb->format, out_buf);
esp_camera_fb_return(fb);
if(!s){
dl_matrix3du_free(image_matrix);
Serial.println("to rgb888 failed");
httpd_resp_send_500(req);
return ESP_FAIL;
}
jpg_chunking_t jchunk = {req, 0};
s = fmt2jpg_cb(out_buf, out_len, out_width, out_height, PIXFORMAT_RGB888, 90, jpg_encode_stream, &jchunk);
dl_matrix3du_free(image_matrix);
if(!s){
Serial.println("JPEG compression failed");
return ESP_FAIL;
}
int64_t fr_end = esp_timer_get_time();
return res;
}
static esp_err_t stream_handler(httpd_req_t *req){
camera_fb_t * fb = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t * _jpg_buf = NULL;
char * part_buf[64];
dl_matrix3du_t *image_matrix = NULL;
int64_t fr_start = 0;
int64_t fr_ready = 0;
static int64_t last_frame = 0;
if(!last_frame) {
last_frame = esp_timer_get_time();
}
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if(res != ESP_OK){
return res;
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
while(true){
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
res = ESP_FAIL;
} else {
fr_start = esp_timer_get_time();
fr_ready = fr_start;
if(fb->width > 400){
if(fb->format != PIXFORMAT_JPEG){
bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
esp_camera_fb_return(fb);
fb = NULL;
if(!jpeg_converted){
Serial.println("JPEG compression failed");
res = ESP_FAIL;
}
} else {
_jpg_buf_len = fb->len;
_jpg_buf = fb->buf;
}
} else {
image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
if (!image_matrix) {
Serial.println("dl_matrix3du_alloc failed");
res = ESP_FAIL;
} else {
if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)){
Serial.println("fmt2rgb888 failed");
res = ESP_FAIL;
} else {
fr_ready = esp_timer_get_time();
if (fb->format != PIXFORMAT_JPEG){
if(!fmt2jpg(image_matrix->item, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len)){
Serial.println("fmt2jpg failed");
res = ESP_FAIL;
}
esp_camera_fb_return(fb);
fb = NULL;
} else {
_jpg_buf = fb->buf;
_jpg_buf_len = fb->len;
}
}
dl_matrix3du_free(image_matrix);
}
}
}
if(res == ESP_OK){
size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if(res == ESP_OK){
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
}
if(fb){
esp_camera_fb_return(fb);
fb = NULL;
_jpg_buf = NULL;
} else if(_jpg_buf){
free(_jpg_buf);
_jpg_buf = NULL;
}
if(res != ESP_OK){
break;
}
int64_t fr_end = esp_timer_get_time();
int64_t ready_time = (fr_ready - fr_start)/1000;
int64_t frame_time = fr_end - last_frame;
last_frame = fr_end;
frame_time /= 1000;
uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time);
Serial.printf("MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps), %u+%u+%u+%u=%u %s%d\n",
(uint32_t)(_jpg_buf_len),
(uint32_t)frame_time, 1000.0 / (uint32_t)frame_time,
avg_frame_time, 1000.0 / avg_frame_time
);
}
last_frame = 0;
return res;
}
static esp_err_t cmd_handler(httpd_req_t *req){
char* buf;
size_t buf_len;
char variable[128] = {0,};
char value[128] = {0,};
String myCmd = "";
buf_len = httpd_req_get_url_query_len(req) + 1;
if (buf_len > 1) {
buf = (char*)malloc(buf_len);
if(!buf){
httpd_resp_send_500(req);
return ESP_FAIL;
}
if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
if (httpd_query_key_value(buf, "var", variable, sizeof(variable)) == ESP_OK &&
httpd_query_key_value(buf, "val", value, sizeof(value)) == ESP_OK) {
}
else {
myCmd = String(buf);
}
}
} else {
httpd_resp_send_404(req);
return ESP_FAIL;
}
Feedback="";Command="";cmd="";P1="";P2="";P3="";P4="";P5="";P6="";P7="";P8="";P9="";
ReceiveState=0,cmdState=1,strState=1,questionstate=0,equalstate=0,semicolonstate=0;
if (myCmd.length()>0) {
myCmd = "?"+myCmd;
for (int i=0;i<myCmd.length();i++) {
getCommand(char(myCmd.charAt(i)));
}
}
if (cmd.length()>0) {
Serial.println("");
//Serial.println("Command: "+Command);
Serial.println("cmd= "+cmd+" ,P1= "+P1+" ,P2= "+P2+" ,P3= "+P3+" ,P4= "+P4+" ,P5= "+P5+" ,P6= "+P6+" ,P7= "+P7+" ,P8= "+P8+" ,P9= "+P9);
Serial.println("");
if (cmd=="your cmd") {
// You can do anything
// Feedback="<font color=\"red\">Hello World</font>";
}
else if (cmd=="ip") {
Feedback="AP IP: "+WiFi.softAPIP().toString();
Feedback+="<br>";
Feedback+="STA IP: "+WiFi.localIP().toString();
}
else if (cmd=="mac") {
Feedback="STA MAC: "+WiFi.macAddress();
}
else if (cmd=="restart") {
ESP.restart();
}
else if (cmd=="digitalwrite") {
ledcDetachPin(P1.toInt());
pinMode(P1.toInt(), OUTPUT);
digitalWrite(P1.toInt(), P2.toInt());
}
else if (cmd=="digitalread") {
Feedback=String(digitalRead(P1.toInt()));
}
else if (cmd=="analogwrite") {
if (P1=="4") {
ledcAttachPin(4, 4);
ledcSetup(4, 5000, 8);
ledcWrite(4,P2.toInt());
}
else {
ledcAttachPin(P1.toInt(), 9);
ledcSetup(9, 5000, 8);
ledcWrite(9,P2.toInt());
}
}
else if (cmd=="analogread") {
Feedback=String(analogRead(P1.toInt()));
}
else if (cmd=="touchread") {
Feedback=String(touchRead(P1.toInt()));
}
else if (cmd=="flash") {
ledcAttachPin(4, 4);
ledcSetup(4, 5000, 8);
int val = P1.toInt();
ledcWrite(4,val);
}
else if (cmd=="serial") {
if (P1!=""&P1!="stop") Serial.println(P1);
if (P2!=""&P2!="stop") Serial.println(P2);
Serial.println();
}
else {
Feedback="Command is not defined";
}
if (Feedback=="") Feedback=Command;
const char *resp = Feedback.c_str();
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, resp, strlen(resp));
}
else {
int val = atoi(value);
sensor_t * s = esp_camera_sensor_get();
int res = 0;
if(!strcmp(variable, "framesize")) {
if(s->pixformat == PIXFORMAT_JPEG)
res = s->set_framesize(s, (framesize_t)val);
}
else if(!strcmp(variable, "quality")) res = s->set_quality(s, val);
else if(!strcmp(variable, "contrast")) res = s->set_contrast(s, val);
else if(!strcmp(variable, "brightness")) res = s->set_brightness(s, val);
else if(!strcmp(variable, "hmirror")) res = s->set_hmirror(s, val);
else if(!strcmp(variable, "vflip")) res = s->set_vflip(s, val);
else if(!strcmp(variable, "flash")) {
ledcAttachPin(4, 4);
ledcSetup(4, 5000, 8);
ledcWrite(4,val);
}
else {
res = -1;
}
if(res){
return httpd_resp_send_500(req);
}
if (buf) {
Feedback = String(buf);
const char *resp = Feedback.c_str();
httpd_resp_set_type(req, "text/html");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, resp, strlen(resp));
}
else {
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, NULL, 0);
}
}
}
static esp_err_t status_handler(httpd_req_t *req){
static char json_response[1024];
sensor_t * s = esp_camera_sensor_get();
char * p = json_response;
*p++ = '{';
p+=sprintf(p, "\"flash\":%d,", 0);
p+=sprintf(p, "\"framesize\":%u,", s->status.framesize);
p+=sprintf(p, "\"quality\":%u,", s->status.quality);
p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);
p+=sprintf(p, "\"contrast\":%d,", s->status.contrast);
p+=sprintf(p, "\"hmirror\":%u,", s->status.hmirror);
p+=sprintf(p, "\"vflip\":%u", s->status.vflip);
*p++ = '}';
*p++ = 0;
httpd_resp_set_type(req, "application/json");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
return httpd_resp_send(req, json_response, strlen(json_response));
}
static const char PROGMEM INDEX_HTML[] = R"rawliteral(<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta http-equiv="Access-Control-Allow-Headers" content="Origin, X-Requested-With, Content-Type, Accept">
<meta http-equiv="Access-Control-Allow-Methods" content="GET,POST,PUT,DELETE,OPTIONS">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<title>Teachable Machine-Nitesh Suthar</title>
<style>
body{font-family:Arial,Helvetica,sans-serif;background:#181818;color:#EFEFEF;font-size:16px}h2{font-size:18px}section.main{display:flex}#menu,section.main{flex-direction:column}#menu{display:flex;flex-wrap:nowrap;min-width:340px;background:#363636;padding:8px;border-radius:4px;margin-top:-10px;margin-right:10px}#content{display:flex;flex-wrap:wrap;align-items:stretch}figure{padding:0;margin:0;-webkit-margin-before:0;margin-block-start:0;-webkit-margin-after:0;margin-block-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0}figure img{display:block;width:100%;height:auto;border-radius:4px;margin-top:8px}@media (min-width: 800px) and (orientation:landscape){#content{display:flex;flex-wrap:nowrap;align-items:stretch}figure img{display:block;max-width:100%;max-height:calc(100vh - 40px);width:auto;height:auto}figure{padding:0;margin:0;-webkit-margin-before:0;margin-block-start:0;-webkit-margin-after:0;margin-block-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-margin-end:0;margin-inline-end:0}}section#buttons{display:flex;flex-wrap:nowrap;justify-content:space-between}#nav-toggle{cursor:pointer;display:block}#nav-toggle-cb{outline:0;opacity:0;width:0;height:0}#nav-toggle-cb:checked+#menu{display:none}.input-group{display:flex;flex-wrap:nowrap;line-height:22px;margin:5px 0}.input-group>label{display:inline-block;padding-right:10px;min-width:47%}.input-group input,.input-group select{flex-grow:1}.range-max,.range-min{display:inline-block;padding:0 5px}button{display:block;margin:5px;padding:0 12px;border:0;line-height:28px;cursor:pointer;color:#fff;background:#ff3034;border-radius:5px;font-size:16px;outline:0}button:hover{background:#ff494d}button:active{background:#f21c21}button.disabled{cursor:default;background:#a0a0a0}input[type=range]{-webkit-appearance:none;width:100%;height:22px;background:#363636;cursor:pointer;margin:0}input[type=range]:focus{outline:0}input[type=range]::-webkit-slider-runnable-track{width:100%;height:2px;cursor:pointer;background:#EFEFEF;border-radius:0;border:0 solid #EFEFEF}input[type=range]::-webkit-slider-thumb{border:1px solid rgba(0,0,30,0);height:22px;width:22px;border-radius:50px;background:#ff3034;cursor:pointer;-webkit-appearance:none;margin-top:-11.5px}input[type=range]:focus::-webkit-slider-runnable-track{background:#EFEFEF}input[type=range]::-moz-range-track{width:100%;height:2px;cursor:pointer;background:#EFEFEF;border-radius:0;border:0 solid #EFEFEF}input[type=range]::-moz-range-thumb{border:1px solid rgba(0,0,30,0);height:22px;width:22px;border-radius:50px;background:#ff3034;cursor:pointer}input[type=range]::-ms-track{width:100%;height:2px;cursor:pointer;background:0 0;border-color:transparent;color:transparent}input[type=range]::-ms-fill-lower{background:#EFEFEF;border:0 solid #EFEFEF;border-radius:0}input[type=range]::-ms-fill-upper{background:#EFEFEF;border:0 solid #EFEFEF;border-radius:0}input[type=range]::-ms-thumb{border:1px solid rgba(0,0,30,0);height:22px;width:22px;border-radius:50px;background:#ff3034;cursor:pointer;height:2px}input[type=range]:focus::-ms-fill-lower{background:#EFEFEF}input[type=range]:focus::-ms-fill-upper{background:#363636}.switch{display:block;position:relative;line-height:22px;font-size:16px;height:22px}.switch input{outline:0;opacity:0;width:0;height:0}.slider{width:50px;height:22px;border-radius:22px;cursor:pointer;background-color:grey}.slider,.slider:before{display:inline-block;transition:.4s}.slider:before{position:relative;content:"";border-radius:50%;height:16px;width:16px;left:4px;top:3px;background-color:#fff}input:checked+.slider{background-color:#ff3034}input:checked+.slider:before{-webkit-transform:translateX(26px);transform:translateX(26px)}select{border:1px solid #363636;font-size:14px;height:22px;outline:0;border-radius:5px}.image-container{position:relative;min-width:160px}.close{position:absolute;right:5px;top:5px;background:#ff3034;width:16px;height:16px;border-radius:100px;color:#fff;text-align:center;line-height:18px;cursor:pointer}.hidden{display:none}
</style>
<script src="https:\/\/ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="https:\/\/cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script>
<script src="https:\/\/cdn.jsdelivr.net/npm/@teachablemachine/image@0.8/dist/teachablemachine-image.min.js"></script>
<script src="https:\/\/cdn.jsdelivr.net/npm/@teachablemachine/pose@0.8/dist/teachablemachine-pose.min.js"></script>
</head>
<body>
<section class="main">
<figure>
<div id="stream-container" class="image-container hidden">
<div class="close" id="close-stream" style="display:none">×</div>
<img id="stream" src="" style="display:none" crossorigin="anonymous">
<canvas id="canvas" width="0" height="0"></canvas>
</div>
</figure>
<section id="buttons">
<table>
<tr><td><button id="restart" onclick="try{fetch(document.location.origin+'/control?restart');}catch(e){}">Restart</button></td><td><button id="get-still" style="display:none">Get Still</button></td><td><button id="toggle-stream" style="display:none"></td></tr>
</table>
</section>
<div id="logo">
<label for="nav-toggle-cb" id="nav-toggle">☰ Toggle settings</label>
</div>
<div id="content">
<div id="sidebar">
<input type="checkbox" id="nav-toggle-cb">
<nav id="menu">
<div class="input-group">
<label for="kind">Kind</label>
<select id="kind">
<option value="image" selected>image</option>
<option value="pose">pose</option>
</select>
</div>
<div class="input-group" style="display:none;">
<label for="modelPath">Model Path</label>
<input type="text" id="modelPath" value=https://teachablemachine.withgoogle.com/models/KhigiCCoU/>
</div>
<div class="input-group" style="display:none;">
<label for="btnModel"></label>
<button type="button" id="btnModel" onclick="LoadModel();">Start Recognition</button>
</div>
<div class="input-group" id="flash-group">
<label for="flash">Flash</label>
<div class="range-min">0</div>
<input type="range" id="flash" min="0" max="255" value="0" class="default-action">
<div class="range-max">255</div>
</div>
<div class="input-group" id="framesize-group">
<label for="framesize">Resolution</label>
<select id="framesize" class="default-action">
<option value="10">UXGA(1600x1200)</option>
<option value="9">SXGA(1280x1024)</option>
<option value="8">XGA(1024x768)</option>
<option value="7">SVGA(800x600)</option>
<option value="6">VGA(640x480)</option>
<option value="5" selected="selected">CIF(400x296)</option>
<option value="4">QVGA(320x240)</option>
<option value="3">HQVGA(240x176)</option>
<option value="0">QQVGA(160x120)</option>
</select>
</div>
<div class="input-group" id="quality-group">
<label for="quality">Quality</label>
<div class="range-min">10</div>
<input type="range" id="quality" min="10" max="63" value="10" class="default-action">
<div class="range-max">63</div>
</div>
<div class="input-group" id="brightness-group">
<label for="brightness">Brightness</label>
<div class="range-min">-2</div>
<input type="range" id="brightness" min="-2" max="2" value="0" class="default-action">
<div class="range-max">2</div>
</div>
<div class="input-group" id="contrast-group">
<label for="contrast">Contrast</label>
<div class="range-min">-2</div>
<input type="range" id="contrast" min="-2" max="2" value="0" class="default-action">
<div class="range-max">2</div>
</div>
<div class="input-group" id="hmirror-group">
<label for="hmirror">H-Mirror</label>
<div class="switch">
<input id="hmirror" type="checkbox" class="default-action" checked="checked">
<label class="slider" for="hmirror"></label>
</div>
</div>
<div class="input-group" id="vflip-group">
<label for="vflip">V-Flip</label>
<div class="switch">
<input id="vflip" type="checkbox" class="default-action" checked="checked">
<label class="slider" for="vflip"></label>
</div>
</div>
</nav>
</div>
</div>
</section>
<br>
<div id="result" style="color:red"><div>
<script>
document.addEventListener('DOMContentLoaded', function (event) {
var baseHost = document.location.origin
var streamUrl = baseHost + ':81'
const hide = el => {
el.classList.add('hidden')
}
const show = el => {
el.classList.remove('hidden')
}
const disable = el => {
el.classList.add('disabled')
el.disabled = true
}
const enable = el => {
el.classList.remove('disabled')
el.disabled = false
}
const updateValue = (el, value, updateRemote) => {
updateRemote = updateRemote == null ? true : updateRemote
let initialValue
if (el.type === 'checkbox') {
initialValue = el.checked
value = !!value
el.checked = value
} else {
initialValue = el.value
el.value = value
}
if (updateRemote && initialValue !== value) {
updateConfig(el);
}
}
function updateConfig (el) {
let value
switch (el.type) {
case 'checkbox':
value = el.checked ? 1 : 0
break
case 'range':
case 'select-one':
value = el.value
break
case 'button':
case 'submit':
value = '1'
break
default:
return
}
const query = `${baseHost}/control?var=${el.id}&val=${value}`
fetch(query)
.then(response => {
console.log(`request to ${query} finished, status: ${response.status}`)
})
}
document
.querySelectorAll('.close')
.forEach(el => {
el.onclick = () => {
hide(el.parentNode)
}
})
// read initial values
fetch(`${baseHost}/status`)
.then(function (response) {
return response.json()
})
.then(function (state) {
document
.querySelectorAll('.default-action')
.forEach(el => {
updateValue(el, state[el.id], false)
})
})
const view = document.getElementById('stream')
const viewContainer = document.getElementById('stream-container')
const stillButton = document.getElementById('get-still')
const streamButton = document.getElementById('toggle-stream')
const closeButton = document.getElementById('close-stream')
const stopStream = () => {
//window.stop();
view.src="";
streamButton.innerHTML = 'Start Stream'
}
const startStream = () => {
view.src = `${streamUrl}/stream`
show(viewContainer)
streamButton.innerHTML = 'Stop Stream'
}
// Attach actions to buttons
stillButton.onclick = () => {
stopStream()
try{
view.src = `${baseHost}/capture?_cb=${Date.now()}`
}
catch(e) {
view.src = `${baseHost}/capture?_cb=${Date.now()}`
}
show(viewContainer)
}
closeButton.onclick = () => {
stopStream()
hide(viewContainer)
}
streamButton.onclick = () => {
const streamEnabled = streamButton.innerHTML === 'Stop Stream'
if (streamEnabled) {
stopStream()
} else {
startStream()
}
}
// Attach default on change action
document
.querySelectorAll('.default-action')
.forEach(el => {
el.onchange = () => updateConfig(el)
})
})
</script>
<script>
var getStill = document.getElementById('get-still');
var ShowImage = document.getElementById('stream');
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var modelPath = document.getElementById('modelPath');
var result = document.getElementById('result');
var kind = document.getElementById('kind');
let Model;
async function LoadModel() {
if (modelPath.value=="") {
result.innerHTML = "Please input model path.";
return;
}
result.innerHTML = "Please wait for loading model.";
const URL = modelPath.value;
const modelURL = URL + "model.json";
const metadataURL = URL + "metadata.json";
if (kind.value=="image") {
Model = await tmImage.load(modelURL, metadataURL);
}
else if (kind.value=="pose") {
Model = await tmPose.load(modelURL, metadataURL);
}
maxPredictions = Model.getTotalClasses();
result.innerHTML = "";
getStill.style.display = "block";
getStill.click();
}
LoadModel();
async function predict() {
var data = "";
var maxClassName = "";
var maxProbability = "";
canvas.setAttribute("width", ShowImage.width);
canvas.setAttribute("height", ShowImage.height);
context.drawImage(ShowImage, 0, 0, ShowImage.width, ShowImage.height);
if (kind.value=="image")
var prediction = await Model.predict(canvas);
else if (kind.value=="pose") {
var { pose, posenetOutput } = await Model.estimatePose(canvas);
var prediction = await Model.predict(posenetOutput);
}
if (maxPredictions>0) {
for (let i = 0; i < maxPredictions; i++) {
if (i==0) {
maxClassName = prediction[i].className;
maxProbability = prediction[i].probability;
a = prediction[1].probability.toFixed(2);
}
else {
if (prediction[i].probability>maxProbability) {
maxClassName