[JAVA] Verwendung des Kameramoduls OV7725 (ESP32-WROVER-B)

Überblick

Ich habe zuvor OV2640 verwendet, um das Bild abzurufen, daher habe ich diesmal versucht, das Bild mit OV7725 abzurufen. Der OV7725 gibt Bilder im BMP-Format anstelle von JPEG aus, daher unterscheidet sich die Steuermethode geringfügig.

Dieses Mal habe ich es möglich gemacht, das OV7725-Register im Browser zu ändern! Aus dem Fazit konnte ich kein sehr schönes Bild mit 300.000 Pixeln machen. Es scheint die gleiche Leistung zu haben wie die in den frühen Handys installierte Kamera ... Wenn Sie schöne Bilder machen möchten, sollten Sie einen Himbeerkuchen verwenden und mit OV5640 fotografieren.

te.jpg

DSC_0418.JPG

Ich habe ESP32-WROOM-32 für OV2640 verwendet, aber ich habe ESP32-WROVER-B mit PSRAM verwendet, da OV7725 bmp ist und die Speichernutzung zunimmt.

offiziell https://github.com/espressif/esp32-camera

Vielleicht bevor es offiziell verabschiedet wurde https://github.com/igrr/esp32-cam-demo

Pin-Platzierung https://www.instructables.com/id/The-Incredible-ESP32-Wrover-From-Espressif/

OV7725 Datenblatt https://cdn.sparkfun.com/datasheets/Sensors/LightImaging/OV7725.pdf

Aufbau

Klonen Sie das Submodul in den Ordner esp-idf.

git submodule add https://github.com/espressif/esp32-camera.git components/esp32-camera
mv esp-idf/components/esp32-camera/driver/private_include/sccb.h esp-idf/components/esp32-camera/driver/include/sccb.h
mv esp-idf/components/esp32-camera/driver/private_include/sensor.h esp-idf/components/esp32-camera/driver/include/sensor.h

wichtiger Punkt

Code

Der einfache Server im Beispiel von esp-idf wurde verbessert. Wenn Sie mit einem Browser auf "http: // /" zugreifen, wird das aufgenommene Bild angezeigt. Bilddaten (von base64 konvertierte Daten) werden von Ajax erfasst und im Browser angezeigt.

Alle Codes sind unten aufgeführt. https://github.com/koki-iwaizumi/esp32-ov7725

Die Größe ist VGA und das Ausgabeformat ist YUV422. Bitte ändern Sie die Einstellungen rund um WLAN.

app_main.c



#include <string.h>
#include <esp_wifi.h>
#include <esp_event_loop.h>
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <esp_http_server.h>
#include <esp_camera.h>

#include "mbedtls/base64.h"
#include "cJSON.h"

#include "sensor.h"
#include "sccb.h"

/********* io ***********/
#define CAM_PIN_PWDN	2
#define CAM_PIN_RESET	15
#define CAM_PIN_XCLK	27
#define CAM_PIN_SIOD	25
#define CAM_PIN_SIOC	23
#define CAM_PIN_VSYNC	22
#define CAM_PIN_HREF	26
#define CAM_PIN_PCLK	21
#define CAM_PIN_D9		19
#define CAM_PIN_D8		36
#define CAM_PIN_D7		18
#define CAM_PIN_D6		39
#define CAM_PIN_D5		5
#define CAM_PIN_D4		34
#define CAM_PIN_D3		32
#define CAM_PIN_D2		35

/********* wifi ***********/
#define EXAMPLE_WIFI_SSID "*"
#define EXAMPLE_WIFI_PASS "*"

static const char *TAG = "APP";
sensor_t* sensor = NULL;

static camera_config_t camera_config = {
	.pin_pwdn  = CAM_PIN_PWDN,
	.pin_reset = CAM_PIN_RESET,
	.pin_xclk = CAM_PIN_XCLK,
	.pin_sscb_sda = CAM_PIN_SIOD,
	.pin_sscb_scl = CAM_PIN_SIOC,

	.pin_d7 = CAM_PIN_D9,
	.pin_d6 = CAM_PIN_D8,
	.pin_d5 = CAM_PIN_D7,
	.pin_d4 = CAM_PIN_D6,
	.pin_d3 = CAM_PIN_D5,
	.pin_d2 = CAM_PIN_D4,
	.pin_d1 = CAM_PIN_D3,
	.pin_d0 = CAM_PIN_D2,
	.pin_vsync = CAM_PIN_VSYNC,
	.pin_href = CAM_PIN_HREF,
	.pin_pclk = CAM_PIN_PCLK,

	.xclk_freq_hz = 6000000,
	.ledc_timer = LEDC_TIMER_0,
	.ledc_channel = LEDC_CHANNEL_0,

	.pixel_format = PIXFORMAT_YUV422,
	.frame_size = FRAMESIZE_VGA,

	.jpeg_quality = 12,
	.fb_count = 1
};

