raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
891 stars 188 forks source link

how to Optimize Raspberry Pi Camera V3 for Fast 12MP Image Capture in DIY Book Scanner #926

Closed konos93 closed 3 months ago

konos93 commented 10 months ago

I am currently working on a DIY book scanner project using a Raspberry Pi Camera V3 with 12 megapixels. I have tried using both libcamera and picamera2 to capture images, but I am facing performance issues. The capture process takes more than 6 seconds for each image, which is not ideal for my application.

has ever anybody use a camera on raspberry that capture images but not from the frame of the video? i need 12 mp because i need the most possible detail from the image of the book page.

i think that camera open and close in raspberry while i use the code but i did not find something that keep it open. ok probabply is of topic but the same sensors on smarphone can capture on the same resolution in much less than a sec .

import subprocess
import os
import re
import time
import RPi.GPIO as GPIO

output_folder = "your_output_folder"  # Replace with your desired output folder
base_filename = "image"
file_extension = "jpg"
gpio_pin = 18  # GPIO pin to use

if not os.path.exists(output_folder):
    os.makedirs(output_folder)

# Find the last image file in the folder
existing_files = [f for f in os.listdir(output_folder) if f.endswith(f".{file_extension}")]
if existing_files:
    last_file = max(existing_files, key=lambda x: int(re.search(r'\d+', x).group()))
    last_number = int(re.search(r'\d+', last_file).group())
else:
    last_number = 0

GPIO.setmode(GPIO.BCM)
GPIO.setup(gpio_pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

while True:
    GPIO.wait_for_edge(gpio_pin, GPIO.FALLING)

    # Record the start time
    start_time = time.time()

    # Increment the counter
    last_number += 1

    # Generate the output filename
    output_filename = f"{base_filename}{last_number:04d}.{file_extension}"
    output_path = os.path.join(output_folder, output_filename)

    # Run the libcamera-jpeg command
    command = ["libcamera-jpeg", "-n", "-o", output_path]
    subprocess.run(command)

    # Calculate and print the elapsed time with 1 decimal place
    end_time = time.time()
    elapsed_time = round(end_time - start_time, 1)
    print(f"Image captured: {output_filename}, Elapsed Time: {elapsed_time} seconds")

result

User
[0:24:08.427953396] [2517]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:24:08.581691708] [2523]  WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[0:24:08.588225484] [2523]  INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx708@1a to Unicam device /dev/media3 and ISP device /dev/media0
[0:24:08.588380899] [2523]  INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
Mode selection for 2304:1296:12:P
    SRGGB10_CSI2P,1536x864/0 - Score: 3400
    SRGGB10_CSI2P,2304x1296/0 - Score: 1000
    SRGGB10_CSI2P,4608x2592/0 - Score: 1900
Stream configuration adjusted
[0:24:08.591796900] [2517]  INFO Camera camera.cpp:1183 configuring streams: (0) 2304x1296-YUV420 (1) 2304x1296-SBGGR10_CSI2P
[0:24:08.592701680] [2523]  INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected unicam format: 2304x1296-pBAA
Mode selection for 4608:2592:12:P
    SRGGB10_CSI2P,1536x864/0 - Score: 10600
    SRGGB10_CSI2P,2304x1296/0 - Score: 8200
    SRGGB10_CSI2P,4608x2592/0 - Score: 1000
[0:24:13.816165872] [2517]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-YUV420 (1) 4608x2592-SBGGR10_CSI2P
[0:24:13.824487022] [2523]  INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected unicam format: 4608x2592-pBAA
Still capture image received
Image captured: image0040.jpg, Elapsed Time: 9.4 seconds
dgalland commented 10 months ago

Hi,

Running libcamera-jpeg as a command line in a subprocess is certainly not the most efficient way to do a capture, there is the cost of launching a process and the camera is restarted each time with probably an additional delay of stabilization. You must therefore use picamera2 and take inspiration from the capture_jpeg.pi example

davidplowman commented 10 months ago

Hi,

Running libcamera-jpeg as a command line in a subprocess is certainly not the most efficient way to do a capture, there is the cost of launching a process and the camera is restarted each time with probably an additional delay of stabilization. You must therefore use picamera2 and take inspiration from the capture_jpeg.pi example

Agree 100%. Use Picamera2. Configure the camera in full resolution stills mode with at least 2 buffers. Leave the camera running.

Do the capture when the trigger happens.

If it's important that no pixel started to expose before the moment of the trigger, then call capture_request with flush=True.

It will look a bit like this (untested):

from picamera2 import Picamera2

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)
picam2.start()

# wait for your trigger, then:
request = picam2.capture_request(flush=True)
request.save('main', "file.jpg")
request.release()
konos93 commented 10 months ago

i will try something like this

import RPi.GPIO as GPIO
from picamera2 import Picamera2
import time
from datetime import datetime

# Set up GPIO 18 as an input with pull-up
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)
picam2.start()

# Wait for GPIO 18 to go low
while GPIO.input(18):
    time.sleep(0.1)

# When GPIO 18 goes low, capture an image
request = picam2.capture_request(flush=True)

# Generate a timestamp and include it in the filename
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"file_{timestamp}.jpg"

request.save('main', filename)
request.release()

# Clean up GPIO
GPIO.cleanup()
konos93 commented 10 months ago

i am very satisfied with the results thanks for your comments and your great tools u develop i used that on rasbery pi 3b+

i will try to test with a second camera on raspberry pi5 . how to use 2 camera with this code ? (i am not sure here if i shall make a new question your repository ). will it be around 1 sec . i will capture some book pages and i will upload them here asking more question about .

i used this with gpio

import RPi.GPIO as GPIO
from picamera2 import Picamera2
import time
from datetime import datetime

# Set up GPIO 18 as an input with pull-up
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=1)
picam2.configure(config)
picam2.start()

try:
    while True:
        # Wait for GPIO 18 to go low
        while GPIO.input(18):
            time.sleep(0.1)

        # Record the start time
        start_time = time.time()

        # When GPIO 18 goes low, capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"file_{timestamp}.jpg"

        request = picam2.capture_request(flush=True)
        request.save('main', filename)
        request.release()

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken
        capture_time = end_time - start_time
        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds")

        # Wait for GPIO 18 to go high again (to prevent multiple captures on a single press)
        while not GPIO.input(18):
            time.sleep(0.1)

except KeyboardInterrupt:
    pass
finally:
    # Clean up GPIO
    GPIO.cleanup()
    picam2.stop()

results

[1:26:37.145669248] [3223]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:26:37.311021339] [3229]  WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[1:26:37.317354895] [3229]  INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx708@1a to Unicam device /dev/media3 and ISP device /dev/media0
[1:26:37.317603540] [3229]  INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[1:26:37.327167389] [3223]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:26:37.427623251] [3232]  WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[1:26:37.433518476] [3232]  INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx708@1a to Unicam device /dev/media3 and ISP device /dev/media0
[1:26:37.433667329] [3232]  INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[1:26:37.452664456] [3223]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-SBGGR10_CSI2P
[1:26:37.453633356] [3232]  INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected unicam format: 4608x2592-pBAA
Image captured: file_20240118_043222.jpg, Time taken: 1.06 seconds
Image captured: file_20240118_043224.jpg, Time taken: 1.09 seconds
Image captured: file_20240118_043226.jpg, Time taken: 0.95 seconds

and with keyboard

