espressif / esp32-camera

Apache License 2.0
1.94k stars 644 forks source link

Changing framesize while capturing images in RGB565 and converting them to BMP leads to corrupt images #697

Open cnadler86 opened 4 weeks ago

cnadler86 commented 4 weeks ago

Checklist

How often does this bug occurs?

always

Expected behavior

I expect the image converted to be correct.

Actual behavior (suspected bug)

Some lines of the image are right, but some others don't.

Error logs or terminal output

No response

Steps to reproduce the behavior

Here is my code (its a micropython wrapper library):

Capture image:

mp_obj_t mp_camera_hal_capture(mp_camera_obj_t *self, int8_t out_format) {
if (!self->initialized) {
        mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Failed to capture image: Camera not initialized"));
    }
    if (self->captured_buffer) {
        esp_camera_fb_return(self->captured_buffer);
        self->captured_buffer = NULL;
    }

    static size_t out_len = 0;
    static uint8_t *out_buf = NULL;
    if (out_len>0 || out_buf) {
        free(out_buf);
        out_len = 0;
        out_buf = NULL;
    }

    ESP_LOGI(TAG, "Capturing image");
    self->captured_buffer = esp_camera_fb_get();
    if (!self->captured_buffer) {
        ESP_LOGE(TAG, "Failed to capture image");
        return mp_const_none;
    }

    if (out_format >= 0 && (mp_camera_pixformat_t)out_format != self->camera_config.pixel_format) {
        switch (out_format) {
            case PIXFORMAT_JPEG:
                if (frame2jpg(self->captured_buffer, self->camera_config.jpeg_quality, &out_buf, &out_len)) {
                    esp_camera_fb_return(self->captured_buffer);
                    mp_obj_t result = mp_obj_new_memoryview('b', out_len, out_buf);
                    return result;
                } else {
                    return mp_const_none;
                }

            case PIXFORMAT_RGB888:
                out_len = self->captured_buffer->width * self->captured_buffer->height * 3;
                out_buf = (uint8_t *)malloc(out_len);
                if (!out_buf) {
                    ESP_LOGE(TAG, "out_buf malloc failed");
                    return mp_const_none;
                }
                if (fmt2rgb888(self->captured_buffer->buf, self->captured_buffer->len, self->captured_buffer->format, out_buf)) {
                    esp_camera_fb_return(self->captured_buffer);
                    mp_obj_t result = mp_obj_new_memoryview('b', out_len, out_buf);
                    return result;
                } else {
                    return mp_const_none;
                }

            default:
                ESP_LOGI(TAG, "Returning image as bitmap");
                if (frame2bmp(self->captured_buffer, &out_buf, &out_len)) {
                    esp_camera_fb_return(self->captured_buffer);
                    mp_obj_t result = mp_obj_new_memoryview('b', out_len, out_buf);
                    return result;
                } else {
                    return mp_const_none;
                }
        }
    }

    if (self->camera_config.pixel_format == PIXFORMAT_JPEG) {
        ESP_LOGI(TAG, "Captured image in JPEG format");
        return mp_obj_new_memoryview('b', self->captured_buffer->len, self->captured_buffer->buf);
    } else {
        ESP_LOGI(TAG, "Returning image as bitmap");
        if (frame2bmp(self->captured_buffer, &out_buf, &out_len)) {
            esp_camera_fb_return(self->captured_buffer);
            mp_obj_t result = mp_obj_new_memoryview('b', out_len, out_buf);
            return result;
        } else {
            return mp_const_none;
        }
    }
}

Change Framesize:

void mp_camera_hal_set_frame_size(mp_camera_obj_t * self, framesize_t value) {
    if (!self->initialized) {
        mp_raise_ValueError(MP_ERROR_TEXT("Camera not initialized"));
    }
    sensor_t *sensor = esp_camera_sensor_get();
    if (!sensor->set_framesize) {
        mp_raise_ValueError(MP_ERROR_TEXT("No attribute frame_size"));
    }
    if (sensor->set_framesize(sensor, value) < 0) {
        mp_raise_ValueError(MP_ERROR_TEXT("Invalid setting for frame_size"));
    } else {
        self->camera_config.frame_size = value;
    }
}

Project release version

latest

System architecture

Intel/AMD 64-bit (modern PC, older Mac)

Operating system

Linux

Operating system version

ubuntu 2204 on WSL

Shell

Bash

Additional context

No response

cnadler86 commented 4 weeks ago

This doesn't happen when converting from jpeg. Also, if I return to the initial frame size, the image is once again correct.

Here one screenshot (changed from QQVGA to QVGA): image