web页面实现摄像头,图像采集,照片上传至服务器,代码已发布-printScreen4web

printScreen4web是一款免安装的网页控件,能够实现网页图像采集与上传功能,适用于Java、PHP等多种语言环境。该控件支持跨浏览器使用,并提供了一个现成的解决方案,便于网页设计师和开发者在项目中集成摄像头图像采集功能。

2014.03.24

 

新控件,免安装版本:

printscreen4web控件实现网页采集图像,并实现上传的功能,为网页设计师提供一个现成的,优质的控件。在实际项目中,使用场景为java采集摄像头的图像,并上传。因为控件是js调用的,所以可以使用多种语言php,asp等都可以使用,而且是跨浏览器的。

使用方法1:

下载 printscreen4web-jsp.war,然后放到tamcat目录webapp文件夹下面,启动tomcat,访问http://127.0.0.1:8080/printscreen4web-jsp/

 




 
 

 下载地址:http://602.s21d-2.faidns.com/2872602/0/ABUIABAAGAAgu8SUogUo0s77mQI?f=printScreen4web-struts2.zip&v=1413816889

 

 

 

 最近在做一个项目,用到摄像头采集图片,并上传到服务器,经过几天努力,终于实现了这个功能,现在发布代码。 由于现在的摄像头都是usb的,最后终于实现了在web程序中调用摄像头,可以通过js代码控制拍照,通过ajax技术实现数据的上传,因为是是js调用的,所以也可以用于jsp,asp,php和html页面上,就是说支持多种服务器,刚弄完,在IE下测试通过,下面上图看效果: printScreen4web



 
 

现在共享给大家。因为以前很少参与开源社区活动,以后会继续共享一些c++或JS方面的组件或插件。使用愉快。 

如有使用不成功的可联系 247664798@qq.com

废话少说,上代码:

imagesUpload.rar这个可以直接部署到tomcat目录webapps中;

imagesUpload_4myeclipse.rar这个可以导入到myeclipse;

 

2013-12-20 bug fix:

重新编译demo.cab控件,修复原来在win7下可以正常调用摄像头在xp下有问题的bug,代码已重新上传

 

用人反映,如何使用,

使用需要设置可信站点:



 

 printScreen4web功能更新:

保存成bmp,图片比较大,保存jpg格式图片较小,

调用方法:

Camer.TakePhoto("XXX.jpg")

 

2013.12.23

有人反映电脑使用之后浏览器会崩溃,点击启动摄像头再点击拍照,浏览器会崩溃刷新,下面给出解决方法:

       XP系统:

关闭应用程序保护(DEP),方法为:右键点击“我的电脑”->“属性”->“高级系统设置”->“高级”->“设置”->”数据执行保护,选择“仅为基本windows程序和服务启用DEP(T)

win7系统也一样,截图:



 

 12.24 bug fix:

printScreen4web更新控件,当电脑是内置摄像头或者有多个摄像头时,浏览器崩溃问题,附件已更新。

 

 

2014.01.01

printScreen4web功能更新:

增加图片转成base64编码,方便后台取得图片,给出一个demo整合到struts2中,里面有使用方法。

 

printScreen4web网盘下载地址:

html版本,用浏览器打开index.html,即可预览:

http://pan.baidu.com/s/1bnGeEiN

整合到strut2:

http://pan.baidu.com/s/1mg8uKMO