import keyboard
from picamera2 import Picamera2
import time
from datetime import datetime

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=1)
picam2.configure(config)
picam2.start()

try:
    while True:
        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Record the start time
        start_time = time.time()

        # Capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"file_{timestamp}.jpg"

        request = picam2.capture_request(flush=True)
        request.save('main', filename)
        request.release()

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken
        capture_time = end_time - start_time
        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
    picam2.stop()

results i think is slightly slower


User
 [1:37:27.046278964] [3437]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:37:27.146640856] [3443]  WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[1:37:27.152654707] [3443]  INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx708@1a to Unicam device /dev/media3 and ISP device /dev/media0
[1:37:27.152879340] [3443]  INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[1:37:27.159286677] [3437]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:37:27.256174174] [3446]  WARN RPiSdn sdn.cpp:39 Using legacy SDN tuning - please consider moving SDN inside rpi.denoise
[1:37:27.261940892] [3446]  INFO RPI vc4.cpp:444 Registered camera /base/soc/i2c0mux/i2c@1/imx708@1a to Unicam device /dev/media3 and ISP device /dev/media0
[1:37:27.262091672] [3446]  INFO RPI pipeline_base.cpp:1142 Using configuration file '/usr/share/libcamera/pipeline/rpi/vc4/rpi_apps.yaml'
[1:37:27.280776448] [3437]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-SBGGR10_CSI2P
[1:37:27.281792376] [3446]  INFO RPI vc4.cpp:608 Sensor: /base/soc/i2c0mux/i2c@1/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected unicam format: 4608x2592-pBAA
 Image captured: file_20240118_044312.jpg, Time taken: 1.88 seconds
 Image captured: file_20240118_044315.jpg, Time taken: 1.12 seconds
 Image captured: file_20240118_044317.jpg, Time taken: 1.01 seconds
 Image captured: file_20240118_044318.jpg, Time taken: 1.05 seconds
konos93 commented 10 months ago

on raspbery pi5 brilliant how fast would it be if i add a second camera? what changes should i do ? i didn't see so much different between keyboard and gpio Image captured: file_20240118_053824.jpg, Time taken: 0.29 seconds Image captured: file_20240118_053825.jpg, Time taken: 0.39 seconds Image captured: file_20240118_053826.jpg, Time taken: 0.38 seconds Image captured: file_20240118_053827.jpg, Time taken: 0.41 seconds Image captured: file_20240118_053828.jpg, Time taken: 0.38 seconds

davidplowman commented 10 months ago

You can open a second camera with

picam2_1 = Picamera2(1)

and configure and start it in the same way.

To capture both images as quickly as possible after the trigger you could use a thread per camera. Each thread would wait for the trigger and do the capture in the same way as you did before. Doing it in a single thread is a bit trickier because (I assume) you don't want to wait for the first capture to finish before asking for the second. Nonetheless, I think the 2 thread solution is probably better.

BTW, I notice you have buffer_count=1 in your code. I would recommend increasing that to at least 2 if you can. The value 1 means that every other camera frame gets dropped, so that you're running at effectively half the framerate. This will increase the capture latency, though obviously there's no effect on the time spent encoding the image.

konos93 commented 10 months ago

ok i change the buffer to 3 should i do something for autofocus or for the module v3 doestn't need to ?

konos93 commented 10 months ago

it does not seem to auto focus zfile_20240118_154622

davidplowman commented 10 months ago

TBH I'm not sure if it enables autofocus automatically or not, but it doesn't look like it. Check out section 5.2 of the manual.

konos93 commented 10 months ago

i think that work fine

i will try and with gpio to have liveview from the camera because qt ask permission and i already run the script with root permissions

import keyboard
from picamera2 import Picamera2
import time
from datetime import datetime
from libcamera import controls
import os

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)
picam2.start(show_preview=False)
picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})

try:
    while True:

        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Record the start time
        start_time = time.time()

        # Capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"z_img_{timestamp}.jpg"

        request = picam2.capture_request(flush=True)
        request.save('main', filename)
        request.release()

        # Get the size of the captured image in bytes
        file_size_bytes = os.path.getsize(filename)

        # Convert the file size to megabytes
        file_size_mb = file_size_bytes / (1024 ** 2)

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken and the size of the image in megabytes
        capture_time = end_time - start_time

        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
        picam2.stop()

results

^Ckonos93@raspberrypi:~/Desktop/camera $ sudo python k.py 
[1:06:13.537387199] [5054]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:06:13.551804215] [5060]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:06:13.562088602] [5060]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[1:06:13.563516768] [5054]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:06:13.581083617] [5063]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:06:13.591861763] [5063]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[1:06:13.594569762] [5054]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[1:06:13.594628188] [5054]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[1:06:13.594636373] [5054]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[1:06:13.594646132] [5054]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[1:06:13.595732169] [5054]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[1:06:13.595897891] [5063]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
 Image captured: z_img_20240118_173253.jpg, Time taken: 0.37 seconds, Size: 1.68 MB
 Image captured: z_img_20240118_173254.jpg, Time taken: 0.30 seconds, Size: 1.72 MB
 Image captured: z_img_20240118_173255.jpg, Time taken: 0.34 seconds, Size: 1.84 MB

z_img_20240118_173255

konos93 commented 10 months ago

for some reason qt preview is gray .why ?

import RPi.GPIO as GPIO
import keyboard
from picamera2 import Picamera2
import time
from datetime import datetime
from libcamera import controls
import os

# Set up GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_UP)

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)
picam2.start(show_preview=True)
picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})

try:
    while True:
        # Wait for the GPIO pin to be triggered (falling edge)
        GPIO.wait_for_edge(18, GPIO.FALLING)

        # Record the start time
        start_time = time.time()

        # Capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"z_img_{timestamp}.jpg"

        request = picam2.capture_request(flush=True)
        request.save('main', filename)
        request.release()

        # Get the size of the captured image in bytes
        file_size_bytes = os.path.getsize(filename)

        # Convert the file size to megabytes
        file_size_mb = file_size_bytes / (1024 ** 2)

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken and the size of the image in megabytes
        capture_time = end_time - start_time

        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
    picam2.stop()
    GPIO.cleanup()
results
    [2:17:23.969790214] [6849]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[2:17:23.984230690] [6860]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[2:17:23.994279532] [6860]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[2:17:23.996332571] [6849]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[2:17:24.017796535] [6863]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[2:17:24.031213862] [6863]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[2:17:24.040600482] [6849]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[2:17:24.040722389] [6849]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[2:17:24.040731426] [6849]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[2:17:24.040740389] [6849]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[2:17:24.041921761] [6849]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[2:17:24.042136076] [6863]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
Image captured: z_img_20240118_184406.jpg, Time taken: 0.33 seconds, Size: 1.14 MB
Image captured: z_img_20240118_184407.jpg, Time taken: 0.31 seconds, Size: 1.18 MB
Image captured: z_img_20240118_184408.jpg, Time taken: 0.38 seconds, Size: 1.19 MB
Image captured: z_img_20240118_184408.jpg, Time taken: 0.36 seconds, Size: 1.19 MB
Image captured: z_img_20240118_184409.jpg, Time taken: 0.34 seconds, Size: 1.19 MB
davidplowman commented 10 months ago

Don't know. Is this a colour or a NoIR camera? Do you have any other cameras to try?

konos93 commented 10 months ago

