import cv2 from PIL import Image import numpy as np import functools import time def calTime(mark): """ 一个输出函数时间的装饰器. :param mark: str, 可选填, 如果填了就会在print开头加上mark标签。 """ if isinstance(mark, str): def decorater(func): @functools.wraps(func) def wrapper(*args, **kw): start_time = time.time() return_param = func(*args, **kw) print("[Mark-{}] {} 函数花费的时间为 {:.2f}.".format(mark, func.__name__, time.time() - start_time)) return return_param return wrapper return decorater else: func = mark @functools.wraps(func) def wrapper(*args, **kw): start_time = time.time() return_param = func(*args, **kw) print("{} 函数花费的时间为 {:.2f}.".format(func.__name__, time.time() - start_time)) return return_param return wrapper def ChangeImageDPI(input_path, output_path, dpi=300): """ 改变输入图像的dpi. input_path: 输入图像路径 output_path: 输出图像路径 dpi:打印分辨率 """ image = Image.open(input_path) image.save(output_path, dpi=(dpi, dpi)) # print(1) print("Your Image's DPI have been changed. The last DPI = ({},{}) ".format(dpi,dpi)) def IDphotos_cut(x1, y1, x2, y2, img): """ 在图片上进行滑动裁剪,输入输出为 输入:一张图片img,和裁剪框信息(x1,x2,y1,y2) 输出: 裁剪好的图片,然后裁剪框超出了图像范围,那么将用0矩阵补位 ------------------------------------ x:裁剪框左上的横坐标 y:裁剪框左上的纵坐标 x2:裁剪框右下的横坐标 y2:裁剪框右下的纵坐标 crop_size:裁剪框大小 img:裁剪图像(numpy.array) output_path:裁剪图片的输出路径 ------------------------------------ """ crop_size = (y2-y1, x2-x1) """ ------------------------------------ temp_x_1:裁剪框左边超出图像部分 temp_y_1:裁剪框上边超出图像部分 temp_x_2:裁剪框右边超出图像部分 temp_y_2:裁剪框下边超出图像部分 ------------------------------------ """ temp_x_1 = 0 temp_y_1 = 0 temp_x_2 = 0 temp_y_2 = 0 if y1 < 0: temp_y_1 = abs(y1) y1 = 0 if y2 > img.shape[0]: temp_y_2 = y2 y2 = img.shape[0] temp_y_2 = temp_y_2 - y2 if x1 < 0: temp_x_1 = abs(x1) x1 = 0 if x2 > img.shape[1]: temp_x_2 = x2 x2 = img.shape[1] temp_x_2 = temp_x_2 - x2 # 生成一张全透明背景 print("crop_size:", crop_size) background_bgr = np.full((crop_size[0], crop_size[1]), 255, dtype=np.uint8) background_a = np.full((crop_size[0], crop_size[1]), 0, dtype=np.uint8) background = cv2.merge((background_bgr, background_bgr, background_bgr, background_a)) background[temp_y_1: crop_size[0] - temp_y_2, temp_x_1: crop_size[1] - temp_x_2] = img[y1:y2, x1:x2] return background def resize_image_esp(input_image, esp=2000): """ 输入: input_path:numpy图片 esp:限制的最大边长 """ # resize函数=>可以让原图压缩到最大边为esp的尺寸(不改变比例) width = input_image.shape[0] length = input_image.shape[1] max_num = max(width, length) if max_num > esp: print("Image resizing...") if width == max_num: length = int((esp / width) * length) width = esp else: width = int((esp / length) * width) length = esp print(length, width) im_resize = cv2.resize(input_image, (length, width), interpolation=cv2.INTER_AREA) return im_resize else: return input_image def resize_image_by_min(input_image, esp=600): """ 将图像缩放为最短边至少为esp的图像。 :param input_image: 输入图像(OpenCV矩阵) :param esp: 缩放后的最短边长 :return: 缩放后的图像,缩放倍率 """ height, width = input_image.shape[0], input_image.shape[1] min_border = min(height, width) if min_border < esp: if height >= width: new_width = esp new_height = height * esp // width else: new_height = esp new_width = width * esp // height return cv2.resize(input_image, (new_width, new_height), interpolation=cv2.INTER_AREA), new_height / height else: return input_image, 1 def detect_distance(value, crop_heigh, max=0.06, min=0.04): """ 检测人头顶与照片顶部的距离是否在适当范围内。 输入:与顶部的差值 输出:(status, move_value) status=0 不动 status=1 人脸应向上移动(裁剪框向下移动) status-2 人脸应向下移动(裁剪框向上移动) --------------------------------------- value:头顶与照片顶部的距离· crop_heigh: 裁剪框的高度 max: 距离的最大值 min: 距离的最小值 --------------------------------------- """ value = value / crop_heigh # 头顶往上的像素占图像的比例 if min <= value <= max: return 0, 0 elif value > max: # 头顶往上的像素比例高于max move_value = value - max move_value = int(move_value * crop_heigh) # print("上移{}".format(move_value)) return 1, move_value else: # 头顶往上的像素比例低于min move_value = min - value move_value = int(move_value * crop_heigh) # print("下移{}".format(move_value)) return -1, move_value def draw_picture_dots(image, dots, pen_size=10, pen_color=(0, 0, 255)): """ 给一张照片上绘制点。 image: Opencv图像矩阵 dots: 一堆点,形如[(100,100),(150,100)] pen_size: 画笔的大小 pen_color: 画笔的颜色 """ if isinstance(dots, dict): dots = [v for u, v in dots.items()] image = image.copy() for x, y in dots: cv2.circle(image, (int(x), int(y)), pen_size, pen_color, -1) return image def draw_picture_rectangle(image, bbox, pen_size=2, pen_color=(0, 0, 255)): image = image.copy() x1 = int(bbox[0]) y1 = int(bbox[1]) x2 = int(bbox[2]) y2 = int(bbox[3]) cv2.rectangle(image, (x1,y1), (x2, y2), pen_color, pen_size) return image def generate_gradient(start_color, width, height, mode="updown"): # 定义背景颜色 end_color = (255, 255, 255) # 白色 # 创建一个空白图像 r_out = np.zeros((height, width), dtype=int) g_out = np.zeros((height, width), dtype=int) b_out = np.zeros((height, width), dtype=int) if mode == "updown": # 生成上下渐变色 for y in range(height): r = int((y / height) * end_color[0] + ((height - y) / height) * start_color[0]) g = int((y / height) * end_color[1] + ((height - y) / height) * start_color[1]) b = int((y / height) * end_color[2] + ((height - y) / height) * start_color[2]) r_out[y, :] = r g_out[y, :] = g b_out[y, :] = b else: # 生成中心渐变色 img = np.zeros((height, width, 3)) # 定义椭圆中心和半径 center = (width//2, height//2) end_axies = max(height, width) # 定义渐变色 end_color = (255, 255, 255) # 绘制椭圆 for y in range(end_axies): axes = (end_axies - y, end_axies - y) r = int((y / end_axies) * end_color[0] + ((end_axies - y) / end_axies) * start_color[0]) g = int((y / end_axies) * end_color[1] + ((end_axies - y) / end_axies) * start_color[1]) b = int((y / end_axies) * end_color[2] + ((end_axies - y) / end_axies) * start_color[2]) cv2.ellipse(img, center, axes, 0, 0, 360, (b, g, r), -1) b_out, g_out, r_out = cv2.split(np.uint64(img)) return r_out, g_out, b_out def add_background(input_image, bgr=(0, 0, 0), mode="pure_color"): """ 本函数的功能为为透明图像加上背景。 :param input_image: numpy.array(4 channels), 透明图像 :param bgr: tuple, 合成纯色底时的BGR值 :param new_background: numpy.array(3 channels),合成自定义图像底时的背景图 :return: output: 合成好的输出图像 """ height, width = input_image.shape[0], input_image.shape[1] b, g, r, a = cv2.split(input_image) a_cal = a / 255 if mode == "pure_color": # 纯色填充 b2 = np.full([height, width], bgr[0], dtype=int) g2 = np.full([height, width], bgr[1], dtype=int) r2 = np.full([height, width], bgr[2], dtype=int) elif mode == "updown_gradient": b2, g2, r2 = generate_gradient(bgr, width, height, mode="updown") else: b2, g2, r2 = generate_gradient(bgr, width, height, mode="center") output = cv2.merge(((b - b2) * a_cal + b2, (g - g2) * a_cal + g2, (r - r2) * a_cal + r2)) return output def rotate_bound(image, angle): """ 一个旋转函数,输入一张图片和一个旋转角,可以实现不损失图像信息的旋转。 - image: numpy.array(3 channels) - angle: 旋转角(度) """ (h, w) = image.shape[:2] (cX, cY) = (w / 2, h / 2) M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0) cos = np.abs(M[0, 0]) sin = np.abs(M[0, 1]) nW = int((h * sin) + (w * cos)) nH = int((h * cos) + (w * sin)) M[0, 2] += (nW / 2) - cX M[1, 2] += (nH / 2) - cY return cv2.warpAffine(image, M, (nW, nH)), cos, sin def rotate_bound_4channels(image, a, angle): """ 【rotate_bound_4channels的4通道版本】 一个旋转函数,输入一张图片和一个旋转角,可以实现不损失图像信息的旋转。 Inputs: - image: numpy.array(3 channels), 输入图像 - a: numpy.array(1 channels), 输入图像的A矩阵 - angle: 旋转角(度) Returns: - input_image: numpy.array(3 channels), 对image进行旋转后的图像 - result_image: numpy.array(4 channels), 旋转且透明的图像 - cos: float, 旋转角的余弦值 - sin: float, 旋转角的正弦值 """ input_image, cos, sin = rotate_bound(image, angle) new_a, _, _ = rotate_bound(a, angle) # 对做matte旋转,以便之后merge b, g, r = cv2.split(input_image) result_image = cv2.merge((b, g, r, new_a)) # 得到抠图结果图的无损旋转结果 return input_image, result_image, cos, sin def cover_image(image, background, x, y, mode=1): """ mode = 1: directly cover mode = 2: cv2.add mode = 3: bgra cover """ image = image.copy() background = background.copy() height1, width1 = background.shape[0], background.shape[1] height2, width2 = image.shape[0], image.shape[1] wuqiong_bg_y = height1 + 1 wuqiong_bg_x = width1 + 1 wuqiong_img_y = height2 + 1 wuqiong_img_x = width2 + 1 def cover_mode(image, background, imgy1=0, imgy2=-1, imgx1=0, imgx2=-1, bgy1=0, bgy2=-1, bgx1=0, bgx2=-1, mode=1): if mode == 1: background[bgy1:bgy2, bgx1:bgx2] = image[imgy1:imgy2, imgx1:imgx2] elif mode == 2: background[bgy1:bgy2, bgx1:bgx2] = cv2.add(background[bgy1:bgy2, bgx1:bgx2], image[imgy1:imgy2, imgx1:imgx2]) elif mode == 3: b, g, r, a = cv2.split(image[imgy1:imgy2, imgx1:imgx2]) b2, g2, r2, a2 = cv2.split(background[bgy1:bgy2, bgx1:bgx2]) background[bgy1:bgy2, bgx1:bgx2, 0] = b * (a / 255) + b2 * (1 - a / 255) background[bgy1:bgy2, bgx1:bgx2, 1] = g * (a / 255) + g2 * (1 - a / 255) background[bgy1:bgy2, bgx1:bgx2, 2] = r * (a / 255) + r2 * (1 - a / 255) background[bgy1:bgy2, bgx1:bgx2, 3] = cv2.add(a, a2) return background if x >= 0 and y >= 0: x2 = x + width2 y2 = y + height2 if x2 <= width1 and y2 <= height1: background = cover_mode(image, background,0,wuqiong_img_y,0,wuqiong_img_x,y,y2,x,x2,mode) elif x2 > width1 and y2 <= height1: # background[y:y2, x:] = image[:, :width1 - x] background = cover_mode(image, background, 0, wuqiong_img_y, 0, width1-x, y, y2, x, wuqiong_bg_x,mode) elif x2 <= width1 and y2 > height1: # background[y:, x:x2] = image[:height1 - y, :] background = cover_mode(image, background, 0, height1-y, 0, wuqiong_img_x, y, wuqiong_bg_y, x, x2,mode) else: # background[y:, x:] = image[:height1 - y, :width1 - x] background = cover_mode(image, background, 0, height1-y, 0, width1-x, y, wuqiong_bg_y, x, wuqiong_bg_x,mode) elif x < 0 and y >= 0: x2 = x + width2 y2 = y + height2 if x2 <= width1 and y2 <= height1: # background[y:y2, :x + width2] = image[:, abs(x):] background = cover_mode(image, background, 0, wuqiong_img_y, abs(x), wuqiong_img_x, y, y2, 0, x+width2,mode) elif x2 > width1 and y2 <= height1: background = cover_mode(image, background, 0, wuqiong_img_y, abs(x), width1+abs(x), y, y2, 0, wuqiong_bg_x,mode) elif x2 <= 0: pass elif x2 <= width1 and y2 > height1: background = cover_mode(image, background, 0, height1-y, abs(x), wuqiong_img_x, y, wuqiong_bg_y, 0, x2, mode) else: # background[y:, :] = image[:height1 - y, abs(x):width1 + abs(x)] background = cover_mode(image, background, 0, height1-y, abs(x), width1+abs(x), y, wuqiong_bg_y, 0, wuqiong_bg_x,mode) elif x >= 0 and y < 0: x2 = x + width2 y2 = y + height2 if y2 <= 0: pass if x2 <= width1 and y2 <= height1: # background[:y2, x:x2] = image[abs(y):, :] background = cover_mode(image, background, abs(y), wuqiong_img_y, 0, wuqiong_img_x, 0, y2, x, x2,mode) elif x2 > width1 and y2 <= height1: # background[:y2, x:] = image[abs(y):, :width1 - x] background = cover_mode(image, background, abs(y), wuqiong_img_y, 0, width1-x, 0, y2, x, wuqiong_bg_x,mode) elif x2 <= width1 and y2 > height1: # background[:, x:x2] = image[abs(y):height1 + abs(y), :] background = cover_mode(image, background, abs(y), height1+abs(y), 0, wuqiong_img_x, 0, wuqiong_bg_y, x, x2,mode) else: # background[:, x:] = image[abs(y):height1 + abs(y), :width1 - abs(x)] background = cover_mode(image, background, abs(y), height1+abs(y), 0, width1-abs(x), 0, wuqiong_bg_x, x, wuqiong_bg_x,mode) else: x2 = x + width2 y2 = y + height2 if y2 <= 0 or x2 <= 0: pass if x2 <= width1 and y2 <= height1: # background[:y2, :x2] = image[abs(y):, abs(x):] background = cover_mode(image, background, abs(y), wuqiong_img_y, abs(x), wuqiong_img_x, 0, y2, 0, x2,mode) elif x2 > width1 and y2 <= height1: # background[:y2, :] = image[abs(y):, abs(x):width1 + abs(x)] background = cover_mode(image, background, abs(y), wuqiong_img_y, abs(x), width1+abs(x), 0, y2, 0, wuqiong_bg_x,mode) elif x2 <= width1 and y2 > height1: # background[:, :x2] = image[abs(y):height1 + abs(y), abs(x):] background = cover_mode(image, background, abs(y), height1+abs(y), abs(x), wuqiong_img_x, 0, wuqiong_bg_y, 0, x2,mode) else: # background[:, :] = image[abs(y):height1 - abs(y), abs(x):width1 + abs(x)] background = cover_mode(image, background, abs(y), height1-abs(y), abs(x), width1+abs(x), 0, wuqiong_bg_y, 0, wuqiong_bg_x,mode) return background def image2bgr(input_image): if len(input_image.shape) == 2: input_image = input_image[:, :, None] if input_image.shape[2] == 1: result_image = np.repeat(input_image, 3, axis=2) elif input_image.shape[2] == 4: result_image = input_image[:, :, 0:3] else: result_image = input_image return result_image if __name__ == "__main__": image = cv2.imread("./03.png", -1) result_image = add_background(image, bgr=(255, 255, 255)) cv2.imwrite("test.jpg", result_image)