esp_err_t index_get_handler(httpd_req_t *req)
{
	extern const unsigned char index_start[] asm("_binary_index_html_start");
	extern const unsigned char index_end[]   asm("_binary_index_html_end");
	const size_t index_size = (index_end - index_start);

	httpd_resp_send_chunk(req, (const char *)index_start, index_size);
	httpd_resp_sendstr_chunk(req, NULL);

	return ESP_OK;
}

esp_err_t image_post_handler(httpd_req_t *req)
{
	int content_buf_size = 10 * 1000;
	char *content_buf = calloc(content_buf_size, sizeof(char));
    if(content_buf == NULL){
		ESP_LOGE(TAG, "Failed to allocate frame buffer - content_buf");
		httpd_resp_send_500(req);
		return ESP_FAIL;
    }

	if(httpd_req_recv(req, content_buf, req->content_len) <= 0){
		ESP_LOGE(TAG, "httpd_req_recv failed");
		httpd_resp_send_500(req);
		return ESP_FAIL;
	}

	ESP_LOGE(TAG, "httpd_req_recv content=%s", content_buf);

	cJSON *content_json = cJSON_Parse(content_buf);

	for(int i = 0; i <= 172; i++){
		char key[4];
		itoa(i,key,10);
		int value = strtol(cJSON_GetObjectItem(content_json, key)->valuestring, NULL, 16);

		SCCB_Write(sensor->slv_addr, i, value);
	}

	cJSON_Delete(content_json);
	free(content_buf);

	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){
		ESP_LOGE(TAG, "Camera capture failed");
		httpd_resp_send_500(req);
		return ESP_FAIL;
	}

	uint8_t *buf = NULL;
	size_t buf_len = 0;
	bool converted = frame2bmp(fb, &buf, &buf_len);
	esp_camera_fb_return(fb);
	if( ! converted){
		ESP_LOGE(TAG, "BMP conversion failed");
		httpd_resp_send_500(req);
		return ESP_FAIL;
	}

	ESP_LOGI(TAG, "esp_get_free_heap_size (%d bytes)", esp_get_free_heap_size());
	ESP_LOGI(TAG, "esp_get_minimum_free_heap_size (%d bytes)", esp_get_minimum_free_heap_size());
	ESP_LOGI(TAG, "heap_caps_get_free_size(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_free_size(MALLOC_CAP_8BIT));
	ESP_LOGI(TAG, "heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT));
	ESP_LOGI(TAG, "heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));

	int image_buf_size = 1300 * 1000;
	uint8_t *image_buf = calloc(image_buf_size, sizeof(char));
    if(image_buf == NULL){
		free(buf);
		ESP_LOGE(TAG, "Failed to allocate frame buffer - image_buf");
		httpd_resp_send_500(req);
		return ESP_FAIL;
    }

	size_t olen = 0;
	int base64_err = mbedtls_base64_encode(image_buf, image_buf_size, &olen, buf, buf_len);
	free(buf);
	if (base64_err != 0) {
		ESP_LOGE(TAG, "error base64 encoding, error %d, buff size: %d", base64_err, olen);
		httpd_resp_send_500(req);
		return ESP_FAIL;
	}

	ESP_LOGI(TAG, "esp_get_free_heap_size (%d bytes)", esp_get_free_heap_size());
	ESP_LOGI(TAG, "esp_get_minimum_free_heap_size (%d bytes)", esp_get_minimum_free_heap_size());
	ESP_LOGI(TAG, "heap_caps_get_free_size(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_free_size(MALLOC_CAP_8BIT));
	ESP_LOGI(TAG, "heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT));
	ESP_LOGI(TAG, "heap_caps_get_largest_free_block(MALLOC_CAP_8BIT) (%d bytes)", heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));

	uint8_t *image_json = calloc(image_buf_size, sizeof(char));
    if(image_json == NULL){
		free(image_buf);
		ESP_LOGE(TAG, "Failed to allocate frame buffer - image_json");
		httpd_resp_send_500(req);
		return ESP_FAIL;
    }

	sprintf((char *)image_json, "{\"image\":\"%s\"}", (const char *)image_buf);
	free(image_buf);
	ESP_LOGI(TAG, "image_json length=%d", strlen((const char*)image_json));

	res = httpd_resp_set_type(req, "application/json") || httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*") || httpd_resp_send(req, (const char *)image_json, strlen((const char*)image_json));
	free(image_json);

	int64_t fr_end = esp_timer_get_time();
	ESP_LOGI(TAG, "BMP: %uKB %ums", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000));
	return res;
}

esp_err_t config_get_handler(httpd_req_t *req)
{
	int data_json_size = 10 * 1000;
	char *data_json = calloc(data_json_size, sizeof(char));
    if(data_json == NULL){
		ESP_LOGE(TAG, "Failed to allocate frame buffer - data_json");
		httpd_resp_send_500(req);
		return ESP_FAIL;
    }

	strcat(data_json, "{");
	for(int i = 0; i <= 172; i++){
		char data_json_buf[255] = {'\0'};
		sprintf(data_json_buf, "\"%d\":\"%d\"", i, SCCB_Read(sensor->slv_addr, i));
		strcat(data_json, data_json_buf);
		if(i != 172) strcat(data_json, ",");
	}
	strcat(data_json, "}");

	ESP_LOGI(TAG, "data_json=%s", data_json);
	ESP_LOGI(TAG, "data_json length=%d", strlen((const char*)data_json));

	esp_err_t res = httpd_resp_set_type(req, "application/json") || httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*") || httpd_resp_send(req, (const char *)data_json, strlen((const char*)data_json));
	free(data_json);

	return res;
}

httpd_uri_t index_uri = {
	.uri = "/",
	.method = HTTP_GET,
	.handler = index_get_handler,
};

httpd_uri_t image_uri = {
	.uri = "/image",
	.method = HTTP_POST,
	.handler = image_post_handler,
};

httpd_uri_t config_uri = {
	.uri = "/config",
	.method = HTTP_GET,
	.handler = config_get_handler,
};

httpd_handle_t start_webserver(void)
{
	httpd_handle_t server = NULL;
	httpd_config_t config = HTTPD_DEFAULT_CONFIG();

	ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
	if(httpd_start(&server, &config) == ESP_OK){
		ESP_LOGI(TAG, "Registering URI handlers");
		httpd_register_uri_handler(server, &index_uri);
		httpd_register_uri_handler(server, &image_uri);
		httpd_register_uri_handler(server, &config_uri);
		return server;
	}

	ESP_LOGI(TAG, "Error starting server!");
	return NULL;
}

void stop_webserver(httpd_handle_t server)
{
	httpd_stop(server);
}

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
	httpd_handle_t *server = (httpd_handle_t *) ctx;

	switch(event->event_id){
		case SYSTEM_EVENT_STA_START:
			ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
			ESP_ERROR_CHECK(esp_wifi_connect());
			break;
		case SYSTEM_EVENT_STA_GOT_IP:
			ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
			ESP_LOGI(TAG, "Got IP: '%s'", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));

			if(*server == NULL){
				*server = start_webserver();
			}
			break;
		case SYSTEM_EVENT_STA_DISCONNECTED:
			ESP_LOGI(TAG, "SYSTEM_EVENT_STA_DISCONNECTED");
			ESP_ERROR_CHECK(esp_wifi_connect());

			if(*server){
				stop_webserver(*server);
				*server = NULL;
			}
			break;
		default:
			break;
	}
	return ESP_OK;
}

static void initialise_wifi(void *arg)
{
	tcpip_adapter_init();
	ESP_ERROR_CHECK(esp_event_loop_init(event_handler, arg));
	wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
	ESP_ERROR_CHECK(esp_wifi_init(&cfg));
	ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
	wifi_config_t wifi_config = {
		.sta = {
			.ssid = EXAMPLE_WIFI_SSID,
			.password = EXAMPLE_WIFI_PASS,
		},
	};
	ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
	ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
	ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
	ESP_ERROR_CHECK(esp_wifi_start());
}

void app_main()
{
	static httpd_handle_t server = NULL;
	ESP_ERROR_CHECK(nvs_flash_init());

	esp_err_t err = esp_camera_init(&camera_config);
	if(err != ESP_OK){
		ESP_LOGE(TAG, "Camera Init Failed");
		return;
	}

	sensor = esp_camera_sensor_get();

	initialise_wifi(&server);
}

Rund um HTML

index.html



<!doctype html>
<html lang="ja">
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
		<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.4/css/all.css">
		<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
		<title>OV7725</title>
		<style>
			.alert{
				display:none;
			}
			#overlay{   
				position: fixed;
				top: 0;
				z-index: 100;
				width: 100%;
				height:100%;
				display: none;
				background: rgba(0,0,0,0.6);
			}
			.cv-spinner{
				height: 100%;
				display: flex;
				justify-content: center;
				align-items: center;  
			}
			.spinner{
				width: 40px;
				height: 40px;
				border: 4px #ddd solid;
				border-top: 4px #2e93e6 solid;
				border-radius: 50%;
				animation: sp-anime 0.8s infinite linear;
			}
			@keyframes sp-anime{
				0% { 
					transform: rotate(0deg); 
				}
				100% { 
					transform: rotate(359deg); 
				}
			}
			.is-hide{
				display:none;
			}
			.ov_a{
				height:600px;
				overflow-y:auto;
			}
		</style>
	</head>
	<body>
 
		<div id="overlay">
			<div class="cv-spinner">
				<span class="spinner"></span>
			</div>
		</div>

		<div class="text-center mt-3 mb-3">
			<h1>OV7725</h1>
		</div>

		<div class="container-fluid">
			<div class="row">
				<div class="col-lg-6 text-center mb-4">
					<div class="row">
						<div class="col-md-12">
							<div class="alert alert-success" role="alert">success</div>
							<div class="alert alert-danger" role="alert">failed</div>
						</div>
						<div class="col-md-12">
							<img id="img" class="mw-100">
						</div>
						<div class="col-md-12 mt-4">
							<button id="image_button" type="button" class="btn btn-success w-100">Take a Picture</button>
						</div>
					</div>
				</div>

				<div class="col-lg-6">
					<div class="ov_a">
						<form id="form">
							<table id="table_regs" class="table table-striped">
								<tr>
									<th>Address(Hex)</th>
									<th>Value(Hex)</th>
								</tr>
							</table>
						</form>
					</div>
				</div>
			</div>
		</div>
 
		<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
		<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

		<script type="text/javascript">
			$(function(){

				var parseJson = function(data) {
					var returnJson = {};
					for(idx = 0; idx < data.length; idx++){
					returnJson[data[idx].name] = data[idx].value
					}
					return returnJson;
				};

				$(document).ready(function(){
					read_config();
					get_image();
				});

				$("#image_button").on("click", get_image);

				function get_image(){
					$.ajax({
						url: "./image",
						type: "POST",
						data: JSON.stringify(parseJson($("#form").serializeArray())),
						dataType: "json",
						beforeSend: function() {
							$(".alert").css("display", "none");
							$("#overlay").fadeIn(300);
						}
					})
					.done((data) => {
						$(".alert").css("display", "none");
						$(".alert-success").css("display", "block");
						$("#img").attr("src", "data:image/jpeg;base64," + data["image"]);
					})
					.fail((data) => {
						$(".alert").css("display", "none");
						$(".alert-danger").css("display", "block");
						console.log(data);
					})
					.always((data) => {
						setTimeout(function(){
							$("#overlay").fadeOut(300);
						},500);
					});
				}

				function read_config(){
					$.ajax({
						url: "./config",
						type: "GET",
						dataType: "json",
						async: false,
					})
					.done((data) => {
						$.each(data, function(i, item){
							$("#table_regs").append('<tr><td>0x' + Number(i).toString(16) + '</td><td><div class="input-group"><div class="input-group-prepend"><span class="input-group-text" id="text1a">0x</span></div><input name="' + i + '" value="' + Number(item).toString(16) + '" type="text" class="form-control"></div></td></tr>');
						});
					})
				}
			});
		</script>
	</body>
