Spaces:
Build error
Build error
#coding=utf-8 | |
''' | |
@author: dengdan | |
''' | |
import cv2 | |
import numpy as np | |
import logging | |
import math | |
import event | |
import util | |
IMREAD_GRAY = 0 | |
IMREAD_COLOR = 1 | |
IMREAD_UNCHANGED = -1 | |
COLOR_WHITE =(255, 255, 255) | |
COLOR_BLACK = (0, 0, 0) | |
COLOR_GREEN = (0, 255, 0) | |
COLOR_RGB_RED = (255, 0, 0) | |
COLOR_BGR_RED = (0, 0, 255) | |
COLOR_RGB_BLUE = (0, 0, 255) | |
COLOR_BGR_BLUE = (255, 0, 0) | |
COLOR_RGB_YELLOW = (255, 255, 0) | |
COLOR_BGR_YELLOW = (0, 255, 255) | |
COLOR_RGB_GRAY = (47, 79, 79) | |
COLOR_RGB_PINK = (255, 192, 203) | |
def imread(path, rgb = False, mode = cv2.IMREAD_COLOR): | |
path = util.io.get_absolute_path(path) | |
img = cv2.imread(path, mode) | |
if img is None: | |
raise IOError('File not found:%s'%(path)) | |
if rgb: | |
img = bgr2rgb(img) | |
return img | |
def imshow(winname, img, block = True, position = None, maximized = False, rgb = False): | |
if isinstance(img, str): | |
img = imread(path = img) | |
cv2.namedWindow(winname, cv2.WINDOW_NORMAL) | |
if rgb: | |
img = rgb2bgr(img) | |
cv2.imshow(winname, img) | |
if position is not None: | |
# cv2.moveWindow(winname, position[0], position[1]) | |
move_win(winname, position) | |
if maximized: | |
maximize_win(winname) | |
if block: | |
# cv2.waitKey(0) | |
event.wait_key(" ") | |
cv2.destroyAllWindows() | |
def imwrite(path, img, rgb = False): | |
if rgb: | |
img = rgb2bgr(img) | |
path = util.io.get_absolute_path(path) | |
util.io.make_parent_dir(path) | |
cv2.imwrite(path, img) | |
def move_win(winname, position = (0, 0)): | |
""" | |
move pyplot window | |
""" | |
cv2.moveWindow(winname, position[0], position[1]) | |
def maximize_win(winname): | |
cv2.setWindowProperty(winname, cv2.WND_PROP_FULLSCREEN, True); | |
def eq_color(target, color): | |
for i, c in enumerate(color): | |
if target[i] != color[i]: | |
return False | |
return True | |
def is_white(color): | |
for c in color: | |
if c < 255: | |
return False | |
return True | |
def black(shape): | |
if len(np.shape(shape)) >= 2: | |
shape = get_shape(shape) | |
shape = [int(v) for v in shape] | |
return np.zeros(shape, np.uint8) | |
def white(shape, value = 255): | |
if len(np.shape(shape)) >= 2: | |
shape = get_shape(shape) | |
return np.ones(shape, np.uint8) * np.uint8(value) | |
def bgr2rgb(img): | |
return cv2.cvtColor(img, cv2.COLOR_BGR2RGB) | |
def rgb2bgr(img): | |
return cv2.cvtColor(img, cv2.COLOR_RGB2BGR) | |
def rgb2gray(img): | |
return cv2.cvtColor(img, cv2.COLOR_RGB2GRAY) | |
def bgr2gray(img): | |
return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) | |
def ds_size(image_size, kernel_size, stride): | |
"""calculate the size of downsampling result""" | |
image_x, image_y = image_size | |
kernel_x, kernel_y = kernel_size | |
stride_x, stride_y = stride | |
def f(iw, kw, sw): | |
return int(np.floor((iw - kw) / sw) + 1) | |
output_size = (f(image_x, kernel_x, stride_x), f(image_y, kernel_y, stride_y)) | |
return output_size | |
def get_roi(img, p1, p2): | |
""" | |
extract region of interest from an image. | |
p1, p2: two tuples standing for two opposite corners of the rectangle bounding the roi. | |
Their order is arbitrary. | |
""" | |
x1, y1 = p1 | |
x2, y2 = p2 | |
x_min = min([x1, x2]) | |
y_min = min([y1, y2]) | |
x_max = max([x1, x2]) + 1 | |
y_max = max([y1, y2]) + 1 | |
return img[y_min: y_max, x_min: x_max] | |
def rectangle(img, left_up, right_bottom, color, border_width = 1): | |
left_up = (int(left_up[0]), int(left_up[1])) | |
right_bottom = (int(right_bottom[0]), int(right_bottom[1])) | |
cv2.rectangle(img, left_up, right_bottom, color, border_width) | |
def circle(img, center, r, color, border_width = 1): | |
center = (int(center[0]), int(center[1])) | |
cv2.circle(img, center, r, color, border_width) | |
def render_points(img, points, color): | |
for p in points: | |
x, y = p | |
img[y][x] = color | |
def draw_contours(img, contours, idx = -1, color = 1, border_width = 1): | |
# img = img.copy() | |
cv2.drawContours(img, contours, idx, color, border_width) | |
return img | |
def get_contour_rect_box(contour): | |
x,y,w,h = cv2.boundingRect(contour) | |
return x, y, w, h | |
def get_contour_region_in_rect(img, contour): | |
x, y, w, h = get_contour_rect_box(contour) | |
lu, rb = (x, y), (x + w, y + h) | |
return get_roi(img, lu, rb) | |
def get_contour_min_area_box(contour): | |
rect = cv2.minAreaRect(contour) | |
box = cv2.cv.BoxPoints(rect) | |
box = np.int0(box) | |
return box | |
def get_contour_region_in_min_area_rect(img, cnt): | |
# find the min area rect of contour | |
rect = cv2.minAreaRect(cnt) | |
angle = rect[-1] | |
box = cv2.cv.BoxPoints(rect) | |
box_cnt = points_to_contour(box) | |
# find the rectangle containing box_cnt, and set it as ROI | |
outer_rect = get_contour_rect_box(box_cnt) | |
x, y, w, h = outer_rect | |
img = get_roi(img, (x, y), (x + w, y + h)) | |
box = [(ox - x, oy - y) for (ox, oy) in box] | |
# rotate ROI and corner points | |
rows, cols = get_shape(img) | |
M = cv2.getRotationMatrix2D((cols/2,rows/2), angle, scale = 1) | |
dst = cv2.warpAffine(img,M,(cols,rows)) | |
bar_xy = np.hstack((box, np.ones((4, 1)))) | |
new_corners = np.dot(M, np.transpose(bar_xy)) | |
new_corners = util.dtype.int(np.transpose(new_corners)) | |
# cnt = points_to_contour(new_corners) | |
xs = new_corners[:, 0] | |
ys = new_corners[:, 1] | |
lu = (min(xs), min(ys)) | |
rb = (max(xs), max(ys)) | |
return get_roi(dst, lu, rb) | |
def contour_to_points(contour): | |
return np.asarray([c[0] for c in contour]) | |
def points_to_contour(points): | |
contours = [[list(p)]for p in points] | |
return np.asarray(contours, dtype = np.int32) | |
def points_to_contours(points): | |
return np.asarray([points_to_contour(points)]) | |
def get_contour_region_iou(I, cnt1, cnt2): | |
""" | |
calculate the iou of two contours | |
""" | |
mask1 = util.img.black(I) | |
draw_contours(mask1, [cnt1], color = 1, border_width = -1) | |
mask2 = util.img.black(I) | |
draw_contours(mask2, [cnt2], color = 1, border_width = -1) | |
union_mask = ((mask1 + mask2) >=1) * 1 | |
intersect_mask = (mask1 * mask2 >= 1) * 1 | |
return np.sum(intersect_mask) * 1.0 / np.sum(union_mask) | |
def fill_bbox(img, box, color = 1): | |
""" | |
filling a bounding box with color. | |
box: a list of 4 points, in clockwise order, as the four vertice of a bounding box | |
""" | |
util.test.assert_equal(np.shape(box), (4, 2)) | |
cnt = to_contours(box) | |
draw_contours(img, cnt, color = color, border_width = -1) | |
def get_rect_points(left_up, right_bottom): | |
""" | |
given the left up and right bottom points of a rectangle, return its four points | |
""" | |
right_bottom, left_up = np.asarray(right_bottom), np.asarray(left_up) | |
w, h = right_bottom - left_up | |
x, y = left_up | |
points = [(x, y), (x + w, y), (x + w, y + h), (x, y + h)] | |
return points | |
def rect_perimeter(left_up, right_bottom): | |
""" | |
calculate the perimeter of the rectangle described by its left-up and right-bottom point. | |
""" | |
return sum(np.asarray(right_bottom) - np.asarray(left_up)) * 2 | |
def rect_area(left_up, right_bottom): | |
wh = np.asarray(right_bottom) - np.asarray(left_up) + 1 | |
return np.prod(wh) | |
def apply_mask(img, mask): | |
""" | |
the img will be masked in place. | |
""" | |
c = np.shape(img)[-1] | |
for i in range(c): | |
img[:, :, i] = img[:, :, i] * mask | |
return img | |
def get_shape(img): | |
""" | |
return the height and width of an image | |
""" | |
return np.shape(img)[0:2] | |
def get_wh(img): | |
return np.shape(img)[0:2][::-1] | |
def get_value(img, x, y = None): | |
if y == None: | |
y = x[1] | |
x = x[0] | |
return img[y][x] | |
def set_value(img, xy, val): | |
x, y = xy | |
img[y][x] = val | |
def filter2D(img, kernel): | |
dst = cv2.filter2D(img, -1, kernel) | |
return dst | |
def average_blur(img, shape = (5, 5)): | |
return cv2.blur(img, shape) | |
def gaussian_blur(img, shape = (5, 5), sigma = 0): | |
# sigma --> sigmaX, sigmaY | |
blur = cv2.GaussianBlur(img,shape, sigma) | |
return blur | |
def bilateral_blur(img, d = 9, sigmaColor = 75, sigmaSpace = 75): | |
dst = cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace) | |
return dst | |
BLUR_AVERAGE = 'average' | |
BLUR_GAUSSIAN = 'gaussian' | |
BLUR_BILATERAL = 'bilateral' | |
_blur_dict = { | |
BLUR_AVERAGE: average_blur, | |
BLUR_GAUSSIAN: gaussian_blur, | |
BLUR_BILATERAL: bilateral_blur | |
} | |
def blur(img, blur_type): | |
fn = _blur_dict[blur_type] | |
return fn(img) | |
def put_text(img, text, pos, scale = 1, color = COLOR_WHITE, thickness = 1): | |
pos = np.int32(pos) | |
font = cv2.FONT_HERSHEY_SIMPLEX | |
cv2.putText(img = img, text = text, org = tuple(pos), fontFace = font, fontScale = scale, color = color, thickness = thickness) | |
def resize(img, f = None, fx = None, fy = None, size = None, interpolation = cv2.INTER_LINEAR): | |
""" | |
size: (w, h) | |
""" | |
h, w = get_shape(img) | |
if fx != None and fy != None: | |
return cv2.resize(img, None, fx = fx, fy = fy, interpolation = interpolation) | |
if size != None: | |
size = util.dtype.int(size) | |
# size = (size[1], size[0]) | |
size = tuple(size) | |
return cv2.resize(img, size, interpolation = interpolation) | |
return cv2.resize(img, None, fx = f, fy = f, interpolation = interpolation) | |
def translate(img, delta_x, delta_y, size = None): | |
M = np.float32([[1,0, delta_x],[0,1, delta_y]]) | |
if size == None: | |
size = get_wh(img) | |
dst = cv2.warpAffine(img,M, size) | |
return dst | |
def rotate_about_center(src, angle, scale=1.): | |
"""https://www.oschina.net/translate/opencv-rotation""" | |
w = src.shape[1] | |
h = src.shape[0] | |
rangle = np.deg2rad(angle) # angle in radians | |
# now calculate new image width and height | |
nw = (abs(np.sin(rangle)*h) + abs(np.cos(rangle)*w))*scale | |
nh = (abs(np.cos(rangle)*h) + abs(np.sin(rangle)*w))*scale | |
# ask OpenCV for the rotation matrix | |
rot_mat = cv2.getRotationMatrix2D((nw*0.5, nh*0.5), angle, scale) | |
# calculate the move from the old center to the new center combined | |
# with the rotation | |
rot_move = np.dot(rot_mat, np.array([(nw-w)*0.5, (nh-h)*0.5,0])) | |
# the move only affects the translation, so update the translation | |
# part of the transform | |
rot_mat[0,2] += rot_move[0] | |
rot_mat[1,2] += rot_move[1] | |
return cv2.warpAffine(src, rot_mat, (int(math.ceil(nw)), int(math.ceil(nh))), flags=cv2.INTER_LANCZOS4), rot_mat | |
def get_rect_iou(rects1, rects2): | |
""" | |
calculate the iou between rects1 and rects2 | |
each rect consists of four points:[min_x, min_y, max_x, max_y] | |
return: a iou matrix, len(rects1) * len(rects2) | |
""" | |
rects1, rects2 = np.asarray(rects1), np.asarray(rects2) | |
def _to_matrix(p, ps): | |
p = np.ones((len(ps), 1)) * p | |
ps = np.reshape(ps, (len(ps), 1)) | |
temp =np.hstack([p, ps]) | |
return temp | |
def _get_max(p, ps): | |
return np.max(_to_matrix(p, ps), axis = 1) | |
def _get_min(p, ps): | |
return np.min(_to_matrix(p, ps), axis = 1) | |
def _get_area(rect): | |
w, h = rect[:, 2] - rect[:, 0] + 1.0 , rect[:, 3] - rect[:, 1] + 1.0 | |
return w * h | |
def _get_inter(rect1, rects2): | |
x1 = _get_max(rect1[0], rects2[:, 0]) | |
y1 = _get_max(rect1[1], rects2[:, 1]) | |
x2 = _get_min(rect1[2], rects2[:, 2]) | |
y2 = _get_min(rect1[3], rects2[:, 3]) | |
w,h = x2-x1 +1, y2 - y1 + 1 | |
areas = w * h | |
areas[np.where(w < 0)] = 0 | |
areas[np.where(h < 0)] = 0 | |
return areas | |
area2 = _get_area(rects2) | |
area1 = _get_area(rects1) | |
iou = np.zeros((len(rects1), len(rects2))) | |
for ri in range(len(rects1)): | |
inter = _get_inter(rects1[ri, :], rects2) | |
union = area1[ri] + area2 - inter | |
iou[ri, :] = np.transpose( inter / union) | |
return iou | |
def find_contours(mask): | |
mask = np.asarray(mask, dtype = np.uint8) | |
mask = mask.copy() | |
contours, _ = cv2.findContours(mask, mode = cv2.RETR_CCOMP, | |
method = cv2.CHAIN_APPROX_SIMPLE) | |
return contours | |
def find_two_level_contours(mask): | |
mask = mask.copy() | |
contours, tree = cv2.findContours(mask, mode = cv2.RETR_CCOMP, | |
method = cv2.CHAIN_APPROX_SIMPLE) | |
return contours, tree | |
def is_in_contour(point, cnt): | |
"""tell whether a point is in contour or not. | |
In-contour here includes both the 'in contour' and 'on contour' cases. | |
point:(x, y) | |
cnt: a cv2 contour | |
""" | |
# doc of pointPolygonTest: http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=pointpolygontest#cv.PointPolygonTest | |
# the last argument means only tell if in or not, without calculating the shortest distance | |
in_cnt = cv2.pointPolygonTest(cnt, point, False) | |
return in_cnt >= 0; | |
def convex_hull(contour): | |
hull = cv2.convexHull(contour, returnPoints=1) | |
return hull | |
def random_color_3(): | |
c = util.rand.randint(low = 0, high = 255, shape = (3, )) | |
# c = np.uint8(c) | |
return c | |
def get_contour_area(cnt): | |
return cv2.contourArea(cnt) | |
def is_valid_jpg(jpg_file): | |
with open(jpg_file, 'rb') as f: | |
f.seek(-2, 2) | |
return f.read() == '\xff\xd9' | |
def rotate_point_by_90(x, y, k, w = 1.0, h = 1.0): | |
""" | |
Rotate a point xy on an image by k * 90 | |
degrees. | |
Params: | |
x, y: a point, (x, y). If not normalized within 0 and 1, the | |
width and height of the image should be specified clearly. | |
w, h: the width and height of image | |
k: k * 90 degrees will be rotated | |
""" | |
k = k % 4 | |
if k == 0: | |
return x, y | |
elif k == 1: | |
return y, w - x | |
elif k == 2: | |
return w - x, h - y | |
elif k == 3: | |
return h - y, x | |
def min_area_rect(xs, ys): | |
""" | |
Args: | |
xs: numpy ndarray with shape=(N,4). N is the number of oriented bboxes. 4 contains [x1, x2, x3, x4] | |
ys: numpy ndarray with shape=(N,4), [y1, y2, y3, y4] | |
Note that [(x1, y1), (x2, y2), (x3, y3), (x4, y4)] can represent an oriented bbox. | |
Return: | |
the oriented rects sorrounding the box, in the format:[cx, cy, w, h, theta]. | |
""" | |
xs = np.asarray(xs, dtype = np.float32) | |
ys = np.asarray(ys, dtype = np.float32) | |
num_rects = xs.shape[0] | |
box = np.empty((num_rects, 5))#cx, cy, w, h, theta | |
for idx in xrange(num_rects): | |
points = zip(xs[idx, :], ys[idx, :]) | |
cnt = points_to_contour(points) | |
rect = cv2.minAreaRect(cnt) | |
cx, cy = rect[0] | |
w, h = rect[1] | |
theta = rect[2] | |
box[idx, :] = [cx, cy, w, h, theta] | |
box = np.asarray(box, dtype = xs.dtype) | |
return box | |