Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import numpy as np
- import cv2
- import math
- def subimage(image, center, theta, width, height):
- if 45 < theta <= 90:
- theta = theta - 90
- width, height = height, width
- theta *= math.pi / 180 # convert to rad
- v_x = (math.cos(theta), math.sin(theta))
- v_y = (-math.sin(theta), math.cos(theta))
- s_x = center[0] - v_x[0] * (width / 2) - v_y[0] * (height / 2)
- s_y = center[1] - v_x[1] * (width / 2) - v_y[1] * (height / 2)
- mapping = np.array([[v_x[0],v_y[0], s_x], [v_x[1],v_y[1], s_y]])
- return cv2.warpAffine(image, mapping, (width, height), flags=cv2.WARP_INVERSE_MAP, borderMode=cv2.BORDER_REPLICATE)
- def get_threshold_clr(image_source):
- h, w = image_source.shape[:2]
- inset = math.ceil(.1*(h + w)/2)
- mismatch = 0
- corners = ((inset, inset), (w-inset, h-inset), (inset, h-inset), (w-inset, inset))
- clr = None
- for crnr1 in corners:
- for crnr2 in corners:
- if (np.linalg.norm(image_src[crnr1] - image_src[crnr2]) > 3):
- mismatch += 1
- break
- else:
- clr = image_src[crnr1]
- if (mismatch > 3 + 3 or clr == None):
- return None
- else:
- # Get one threshold value
- clr = np.mean(clr)
- if (clr > 250):
- return 240
- elif(clr < 10):
- return 20
- else:
- None
- def auto_crop(image_source):
- # First slightly crop edge - some images had a rogue 2 pixel black edge on one side
- init_crop = 5
- h, w = image_source.shape[:2]
- image_source = image_source[init_crop:init_crop+(h-init_crop*2), init_crop:init_crop+(w-init_crop*2)]
- threshold = get_threshold_clr(image_source)
- if (threshold == None):
- return image_source
- edge_clr = 255
- if (threshold < 128):
- edge_clr = 0
- # Add back a white border
- image_source = cv2.copyMakeBorder(image_source, 5,5,5,5, cv2.BORDER_CONSTANT, value=(edge_clr, edge_clr, edge_clr))
- image_gray = cv2.cvtColor(image_source, cv2.COLOR_BGR2GRAY)
- _, image_thresh = cv2.threshold(image_gray, threshold, 255, cv2.THRESH_BINARY)
- image_thresh2 = image_thresh.copy()
- image_thresh2 = cv2.Canny(image_thresh2, 100, 100, apertureSize=3)
- points = cv2.findNonZero(image_thresh2)
- centre, dimensions, theta = cv2.minAreaRect(points)
- rect = cv2.minAreaRect(points)
- width = int(dimensions[0])
- height = int(dimensions[1])
- box = cv2.boxPoints(rect)
- box = np.int0(box)
- temp = image_source.copy()
- cv2.drawContours(temp, [box], 0, (255,0,0), 2)
- M = cv2.moments(box)
- cx = int(M['m10']/M['m00'])
- cy = int(M['m01']/M['m00'])
- image_patch = subimage(image_source, (cx, cy), theta+90, height, width)
- # add back a small border
- image_patch = cv2.copyMakeBorder(image_patch, 1,1,1,1, cv2.BORDER_CONSTANT, value=(edge_clr,edge_clr,edge_clr))
- # Convert image to binary, edge is black. Do edge detection and convert edges to a list of points.
- # Then calculate a minimum set of points that can enclose the points.
- _, image_thresh = cv2.threshold(image_patch, threshold, 255, 1)
- image_thresh = cv2.Canny(image_thresh, 100, 100, 3)
- points = cv2.findNonZero(image_thresh)
- hull = cv2.convexHull(points)
- # Find min epsilon resulting in exactly 4 points, typically between 7 and 21
- # This is the smallest set of 4 points to enclose the image.
- for epsilon in range(3, 50):
- hull_simple = cv2.approxPolyDP(hull, epsilon, 1)
- if len(hull_simple) == 4:
- break
- hull = hull_simple
- # Find closest fitting image size and warp/crop to fit
- # (ie reduce scaling to a minimum)
- x,y,w,h = cv2.boundingRect(hull)
- target_corners = np.array([[0,0],[w,0],[w,h],[0,h]], np.float32)
- # Sort hull into tl,tr,br,bl order.
- # n.b. hull is already sorted in clockwise order, we just need to know where top left is.
- source_corners = hull.reshape(-1,2).astype('float32')
- min_dist = 100000
- index = 0
- for n in xrange(len(source_corners)):
- x,y = source_corners[n]
- dist = math.hypot(x,y)
- if dist < min_dist:
- index = n
- min_dist = dist
- # Rotate the array so tl is first
- source_corners = np.roll(source_corners , -(2*index))
- try:
- transform = cv2.getPerspectiveTransform(source_corners, target_corners)
- return cv2.warpPerspective(image_patch, transform, (w,h))
- except:
- print "Warp failure"
- return image_patch
- if __name__ == "__main__":
- import os
- import re
- import sys
- cv2.namedWindow("Original")
- cv2.namedWindow("Cropped")
- if (len(sys.argv) < 2):
- sys.exit()
- else:
- source_dir = sys.argv[1]
- if (not re.search("^/", source_dir)):
- source_dir = "{0}/{1}".format(os.path.dirname(os.path.realpath(__file__)),
- source_dir)
- if not os.path.isdir(source_dir):
- print "The source directory '{0}' does not exist".format(source_dir)
- sys.exit()
- for (directory, _, files) in os.walk(source_dir):
- for f in files:
- if re.search("\\.png$", f) and\
- not re.search("^cropped_", f):
- path = os.path.join(directory, f)
- image_src = cv2.imread(path)
- image_cropped = auto_crop(image_src)
- cv2.imwrite(os.path.join(directory, "cropped_{0}".format(f)),
- image_cropped)
- print "Processed file {0}".format(f)
- cv2.imshow("Original", image_src)
- cv2.imshow("Cropped", image_cropped)
- cv2.waitKey(0)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement