Spaces:
Sleeping
Sleeping
File size: 5,985 Bytes
f89e218 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
"""
Technical metrics for image quality assessment without using AI models.
These metrics evaluate basic technical aspects of images like sharpness, noise, etc.
"""
import numpy as np
import cv2
from skimage.metrics import structural_similarity as ssim
from skimage.measure import shannon_entropy
from PIL import Image, ImageStat
class TechnicalMetrics:
"""Class for computing technical image quality metrics."""
@staticmethod
def calculate_sharpness(image_array):
"""
Calculate image sharpness using Laplacian variance.
Higher values indicate sharper images.
Args:
image_array: numpy array of the image
Returns:
float: sharpness score
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
# Calculate variance of Laplacian
return cv2.Laplacian(gray, cv2.CV_64F).var()
@staticmethod
def calculate_noise(image_array):
"""
Estimate image noise level.
Lower values indicate less noisy images.
Args:
image_array: numpy array of the image
Returns:
float: noise level
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
# Estimate noise using median filter difference
denoised = cv2.medianBlur(gray, 5)
diff = cv2.absdiff(gray, denoised)
return np.mean(diff)
@staticmethod
def calculate_contrast(image_array):
"""
Calculate image contrast.
Higher values indicate higher contrast.
Args:
image_array: numpy array of the image
Returns:
float: contrast score
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
# Calculate standard deviation as a measure of contrast
return np.std(gray)
@staticmethod
def calculate_saturation(image_array):
"""
Calculate color saturation.
Higher values indicate more saturated colors.
Args:
image_array: numpy array of the image
Returns:
float: saturation score
"""
if len(image_array.shape) != 3:
return 0.0 # Grayscale images have no saturation
# Convert to HSV and calculate mean saturation
hsv = cv2.cvtColor(image_array, cv2.COLOR_RGB2HSV)
return np.mean(hsv[:, :, 1])
@staticmethod
def calculate_entropy(image_array):
"""
Calculate image entropy as a measure of detail/complexity.
Higher values indicate more complex images.
Args:
image_array: numpy array of the image
Returns:
float: entropy score
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
return shannon_entropy(gray)
@staticmethod
def detect_compression_artifacts(image_array):
"""
Detect JPEG compression artifacts.
Higher values indicate more artifacts.
Args:
image_array: numpy array of the image
Returns:
float: artifact score
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
# Apply edge detection to find blocky artifacts
edges = cv2.Canny(gray, 100, 200)
return np.mean(edges) / 255.0
@staticmethod
def calculate_dynamic_range(image_array):
"""
Calculate dynamic range of the image.
Higher values indicate better use of available intensity range.
Args:
image_array: numpy array of the image
Returns:
float: dynamic range score
"""
if len(image_array.shape) == 3:
gray = cv2.cvtColor(image_array, cv2.COLOR_RGB2GRAY)
else:
gray = image_array
p1 = np.percentile(gray, 1)
p99 = np.percentile(gray, 99)
return (p99 - p1) / 255.0
@staticmethod
def calculate_all_metrics(image_path):
"""
Calculate all technical metrics for an image.
Args:
image_path: path to the image file
Returns:
dict: dictionary with all metric scores
"""
# Load image with PIL for metadata
pil_image = Image.open(image_path)
# Convert to numpy array for OpenCV processing
image_array = np.array(pil_image)
# Calculate all metrics
metrics = {
'sharpness': TechnicalMetrics.calculate_sharpness(image_array),
'noise': TechnicalMetrics.calculate_noise(image_array),
'contrast': TechnicalMetrics.calculate_contrast(image_array),
'saturation': TechnicalMetrics.calculate_saturation(image_array),
'entropy': TechnicalMetrics.calculate_entropy(image_array),
'compression_artifacts': TechnicalMetrics.detect_compression_artifacts(image_array),
'dynamic_range': TechnicalMetrics.calculate_dynamic_range(image_array),
'resolution': f"{pil_image.width}x{pil_image.height}",
'aspect_ratio': pil_image.width / pil_image.height if pil_image.height > 0 else 0,
'file_size_kb': pil_image.fp.tell() / 1024 if hasattr(pil_image.fp, 'tell') else 0,
}
return metrics
|