|
- # -*- coding: utf-8 -*-
- from io import BytesIO
- from traceback import format_exc
-
- import cv2
- import requests
- from PIL import Image, ImageDraw, ImageFont
- import numpy as np
- from loguru import logger
-
- from enums.ExceptionEnum import ExceptionType
- from exception.CustomerException import ServiceException
-
- '''
- 文字水印
- '''
-
-
- class TextWaterMark():
- def __init__(self):
- self.color_dict = {
- # R G B
- # 网址查看:https://tool.oschina.net/commons?type=3
- # 网址查看:http://tools.jb51.net/static/colorpicker/
- 'white': (255, 255, 255, 255),
- 'black': (0, 0, 0, 255),
- 'gray': (205, 201, 201, 255),
- 'red': (255, 0, 0, 255),
- 'yellow': (255, 215, 0, 255),
- 'blue': (0, 0, 170, 255),
- 'purple': (205, 105, 201, 255),
- 'green': (0, 205, 0, 255)
- }
- self.position_list = [1, 2, 3, 4]
-
- """
- 普通照片水印
- params:
- image:图片
- text:水印文字
- position:水印位置
- 1:左上
- 2:右上
- 3:右下
- 4:左下
- fontface: 字体
- fontsize:字体大小
- fontcolor:字体颜色
- [white, black, gray, red, yellow, blue, purple, green]
- """
-
- def common_water(self, image, text, position=1, fontface='../font/simsun.ttc', fontsize=20, fontcolor='black'):
- flag = False
- if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型
- flag = True
- image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))
- if position not in self.position_list:
- position = 1
- w, h = image.size[:2]
- keys = self.color_dict.keys()
- if fontcolor not in keys:
- fontcolor = 'black'
- color = self.color_dict[fontcolor]
- fnt = ImageFont.truetype(fontface, fontsize)
- im = image.convert('RGBA')
- mask = Image.new('RGBA', im.size, (0, 0, 0, 0))
- d = ImageDraw.Draw(mask)
- size_w, size_h = d.textsize(text, font=fnt)
- if position == 1:
- weizhi = (w * 0.1, h * 0.1)
- elif position == 2:
- weizhi = (w * 0.9 - size_w, h * 0.1)
- elif position == 3:
- weizhi = (w * 0.9 - size_w, h * 0.9 - size_h)
- else:
- weizhi = (w * 0.1, h * 0.9 - size_h)
- # position 为左上角位置
- d.text(weizhi, text, font=fnt, fill=color)
- out = Image.alpha_composite(im, mask)
- if flag:
- out = cv2.cvtColor(np.asarray(out), cv2.COLOR_BGRA2RGBA)
- return out
-
- """
- 半透明水印,布满整张图,并且自动旋转45°
- params:
- image:图片
- text:文字
- fontsize:文字大小
- """
-
- def fill_water(self, image, text, fontsize):
- flag = False
- if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型
- flag = True
- image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA))
- font = ImageFont.truetype('../font/simsun.ttc', fontsize)
- # 添加背景
- new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255))
- new_img.paste(image, image.size)
-
- # 添加水印
- font_len = len(text)
- rgba_image = new_img.convert('RGBA')
- text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0))
- image_draw = ImageDraw.Draw(text_overlay)
-
- for i in range(0, rgba_image.size[0], font_len * 40 + 100):
- for j in range(0, rgba_image.size[1], 200):
- # print(f'i:{i}, j:{j}, text:{text}, font:{font}')
- image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50))
- text_overlay = text_overlay.rotate(-45)
- image_with_text = Image.alpha_composite(rgba_image, text_overlay)
-
- image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2))
- if flag:
- image_with_text = cv2.cvtColor(np.asarray(image_with_text), cv2.COLOR_BGRA2RGBA)
- return image_with_text
-
-
- class PictureWaterMark:
- __slots__ = ('logo', '__requestId')
-
- def __init__(self, logo=None, requestId=None):
- self.__requestId = requestId
- self.logo = logo
- if requestId is None:
- self.__requestId = '1'
- if logo is None:
- self.logo = cv2.imread("./image/logo.png", -1)
-
- # def common_water(self, image, logo):
- # width, height = image.shape[1], image.shape[0]
- # mark_width, mark_height = logo.shape[1], logo.shape[0]
- # rate = int(width * 0.2) / mark_width
- # logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
- # position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0]))
- # b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明'
- # a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
- # watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA))
- # # 图片旋转
- # # watermark = watermark.rotate(45)
- # b.paste(a, (0, 0))
- # b.paste(watermark, position, mask=watermark)
- # return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB)
-
- def common_water_1(self, image, logo, alpha=1):
- try:
- h, w = image.shape[0], image.shape[1]
- # if w >= h:
- rate = int(w * 0.1) / logo.shape[1]
- # else:
- # rate = int(h * 0.1) / logo.shape[0]
- mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
- mask_h, mask_w = mask.shape[0], mask.shape[1]
- mask_channels = cv2.split(mask)
- dst_channels = cv2.split(image)
- # b, g, r, a = cv2.split(mask)
- # 计算mask在图片的坐标
- # if w >= h:
- ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
- dr_points = (int(h * 0.95), int(w - h * 0.05))
- # else:
- # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
- # dr_points = (int(h * 0.95), int(w - h * 0.05))
- for i in range(3):
- dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][
- ul_points[0]: dr_points[0],
- ul_points[1]: dr_points[
- 1]] * (
- 255.0 - mask_channels[
- 3] * alpha) / 255
- dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array(
- mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8)
- dst_img = cv2.merge(dst_channels)
- return dst_img
- except Exception:
- logger.error("加水印异常:{}, requestId:{}", format_exc(), self.__requestId)
- return image
-
-
- def add_water_pic(image, logo, requestId, alpha=1):
- try:
- h, w = image.shape[0], image.shape[1]
- # if w >= h:
- rate = int(w * 0.1) / logo.shape[1]
- # else:
- # rate = int(h * 0.1) / logo.shape[0]
- mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST)
- mask_h, mask_w = mask.shape[0], mask.shape[1]
- mask_channels = cv2.split(mask)
- dst_channels = cv2.split(image)
- # b, g, r, a = cv2.split(mask)
- # 计算mask在图片的坐标
- # if w >= h:
- ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
- dr_points = (int(h * 0.95), int(w - h * 0.05))
- # else:
- # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w))
- # dr_points = (int(h * 0.95), int(w - h * 0.05))
- for i in range(3):
- dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][
- ul_points[0]: dr_points[0],
- ul_points[1]: dr_points[
- 1]] * (
- 255.0 - mask_channels[
- 3] * alpha) / 255
- dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array(
- mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8)
- dst_img = cv2.merge(dst_channels)
- return dst_img
- except Exception:
- logger.error("加水印异常:{}, requestId:{}", format_exc(), requestId)
- return image
-
-
- # 差值感知算法
- def dHash(image):
- # 缩放9*8
- image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC)
- # 转换灰度图
- image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
- # print(image.shape)
- hash = []
- # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
- for i in range(8):
- for j in range(8):
- if image[i, j] > image[i, j + 1]:
- hash.append(1)
- else:
- hash.append(0)
- return hash
-
-
- # 计算汉明距离
- def Hamming_distance(hash1, hash2):
- num = 0
- for index in range(len(hash1)):
- if hash1[index] != hash2[index]:
- num += 1
- return num
-
-
- def url2Array(url, enable_ex=True):
- try:
- response = requests.get(url)
- image = Image.open(BytesIO(response.content))
- image1 = np.array(image)
- img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR)
- return img_bgr
- except Exception:
- logger.exception("url地址请求异常: {}", format_exc())
- if enable_ex:
- raise ServiceException(ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0],
- ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1])
- return None
-
-
- def url2Content(url):
- response = requests.get(url)
- return response.content
-
-
- def url2Image(url):
- response = requests.get(url)
- image = Image.open(BytesIO(response.content))
- image1 = np.array(image)
- img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR)
- img = Image.fromarray(img_bgr)
- return img
-
-
- def url2Byte(url):
- response = requests.get(url)
- return BytesIO(response.content)
-
-
- def markRectangle(url, text, textCoordinate, imageLeftUpCoordinate, imageRightDownCoordinate, color):
- img = url2Array(url)
- # ( 蓝, 绿, 红)
- # 红色 (0, 0, 255)
- # 洋红色 (255, 0, 255)
- # 青色 (255, 255, 0)
- # 黑色 (0, 0, 0)
- # 蓝色 (255, 0, 0)
- # 绿色 (0, 255, 0)
- # 黄色 (0, 255, 255) # 不考虑
- cv2.putText(img, text, textCoordinate, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 1, cv2.LINE_AA)
- # rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2), 颜色 , 粗细
- cv2.rectangle(img, imageLeftUpCoordinate, imageRightDownCoordinate, color, 2)
- return img
-
-
- # def draw_painting_joint(img, xywh, score=0.5, color=None,
- # font={'line_thickness': None, 'boxLine_thickness': None, 'fontSize': None}):
- # imh, imw, imc = img.shape
- # tl = font['line_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1
- # box_tl = font['boxLine_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 根据图像的尺寸计算出适合用于绘制图像边框的线宽。
- # c1, c2 = (int(xywh[0]), int(xywh[1])), (int(xywh[2]), int(xywh[3]))
- # cv2.rectangle(img, c1, c2, color, thickness=box_tl, lineType=cv2.LINE_AA)
- #
- # label = ' %.2f' % (score)
- # tf = max(tl, 1) # font thickness
- # fontScale = font['fontSize'] or tl * 0.33
- # t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0]
- # cv2.rectangle(img, (int(box[0]) + lw, int(box[1])), c2, color, -1, cv2.LINE_AA) # filled
- # cv2.putText(img, label, (c1[0] + lw, c1[1] - (lh - t_size[1]) // 2), 0, fontScale, [225, 255, 255], thickness=tf,
- # lineType=cv2.LINE_AA)
- # # print('#####line224 fontScale:',fontScale,' thickness:',tf,' line_thickness:',font['line_thickness'],' boxLine thickness:',box_tl)
- # return img
-
-
- def img_pad(img, size, pad_value=[114, 114, 114]):
- ###填充成固定尺寸
- H, W, _ = img.shape
- r = max(H / size[0], W / size[1])
- img_r = cv2.resize(img, (int(W / r), int(H / r)))
- tb = size[0] - img_r.shape[0]
- lr = size[1] - img_r.shape[1]
- top = int(tb / 2)
- bottom = tb - top
- left = int(lr / 2)
- right = lr - left
- pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_value)
- return pad_image, (top, left, r)
-
-
- def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32):
- # 调整图像大小和填充图像,同时满足步幅多重约束
- shape = img.shape[:2] # current shape [height, width] 当前形状 [高度、宽度]
- if isinstance(new_shape, int):
- new_shape = (new_shape, new_shape)
-
- # Scale ratio (new / old) 缩放比例(新/旧)
- r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
- if not scaleup: # 仅缩减,不纵向扩展(为了更好的测试 mAP)
- r = min(r, 1.0)
-
- ratio = r, r # width, height ratios 宽度、高度比
- new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))
- dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding
- if auto: # 最小矩形
- dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding
- elif scaleFill: # stretch
- dw, dh = 0.0, 0.0
- new_unpad = (new_shape[1], new_shape[0])
- ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios
-
- dw /= 2 # divide padding into 2 sides
- dh /= 2
-
- if shape[::-1] != new_unpad: # resize
- img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
- top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))
- left, right = int(round(dw - 0.1)), int(round(dw + 0.1))
- img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border
- return img, ratio, (dw, dh)
-
- # if __name__ == '__main__':
- # # img = cv2.imread("../test/a.jpg", -1)
- # # fontcolor = 'yellow'
- # #
- # # water = TextWaterMark()
- # # text = "hello world"
- # #
- # # # fill_img = water.common_water(img, text, position=4, fontface='../font/庞门正道标题体2.0增强版.ttf', fontsize=20, fontcolor='black')
- # # fill_img = water.fill_water(img, text, 20)
- # # # 一定要保存为png格式
- # # cv2.imshow('result', fill_img)
- # # cv2.waitKey(111111110)
- # # print('finish')
- # pic = PictureWaterMark()
- # image = cv2.imread("a.jpg")
- # logo = cv2.imread("../image/logo.png", -1)
- # # print(image, logo)
- # start = time.time()
- # frame = pic.common_water(image, logo)
- # print(time.time() - start)
- # start1 = time.time()
- # frame1 = pic.common_water_1(image, logo)
- # # cv2.imwrite("watermarked.jpg", frame1)
- # print(time.time() - start1)
- # # cap = cv2.VideoCapture("../data/111111.mp4")
- # # logo = cv2.imread("../image/logo.png", -1)
- # # while True:
- # # is_opened, frame = cap.read()
- # # frame = pic.common_water(frame, logo)
- # # cv2.imshow('frame', frame)
- # # cv2.waitKey(1) # 等待输入任何按键
- # # # 关闭
- # # cap.release()
|