color camera i found that there also some apps https://github.com/raspberrypi/picamera2/tree/main/apps

i run app_capture_af.py

lol it does the job that i want

but why show_preview=True doesnt work

i mean in app_2 resuls is like this

[2:36:30.168744736] [7530]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[2:36:30.182973516] [7536]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[2:36:30.193782837] [7536]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[2:36:30.195495669] [7530]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[2:36:30.219480716] [7539]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[2:36:30.236342215] [7539]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[2:36:30.240150785] [7530]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[2:36:30.240197248] [7530]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[2:36:30.240205526] [7530]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[2:36:30.240214951] [7530]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[2:36:30.241611672] [7530]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[2:36:30.241886468] [7539]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.

with the qt app vieo

konos93 commented 10 months ago

ok seems that this is ideal

https://github.com/raspberrypi/picamera2/blob/main/apps/app_full.py

konos93 commented 10 months ago

sorry that i reopen this is some comments for app_full.py it needs some changes for diybookscanner like press space or use gpio to capture and save img like img_00040.jpg ,img_00041.jpg or with time like smartphones . it also needs a second gui with preview and settings for the second camera.

now main examples from datasheet and scripts with qt preview work fine

here why does not work the preview or stuck i mean its like starting it open a qt square with no image but cant press space or anthing


import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from libcamera import controls
import os

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)
picam2.start(show_preview=False) # (show_preview=True) to see the grey qr code
#picam2.start_preview(Preview.DRM)
#picam2.start_preview(Preview.QTGL)
#picam2.start_preview(Preview.QT)
#picam2.start_preview(Preview.NULL)
picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous })
#picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 4.5})# use the app_full.py to check the #better lens potition or use afmode and keep the images with the most size 

try:
    while True:

        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Record the start time
        start_time = time.time()

        # Capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"z_img_{timestamp}.jpg"

        request = picam2.capture_request(flush=True)
        request.save('main', filename)
        request.release()

        # Get the size of the captured image in bytes
        file_size_bytes = os.path.getsize(filename)

        # Convert the file size to megabytes
        file_size_mb = file_size_bytes / (1024 ** 2)

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken and the size of the image in megabytes
        capture_time = end_time - start_time

        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
    picam2.stop()
davidplowman commented 10 months ago

Hi again, I'm afraid you're going to have to do some debugging. For example:

As regards app_full.py, it's just an example. It's not designed for any purpose other than to educate users. If you want it to do something different, the software license lets you copy and reuse the code in any way that you want. If you would like to submit demo applications back to us, we're also very happy to take those.

konos93 commented 9 months ago

this seems to work fine for one camera and preview with auto focus i will add a second camera and a second preview window if i stuck again i will ask help here

import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from libcamera import controls
import os

picam2 = Picamera2()
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)   
picam2.start_preview(Preview.QTGL)
preview_config = picam2.create_preview_configuration({"size": (4096, 2592)})
picam2.configure(preview_config)

picam2.start()

picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous })

try:
    while True:

        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Record the start time
        start_time = time.time()

        # Capture an image
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        filename = f"z_img_{timestamp}.jpg"

        request = picam2.capture_request(flush=False  )
        request.save('main', filename)
        request.release()

        # Get the size of the captured image in bytes
        file_size_bytes = os.path.getsize(filename)

        # Convert the file size to megabytes
        file_size_mb = file_size_bytes / (1024 ** 2)

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken and the size of the image in megabytes
        capture_time = end_time - start_time

        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
    picam2.stop()

logs


>>> %Run 'press_space_to capture.py'
[0:57:27.857192152] [6099]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:57:27.872073930] [6109]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:57:27.976497693] [6109]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:57:27.978079356] [6099]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:57:27.995217462] [6112]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:57:28.132719052] [6112]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:57:28.135331546] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:57:28.135365601] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:57:28.135371416] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:57:28.135377657] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:57:28.136097877] [6099]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:57:28.136233192] [6112]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
[0:57:30.141689863] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:57:30.141772474] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:57:30.141780900] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:57:30.141788159] [6099]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:57:30.143012323] [6099]  INFO Camera camera.cpp:1183 configuring streams: (0) 4096x2592-XBGR8888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:57:30.143355840] [6112]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
Image captured: z_img_20240125_040611.jpg, Time taken: 0.21 seconds, Size: 1.53 MB
Image captured: z_img_20240125_040613.jpg, Time taken: 0.17 seconds, Size: 1.54 MB
Image captured: z_img_20240125_040614.jpg, Time taken: 0.18 seconds, Size: 1.54 MB
Image captured: z_img_20240125_040614.jpg, Time taken: 0.17 seconds, Size: 1.54 MB
Image captured: z_img_20240125_040615.jpg, Time taken: 0.17 seconds, Size: 1.54 MB
Image captured: z_img_20240125_040654.jpg, Time taken: 0.20 seconds, Size: 1.52 MB
Image captured: z_img_20240125_040654.jpg, Time taken: 0.21 seconds, Size: 1.52 MB
Image captured: z_img_20240125_040659.jpg, Time taken: 0.18 seconds, Size: 1.52 MB
konos93 commented 9 months ago

does pi camera 2 support something like crosshair and grid lines ?

to use one camera v3

import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from datetime import datetime
from libcamera import controls
import os

picam2 = Picamera2() # if u have one camera it will try to check it
#if u have alrerd two connected and wanna use only one use Picamera2(1) or Picamera2(1)
config = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config)   

picam2.start_preview(Preview.QTGL)
preview_config = picam2.create_preview_configuration({"size": (4096, 2592)})
picam2.configure(preview_config)

picam2.start()

picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous })

try:
    while True:

        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Record the start time
        start_time = time.time()

        # Capture an image
        timeStamp = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-4]
        filename = f"z_img_{timeStamp}.jpg"

        request = picam2.capture_request(flush=False  )
        request.save('main', filename)
        request.release()

        # Get the size of the captured image in bytes
        file_size_bytes = os.path.getsize(filename)

        # Convert the file size to megabytes
        file_size_mb = file_size_bytes / (1024 ** 2)

        # Record the end time
        end_time = time.time()

        # Calculate and print the time taken and the size of the image in megabytes
        capture_time = end_time - start_time

        print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

except KeyboardInterrupt:
    pass
finally:
    # Clean up
    picam2.stop_preview()
    picam2.stop()

for two camera v3


import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from libcamera import controls
import os

def capture_image(picam2, filename_prefix):
    # Record the start time
    start_time = time.time()

    # Capture an image
    timeStamp = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-4]
    filename = f"{filename_prefix}_img_{timeStamp}.jpg"

    request = picam2.capture_request(flush=False)
    request.save('main', filename)
    request.release()

    # Get the size of the captured image in bytes
    file_size_bytes = os.path.getsize(filename)

    # Convert the file size to megabytes
    file_size_mb = file_size_bytes / (1024 ** 2)

    # Record the end time
    end_time = time.time()

    # Calculate and print the time taken and the size of the image in megabytes
    capture_time = end_time - start_time

    print(f"Image captured: {filename}, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

# Set up the first camera
picam1 = Picamera2(1)
config1 = picam1.create_still_configuration(buffer_count=3)
picam1.configure(config1)
picam1.start_preview(Preview.QTGL)
preview_config1 = picam1.create_preview_configuration({"size": (4096, 2592)})
picam1.configure(preview_config1)
picam1.start()
picam1.set_controls({"AfMode": controls.AfModeEnum.Continuous})

# Set up the second camera
picam2 = Picamera2(0)
config2 = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config2)
picam2.start_preview(Preview.QTGL)
preview_config2 = picam2.create_preview_configuration({"size": (4096, 2592)})
picam2.configure(preview_config2)
picam2.start()
picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous})

try:
    while True:
        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Capture images from both cameras
        capture_image(picam1, "y")
        capture_image(picam2, "x")

except KeyboardInterrupt:
    pass
finally:
    # Close QtGL preview windows
    picam1.stop_preview()
    picam2.stop_preview()

    # Clean up both cameras
    picam1.stop()
    picam2.stop()
konos93 commented 9 months ago

ok i will use the app_capture_overlay.py before i use what script we made .

if u wanna have lens opposite from a glass u have to see in the middle the lens on a mirror
0-02-05-d9816ea46b3ab0f83af6eb8c6238353aeb8717fc12723176df99ad35166b77ef_ebee972a2f0c6dd6

and the scanner

0-02-05-6896ef5fb48f200be28bfb9aaf85ebad41cf47fec296d76d3ad1948e2bced6fd_3c7b8bd833e9064

davidplowman if u ever be in athens let me know to grab u a beer . your comments made a great work for future diybookscanner projects

konos93 commented 9 months ago

2024-01-26 12_26_29-Fullscreen Projector (Preview)

konos93 commented 9 months ago

em hello again i made this its a ^shape diybookscanner 0-02-05-bcc4791cf2861f8fcec76c0f5252b687147abc79b4516a4eda6b30865a0902b8_a7a1b0c3a9978dfc

how to reduce the time that camera calibrate whiteness , brightness i dont know how to tell it it happen every time i flat a new page on the glass here is a video that probably help u

https://www.youtube.com/watch?v=aqaoUlu7En0 also i there any way if i use auto focus to check at what lens potition the camera capture ?

import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from libcamera import controls
import os

def capture_image(picam, filename_prefix, save_path):
    # Record the start time

    start_time = time.time()

    # Capture an image
    timeStamp = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-4]
    filename = os.path.join(save_path, f"{filename_prefix}_img_{timeStamp}.jpg")

    request = picam.capture_request(flush=False)
    request.save('main', filename)
    request.release()

    # Get the size of the captured image in bytes
    file_size_bytes = os.path.getsize(filename)

    # Convert the file size to megabytes
    file_size_mb = file_size_bytes / (1024 ** 2)

    # Record the end time
    end_time = time.time()

    # Calculate and print the time taken and the size of the image in megabytes
    capture_time = end_time - start_time

    print(f"Image captured: {filename_prefix}_img_{timeStamp}.jpg, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

# Specify the desired paths for both cameras
save_path1 = "/home/konos93/Desktop/camera/your_output_folder1"
save_path2 = "/home/konos93/Desktop/camera/your_output_folder2"

# Set up the first camera
picam1 = Picamera2(1)
config1 = picam1.create_still_configuration(buffer_count=3)
picam1.configure(config1)
picam1.start_preview(Preview.QTGL)
preview_config1 = picam1.create_preview_configuration({"size": (4096, 2592)})
picam1.configure(preview_config1)
picam1.start()
#picam1.set_controls({"AfMode": controls.AfModeEnum.Continuous, "AfSpeed": controls.AfSpeedEnum.Fast})
picam1.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 5.1}) #use first app_full.py to check the focus

# Set up the second camera
picam2 = Picamera2(0)
config2 = picam2.create_still_configuration(buffer_count=3)
picam2.configure(config2)
picam2.start_preview(Preview.QTGL)
preview_config2 = picam2.create_preview_configuration({"size": (4096, 2592)})
picam2.configure(preview_config2)
picam2.start()
#picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous, "AfSpeed": controls.AfSpeedEnum.Fast})
picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 5.1}) #use first app_full.py to check the focus

try:
    while True:
        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Capture images from both cameras
        capture_image(picam1, "y", save_path1)
        capture_image(picam2, "x", save_path2)

except KeyboardInterrupt:
    pass
finally:
    # Close QtGL preview windows
    picam1.stop_preview()
    picam2.stop_preview()

    # Clean up both cameras
    picam1.stop()
    picam2.stop() 

results


>>> %Run 2_camera_manual_Af.py
[1:04:30.695140035] [4524]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:04:30.718554042] [4532]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:04:30.819736367] [4532]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media2 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[1:04:30.819841182] [4532]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:04:30.925311964] [4532]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media1 using PiSP variant BCM2712_C0
[1:04:30.927383229] [4524]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[1:04:30.951505311] [4537]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:04:31.067004490] [4537]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media2 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[1:04:31.067100212] [4537]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[1:04:31.168611909] [4537]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media1 using PiSP variant BCM2712_C0
[1:04:31.171646343] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[1:04:31.171691473] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[1:04:31.171697158] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[1:04:31.171704769] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[1:04:31.172718642] [4524]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[1:04:31.172884087] [4537]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
[1:04:32.823625602] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[1:04:32.823671047] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[1:04:32.823676343] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[1:04:32.823683158] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[1:04:32.824641031] [4524]  INFO Camera camera.cpp:1183 configuring streams: (0) 4096x2592-XBGR8888 (1) 4608x2592-BGGR16_PISP_COMP1
[1:04:32.824849180] [4537]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[1:04:33.085609449] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[1:04:33.085664301] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[1:04:33.085669987] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[1:04:33.085677561] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[1:04:33.086325655] [4524]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[1:04:33.086517989] [4537]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[1:04:33.261567734] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[1:04:33.261643475] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[1:04:33.261648734] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[1:04:33.261656438] [4524]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[1:04:33.262404329] [4524]  INFO Camera camera.cpp:1183 configuring streams: (0) 4096x2592-XBGR8888 (1) 4608x2592-BGGR16_PISP_COMP1
[1:04:33.262658533] [4537]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
Image captured: y_img_20240202-151237.71.jpg, Time taken: 0.26 seconds, Size: 1.48 MB
Image captured: x_img_20240202-151237.98.jpg, Time taken: 0.18 seconds, Size: 1.74 MB
Image captured: y_img_20240202-151251.65.jpg, Time taken: 0.23 seconds, Size: 1.90 MB
Image captured: x_img_20240202-151251.88.jpg, Time taken: 0.22 seconds, Size: 2.09 MB
Image captured: y_img_20240202-151304.23.jpg, Time taken: 0.19 seconds, Size: 1.86 MB
Image captured: x_img_20240202-151304.41.jpg, Time taken: 0.22 seconds, Size: 1.79 MB
Image captured: y_img_20240202-151321.06.jpg, Time taken: 0.19 seconds, Size: 1.75 MB
Image captured: x_img_20240202-151321.25.jpg, Time taken: 0.21 seconds, Size: 1.59 MB
Image captured: y_img_20240202-151334.13.jpg, Time taken: 0.23 seconds, Size: 1.87 MB
Image captured: x_img_20240202-151334.37.jpg, Time taken: 0.21 seconds, Size: 1.85 MB
davidplowman commented 9 months ago

Could you simply disable the AEC when you do the first capture?

konos93 commented 9 months ago

picam.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 5.1, "AeEnable": False})

works beautiful .

if i use auto focus is there any way to check at what lens position the camera captured the page ?

davidplowman commented 9 months ago

Yes, if you look in the image metadata of the captured image there should be some 'LensPosition' metadata.

konos93 commented 9 months ago

should i use metadata_with_image.py or i will use any program ?

davidplowman commented 9 months ago

Looking at your code above, once you've captured your request you should be able to do:

lens_position = request.get_metadata()['LensPosition']
picam2.set_controls({'LensPosition': lens_position})
konos93 commented 9 months ago

is it possible to auto-focus on range of specific lenspotition around 4 and 6 ? i think that i need to change the way the preview work in what i made

i used app_capture_af.py if i run it on two terminals for 2 camera it seems it work faster in the auto focus here is a video for help first is app_capture_af.py after 18 sec is what i made [(https://www.youtube.com/watch?v=0nzq46YIENE)]

the results are like that if i press one time capture button

>>> %Run app_capture_af.py
[0:04:40.089132883] [2470]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:04:40.114705396] [2479]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:04:40.127852140] [2479]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:04:40.127953231] [2479]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:04:40.128731185] [2479] ERROR V4L2 v4l2_device.cpp:353 'imx708': Unable to set controls: Device or resource busy
[0:04:40.140561332] [2479]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media3 using PiSP variant BCM2712_C0
[0:04:40.143722649] [2470]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:04:40.167272555] [2484]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:04:40.183179805] [2484]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:04:40.183282712] [2484]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:04:40.183956871] [2484] ERROR V4L2 v4l2_device.cpp:353 'imx708': Unable to set controls: Device or resource busy
[0:04:40.197139743] [2484]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media3 using PiSP variant BCM2712_C0
[0:04:40.200718019] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:04:40.200786592] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:04:40.200792240] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:04:40.200801333] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:04:40.201900006] [2470]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[0:04:40.202126040] [2484]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
[0:04:48.688420655] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:04:48.688495469] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:04:48.688503302] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:04:48.688512561] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:04:48.689610513] [2470]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:04:48.696944794] [2484]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[0:04:49.343240722] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:04:49.343311629] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:04:49.343318462] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:04:49.343328517] [2470]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:04:49.344277397] [2470]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[0:04:49.352228672] [2484]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B

if i run mine

import keyboard
from picamera2 import Picamera2, Preview
import time
from datetime import datetime
from libcamera import controls
import os

def capture_image(picam, filename_prefix, save_path):
    # Record the start time
    start_time = time.time()

    # Capture an image
    timeStamp = datetime.now().strftime("%Y%m%d-%H%M%S.%f")[:-4]
    filename = os.path.join(save_path, f"{filename_prefix}_img_{timeStamp}.jpg")

    request = picam.capture_request(flush=False)
    request.save('main', filename)
    request.release()

    # Get the size of the captured image in bytes
    file_size_bytes = os.path.getsize(filename)

    # Convert the file size to megabytes
    file_size_mb = file_size_bytes / (1024 ** 2)

    # Record the end time
    end_time = time.time()

    # Calculate and print the time taken and the size of the image in megabytes
    capture_time = end_time - start_time

    print(f"Image captured: {filename_prefix}_img_{timeStamp}.jpg, Time taken: {capture_time:.2f} seconds, Size: {file_size_mb:.2f} MB")

# Specify the desired paths for both cameras
save_path1 = "/home/konos93/Desktop/camera/your_output_folder1"
save_path2 = "/home/konos93/Desktop/camera/your_output_folder2"

# Set up the first camera
picam1 = Picamera2(1)

config1 = picam1.create_still_configuration(buffer_count=3)
picam1.configure(config1)
picam1.start_preview(Preview.QTGL, x = 1,y = 150 , width = 950 , height = 650)
preview_config1 = picam1.create_preview_configuration({"size": (4096, 2592)})

picam1.configure(preview_config1)
picam1.start()

#picam1.set_controls({"AfMode": controls.AfModeEnum.Continuous, "AfSpeed": controls.AfSpeedEnum.Fast,"AeEnable":False, "Brightness": -0.1, "ExposureValue": -1.0 })
#picam1.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 5.0, "AfSpeed": controls.AfSpeedEnum.Fast,"AeEnable":False, "Brightness": -0.1, "ExposureValue": -1.0}) #use first app_full.py to check the focus
picam1.set_controls({"AfMode": controls.AfModeEnum.Continuous,"AfRange": controls.AfRangeEnum.Normal, "AfSpeed": controls.AfSpeedEnum.Fast,"AeEnable":False, "Brightness": -0.1, "ExposureValue": -1.0 })

# Set up the second camera

picam2 = Picamera2(0)
config2 = picam2.create_still_configuration(buffer_count=3) 
picam2.configure(config2)
picam2.start_preview(Preview.QTGL, x =961 ,y=150 , width=950 , height =650)
preview_config2 = picam2.create_preview_configuration({"size": (4096, 2592)})
picam2.configure(preview_config2)
picam2.start()
picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous,"AfRange": controls.AfRangeEnum.Normal, "AfSpeed": controls.AfSpeedEnum.Fast,"AeEnable":False, "Brightness": -0.1, "ExposureValue": -1.0 })
#picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": 5.0, "AfSpeed": controls.AfSpeedEnum.Fast,"AeEnable":False, "Brightness": -0.1, "ExposureValue": -1.0}) #use first app_full.py to check the focus

try:
    while True:
        # Wait for the space key to be pressed
        keyboard.wait("space")

        # Capture images from both cameras
        capture_image(picam1, "y", save_path1)

        capture_image(picam2, "x", save_path2)

except KeyboardInterrupt:
    pass
finally:
    # Close QtGL preview windows
    picam1.stop_preview()
    picam2.stop_preview()

    # Clean up both cameras
    picam1.stop()
    picam2.stop() 

the results are like


>>> %Run 2_camera_manual_Af.py
[0:29:01.990343210] [5408]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:29:02.016189512] [5416]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:29:02.125928536] [5416]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:29:02.126026369] [5416]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:29:02.227709544] [5416]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media3 using PiSP variant BCM2712_C0
[0:29:02.230518117] [5408]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:29:02.253656051] [5421]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:29:02.381616658] [5421]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media0 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:29:02.381679195] [5421]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:29:02.481235501] [5421]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media3 using PiSP variant BCM2712_C0
[0:29:02.483561611] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:29:02.483593074] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:29:02.483598889] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:29:02.483604963] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:29:02.484279703] [5408]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:29:02.484403592] [5421]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
[0:29:04.313816409] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:29:04.313862631] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:29:04.313870686] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:29:04.313877557] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:29:04.314520353] [5408]  INFO Camera camera.cpp:1183 configuring streams: (0) 4096x2592-XBGR8888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:29:04.314706019] [5421]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[0:29:04.596084277] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:29:04.596129054] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:29:04.596134499] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:29:04.596143295] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:29:04.596732999] [5408]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:29:04.596946276] [5421]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[0:29:04.833731814] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:29:04.833781277] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:29:04.833789869] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:29:04.833798999] [5408]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:29:04.834521591] [5408]  INFO Camera camera.cpp:1183 configuring streams: (0) 4096x2592-XBGR8888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:29:04.914585683] [5421]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
Image captured: y_img_20240204-175520.39.jpg, Time taken: 0.24 seconds, Size: 1.72 MB
Image captured: x_img_20240204-175520.63.jpg, Time taken: 0.21 seconds, Size: 1.71 MB

with capture _af .py i can see better the range lens position should be . but still autofocus is neccesary because it may some letters be blurred .

