init
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.12 (FDv2)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (FDv2)" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/FDv2.iml" filepath="$PROJECT_DIR$/.idea/FDv2.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings" defaultProject="true" />
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import joblib
|
||||||
|
from skimage.feature import hog
|
||||||
|
import imutils
|
||||||
|
from imutils.object_detection import non_max_suppression
|
||||||
|
from skimage.transform import pyramid_gaussian
|
||||||
|
|
||||||
|
|
||||||
|
def sliding_window(image, stepSize, windowSize):
|
||||||
|
for y in range(0, image.shape[0] - windowSize[1] + 1, stepSize):
|
||||||
|
for x in range(0, image.shape[1] - windowSize[0] + 1, stepSize):
|
||||||
|
yield (x, y, image[y:y + windowSize[1], x:x + windowSize[0]])
|
||||||
|
|
||||||
|
|
||||||
|
# HOG parameters (should match those used during training)
|
||||||
|
hog_params = {
|
||||||
|
'orientations': 9,
|
||||||
|
'pixels_per_cell': (8, 8),
|
||||||
|
'cells_per_block': (2, 2),
|
||||||
|
'block_norm': 'L2-Hys'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load the pre-trained model (grid search object containing the best estimator)
|
||||||
|
model = joblib.load('svm_natural_images_modelUTC.pkl')
|
||||||
|
# If the saved object is a GridSearchCV, extract the best estimator.
|
||||||
|
if hasattr(model, 'best_estimator_'):
|
||||||
|
model = model.best_estimator_
|
||||||
|
|
||||||
|
# Detection parameters
|
||||||
|
windowSize = (64, 64)
|
||||||
|
hog_size = (64, 64)
|
||||||
|
stepSize = 8 # Step size for sliding window.
|
||||||
|
scale_factor = 1.01 # Scaling factor for image pyramid.
|
||||||
|
detection_threshold = 0.85 # Minimum probability to consider a detection valid.
|
||||||
|
|
||||||
|
# Load the test image (change the filename as needed)
|
||||||
|
image = cv2.imread("test3.jpg")
|
||||||
|
|
||||||
|
orig = image.copy()
|
||||||
|
detections = []
|
||||||
|
|
||||||
|
# Loop over the image pyramid
|
||||||
|
for resized in tuple(pyramid_gaussian(image, downscale=scale_factor, channel_axis=-1)):
|
||||||
|
# The ratio of the current resized image relative to the original image
|
||||||
|
scale_ratio = image.shape[1] / float(resized.shape[1])
|
||||||
|
|
||||||
|
# Slide a window across the resized image
|
||||||
|
for (x, y, window) in sliding_window(resized, stepSize, windowSize):
|
||||||
|
# Ensure the window is of the desired size
|
||||||
|
if window.shape[0] != windowSize[1] or window.shape[1] != windowSize[0]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if window.dtype != np.uint8:
|
||||||
|
window = (window * 255).astype(np.uint8)
|
||||||
|
|
||||||
|
|
||||||
|
gray = cv2.cvtColor(window, cv2.COLOR_BGR2GRAY)
|
||||||
|
gray = cv2.resize(gray, hog_size, interpolation=cv2.INTER_AREA)
|
||||||
|
|
||||||
|
features = hog(gray, **hog_params)
|
||||||
|
features = features.reshape(1, -1)
|
||||||
|
|
||||||
|
# Predict the class and probability for this window
|
||||||
|
pred = model.predict(features)
|
||||||
|
prob = model.predict_proba(features)[0]
|
||||||
|
|
||||||
|
if 'person' in model.classes_:
|
||||||
|
person_index = list(model.classes_).index('person')
|
||||||
|
person_prob = prob[person_index]
|
||||||
|
else:
|
||||||
|
person_prob = 0
|
||||||
|
|
||||||
|
if pred[0] == 'person' and person_prob > detection_threshold:
|
||||||
|
startX = int(x * scale_ratio)
|
||||||
|
startY = int(y * scale_ratio)
|
||||||
|
endX = int((x + windowSize[0]) * scale_ratio)
|
||||||
|
endY = int((y + windowSize[1]) * scale_ratio)
|
||||||
|
detections.append((startX, startY, endX, endY))
|
||||||
|
|
||||||
|
if len(detections) > 0:
|
||||||
|
detections = np.array(detections)
|
||||||
|
pick = non_max_suppression(detections, probs=None, overlapThresh=0.3)
|
||||||
|
# Draw the final bounding boxes on the original image.
|
||||||
|
for (xA, yA, xB, yB) in pick:
|
||||||
|
cv2.rectangle(orig, (xA, yA), (xB, yB), (0, 255, 0), 2)
|
||||||
|
|
||||||
|
# Display the detections
|
||||||
|
cv2.imshow("Detections", orig)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
cv2.destroyAllWindows()
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import joblib
|
||||||
|
from skimage.feature import hog
|
||||||
|
import imutils
|
||||||
|
from imutils.object_detection import non_max_suppression
|
||||||
|
from skimage.transform import pyramid_gaussian
|
||||||
|
import asyncio
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
|
|
||||||
|
def sliding_window(image, stepSize, windowSize):
|
||||||
|
for y in range(0, image.shape[0] - windowSize[1] + 1, stepSize):
|
||||||
|
for x in range(0, image.shape[1] - windowSize[0] + 1, stepSize):
|
||||||
|
yield (x, y, image[y:y + windowSize[1], x:x + windowSize[0]])
|
||||||
|
|
||||||
|
|
||||||
|
# HOG parameters (should match those used during training)
|
||||||
|
hog_params = {
|
||||||
|
'orientations': 9,
|
||||||
|
'pixels_per_cell': (8, 8),
|
||||||
|
'cells_per_block': (2, 2),
|
||||||
|
'block_norm': 'L2-Hys'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detection parameters
|
||||||
|
windowSize = (64, 64)
|
||||||
|
hogSize = (128, 128) # Must match the window size used for training HOG features.
|
||||||
|
stepSize = 8 # Step size for sliding window.
|
||||||
|
scale_factor = 1.1 # Scaling factor for image pyramid.
|
||||||
|
detection_threshold = 0.9 # Minimum probability to consider a detection valid.
|
||||||
|
|
||||||
|
# Load the pre-trained model (grid search object containing the best estimator)
|
||||||
|
model = joblib.load('svm_natural_images_model.pkl')
|
||||||
|
# If the saved object is a GridSearchCV, extract the best estimator.
|
||||||
|
if hasattr(model, 'best_estimator_'):
|
||||||
|
model = model.best_estimator_
|
||||||
|
|
||||||
|
|
||||||
|
# This initializer will be run in each worker process to set globals.
|
||||||
|
def init_worker(_model, _hog_params, _hogSize, _detection_threshold, _windowSize):
|
||||||
|
global model, hog_params, hogSize, detection_threshold, windowSize
|
||||||
|
model = _model
|
||||||
|
hog_params = _hog_params
|
||||||
|
hogSize = _hogSize
|
||||||
|
detection_threshold = _detection_threshold
|
||||||
|
windowSize = _windowSize
|
||||||
|
|
||||||
|
|
||||||
|
def process_window(args):
|
||||||
|
# Unpack arguments
|
||||||
|
window, x, y, scale_ratio = args
|
||||||
|
# Ensure proper datatype
|
||||||
|
if window.dtype != np.uint8:
|
||||||
|
window = (window * 255).astype(np.uint8)
|
||||||
|
# Convert to grayscale and resize for HOG extraction
|
||||||
|
gray = cv2.cvtColor(window, cv2.COLOR_BGR2GRAY)
|
||||||
|
gray = cv2.resize(gray, hogSize)
|
||||||
|
# Compute HOG features
|
||||||
|
features = hog(gray, **hog_params)
|
||||||
|
features = features.reshape(1, -1)
|
||||||
|
# Make predictions
|
||||||
|
pred = model.predict(features)
|
||||||
|
prob = model.predict_proba(features)[0]
|
||||||
|
if 'person' in model.classes_:
|
||||||
|
person_index = list(model.classes_).index('person')
|
||||||
|
person_prob = prob[person_index]
|
||||||
|
else:
|
||||||
|
person_prob = 0
|
||||||
|
# Return bounding box if detection meets the criteria
|
||||||
|
if pred[0] == 'person' and person_prob > detection_threshold:
|
||||||
|
startX = int(x * scale_ratio)
|
||||||
|
startY = int(y * scale_ratio)
|
||||||
|
endX = int((x + windowSize[0]) * scale_ratio)
|
||||||
|
endY = int((y + windowSize[1]) * scale_ratio)
|
||||||
|
return (startX, startY, endX, endY)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def async_detection(image):
|
||||||
|
detections = []
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
tasks = []
|
||||||
|
# Set up the ProcessPoolExecutor with max 10 processes and initializer
|
||||||
|
with concurrent.futures.ProcessPoolExecutor(
|
||||||
|
max_workers=20,
|
||||||
|
initializer=init_worker,
|
||||||
|
initargs=(model, hog_params, hogSize, detection_threshold, windowSize)
|
||||||
|
) as executor:
|
||||||
|
for resized in pyramid_gaussian(image, downscale=scale_factor, channel_axis=-1):
|
||||||
|
scale_ratio = image.shape[1] / float(resized.shape[1])
|
||||||
|
for (x, y, window) in sliding_window(resized, stepSize, windowSize):
|
||||||
|
if window.shape[0] != windowSize[1] or window.shape[1] != windowSize[0]:
|
||||||
|
continue
|
||||||
|
args = (window, x, y, scale_ratio)
|
||||||
|
tasks.append(loop.run_in_executor(executor, process_window, args))
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
for result in results:
|
||||||
|
if result is not None:
|
||||||
|
detections.append(result)
|
||||||
|
return detections
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
# Load the test image (update the filename as needed)
|
||||||
|
image = cv2.imread("test.jpg")
|
||||||
|
if image is None:
|
||||||
|
print("Failed to load image!")
|
||||||
|
return
|
||||||
|
|
||||||
|
orig = image.copy()
|
||||||
|
# Run the asynchronous detection
|
||||||
|
detections = await async_detection(image)
|
||||||
|
|
||||||
|
# Apply non-maxima suppression to reduce overlapping boxes
|
||||||
|
if len(detections) > 0:
|
||||||
|
detections = np.array(detections)
|
||||||
|
pick = non_max_suppression(detections, probs=None, overlapThresh=0.3)
|
||||||
|
# Draw the final bounding boxes on the original image.
|
||||||
|
for (xA, yA, xB, yB) in pick:
|
||||||
|
cv2.rectangle(orig, (xA, yA), (xB, yB), (0, 255, 0), 2)
|
||||||
|
|
||||||
|
# Display the detections
|
||||||
|
cv2.imshow("Detections", orig)
|
||||||
|
cv2.waitKey(0)
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
asyncio.run(main())
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
import joblib
|
||||||
|
from skimage.feature import hog
|
||||||
|
import imutils
|
||||||
|
from imutils.object_detection import non_max_suppression
|
||||||
|
from skimage.transform import pyramid_gaussian
|
||||||
|
import asyncio
|
||||||
|
import concurrent.futures
|
||||||
|
|
||||||
|
def sliding_window(image, stepSize, windowSize):
|
||||||
|
# Standard (synchronous) sliding window generator (not used in async version)
|
||||||
|
for y in range(0, image.shape[0] - windowSize[1] + 1, stepSize):
|
||||||
|
for x in range(0, image.shape[1] - windowSize[0] + 1, stepSize):
|
||||||
|
yield (x, y, image[y:y + windowSize[1], x:x + windowSize[0]])
|
||||||
|
|
||||||
|
# Helper function: generate sliding windows for a given y-range
|
||||||
|
def generate_windows_for_y_range(image, stepSize, windowSize, y_start, y_end):
|
||||||
|
windows = []
|
||||||
|
# Ensure y_end does not exceed allowed range
|
||||||
|
for y in range(y_start, min(y_end, image.shape[0] - windowSize[1] + 1), stepSize):
|
||||||
|
for x in range(0, image.shape[1] - windowSize[0] + 1, stepSize):
|
||||||
|
window = image[y:y + windowSize[1], x:x + windowSize[0]]
|
||||||
|
# Only add if the window has the desired size
|
||||||
|
if window.shape[0] == windowSize[1] and window.shape[1] == windowSize[0]:
|
||||||
|
windows.append((x, y, window))
|
||||||
|
return windows
|
||||||
|
|
||||||
|
# Asynchronous sliding window generator using 5 workers
|
||||||
|
async def async_sliding_window(image, stepSize, windowSize, num_workers=5):
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
height = image.shape[0] - windowSize[1] + 1
|
||||||
|
segment_size = max(1, height // num_workers)
|
||||||
|
tasks = []
|
||||||
|
with concurrent.futures.ThreadPoolExecutor(max_workers=num_workers) as executor:
|
||||||
|
for i in range(0, height, segment_size):
|
||||||
|
y_start = i
|
||||||
|
y_end = i + segment_size
|
||||||
|
tasks.append(loop.run_in_executor(
|
||||||
|
executor,
|
||||||
|
generate_windows_for_y_range,
|
||||||
|
image, stepSize, windowSize, y_start, y_end
|
||||||
|
))
|
||||||
|
results = await asyncio.gather(*tasks)
|
||||||
|
# Flatten the list of lists into a single list of windows
|
||||||
|
windows = [win for sublist in results for win in sublist]
|
||||||
|
return windows
|
||||||
|
|
||||||
|
# HOG parameters (must match training parameters)
|
||||||
|
hog_params = {
|
||||||
|
'orientations': 9,
|
||||||
|
'pixels_per_cell': (8, 8),
|
||||||
|
'cells_per_block': (2, 2),
|
||||||
|
'block_norm': 'L2-Hys'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detection parameters
|
||||||
|
windowSize = (64, 64)
|
||||||
|
hogSize = (128, 128) # Size to which each window is resized for HOG extraction.
|
||||||
|
stepSize = 8 # Sliding window step size.
|
||||||
|
scale_factor = 1.1 # Pyramid downscale factor.
|
||||||
|
detection_threshold = 0.9 # Minimum probability to consider a detection valid.
|
||||||
|
|
||||||
|
# Load the pre-trained model
|
||||||
|
model = joblib.load('svm_natural_images_model.pkl')
|
||||||
|
if hasattr(model, 'best_estimator_'):
|
||||||
|
model = model.best_estimator_
|
||||||
|
|
||||||
|
# Initializer for each worker process
|
||||||
|
def init_worker(_model, _hog_params, _hogSize, _detection_threshold, _windowSize):
|
||||||
|
global model, hog_params, hogSize, detection_threshold, windowSize
|
||||||
|
model = _model
|
||||||
|
hog_params = _hog_params
|
||||||
|
hogSize = _hogSize
|
||||||
|
detection_threshold = _detection_threshold
|
||||||
|
windowSize = _windowSize
|
||||||
|
|
||||||
|
# Process a single window: extract features and run prediction
|
||||||
|
def process_window(args):
|
||||||
|
window, x, y, scale_ratio = args
|
||||||
|
if window.dtype != np.uint8:
|
||||||
|
window = (window * 255).astype(np.uint8)
|
||||||
|
# Convert to grayscale and resize for HOG
|
||||||
|
gray = cv2.cvtColor(window, cv2.COLOR_BGR2GRAY)
|
||||||
|
gray = cv2.resize(gray, hogSize)
|
||||||
|
features = hog(gray, **hog_params)
|
||||||
|
features = features.reshape(1, -1)
|
||||||
|
pred = model.predict(features)
|
||||||
|
prob = model.predict_proba(features)[0]
|
||||||
|
if 'person' in model.classes_:
|
||||||
|
person_index = list(model.classes_).index('person')
|
||||||
|
person_prob = prob[person_index]
|
||||||
|
else:
|
||||||
|
person_prob = 0
|
||||||
|
if pred[0] == 'person' and person_prob > detection_threshold:
|
||||||
|
startX = int(x * scale_ratio)
|
||||||
|
startY = int(y * scale_ratio)
|
||||||
|
endX = int((x + windowSize[0]) * scale_ratio)
|
||||||
|
endY = int((y + windowSize[1]) * scale_ratio)
|
||||||
|
return (startX, startY, endX, endY)
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Main asynchronous detection function
|
||||||
|
async def async_detection(image):
|
||||||
|
detections = []
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
tasks = []
|
||||||
|
# ProcessPoolExecutor for heavy computation (up to 10 processes)
|
||||||
|
with concurrent.futures.ProcessPoolExecutor(
|
||||||
|
max_workers=10,
|
||||||
|
initializer=init_worker,
|
||||||
|
initargs=(model, hog_params, hogSize, detection_threshold, windowSize)
|
||||||
|
) as process_executor:
|
||||||
|
# Iterate over each level in the image pyramid
|
||||||
|
for resized in pyramid_gaussian(image, downscale=scale_factor, channel_axis=-1):
|
||||||
|
scale_ratio = image.shape[1] / float(resized.shape[1])
|
||||||
|
# Asynchronously generate sliding
|
||||||
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 9.3 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 12 KiB |