#include "camera_pins.h" #include <WiFi.h> #include "esp_camera.h" #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // Edge Impulse模型库(需手动添加到项目目录) #include "shibie_inferencing.h" #include "edge-impulse-sdk/dsp/image/image.hpp" #include "esp_task_wdt.h" // 功能开关 #define ENABLE_INFERENCE        1 #define ENABLE_HTTP_SERVER      1 #define ENABLE_OLED_DISPLAY     1 #define SUPPORT_OBJECT_DETECTION 0 // 摄像头配置 #define CAMERA_MODEL_AI_THINKER #define XCLK_FREQ_HZ            8000000   // 8MHz时钟,更稳定 #define FRAME_SIZE              FRAMESIZE_QVGA  // 320x240 #define JPEG_QUALITY            10         // 低压缩比,高质量 #define MAX_CAPTURE_RETRIES     3          // 捕获重试次数 // 图像尺寸 #define EI_CAMERA_COLS          320 #define EI_CAMERA_ROWS          240 #define MODEL_INPUT_WIDTH       EI_CLASSIFIER_INPUT_WIDTH #define MODEL_INPUT_HEIGHT      EI_CLASSIFIER_INPUT_HEIGHT // OLED配置 #define OLED_WIDTH              128 #define OLED_HEIGHT             64 #define OLED_RESET              -1 #define OLED_SDA                21 #define OLED_SCL                22 Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, OLED_RESET); // WiFi配置 const char* ssid     = "88888888"; const char* password = "11111111"; // 全局变量 WiFiServer server(80); static bool is_initialised = false; static bool wifi_connected = false; uint8_t* snapshot_buf = NULL;  // 原始RGB缓冲区 uint8_t* model_buf = NULL;     // 模型输入缓冲区 camera_fb_t* fb = NULL; // 摄像头配置 static camera_config_t camera_config = {     .pin_pwdn     = PWDN_GPIO_NUM,     .pin_reset    = RESET_GPIO_NUM,     .pin_xclk     = XCLK_GPIO_NUM,     .pin_sscb_sda = SIOD_GPIO_NUM,     .pin_sscb_scl = SIOC_GPIO_NUM,     .pin_d7       = Y9_GPIO_NUM,     .pin_d6       = Y8_GPIO_NUM,     .pin_d5       = Y7_GPIO_NUM,     .pin_d4       = Y6_GPIO_NUM,     .pin_d3       = Y5_GPIO_NUM,     .pin_d2       = Y4_GPIO_NUM,     .pin_d1       = Y3_GPIO_NUM,     .pin_d0       = Y2_GPIO_NUM,     .pin_vsync    = VSYNC_GPIO_NUM,     .pin_href     = HREF_GPIO_NUM,     .pin_pclk     = PCLK_GPIO_NUM,     .xclk_freq_hz = XCLK_FREQ_HZ,     .ledc_timer   = LEDC_TIMER_0,     .ledc_channel = LEDC_CHANNEL_0,     .pixel_format = PIXFORMAT_JPEG,     .frame_size   = FRAME_SIZE,     .jpeg_quality = JPEG_QUALITY,     .fb_count     = 2,  // 双缓冲     .fb_location  = CAMERA_FB_IN_PSRAM,     .grab_mode    = CAMERA_GRAB_WHEN_EMPTY, }; // 正确的JPEG转RGB888函数(使用ESP32官方函数) bool convert_jpeg_to_rgb888(const uint8_t* jpeg_data, size_t jpeg_size, uint8_t* rgb_data, size_t rgb_size) {     // 使用ESP32摄像头库自带的fmt2rgb888函数(官方推荐)     return fmt2rgb888(jpeg_data, jpeg_size, PIXFORMAT_JPEG, rgb_data); } // 备用缩放函数(双线性插值,解决SDK缩放失败问题) bool backup_resize_rgb888(const uint8_t* src, uint32_t src_width, uint32_t src_height,                          uint8_t* dst, uint32_t dst_width, uint32_t dst_height) {     if (!src || !dst || src_width == 0 || src_height == 0 || dst_width == 0 || dst_height == 0) {         return false;     }     float x_ratio = (float)src_width / (float)dst_width;     float y_ratio = (float)src_height / (float)dst_height;     for (uint32_t y = 0; y < dst_height; y++) {         for (uint32_t x = 0; x < dst_width; x++) {             float src_x = x * x_ratio;             float src_y = y * y_ratio;                         uint32_t x1 = (uint32_t)src_x;             uint32_t y1 = (uint32_t)src_y;             uint32_t x2 = (x1 < src_width - 1) ? x1 + 1 : x1;             uint32_t y2 = (y1 < src_height - 1) ? y1 + 1 : y1;                         float fx = src_x - x1;             float fy = src_y - y1;                         for (uint8_t c = 0; c < 3; c++) {                 uint8_t v11 = src[(y1 * src_width + x1) * 3 + c];                 uint8_t v12 = src[(y2 * src_width + x1) * 3 + c];                 uint8_t v21 = src[(y1 * src_width + x2) * 3 + c];                 uint8_t v22 = src[(y2 * src_width + x2) * 3 + c];                                 uint8_t v1 = (uint8_t)((1 - fx) * v11 + fx * v21);                 uint8_t v2 = (uint8_t)((1 - fx) * v12 + fx * v22);                                 dst[(y * dst_width + x) * 3 + c] = (uint8_t)((1 - fy) * v1 + fy * v2);             }         }     }         return true; } /* -------------------------- 工具函数 -------------------------- */ void oled_print(const char* line1, const char* line2 = "", const char* line3 = "") { #ifdef ENABLE_OLED_DISPLAY     display.clearDisplay();     display.setTextSize(1);     display.setTextColor(SSD1306_WHITE);     display.setCursor(0, 0);     display.println(line1);     if (strlen(line2) > 0) {         display.setCursor(0, 16);         display.println(line2);     }     if (strlen(line3) > 0) {         display.setCursor(0, 32);         display.println(line3);     }     display.display(); #endif } /* -------------------------- 摄像头操作 -------------------------- */ bool camera_init() {     if (is_initialised) return true;     // 初始化摄像头(带重试)     esp_err_t err;     int init_retry = 0;     while (init_retry < 3) {         err = esp_camera_init(&camera_config);         if (err == ESP_OK) break;         Serial.printf("摄像头初始化失败(重试%d): %s\n", init_retry+1, esp_err_to_name(err));         init_retry++;         vTaskDelay(1000 / portTICK_PERIOD_MS);     }     if (err != ESP_OK) {         Serial.println("摄像头初始化彻底失败");         return false;     }     // 优化传感器参数     sensor_t* s = esp_camera_sensor_get();     if (s) {         s->set_vflip(s, 1);         // 翻转图像         s->set_hmirror(s, 1);       // 镜像图像         s->set_awb_gain(s, 1);      // 自动白平衡         s->set_exposure_ctrl(s, 1); // 自动曝光         s->set_gain_ctrl(s, 1);     // 自动增益         s->set_brightness(s, 0);    // 亮度适中         s->set_contrast(s, 0);      // 对比度适中     }     // 分配内存缓冲区(4字节对齐)     size_t snapshot_size = EI_CAMERA_COLS * EI_CAMERA_ROWS * 3;     size_t model_size = MODEL_INPUT_WIDTH * MODEL_INPUT_HEIGHT * 3;         snapshot_buf = (uint8_t*)aligned_alloc(4, snapshot_size);     model_buf = (uint8_t*)aligned_alloc(4, model_size);         // 对齐分配失败时降级为普通分配     if (!snapshot_buf) snapshot_buf = (uint8_t*)malloc(snapshot_size);     if (!model_buf) model_buf = (uint8_t*)malloc(model_size);         if (!snapshot_buf || !model_buf) {         Serial.println("内存缓冲区分配失败");         camera_deinit();         return false;     }     Serial.printf("分配内存: snapshot=%zu bytes, model=%zu bytes\n", snapshot_size, model_size);     is_initialised = true;     Serial.println("摄像头初始化成功");     return true; } void camera_deinit() {     if (is_initialised) {         esp_camera_deinit();         if (snapshot_buf) free(snapshot_buf);         if (model_buf) free(model_buf);         snapshot_buf = NULL;         model_buf = NULL;         is_initialised = false;     } } // 优化后的图像捕获函数(修复JPEG转RGB错误) bool camera_capture(uint32_t img_width, uint32_t img_height, uint8_t* out_buf) {     if (!is_initialised) {         Serial.println("摄像头未初始化");         return false;     }     for (int retry = 0; retry < MAX_CAPTURE_RETRIES; retry++) {         // 获取JPEG帧         fb = esp_camera_fb_get();         if (!fb) {             Serial.printf("获取帧失败(重试%d)\n", retry+1);             vTaskDelay(200 / portTICK_PERIOD_MS);             continue;         }         // 过滤无效帧(1KB~200KB)         if (fb->len < 1024 || fb->len > 1024*200) {             Serial.printf("JPEG数据异常(%u字节),重试\n", fb->len);             esp_camera_fb_return(fb);             continue;         }         // 打印JPEG文件头(验证格式是否正确)         Serial.print("JPEG头: ");         for (int i = 0; i < 8 && i < fb->len; i++) {             Serial.printf("%02X ", fb->buf[i]); // 正常JPEG头应为FF D8 FF E0 ...         }         Serial.println();         // 转换JPEG到RGB888(使用正确的convert函数)         bool converted = convert_jpeg_to_rgb888(fb->buf, fb->len, snapshot_buf,                                               EI_CAMERA_COLS * EI_CAMERA_ROWS * 3);         esp_camera_fb_return(fb);         fb = NULL;         if (converted) {             // 打印RGB数据前8字节(验证是否有效)             Serial.print("RGB头: ");             for (int i = 0; i < 8; i++) {                 Serial.printf("%02X ", snapshot_buf[i]);             }             Serial.println();             // 尝试SDK缩放函数             bool resized = false;             Serial.println("尝试SDK缩放...");             resized = ei::image::processing::crop_and_interpolate_rgb888(                 snapshot_buf, EI_CAMERA_COLS, EI_CAMERA_ROWS,                 out_buf, img_width, img_height             );             if (!resized) {                 // SDK缩放失败时用备用函数                 Serial.println("SDK缩放失败,尝试备用缩放...");                 resized = backup_resize_rgb888(                     snapshot_buf, EI_CAMERA_COLS, EI_CAMERA_ROWS,                     out_buf, img_width, img_height                 );             }             if (resized) {                 Serial.println("缩放成功");                 return true;             }             // 缩放失败原因             Serial.println("缩放失败原因:数据格式异常");         } else {             Serial.printf("JPEG转RGB失败(重试%d)\n", retry+1);         }         vTaskDelay(200 / portTICK_PERIOD_MS);     }     Serial.println("图像处理最终失败");     return false; } /* -------------------------- 推理核心 -------------------------- */ #ifdef ENABLE_INFERENCE void run_inference() {     if (!is_initialised || !snapshot_buf || !model_buf) {         oled_print("未就绪", "摄像头异常");         return;     }     Serial.println("\n===== 开始推理 =====");     oled_print("识别中...");     if (!camera_capture(MODEL_INPUT_WIDTH, MODEL_INPUT_HEIGHT, model_buf)) {         oled_print("处理失败", "图像异常");         return;     }     // 准备模型输入信号     ei::signal_t signal;     signal.total_length = MODEL_INPUT_WIDTH * MODEL_INPUT_HEIGHT;     signal.get_data = [](size_t offset, size_t length, float* out) {         size_t pixel_ix = offset * 3;         for (size_t i = 0; i < length; i++) {             out[i] = (model_buf[pixel_ix] - 127.5f) / 127.5f;    // R             out[i + length] = (model_buf[pixel_ix + 1] - 127.5f) / 127.5f;  // G             out[i + length * 2] = (model_buf[pixel_ix + 2] - 127.5f) / 127.5f;  // B             pixel_ix += 3;         }         return 0;     };     // 运行推理     ei_impulse_result_t result;     EI_IMPULSE_ERROR err = run_classifier(&signal, &result, false);     if (err != EI_IMPULSE_OK) {         Serial.printf("推理失败: %d\n", err);         oled_print("推理错误", String(err).c_str());         return;     }     // 解析结果     float max_prob = 0;     const char* max_label = "未知";     for (uint16_t i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {         if (result.classification[i].value > max_prob) {             max_prob = result.classification[i].value;             max_label = ei_classifier_inferencing_categories[i];         }     }     // 显示结果     Serial.printf("识别结果: %s (%.1f%%)\n", max_label, max_prob*100);     oled_print("识别为:", max_label, (String(max_prob*100, 1) + "%").c_str());     Serial.println("===== 推理结束 ====="); } #endif /* -------------------------- HTTP服务 -------------------------- */ #ifdef ENABLE_HTTP_SERVER void handle_client(WiFiClient& client) {     String req = client.readStringUntil('\n');     req.trim();     Serial.println("HTTP请求: " + req);     if (req.startsWith("GET /photo")) {         client.println("HTTP/1.1 200 OK");         client.println("Content-Type: image/jpeg");         client.println("Connection: close");         client.println();         fb = esp_camera_fb_get();         if (fb && fb->len > 1024) {             client.write(fb->buf, fb->len);             esp_camera_fb_return(fb);         } else {             client.print("获取照片失败");             if (fb) esp_camera_fb_return(fb);         }         fb = NULL;     } else if (req.startsWith("GET /infer")) {         client.println("HTTP/1.1 200 OK");         client.println("Content-Type: text/plain");         client.println("Connection: close");         client.println();                 if (ENABLE_INFERENCE) {             run_inference();             client.println("推理已触发");         } else {             client.println("推理功能未启用");         }     } else {         client.println("HTTP/1.1 404 Not Found");         client.println("Content-Type: text/plain");         client.println();         client.println("支持: /photo, /infer");     }     client.stop(); } #endif /* -------------------------- 任务与初始化 -------------------------- */ void inference_task(void* param) {     while (1) {         if (wifi_connected && is_initialised) { #ifdef ENABLE_INFERENCE             run_inference(); #endif         } else {             String status = wifi_connected ? "等待摄像头" : "等待WiFi";             oled_print("准备中", status.c_str());         }         vTaskDelay(5000 / portTICK_PERIOD_MS);     } } void http_task(void* param) {     server.begin();     Serial.println("HTTP服务启动");     while (1) {         if (wifi_connected) {             WiFiClient client = server.available();             if (client) handle_client(client);         }         vTaskDelay(100 / portTICK_PERIOD_MS);     } } void wifi_monitor_task(void* param) {     while (1) {         if (WiFi.status() != WL_CONNECTED) {             if (wifi_connected) {                 wifi_connected = false;                 Serial.println("WiFi连接丢失");                 oled_print("错误", "WiFi断开");             }                         WiFi.reconnect();             Serial.println("尝试重连WiFi...");             oled_print("重连WiFi中");                         int retry = 0;             while (WiFi.status() != WL_CONNECTED && retry < 20) {                 vTaskDelay(500 / portTICK_PERIOD_MS);                 retry++;             }                         if (WiFi.status() == WL_CONNECTED) {                 wifi_connected = true;                 Serial.printf("WiFi重连成功: %s\n", WiFi.localIP().toString().c_str());                 oled_print("WiFi已恢复", WiFi.localIP().toString().c_str());             }         } else if (!wifi_connected) {             wifi_connected = true;             Serial.printf("WiFi已连接: %s\n", WiFi.localIP().toString().c_str());         }                 vTaskDelay(3000 / portTICK_PERIOD_MS);     } } void setup() {     Serial.begin(115200);     while (!Serial) vTaskDelay(100 / portTICK_PERIOD_MS);     Serial.println("Edge Impulse 识别系统启动中");     // 初始化OLED #ifdef ENABLE_OLED_DISPLAY     Wire.begin(OLED_SDA, OLED_SCL);     if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {         Serial.println("OLED初始化失败(忽略)");     } else {         oled_print("系统启动中");     } #endif     // 初始化摄像头     if (!camera_init()) {         oled_print("错误", "摄像头初始化失败");         while (1) vTaskDelay(1000 / portTICK_PERIOD_MS);     }     // 连接WiFi     WiFi.begin(ssid, password);     WiFi.setSleep(false);     Serial.printf("连接WiFi: %s...\n", ssid);     oled_print("连接WiFi", ssid);     // 创建任务     xTaskCreatePinnedToCore(inference_task, "inference", 40960, NULL, 2, NULL, 0);     xTaskCreatePinnedToCore(http_task, "http", 20480, NULL, 1, NULL, 1);     xTaskCreatePinnedToCore(wifi_monitor_task, "wifi_monitor", 8192, NULL, 1, NULL, 1); } void loop() {     vTaskDelay(portMAX_DELAY); }修改
07-22
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值