so do u think if i change the way preview works will the scanner be faster ?

davidplowman commented 9 months ago

I wasn't completely sure what you were asking, but here are some things I'd try:

konos93 commented 9 months ago

ok again thanks for your help all these issues happen after my first attempt to scan a whole book it was about 600 pager per hour and should increase it to 1100 .its necessary to have the least possible number of pages i need to recapture as a user of my scan. in app_capture af.py it is used something like a scale preview .that help to run focus faster and capture image in the best resolution .

i played around with my script trying to have a scale qt preview environment like app_capture af.py , i dont know exactly where these type of commands should go picam2.switch_mode_and_capture_file(cfg, "test.jpg", signal_function=qpicamera2.signal_done) it didnt went well ,everything went black .but when restart and test some scripts everything seems to work five ,

can a deadlock destroy rasperi pi or any camera ?

after that i was afraid to try n error more stuff with camera.

i made big buttons in app_capture _af . i open 2 terminals for each camera .in a third using puautogui i press space and pressed the buttons. its an ugly automation that seems to work fine for my needs .

is there any keypress in picmara2 .like press enter n capture?

using autofocus cycle seems better for book scanner than continuous . but still the staff with range could help in time n response .especially if there are blank pages or pages with letters only on the top like end of chapter. i think that also can happen with the autofocus cycle after some 20 frames change to a specific manual focus n capture n return to af_cycle . af is neccecary because if u manual focus probably some text will be blurred . if i pressure with power the back of the book while i flat the pages lens potition numbers change . but with capture_af in the medatata_request is more helpful to check the lens_potition range .

davidplowman commented 9 months ago

If you're running within the Qt event loop, then you need to call certain Picamera2 functions in a non-blocking manner, or they will deadlock. Are you doing this? (check you've read section 8.5 of the manual). Picamera2 has no mechanism to handle keypresses - you need to use another module or a GUI framework for that.

konos93 commented 9 months ago

i tried to use it with Preview.QTGL and i faced black screen once and in the other the script is stopped. could this destroy raspberry or camera ? burn them or something . or everything will just power off

davidplowman commented 9 months ago

I don't think anything should physically damage the Pi or the camera, so long as you don't plug the camera in or out while the Pi is powered, or connect anything to incorrect power supplies.

konos93 commented 9 months ago

hey again em i want focus in a whole area in the middle (rather than a spot ) .

1question how big is the area than normal focus used.

do i use this part properly

picam2.set_controls({"AfMode": controls.AfModeEnum.Manual,
                     "LensPosition": lens_position_spinbox.value(),
                     "AfMetering" : controls.AfMeteringEnum.Windows,
                     "AfWindows" : [ (0, 0, 400, 500) ]}) #2 question is that in the middle????

here is what i used

#!/usr/bin/python3

from libcamera import controls
from PyQt5 import QtCore
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import (QApplication, QCheckBox, QHBoxLayout, QLabel,
                             QPushButton, QVBoxLayout, QWidget, QDoubleSpinBox)
from picamera2 import Picamera2
from picamera2.previews.qt import QGlPicamera2
import numpy as np
import time

STATE_AF = 0
STATE_CAPTURE = 1

def request_callback(request):
    lens_position = request.get_metadata().get('LensPosition', 'N/A')
    # Format the lens position to display up to 3 decimal places
    lens_position_str = f"{float(lens_position):.3f}" if lens_position != 'N/A' else 'N/A'
    label.setText(f"Lens Position: {lens_position_str}")

picam2 = Picamera2(1)
picam2.post_callback = request_callback
preview_width = 800
preview_height = picam2.sensor_resolution[1] * 800 // picam2.sensor_resolution[0]
preview_height -= preview_height % 2
preview_size = (preview_width, preview_height)
raw_size = tuple([v // 2 for v in picam2.camera_properties['PixelArraySize']])
preview_config = picam2.create_preview_configuration({"size": preview_size}, raw={"size": raw_size})
picam2.configure(preview_config)
if 'AfMode' not in picam2.camera_controls:
    print("Attached camera does not support autofocus")
    quit()
picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,"AfSpeed": controls.AfSpeedEnum.Fast})
app = QApplication([])

def on_button_clicked():
    global state
    button.setEnabled(False)
    manual_focus.setEnabled(False)
    af_checkbox.setEnabled(False)
    state = STATE_AF if af_checkbox.isChecked() else STATE_CAPTURE
    if state == STATE_AF:
        picam2.autofocus_cycle(signal_function=qpicamera2.signal_done)
    else:
        do_capture()
    # Remove focus from QDoubleSpinBox
    lens_position_spinbox.clearFocus()

def on_continuous_af_toggled(checked):
    if checked:
        picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (0, 0, 400, 500) ]})
    else:
        picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (0, 0, 400, 500) ]})

SAVE_DIRECTORY = "/home/konos93/Desktop/camera/cam1"

def do_capture():
    timestamp = time.strftime("%Y%m%d%H%M%S")
    filename = f"{SAVE_DIRECTORY}/bbb{timestamp}.jpg"
    cfg = picam2.create_still_configuration(buffer_count=3)
    picam2.switch_mode_and_capture_file(cfg, filename, signal_function=qpicamera2.signal_done)
    print(f"Image saved: {filename}")

def callback(job):
    global state
    if state == STATE_AF:
        state = STATE_CAPTURE
        success = "succeeded" if picam2.wait(job) else "failed"
        print(f"AF cycle {success} in {job.calls} frames")
        do_capture()
    else:
        picam2.wait(job)
        picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (0, 0, 400, 500) ]})
        button.setEnabled(True)
        manual_focus.setEnabled(True)
        af_checkbox.setEnabled(True)

def on_manual_toggled(checked):
    mode = controls.AfModeEnum.Continuous if checked else controls.AfModeEnum.Auto
    picam2.set_controls({"AfMode": controls.AfModeEnum.Manual,
                         "LensPosition": lens_position_spinbox.value(),
                         "AfMetering" : controls.AfMeteringEnum.Windows,
                         "AfWindows" : [ (0, 0, 400, 500) ]})

def on_lens_position_changed(value):
    picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": value})

# Add an overlay to the camera preview when the checkbox is clicked
def on_overlay_checkbox_toggled(checked):
    global overlay
    if checked:
        qpicamera2.set_overlay(overlay)
    else:
        qpicamera2.set_overlay(None)

overlay_checkbox = QCheckBox("Show Overlay")
overlay_checkbox.setChecked(False)
overlay_checkbox.toggled.connect(on_overlay_checkbox_toggled)

# Define the overlay
overlay = np.zeros((300, 400, 4), dtype=np.uint8)
overlay[:150, 200:] = (255, 0, 0, 64)
overlay[150:, :200] = (0, 255, 0, 64)
overlay[150:, 200:] = (0, 0, 255, 64)    

window = QWidget()
bg_colour = window.palette().color(QPalette.Background).getRgb()[:3]
qpicamera2 = QGlPicamera2(picam2, width=preview_width, height=preview_height, bg_colour=bg_colour, keep_ar=True)
qpicamera2.done_signal.connect(callback, type=QtCore.Qt.QueuedConnection)

button = QPushButton("Click to capture JPEG")
button.clicked.connect(on_button_clicked)

continuous_af_checkbox = QCheckBox("Continuous AF")
continuous_af_checkbox.setChecked(False)
continuous_af_checkbox.toggled.connect(on_continuous_af_toggled)