</html>

Recommended Posts

Verwendung des Kameramoduls OV7725 (ESP32-WROVER-B)
Verwendung der link_to-Methode
Verwendung der include? -Methode
Verwendung der Methode form_with
Verwendung der Wrapper-Klasse
[Java] Verwendung der File-Klasse
[Schienen] Verwendung der Kartenmethode
[Java] Verwendung der toString () -Methode
Studieren der Verwendung des Konstruktors (Java)
[Verarbeitung × Java] Verwendung der Schleife
[Verarbeitung × Java] Verwendung der Klasse
[Verarbeitung × Java] Verwendung der Funktion
[Java] Verwendung der Calendar-Klasse
Verwendung von Map
Wie benutzt man rbenv?
Verwendung mit_option
Verwendung von fields_for
Verwendung von java.util.logging
Verwendung der Karte
Verwendung von collection_select
Wie benutzt man Twitter4J
Wie benutzt man active_hash! !!
Verwendung von MapStruct
Ausgabe der Verwendung der Slice-Methode
Verwendung von TreeSet
[Verwendung des Etiketts]
Wie man Identität benutzt
Wie man Hash benutzt
Verwendung der replace () -Methode (Java Silver)
Verwendung von Dozer.mapper
Wie benutzt man Gradle?
Verwendung von org.immutables
Verwendung von java.util.stream.Collector
Verwendung von VisualVM
Verwendung von Map
[Ruby-Grundlagen] Verwendung der Slice-Methode
[Rails] Ich weiß nicht, wie ich das Modell verwenden soll ...
[Anfänger] Entdecken Sie das N + 1-Problem! Wie benutzt man Bullet?
Verwendung der Ketten-API
[Java] Verwendung von Map
Verwendung der Warteschlange mit Priorität
[Rails] Verwendung von Enum
Verwendung von Java Optional
Verwendung von JUnit (Anfänger)
Verwendung von Ruby return
[Rails] Verwendung von Enum
Verwendung von @Builder (Lombok)
Verwendung der Java-Klasse
Wie man Big Decimal benutzt
[Java] Verwendung von removeAll ()
Verwendung von String [] args