raspberry-pi

Optimizing Raspberry Pi Camera V3 for Fast 12MP Image Capture in DIY Book Scanner


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

Solution

  • this is for raspberry pi5 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()
    

    to calibrate camera i use 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