label = QLabel()
af_checkbox = QCheckBox("AF before capture", checked=True)
manual_focus = QCheckBox("Manual Focus", checked=False)
manual_focus.toggled.connect(on_manual_toggled)

# Add a QDoubleSpinBox for adjusting lens position
lens_position_spinbox = QDoubleSpinBox()
lens_position_spinbox.setSingleStep(0.02)  # Adjust step size to 0.05
lens_position_spinbox.setMinimum(0)     # Set minimum value
lens_position_spinbox.setMaximum(10)    # Set maximum value
lens_position_spinbox.setFixedWidth(100)  # Set fixed width for smaller size
lens_position_spinbox.setValue(5)  # Set initial value to 5
lens_position_spinbox.valueChanged.connect(on_lens_position_changed)

window.setWindowTitle("cam1 App")

label.setFixedWidth(200)
label.setFixedHeight(50)
label.setAlignment(QtCore.Qt.AlignTop)
layout_h = QHBoxLayout()
layout_v = QVBoxLayout()
layout_v.addWidget(label)
layout_v.addWidget(manual_focus)
layout_v.addWidget(lens_position_spinbox)  # Add the lens position QDoubleSpinBox
layout_v.addWidget(af_checkbox)
layout_v.addWidget(continuous_af_checkbox)  # Add the continuous autofocus checkbox
layout_v.addWidget(overlay_checkbox)
layout_v.addWidget(button)
layout_h.addWidget(qpicamera2, 1)
layout_h.addLayout(layout_v, 2)
window.resize(1500, 460)
button.setFixedHeight(200)
button.setFixedWidth(200)

window.setLayout(layout_h)

picam2.start()
window.move(500, 560)
window.show()
app.exec()
picam2.stop()
[4:15:51.741548826] [7091]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[4:15:51.764258589] [7100]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[4:15:51.860457356] [7100]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[4:15:51.860527041] [7100]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[4:15:51.963835964] [7100]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[4:15:51.966117331] [7091]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[4:15:51.988719169] [7105]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[4:15:52.092915461] [7105]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[4:15:52.093009702] [7105]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[4:15:52.194916979] [7105]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[4:15:52.197631567] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[4:15:52.197673660] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[4:15:52.197679178] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[4:15:52.197685382] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[4:15:52.198412214] [7091]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[4:15:52.198543807] [7105]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
AF cycle succeeded in 21 frames
Image saved: /home/konos93/Desktop/camera/cam1/bbb20240208165852.jpg
[4:16:06.213042902] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[4:16:06.213084790] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[4:16:06.213092402] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[4:16:06.213101568] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[4:16:06.213780715] [7091]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[4:16:06.220726390] [7105]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[4:16:06.749302211] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[4:16:06.749343803] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[4:16:06.749349562] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[4:16:06.749356896] [7091]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[4:16:06.749907765] [7091]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[4:16:06.757067051] [7105]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
konos93 commented 9 months ago

should i use ?

                 "AfMetering" : controls.AfMeteringEnum.Windows,
                 "AfWindows" : [ (2104, 1046, 400, 500) ]})

on the autofocus parts in the manual it is locked so yeah

konos93 commented 9 months ago

[(https://www.youtube.com/watch?v=0PodyJVMFxg)]

on 9.00 min what other calculation while the camera capture can be manual so click to capture jpeg be faster ? focus can be manual . lighting ? or something other ?

davidplowman commented 9 months ago

Can you post some code that shows the exact problem? (Please don't post all your code, just post the smallest application that you can which demonstrates the problem, preferably with just one camera. We could also add some timing, so that we obtain useful numbers for measuring the capture delay.)

I'm guessing that it is switching mode and restarting the camera that is slow. This is hard to avoid unless you run the camera permanently in the full resolution mode - but then you will have slower a slower framerate in preview mode.

Maybe your UI also need some indication when the capture has finished?

konos93 commented 9 months ago

i think here is the reason

def do_capture():

timestamp = time.strftime("%Y%m%d%H%M%S")
filename = f"{SAVE_DIRECTORY}/aaa{timestamp}.jpg"
cfg = picam2.create_still_configuration(buffer_count=3)
picam2.switch_mode_and_capture_file(cfg, filename, signal_function=qpicamera2.signal_done)
print(f"Image saved: {filename}")

but still work fine

manual focus is faster than auto focus , i think if i also regulate iso or others probably it will be faster . I'm guessing that it is switching mode and restarting the camera that is slow. This is hard to avoid unless you run the camera permanently in the full resolution mode - but then you will have slower a slower framerate in preview mode.

yeah its still faster the preview with re-scale in the app window rather than without it .

Maybe your UI also need some indication when the capture has finished?

the capture button change colors so i know that during this time i wont move the book

#!/usr/bin/python3

from libcamera import controls
from PyQt5 import QtCore
from PyQt5.QtGui import QPalette
from PyQt5.QtWidgets import (QApplication, QCheckBox, QHBoxLayout, QLabel,
                             QPushButton, QVBoxLayout, QWidget, QDoubleSpinBox)
from picamera2 import Picamera2
from picamera2.previews.qt import QGlPicamera2
import numpy as np
import time

STATE_AF = 0
STATE_CAPTURE = 1

def request_callback(request):
    lens_position = request.get_metadata().get('LensPosition', 'N/A')
    # Format the lens position to display up to 3 decimal places
    lens_position_str = f"{float(lens_position):.3f}" if lens_position != 'N/A' else 'N/A'
    label.setText(f"Lens Position: {lens_position_str}")

picam2 = Picamera2(0)
picam2.post_callback = request_callback
preview_width = 800# change me to check manual focus
preview_height = picam2.sensor_resolution[1] * preview_width // picam2.sensor_resolution[0]
preview_height -= preview_height % 2
preview_size = (preview_width, preview_height)
raw_size = tuple([v // 2 for v in picam2.camera_properties['PixelArraySize']])
preview_config = picam2.create_preview_configuration({"size": preview_size}, raw={"size": raw_size})
picam2.configure(preview_config)
if 'AfMode' not in picam2.camera_controls:
    print("Attached camera does not support autofocus")
    quit()
picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,"AfSpeed": controls.AfSpeedEnum.Fast})
app = QApplication([])

def on_button_clicked():
    global state
    button.setEnabled(False)
    manual_focus.setEnabled(False)
    af_checkbox.setEnabled(False)
    state = STATE_AF if af_checkbox.isChecked() else STATE_CAPTURE
    if state == STATE_AF:
        picam2.autofocus_cycle(signal_function=qpicamera2.signal_done)
    else:
        do_capture()
    # Remove focus from QDoubleSpinBox
    lens_position_spinbox.clearFocus()

def on_continuous_af_toggled(checked):
    if checked:
        picam2.set_controls({"AfMode": controls.AfModeEnum.Continuous,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (2104, 1046, 800,600) ]})
    else:
        picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (2104, 1046, 800,600) ]})

SAVE_DIRECTORY = "/home/konos93/Desktop/camera/cam0"

def do_capture():

    timestamp = time.strftime("%Y%m%d%H%M%S")
    filename = f"{SAVE_DIRECTORY}/aaa{timestamp}.jpg"
    cfg = picam2.create_still_configuration(buffer_count=3)
    picam2.switch_mode_and_capture_file(cfg, filename, signal_function=qpicamera2.signal_done)
    print(f"Image saved: {filename}")

