fixes to split photos
This commit is contained in:
parent
d7431c459d
commit
6fd6aa2733
2 changed files with 23 additions and 41 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
import cv2
|
import cv2
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -36,32 +37,20 @@ def estimate_background_color(image, sample_points=5):
|
||||||
|
|
||||||
return np.median(colors, axis=0)
|
return np.median(colors, axis=0)
|
||||||
|
|
||||||
def auto_rotate(image, angle_threshold=10):
|
def auto_rotate(image, angle_threshold=1):
|
||||||
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
|
||||||
ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
|
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
|
||||||
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
lines = cv2.HoughLines(edges, 1, np.pi / 180, 200)
|
||||||
|
|
||||||
if len(contours) == 0:
|
if lines is None:
|
||||||
return image
|
return image
|
||||||
|
|
||||||
largest_contour = max(contours, key=cv2.contourArea)
|
# compute the median angle of the lines
|
||||||
mu = cv2.moments(largest_contour)
|
angles = []
|
||||||
|
for rho, theta in lines[:, 0]:
|
||||||
|
angles.append((theta * 180) / np.pi - 90)
|
||||||
|
|
||||||
if mu["m00"] == 0:
|
angle = np.median(angles)
|
||||||
return image
|
|
||||||
|
|
||||||
x_centroid = int(mu["m10"] / mu["m00"])
|
|
||||||
y_centroid = int(mu["m01"] / mu["m00"])
|
|
||||||
|
|
||||||
coords = np.column_stack(np.where(binary > 0))
|
|
||||||
u, _, vt = np.linalg.svd(coords - np.array([[y_centroid, x_centroid]]), full_matrices=False)
|
|
||||||
|
|
||||||
angle = np.arctan2(u[1, 0], u[0, 0]) * 180 / np.pi
|
|
||||||
|
|
||||||
if angle < -45:
|
|
||||||
angle = -(90 + angle)
|
|
||||||
else:
|
|
||||||
angle = -angle
|
|
||||||
|
|
||||||
if abs(angle) < angle_threshold:
|
if abs(angle) < angle_threshold:
|
||||||
return image
|
return image
|
||||||
|
@ -73,6 +62,7 @@ def auto_rotate(image, angle_threshold=10):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def crop_borders(image, border_color, tolerance=30):
|
def crop_borders(image, border_color, tolerance=30):
|
||||||
mask = cv2.inRange(image, border_color - tolerance, border_color + tolerance)
|
mask = cv2.inRange(image, border_color - tolerance, border_color + tolerance)
|
||||||
|
|
||||||
|
@ -112,23 +102,15 @@ def split_photos(input_file, output_directory, tolerance=30, min_area=10000, min
|
||||||
print(f"Saved {output_path}")
|
print(f"Saved {output_path}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) < 2:
|
parser = argparse.ArgumentParser(description="Split photos in an image")
|
||||||
print("Usage: python3 split_photos.py <input_file> <output_directory> [tolerance] [min_area] [min_contour_area] [angle_threshold] [border_size]")
|
parser.add_argument("input_file", help="The input scanned image containing multiple photos.")
|
||||||
print("\nParameters:")
|
parser.add_argument("output_directory", help="The directory where the result images should be placed.")
|
||||||
print(" <input_file> - The input scanned image containing multiple photos.")
|
parser.add_argument("--tolerance", type=int, default=30, help="Determines the range of color variation around the estimated background color (default: 30).")
|
||||||
print(" <output_directory> - The directory where the result images should be placed.")
|
parser.add_argument("--min_area", type=int, default=10000, help="Sets the minimum area threshold for a photo (default: 10000).")
|
||||||
print(" [tolerance] - Optional. Determines the range of color variation around the estimated background color (default: 30).")
|
parser.add_argument("--min_contour_area", type=int, default=500, help="Sets the minimum contour area threshold for a photo (default: 500).")
|
||||||
print(" [min_area] - Optional. Sets the minimum area threshold for a photo (default: 10000).")
|
parser.add_argument("--angle_threshold", type=int, default=10, help="Sets the minimum absolute angle required for the image to be rotated (default: 10).")
|
||||||
print(" [min_contour_area] - Optional. Sets the minimum contour area threshold for a photo (default: 500).")
|
parser.add_argument("--border_size", type=int, default=0, help="Sets the size of the border added and removed to prevent white borders in the output (default: 0).")
|
||||||
print(" [angle_threshold] - Optional. Sets the minimum absolute angle required for the image to be rotated (default: 10).")
|
|
||||||
print(" [border_size] - Optional. Sets the size of the border added and removed to prevent white borders in the output (default: 0).")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
input_file = sys.argv[1]
|
args = parser.parse_args()
|
||||||
output_directory = sys.argv[2]
|
|
||||||
tolerance = int(sys.argv[6]) if len(sys.argv) > 3 else 20
|
split_photos(args.input_file, args.output_directory, tolerance=args.tolerance, min_area=args.min_area, min_contour_area=args.min_contour_area, angle_threshold=args.angle_threshold, border_size=args.border_size)
|
||||||
min_area = int(sys.argv[8]) if len(sys.argv) > 4 else 8000
|
|
||||||
min_contour_area = int(sys.argv[10]) if len(sys.argv) > 5 else 500
|
|
||||||
angle_threshold = int(sys.argv[4]) if len(sys.argv) > 6 else 60
|
|
||||||
border_size = int(sys.argv[12]) if len(sys.argv) > 7 else 0
|
|
||||||
split_photos(input_file, output_directory, tolerance=tolerance, min_area=min_area, min_contour_area=min_contour_area, angle_threshold=angle_threshold, border_size=border_size)
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>
|
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label>
|
<label for="angleThreshold" th:text="#{ScannerImageSplit.selectText.1}"></label>
|
||||||
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="5">
|
<input type="number" class="form-control" id="angleThreshold" name="angle_threshold" value="10">
|
||||||
<small id="angleThresholdHelp" class="form-text text-muted" th:text="#{ScannerImageSplit.selectText.2}"></small>
|
<small id="angleThresholdHelp" class="form-text text-muted" th:text="#{ScannerImageSplit.selectText.2}"></small>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
Loading…
Reference in a new issue