Capturing an image higher than video streaming resolution

Hi there! Did a few searches and couldn’t find a similar problem on these forums, hope I’m not asking a common question/ didn’t use the right search terms.

I’m writing an autofocus script for a Raspberry Pi camera. In the script, Laplachian edge detection outputs a variable to act as a rough approximate for focus, and once the variable reaches a certain threshold, it triggers an LED to blink at different speeds. Faster LED, better focus. All this is because don’t want this camera to have a screen, but am using a manual focus lens.

I need to stream at 640x480 for the Raspberry Pi to process the edge detection quick enough for immediate focus feedback, but I want to capture at higher resolutions. (I can seemingly only go to 1920x1080, even though the Pi HQ camera I’m using has a higher resolution for still images–but that’s a problem for later.)

My code is super simple, but I think I’m misunderstanding how the camera stream interacts with image capture. In the code I’m trying to stop the 480p video stream, start a 1080p video stream, capture a frame, and then start the 480p stream again.

If there’s another way to approach this, or a way to fix my existing code, it would be super welcome. Thanks so much for your time!

Code below:

from gpiozero import Button, LED
from time import sleep
import os

#load physical buttons
button = Button(23, hold_time=1)
led = LED(24)

#boot confirmation
print('loaded modules')
led.on()
sleep(.5)
led.off()
sleep(.5)
led.on()
sleep(.5)
led.off()

import cv2
import numpy as np

#boot confirmation
print('loaded modules')
led.on()
sleep(.5)
led.off()
sleep(.5)
led.on()
sleep(.5)
led.off()

#video capture
cap = cv2.VideoCapture(0)

#filename counter
img_counter = 0

#main loop
while True:
	#capture video
	ret, frame = cap.read()
	#grayscale for easier processing
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	#get focus and print
	laplacian_var = cv2.Laplacian(gray, cv2.CV_64F).var()
	print(laplacian_var)
	#led on  sharp
	if laplacian_var > 80:
		led.on()
		sleep(.1)
		led.off()
	#led starting to focus
	if laplacian_var > 30 and laplacian_var < 79:
		led.on()
		sleep(.5)
		led.off()
	#capture image
	if button.is_pressed:
		img_name = 'img_{}.jpg'.format(img_counter)
		os.chdir(r'/home/pi/photos')
		cap.release()
		cap.set(3, 1920)
		cap.set(4, 1080)
		ret, frame = cap.read()
		cv2.imwrite(img_name, frame)
		print('{} written!'.format(img_name))
		img_counter +=1
		cap.release()
		cap.set(3, 640)
		cap.set(4, 480)
	if button.is_held:
		led.on()
		sleep(2)
		led.off()
		break


cap.release()

Thanks again!

Just capture the whole stream in 1080p and resize the images to low resolution for processing.

Stopping the stream, reconfiguring the camera and restarting it takes a long time. After restarting, the camera is reinitialized, so it needs to set exposure again.

Got it, that makes a lot of sense. I’ll give it a go! Thanks so much for the response!