def callback(job):
    global state
    if state == STATE_AF:
        state = STATE_CAPTURE
        success = "succeeded" if picam2.wait(job) else "failed"
        print(f"AF cycle {success} in {job.calls} frames")
        do_capture()
    else:
        picam2.wait(job)
        picam2.wait(job)
        picam2.set_controls({"AfMode": controls.AfModeEnum.Auto,
                             "AfSpeed": controls.AfSpeedEnum.Fast,
                             "AfMetering" : controls.AfMeteringEnum.Windows,
                             "AfWindows" : [ (2104, 1046, 800,600) ]})
        button.setEnabled(True)
        manual_focus.setEnabled(True)
        af_checkbox.setEnabled(True)

def on_manual_toggled(checked):
    mode = controls.AfModeEnum.Continuous if checked else controls.AfModeEnum.Auto
    picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": lens_position_spinbox.value()})

def on_lens_position_changed(value):
    picam2.set_controls({"AfMode": controls.AfModeEnum.Manual, "LensPosition": value})

# Add an overlay to the camera preview when the checkbox is clicked
def on_overlay_checkbox_toggled(checked):
    global overlay
    if checked:
        qpicamera2.set_overlay(overlay)
    else:
        qpicamera2.set_overlay(None)

overlay_checkbox = QCheckBox("Show Overlay")
overlay_checkbox.setChecked(False)
overlay_checkbox.toggled.connect(on_overlay_checkbox_toggled)

# Define the overlay
overlay = np.zeros((300, 400, 4), dtype=np.uint8)
overlay[:150, 200:] = (255, 0, 0, 64)
overlay[150:, :200] = (0, 255, 0, 64)
overlay[150:, 200:] = (0, 0, 255, 64)    

window = QWidget()
bg_colour = window.palette().color(QPalette.Background).getRgb()[:3]
qpicamera2 = QGlPicamera2(picam2, width=preview_width, height=preview_height, bg_colour=bg_colour, keep_ar=True)
qpicamera2.done_signal.connect(callback, type=QtCore.Qt.QueuedConnection)

button = QPushButton("Click to capture JPEG")
button.clicked.connect(on_button_clicked)

continuous_af_checkbox = QCheckBox("Continuous AF")
continuous_af_checkbox.setChecked(False)
continuous_af_checkbox.toggled.connect(on_continuous_af_toggled)

label = QLabel()
af_checkbox = QCheckBox("AF before capture", checked=True)
manual_focus = QCheckBox("Manual Focus", checked=False)
manual_focus.toggled.connect(on_manual_toggled)

# Add a QDoubleSpinBox for adjusting lens position
lens_position_spinbox = QDoubleSpinBox()
lens_position_spinbox.setSingleStep(0.02)  # Adjust step size to 0.02
lens_position_spinbox.setMinimum(0)     
lens_position_spinbox.setMaximum(15)    
lens_position_spinbox.setFixedWidth(100)  
lens_position_spinbox.setValue(5.36)  # Set initial value 
lens_position_spinbox.valueChanged.connect(on_lens_position_changed)

window.setWindowTitle("cam0 App")

label.setFixedWidth(200)
label.setFixedHeight(50)
label.setAlignment(QtCore.Qt.AlignTop)
layout_h = QHBoxLayout()
layout_v = QVBoxLayout()
layout_v.addWidget(label)
layout_v.addWidget(manual_focus)
layout_v.addWidget(lens_position_spinbox)  # Add the lens position QDoubleSpinBox
layout_v.addWidget(af_checkbox)
layout_v.addWidget(continuous_af_checkbox)  # Add the continuous autofocus checkbox
layout_v.addWidget(overlay_checkbox)
layout_v.addWidget(button)
layout_h.addWidget(qpicamera2, 1)
layout_h.addLayout(layout_v, 2)
window.resize(1500, 460)
button.setFixedHeight(200)
button.setFixedWidth(200)

window.setLayout(layout_h)

picam2.start()
window.move(500, 0)
window.show()
app.exec()
picam2.stop()

results

[0:22:30.348846400] [3008]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:22:30.369192042] [3016]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:22:30.465162954] [3016]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[0:22:30.465269602] [3016]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:22:30.558434442] [3016]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:22:30.561892219] [3008]  INFO Camera camera_manager.cpp:284 libcamera v0.1.0+118-563cd78e
[0:22:30.585768915] [3021]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:22:30.694191714] [3021]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a to CFE device /dev/media1 and ISP device /dev/media0 using PiSP variant BCM2712_C0
[0:22:30.694454306] [3021]  INFO RPI pisp.cpp:653 libpisp version v1.0.2 fa44a258644a 22-11-2023 (21:59:22)
[0:22:30.785981425] [3021]  INFO RPI pisp.cpp:1112 Registered camera /base/axi/pcie@120000/rp1/i2c@80000/imx708@1a to CFE device /dev/media3 and ISP device /dev/media2 using PiSP variant BCM2712_C0
[0:22:30.789708405] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:22:30.789776128] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:22:30.789782961] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:22:30.789789979] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:22:30.790527387] [3008]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[0:22:30.790669887] [3021]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
error: XDG_RUNTIME_DIR is invalid or not set in the environment.
Image saved: /home/konos93/Desktop/camera/cam0/aaa20240215131647.jpg
[0:22:36.954651476] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:22:36.954872124] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:22:36.954938661] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:22:36.954990976] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:22:36.956214143] [3008]  INFO Camera camera.cpp:1183 configuring streams: (0) 4608x2592-BGR888 (1) 4608x2592-BGGR16_PISP_COMP1
[0:22:36.964617456] [3021]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 4608x2592-SBGGR10_1X10 - Selected CFE format: 4608x2592-PC1B
[0:22:37.477066525] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format Y16 
[0:22:37.477170007] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format RGB6
[0:22:37.477200025] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format BGR6
[0:22:37.477235748] [3008]  WARN V4L2 v4l2_pixelformat.cpp:338 Unsupported V4L2 pixel format PC1M
[0:22:37.477813322] [3008]  INFO Camera camera.cpp:1183 configuring streams: (0) 800x450-XBGR8888 (1) 2304x1296-BGGR16_PISP_COMP1
[0:22:37.484878876] [3021]  INFO RPI pisp.cpp:1396 Sensor: /base/axi/pcie@120000/rp1/i2c@88000/imx708@1a - Selected sensor format: 2304x1296-SBGGR10_1X10 - Selected CFE format: 2304x1296-PC1B
davidplowman commented 9 months ago

I'm sorry, I haven't really understood what you're asking.

At 9:00 in the video, you click the capture button. It seems reasonably quick to me. But is this actually too slow?

konos93 commented 9 months ago

I'm sorry, I haven't really understood what you're asking.

At 9:00 in the video, you click the capture button. It seems reasonably quick to me. But is this actually too slow?

look i am the one who should apologize most times here i dont know even what exactly i want to ask. and when i ask many times i define what i am looking into. for me its the first time i read a lot so much a datasheet look examples and ask for help here

i run app_full.py i think its slightly faster . it is still good .

but if u have moved images 1 out 10 in 400 pages is about 40 images. of course that didnt happen i had to recapture about 10 out of 400 .

in app_full.py u can regulate stuff like brightness and other . in capture_af which is the script based on the video if i could regulate stuff like ISO, aperture, shutter speed i think that capture button speed will be better because less calculations needed .

i will look out for it and i will inform. again thanks for your help