-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
4ed4f1a
commit 811fdbd
Showing
1 changed file
with
130 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
from typing import Union | ||
|
||
import cv2 | ||
import numpy as np | ||
|
||
|
||
MIN_EXPOSURE = -13 | ||
MAX_EXPOSURE = -3 | ||
DEFAULT_EXPOSURE = -6 | ||
|
||
EXPOSURE_SETTINGS = [DEFAULT_EXPOSURE, 'AUTO'] | ||
EXPOSURE_SETTINGS.extend(list(range(MIN_EXPOSURE, MAX_EXPOSURE + 1))) | ||
|
||
|
||
def run_frame_loop(cap: cv2.VideoCapture, exposure_setting: int, auto_manual_setting:str, frames: int = 10) -> dict: | ||
"""Capture the mean brightness of frames from the video capture device. | ||
Parameters | ||
---------- | ||
cap : cv2.VideoCapture | ||
The video capture device. | ||
frames : int, optional | ||
Number of frames to capture, by default 30. | ||
Returns | ||
------- | ||
dict | ||
Dictionary with mean and standard deviation of brightness. | ||
""" | ||
|
||
brightness_values = [] | ||
r = np.random.randint(0, 99999)# big number to keep window name unique | ||
for fr in range(frames): | ||
success, image = cap.read() | ||
font = cv2.FONT_HERSHEY_SIMPLEX | ||
font_scale = .5 | ||
color = (255, 0, 255) # FFOOFF! | ||
thickness = 2 | ||
position = (10, 30) # top-left corner | ||
position2 = (10, 60) # top-left corner | ||
|
||
# Add text to the image | ||
#put transparent rect under text for legibility | ||
annotated_image = image.copy() | ||
cv2.rectangle(annotated_image, (0, 0), (300, 80), (255, 255, 255, .2), -1) | ||
cv2.putText(annotated_image, f"(Fr#{fr}) Auto/Man: {auto_manual_setting}, Set: {exposure_setting}, Actual: {cap.get(cv2.CAP_PROP_EXPOSURE)}", position, font, font_scale, color, thickness) | ||
cv2.putText(annotated_image, f"`np.mean(image)={np.mean(image):.2f}", position2, font, font_scale, color, thickness) | ||
|
||
cv2.imshow(f"{r}Brightness Calibration (q to quit)", annotated_image) | ||
if cv2.waitKey(1) & 0xFF == ord("q"): | ||
break | ||
|
||
if not success: | ||
continue | ||
brightness_values.append(np.mean(image)) | ||
return { | ||
"mean": np.mean(np.asarray(brightness_values)), | ||
"median": np.median(np.asarray(brightness_values)), | ||
"std": np.std(np.asarray(brightness_values)) | ||
} | ||
|
||
|
||
HYPOTHETICAL_AUTO_EXPOSURE_SETTINGS = [0.75, 3] | ||
HYPOTHETICAL_MANUAL_EXPOSURE_SETTINGS = [0.25, 1] | ||
def main(): | ||
cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) | ||
print(f"Exposure on init: {cap.get(cv2.CAP_PROP_EXPOSURE)}") | ||
cap.set(cv2.CAP_PROP_EXPOSURE, -6) | ||
|
||
results = [] | ||
# Initial capture to let the webcam settle | ||
for auto_exposure_setting, manual_exposure_setting in zip(HYPOTHETICAL_AUTO_EXPOSURE_SETTINGS, HYPOTHETICAL_MANUAL_EXPOSURE_SETTINGS): | ||
print(f"\n-----------------------\nUsing `{auto_exposure_setting}` to enable auto exposure and `{manual_exposure_setting}` to enable manual exposure...") | ||
for _ in range(30): | ||
success, image = cap.read() # let it settle for a bit | ||
print(f"Auto Exposure before set: {cap.get(cv2.CAP_PROP_AUTO_EXPOSURE)}") | ||
|
||
|
||
for exposure_setting in EXPOSURE_SETTINGS: | ||
if exposure_setting =='AUTO': | ||
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, auto_exposure_setting) | ||
print(f"Auto Exposure after set to {auto_exposure_setting}: {cap.get(cv2.CAP_PROP_AUTO_EXPOSURE)} (hypothetically auto exposure)") | ||
else: | ||
cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, manual_exposure_setting) | ||
print(f"Auto Exposure after set to {manual_exposure_setting}: {cap.get(cv2.CAP_PROP_AUTO_EXPOSURE)} (hypothetically manual exposure)") | ||
|
||
results = run_brightness_test(auto_exposure_setting=auto_exposure_setting, | ||
cap = cap, | ||
exposure_setting = exposure_setting, | ||
manual_exposure_setting = manual_exposure_setting, | ||
results=results) | ||
|
||
|
||
|
||
# Print the results as a table | ||
headers = ["(SetAuto, SetManual)", "Exposure", "Mean Brightness", "Median", "Std Dev"] | ||
header_format = "{:<20} {:<15} {:<20} {:<20} {:<20}" | ||
row_format = "{:<20} {:<15} {:<20.1f} {:<20.1f} {:<20.1f}" | ||
print(header_format.format(*headers)) | ||
print("-" * 75) | ||
prev = results[0] | ||
for row in results: | ||
if row[0] != prev[0]: | ||
print("\n") | ||
print(row_format.format(*row)) | ||
prev = row | ||
|
||
cap.release() | ||
|
||
|
||
|
||
|
||
def run_brightness_test(auto_exposure_setting: float, | ||
cap: cv2.VideoCapture, | ||
exposure_setting: Union[str,int], | ||
manual_exposure_setting: float, | ||
results: list) -> list: | ||
if not exposure_setting == 'AUTO': | ||
cap.set(cv2.CAP_PROP_EXPOSURE, exposure_setting) | ||
|
||
|
||
exposure = cap.get(cv2.CAP_PROP_EXPOSURE) | ||
print(f"Exposure after set to {exposure_setting}: {exposure}") | ||
brightness_data = run_frame_loop(cap=cap, exposure_setting=exposure_setting, auto_manual_setting=str(f"({auto_exposure_setting}, {manual_exposure_setting}")) | ||
results.append([f"({auto_exposure_setting},{manual_exposure_setting})", exposure_setting, | ||
brightness_data["mean"], brightness_data["median"], brightness_data["std"]]) | ||
return results | ||
|
||
if __name__ == "__main__": | ||
main() |