基于ESP32CAM的物联网相机系统⑧(用原生JavaWeb实现双摄像头WIFI图传)

news/2024/7/21 7:38:33 标签: HTML, 嵌入式, 单片机, wifi, 图像处理

第一篇:最简单DIY基于ESP32CAM的物联网相机系统①(用网页实现拍照图传)
第二篇:最简单DIY基于ESP32CAM的物联网相机系统②(在JAVAWEB服务器实现图片查看器)
第三篇:最简单DIY基于ESP32CAM的物联网相机系统③(在JSP服务器图传相片给所有客户端欣赏)
第四篇:最简单DIY基于ESP32CAM的物联网相机系统④(用调试串口助手实现串口图传)
第五篇(上):最简单DIY基于ESP32CAM的物联网相机系统⑤(用1306OLED实现WIFI黑白屏照相机)
第五篇(下):最简单DIY基于ESP32CAM的物联网相机系统⑤(用C#上位机实现串口图传)
第六篇:最简单DIY基于ESP32CAM的物联网相机系统⑥(用上位机VS2013 MFC实现WIFI图传
第七篇:基于ESP32CAM的物联网相机系统⑦(用上位机JavaWeb实现WIFI图传)
第八篇:基于ESP32CAM的物联网相机系统⑧(用原生JavaWeb实现双摄像头WIFI图传)


文章目录

  • 前言
  • 一、基于ESP32CAM的物联网相机系统⑧(用原生JavaWeb实现双摄像头WIFI图传)是什么?
  • 二、运行环境说明
    • 1.PC软件环境
    • 2.单片机开发环境Arduino
    • 3.修改上面2的源码变成自己的源码
  • 三、运行与调试
  • 总结


前言

    daodanjishui物联网核心原创技术之基于ESP32CAM的物联网相机系统⑧(用原生JavaWeb实现双摄像头WIFI图传)。
    该专栏的第七篇博文:基于ESP32CAM的物联网相机系统⑦(用上位机JavaWeb实现WIFI图传) 实现的是采用高速WIFI的方式传输图片,ESP32通过总线采集出来的图片在内存里面直接通过高速WIFI输出到电脑JSP服务器上,那么可以通过ESP32CAM的嵌入式网页来控制拍照和传输,在服务器的硬盘上看到传输过来并保存到服务器的图片。缺点就是:服务器接收到的图片文件是存于服务器器硬盘的,没有展示在服务器的主页上!
    本次设计将ESP32CAM摄像头通过高速WIFI的方式传输过来的图片直接存入内存和直接显示服务器的主页上,做图像处理的技术开发者都知道这个功能确实很不错,接收到图片内容很方便使用现有的库进行图像处理,要是接收到文件,肯定会遇到不少麻烦的,你还要将文件读入内存,要是文件不存在还会报错!而且我可以采用多个摄像头图传到服务器,视频演示的用了两个摄像头,其实还能扩展的。目前为止我看过很多开源网站,都没有现成的服务器接收ESP32CAM图片信息存入内存的开源代码。所以我亲自动手写了这个示例代码,也为了推动javaweb与硬件结合做出自己的贡献。因为ESP32CAM开发板上没有可用的开关,所以我就采用嵌入式网页来实现拍照和上传了。这个javaweb代码跟纯java代码不同,既有java后台代码servlet,也有前端html语言,jsp语言和JavaScript语言。前端后端全部包括进去,唯一感到安慰的是我没有采用任何框架,所以适合新手修改达到二次开发,所以下载了我这个项目的源码的读者,现在可以做一个基于ESP32CAM监控摄像头监控之类的设计了,也可以学会如何部署一个能否接收图片的网站服务器,也可以学会图像传输和接收和编码等热门知识!
B站地址:https://www.bilibili.com/video/BV1Qq4y1w7sG?t=0.0
点我跳转

最简单DIY基于ESP32CAM的物联网相机系统8(用原生JavaWeb网站实现双摄像头WIFI图传)

请看看下面的服务器网站效果图
在这里插入图片描述
显示摄像头采集回来的图片和显示服务器调试信息

在这里插入图片描述
单片机工程截图
在这里插入图片描述

手机端浏览器控制ESP32CAM摄像头拍照并且通过http请求上传服务器(局域网)
在这里插入图片描述

项目功能框架图:

在这里插入图片描述


一、基于ESP32CAM的物联网相机系统⑧(用原生JavaWeb实现双摄像头WIFI图传)是什么?

    将ESP32CAM摄像头通过高速WIFI的方式传输过来的图片直接存入内存和直接显示服务器的主页上,做图像处理的技术开发者都知道这个功能确实很不错,接收到图片内容很方便使用现有的库进行图像处理,要是接收到文件,肯定会遇到不少麻烦的,你还要将文件读入内存,要是文件不存在还会报错!而且我可以采用多个摄像头图传到服务器,视频演示的用了两个摄像头,其实还能扩展的。目前为止我看过很多开源网站,都没有现成的服务器接收ESP32CAM图片信息存入内存的开源代码。所以我亲自动手写了这个示例代码,也为了推动javaweb与硬件结合做出自己的贡献。因为ESP32CAM开发板上没有可用的开关,所以我就采用嵌入式网页来实现拍照和上传了。


二、运行环境说明

1.PC软件环境

    服务器搭建:上位机用Eclipse javaee版本,tomcat7,jdk1.7,window7操作系统,网上有很多指导搭建开发环境的教程,我在这里就不多说了。
    下面顺便谈谈该开源我亲自编写服务器的故事:当时自己学习完JSP技术没有找到一个合适的练手项目,想用Javaweb写一个简单一点的网页游戏,也不需要套大型框架,后面写了一个点击大战的游戏,就是记录玩家在限定时间点击按钮的次数,用了数据库和增删改查技术,然后我就把这个游戏的代码去除了数据库功能后加上一些jsp语法实现的图片服务器的功能,我的下位机单片机ESP32CAM用http协议接收嵌入式主页的ajax技术触发的get请求,再用http请求传输图片文件给http短链接的服务器,服务器由于是短连接,资源充分,运行流畅,更适合玩家二次开发,注释详细。这个明修栈道暗度陈仓的功能多少人想写这个功能都写不出来!鲁迅笔下的“拿来主义”在我这里表现的淋漓尽致,这也是当代程序开发者高效捞金的真实写照。


2.单片机开发环境Arduino

官方摄像头源码路径是(只要读者正确安装了ESP32开发环境,这个源码可以在Arduino里面按照下面截图的方式打开的):
在这里插入图片描述

#include "esp_camera.h"
#include <WiFi.h>

//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
//            Ensure ESP32 Wrover Module or other board with PSRAM is selected
//            Partial images will be transmitted if image exceeds buffer size
//

// Select camera model
#define CAMERA_MODEL_WROVER_KIT // Has PSRAM
//#define CAMERA_MODEL_ESP_EYE // Has PSRAM
//#define CAMERA_MODEL_M5STACK_PSRAM // Has PSRAM
//#define CAMERA_MODEL_M5STACK_WIDE	// Has PSRAM
//#define CAMERA_MODEL_AI_THINKER // Has PSRAM
//#define CAMERA_MODEL_TTGO_T_JOURNAL // No PSRAM

#include "camera_pins.h"

const char* ssid = "*********";
const char* password = "*********";

void startCameraServer();

void setup() {
  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 PSRAM IC present, init with UXGA resolution and higher JPEG quality
  //                      for larger pre-allocated frame buffer.
  if(psramFound()){
    config.frame_size = FRAMESIZE_UXGA;
    config.jpeg_quality = 10;
    config.fb_count = 2;
  } else {
    config.frame_size = FRAMESIZE_SVGA;
    config.jpeg_quality = 12;
    config.fb_count = 1;
  }

#if defined(CAMERA_MODEL_ESP_EYE)
  pinMode(13, INPUT_PULLUP);
  pinMode(14, INPUT_PULLUP);
#endif

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK) {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t * s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  if (s->id.PID == OV3660_PID) {
    s->set_vflip(s, 1); // flip it back
    s->set_brightness(s, 1); // up the brightness just a bit
    s->set_saturation(s, -2); // lower the saturation
  }
  // drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_QVGA);

#if defined(CAMERA_MODEL_M5STACK_WIDE)
  s->set_vflip(s, 1);
  s->set_hmirror(s, 1);
#endif

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");

  startCameraServer();

  Serial.print("Camera Ready! Use 'http://");
  Serial.print(WiFi.localIP());
  Serial.println("' to connect");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(10000);
}

3.修改上面2的源码变成自己的源码

核心代码如下(加入发送http请求的代码即可,发送post请求传输图片内容,就是图片字符串,而不是图片文件,这要与上一篇区别开来)

void sendsnapshot_string(String ip){//给服务器发送图片字符串
HTTPClient http;
int httpCode;
String GetUrl;
String response;
camera_fb_t *fb = esp_camera_fb_get();
  //设置超时
  const unsigned long HTTP_TIMEOUT = 5000;              // max respone time from server
  http.setTimeout(HTTP_TIMEOUT);
  //设置请求url
  //send String
  http.begin("http://"+ip+":8080/form1/servlet1");//send picture
  //以下为设置一些头  其实没什么用 最重要是后端服务器支持
  //http.setUserAgent("esp8266");//用户代理版本
  //http.setAuthorization("api-key", API_Key,); //用户校验信息    
   // http.addHeader("Content-Length","16", true);//length
    http.addHeader("Content-Length",""+fb->len+sizeof("user=su&speak="), true);//length
    //http.addHeader("Content-Type", "image/jpg", true);
    http.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8", true);

服务器接收图片部分源码:

/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//System.out.println("doPost"+request.getParameter("name"));
		System.out.println("进入post方法");
		response.setContentType("text/html;charset=UTF-8");//设置响应内容和编码方式
		
		
		
		String user=request.getParameter("name");//昵称
		String speak=request.getParameter("QOS");//说话内容
		System.out.println(user+"say:"+speak);
		
       if(user.indexOf("daodanjishui")>=0){//存入图片记录
			
			//这里需要将字符串数据进行base64编码,再存进去
			 int size =speak.length();
			 byte[] data=null;//数据缓存
       	      Base64 base64 = null;//因为浏览器直接可以显示base64编码的图片
			  data = new byte[size];
			  data=byteArray(speak);//将字符数据存入字节数组							 
			  speak = base64.encode(data);//base64编码
	          application.setAttribute("data", "data:image/jepg;base64,"+speak);//将base64图片信息保存到application  4		
	          //刷新页面显示表单提交的base64图片
			  System.out.println(user+"存入ESP32CAM图片数据"+"data:image/jepg;base64,"+speak);
			  response.getWriter().println("server get your data");//这个是不刷新页面,异步显示后台写好的base64字符串data1="``````";不能显示表单提交的字符串,用第二个异步表单提交
		}

    服务器代码采用JavaWeb和JSP编写,就只有两个java文件非常利于学习。 其实现在很多人做界面开发用C++的QT或者是java swing窗体都是比较麻烦的,最简单的就是网页!下位机的代码也很精简,就两个文件,但是能完成文件传输真心不差。
    在这个项目源码中,读者可以学到很多技术,例如:图片的base64编码,和网页显示图片的技术,网络传输图片文件,服务器与客户端的交互,嵌入式服务器,嵌入式客户端开发,图片分解为字符串传输,服务器与客户单密码验证传输,客户端密码验证查看图片,嵌入式摄像头二次开发等等技术。网上相关开源的代码基本上没有,所谓的几万块学费的嵌入式培训班,大部分是复制别人外国人开源项目的代码来讲解给学员,其实他们真的不是原创。在我这里,我敢保证我的代码纯正的国产原创,也许有些地方可能借鉴了部分网上的内容,但是系统整理架构都是本人亲力亲为创作完成,购买过我代码的读者,都会感到物超所值,没有一个是差评的!
    需要全部工程源码的请到最后链接去下载了。想要自己写出来,不简单的,在物联网软件与硬件交互的代码不经过长期探索很难做出来一套像样子的系统出来的,不信读者可以试试写一个服务器和客户端看看。我反而喜欢用javaweb去写一些简单的网页,复杂的功能我交给java servlet后台去实现,现在能联网的界面一般都用网页显示了。这也是物联网发展的潮流!据说鸿蒙系统的GUI是用JAVAScript来写的,我相机的主页也采用了JAVAScript触发拍照和图传,服务器主页可以直观展示图片,所以到这里可以看到未来是脚本的天下。


三、运行与调试

看上面视频演示的过程就知道了,这里就不多说了。视频演示的效果满足的博客预想的效果。


总结

总结: 在这个项目,读者可以学到很多技术,下载源码这点付出对于这些核心技术来说不值一提,学核心技术不花钱是有可能的,不过可能性不大,收费开源对得起我付出的努力编写此次博文,也对得起我深夜编码付出的劳动。下一期将会推出全网独家第一个ESP32CAM JAVA SWing GUI 技术编写的java版图传服务器,全部逻辑由我daodanjishui全部完成,历时两周时间研发成功,代码精妙无比,后期会加上远程MQTT控制和图像处理,扩展功能水到渠成,敬请期待。

代码工程下载链接:https://www.cirmall.com/circuit/28881/
点我直接跳转


http://www.niftyadmin.cn/n/1322671.html

相关文章

基于ESP32CAM实现WebSocket服务器实时点灯

ESP32-CAM ArduinoIDE开发系列文章目录 第一篇&#xff1a;ESP32-CAM高性价比WIFI图传方案快速入门教程 第二篇&#xff1a;ESP32-CAM第一个无线点灯程序 第三篇&#xff1a;ESP32-CAM智能网关的设计与实现 第四篇&#xff1a;ESP32-CAM创建热点构成并发式DNS服务器 第五篇&…

最简单DIY基于STM32的远程控制电脑系统①(电容触摸+按键控制)

STM32库函数开发系列文章目录 第一篇&#xff1a;STM32F103ZET6单片机双串口互发程序设计与实现 第二篇&#xff1a;最简单DIY基于STM32单片机的蓝牙智能小车设计方案 第三篇&#xff1a;最简单DIY基于STM32F407探索者开发板的MPU6050陀螺仪姿态控制舵机程序 第四篇&#xff1…

链表相关面试题

链表相关面试题链表中的节点每k个一组翻转两数相加链表求和&#xff08;两个链表生成相加链表&#xff09;正序排列链表求和(逆序排列)相交链表反转链表反转链表2&#xff08;指定区间内的反转&#xff09;链表中环的入口节点合并两个有序链表两个链表的第一个公共节点从有序链…

最简单DIY基于STM32的远程控制电脑系统②(无线遥杆+按键控制)

STM32库函数开发系列文章目录 第一篇&#xff1a;STM32F103ZET6单片机双串口互发程序设计与实现 第二篇&#xff1a;最简单DIY基于STM32单片机的蓝牙智能小车设计方案 第三篇&#xff1a;最简单DIY基于STM32F407探索者开发板的MPU6050陀螺仪姿态控制舵机程序 第四篇&#xff1…

输入一个URL发生了什么

输入一个URL发生了什么在浏览器输入一个URL会发生什么呢&#xff1f;浏览器&#xff08;客户端&#xff09;会判断当前输入的URL是否合规&#xff0c;然后进行地址解析&#xff0c;补全域名&#xff0c;最后DNS域名解析获得目的IP&#xff1b;得到目的IP&#xff0c;根据目的IP…

动态规划dp常考面试题(最长xxx)

动态规划dp连续子数组的最大和连续子数组的最大乘积礼物的最大价值矩阵的最小路径&#xff08;最小路径之和&#xff09;三角形最小路径和岛屿的数量不同路径I不同路径II&#xff08;有障碍版&#xff09;最长公共前缀最长无重复子数组最长不重复子串最长上升子序列&#xff08…

CJJ写程序的那些事------Hello, world

今天是一个伟大的日子&#xff0c;CJJ开始了第一篇博客。 第一篇当然是家喻户晓 当时写了将近6h的“hello&#xff0c;world&#xff01;”啦啦啦啦啦啦~ #include<iostream> using namespace std; int main() {cout<<"Hello, world!"<<endl;ret…

线程池知识小结

线程池为什么要有线程池&#xff1f;线程池的优点线程池的执行流程线程池的执行方式线程池的关闭线程池的状态线程池的创建ThreadPoolExecutor创建FixedThreadPool创建SingleThreadExecutorCachedThreadPooFixedThreadPool(10, threadFactory)ScheduledThreadPoolSingleThreadS…