python+opencv生成较真实的车牌号码图片
本文参考github代码:https://github.com/loveandhope/license-plate-generator
效果:
一、代码目录结构:
background目录下存放各种背景图片
font目录下存放车牌中文、字符的ttf字体
images目录下存放蓝色底牌、新能源绿色底牌、污渍(噪声)的图片
完整代码可参考:https://download.csdn.net/download/benben044/87546578?spm=1001.2014.3001.5503
二、生成流程
本代码可以根据车牌list生成对应的车牌图片list。
(1)生成白底黑字的车牌号码图片
首先,生成一个白底的空白车牌号图片
img = np.array(Image.new("RGB", (880, 280), (255, 255, 255)))
然后,逐字(字符)生成图片
ImageDraw.Draw(img).text((0, self.height_offset), char, self.fg_color, font=self.font_en)
最后,将上一步生成的图片逐个复制到上上一步步生成的图片中
img[:, char_width_start:char_width_end] = self.generate_char_image(plate_num[i])
因为生成的图片和img的第一维(height)大小相同,所以在img中直接使用符号":"。
(2)生成车牌底牌
直接读取底牌的图片即可。
plate_image = cv2.imread(LicensePlateImageGenerator.single_blue_plate_bg)
(3)生成最后的车牌图片(以蓝牌为例)
首先,将文字图片转为黑底白字
img = cv2.bitwise_not(char_img)
此时,背景部分值为0,字部分值为255。
然后,将黑底背景变为蓝色底牌背景
img = cv2.bitwise_or(img, template_image)
此时,黑色背景值0 与 蓝色背景值x进行二进制的or操作,只保留了蓝色背景值,实现了背景的替换。
(4)数据增强(增加噪声)
高斯模糊:
通过cv2.blur() 方法实现
高斯噪声:
def add_single_channel_noise(self, single):""" 添加高斯噪声:param single: 单一通道的图像数据"""diff = 255 - single.max()noise = np.random.normal(0, 1 + self.rand_reduce(6), single.shape)noise = (noise - noise.min()) / (noise.max() - noise.min())noise = diff * noisenoise = noise.astype(np.uint8)dst = single + noisereturn dst
添加污渍:
通过cv2.bitwise_not() 和cv2.bitwise_and()操作完成
添加饱和度光照的噪声:
通过调整HSV颜色空间实现,
- Hue:色调
- Saturation:饱和度
- Value:明亮度
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 色调,饱和度,亮度
hsv[:, :, 0] = hsv[:, :, 0] * (self.hue_keep + np.random.random() * (1 - self.hue_keep))
hsv[:, :, 1] = hsv[:, :, 1] * (self.saturation_keep + np.random.random() * (1 - self.saturation_keep))
hsv[:, :, 2] = hsv[:, :, 2] * (self.value_keep + np.random.random() * (1 - self.value_keep))
img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
添加透视变换:
透视变换api整体和放射变化类似,先通过点与点的映射关系获取变换矩阵,然后再将图形进行转换。
以左向投影为例:
->
其计算过程如下:
寻找源图像中4个点和目标图像中的4个点,在左向倾斜时右边两个顶点的height值会做修改。
shape = img.shape
size_src = (shape[1], shape[0]) # width, height
# 源图像四个顶点坐标
pts1 = np.float32([[0, 0], [0, size_src[1]], [size_src[0], 0], [size_src[0], size_src[1]]])
# 计算图片进行投影倾斜后的位置
interval = abs(int(math.sin((float(angle) / 180) * math.pi) * shape[0]))
# 目标图像上四个顶点的坐标
if is_left:pts2 = np.float32([[0, 0], [0, size_src[1]],[size_src[0], interval], [size_src[0], size_src[1] - interval]])
else:pts2 = np.float32([[0, interval], [0, size_src[1] - interval],[size_src[0], 0], [size_src[0], size_src[1]]])
# 获取 3x3的投影映射/透视变换 矩阵
matrix = cv2.getPerspectiveTransform(pts1, pts2)
dst = cv2.warpPerspective(img, matrix, size_src)
三、python代码:
import os
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
import numpy as np
import cv2
import random
import mathclass CharsImageGenerator(object):"""生成字符图像,背景为白色,字体为黑色"""# 数字和英文字母列表numerals = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']alphabet = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J','K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T','U', 'V', 'W', 'X', 'Y', 'Z']def __init__(self, plate_type):self.plate_type = plate_type# 字符图片参数self.font_ch = ImageFont.truetype("./font/platech.ttf", 180, 0) # 中文字体格式self.font_en = ImageFont.truetype('./font/platechar.ttf', 240, 0) # 英文字体格式self.bg_color = (255, 255, 255) # 车牌背景颜色self.fg_color = (0, 0, 0) # 车牌号的字体颜色self.plate_height = 280 # 车牌高度self.left_offset = 32 # 车牌号左边第一个字符的偏移量self.height_offset = 10 # 高度方向的偏移量self.char_height = 180 # 字符高度self.chinese_original_width = 180 # 中文字符原始宽度self.english_original_width = 90 # 非中文字符原始宽度if plate_type in ['single_blue', 'single_yellow']:self.char_num = 7self.char_width = 90 # 字符校正后的宽度self.plate_width = 880 # 车牌的宽度self.char_interval = 24 # 字符间的间隔self.point_size = 20 # 第2个字符与第三个字符间有一个点,该点的尺寸elif plate_type == 'small_new_energy':self.char_num = 8self.first_char_width = 90 # 第一个字符校正后的宽度self.char_width = 86 # 其余字符校正后宽度self.plate_width = 960 # 车牌的宽度self.char_interval = 18 # 字符间的间隔self.point_size = 62 # 第2个字符与第三个字符间有一个点,该点的尺寸else:raise ValueError('目前不支持该类型车牌!')def generate_images(self, plate_num_str_list):if self.plate_type in ['single_blue', 'single_yellow', ]:plate_images = self.generate_440_140_plate(plate_num_str_list)elif self.plate_type == 'small_new_energy':plate_images = self.generate_480_140_plate(plate_num_str_list)else:raise ValueError('该类型车牌目前功能尚未完成!')return plate_imagesdef generate_440_140_plate(self, plate_num_str_list):""" 生成440 * 140尺寸的7位车牌字符图片:param plate_nums::return:"""plate_images = list()for plate_num in plate_num_str_list:# 创建空白车牌号图片img = np.array(Image.new("RGB", (self.plate_width, self.plate_height), self.bg_color))# 每个字符的x轴起始、终止位置char_width_start = self.left_offsetchar_width_end = char_width_start + self.char_widthimg[:, char_width_start:char_width_end] = self.generate_char_image(plate_num[0]) # 生成的图片和img的第一维大小相同,所以在img中直接使用符号":"char_width_start = char_width_end + self.char_intervalchar_width_end = char_width_start + self.char_widthimg[:, char_width_start:char_width_end] = self.generate_char_image(plate_num[1])# 隔开特殊间隙,继续添加车牌的后续车牌号char_width_end = char_width_end + self.point_size + self.char_intervalfor i in range(2, len(plate_num)):char_width_start = char_width_end + self.char_intervalchar_width_end = char_width_start + self.char_widthimg[:, char_width_start:char_width_end] = self.generate_char_image(plate_num[i])plate_images.append(img)# chars_image debug# cv2.imshow("chars_image debug", img)# cv2.waitKey()return plate_imagesdef generate_char_image(self, char):""" 生成字符图片:param char: 字符:return:"""# 根据是否中文字符,选择生成模式if char in CharsImageGenerator.numerals or char in CharsImageGenerator.alphabet:img = self.generate_en_char_image(char)else:img = self.generate_ch_char_image(char)return imgdef generate_ch_char_image(self, char):""" 生成中文字符图片:param char: 待生成的中文字符"""img = Image.new("RGB", (self.chinese_original_width, self.plate_height), self.bg_color)ImageDraw.Draw(img).text((0, self.height_offset), char, self.fg_color, font=self.font_ch)img = img.resize((self.char_width, self.plate_height))return np.array(img)def generate_en_char_image(self, char):"""" 生成英文字符图片:param char: 待生成的英文字符"""img = Image.new("RGB", (self.english_original_width, self.plate_height), self.bg_color)ImageDraw.Draw(img).text((0, self.height_offset), char, self.fg_color, font=self.font_en)img = img.resize((self.char_width, self.plate_height))return np.array(img)class LicensePlateImageGenerator(object):"""根据车牌类型生成底牌图片"""single_blue_plate_bg = './images/single_blue.bmp'small_new_energy_plate_bg = './images/small_new_energy.jpg'def __init__(self, plate_type):self.plate_type = plate_typeif plate_type == 'single_blue':plate_image = cv2.imread(LicensePlateImageGenerator.single_blue_plate_bg)elif plate_type == 'small_new_energy':plate_image = cv2.imread(LicensePlateImageGenerator.small_new_energy_plate_bg)else:raise ValueError('该类型车牌目前功能尚未完成!')# template_image debug# cv2.imshow("template_image debug", plate_image)# cv2.waitKey()self.bg = plate_imagedef generate_template_image(self, width, height):return cv2.resize(self.bg, (width, height))class ImageAugmentation(object):"""图像增强操作:HSV变化,添加背景,高斯噪声,污渍"""horizontal_sight_directions = ('left', 'mid', 'right')vertical_sight_directions = ('up', 'mid', 'down')def __init__(self, plate_type, template_image):self.plate_type = plate_type# 确定字符颜色是否应该为黑色if plate_type == 'single_blue':# 字符为白色self.is_black_char = Falseelif plate_type in ['single_yellow', 'small_new_energy']:# 字符为黑字self.is_black_char = Trueelse:raise ValueError('暂时不支持该类型车牌')self.template_image = template_image# 透视变换self.angle_horizontal = 15self.angle_vertical = 15self.angle_up_down = 10self.angle_left_right = 5self.factor = 10# 色调,饱和度,亮度self.hue_keep = 0.8self.saturation_keep = 0.3self.value_keep = 0.2# 自然环境照片的路径列表self.env_data_paths = ImageAugmentation.search_file("background")# 高斯噪声levelself.level = 1 + ImageAugmentation.rand_reduce(4)# 污渍self.smu = cv2.imread("images/smu.jpg")def left_right_transfer(self, img, is_left=True, angle=None):"""左右视角,默认左视角:param img::param is_left::param angle: 角度:return:"""if angle is None:angle = self.angle_left_rightshape = img.shapesize_src = (shape[1], shape[0]) # width, height# 源图像四个顶点坐标pts1 = np.float32([[0, 0], [0, size_src[1]], [size_src[0], 0], [size_src[0], size_src[1]]])# 计算图片进行投影倾斜后的位置interval = abs(int(math.sin((float(angle) / 180) * math.pi) * shape[0]))# 目标图像上四个顶点的坐标if is_left:pts2 = np.float32([[0, 0], [0, size_src[1]],[size_src[0], interval], [size_src[0], size_src[1] - interval]])else:pts2 = np.float32([[0, interval], [0, size_src[1] - interval],[size_src[0], 0], [size_src[0], size_src[1]]])# 获取 3x3的投影映射/透视变换 矩阵matrix = cv2.getPerspectiveTransform(pts1, pts2)dst = cv2.warpPerspective(img, matrix, size_src)return dst, matrix, size_srcdef up_down_transfer(self, img, is_down=True, angle=None):""" 上下视角,默认下视角:param img: 正面视角原始图片:param is_down: 是否下视角:param angle: 角度:return:"""if angle is None:angle = self.rand_reduce(self.angle_up_down)shape = img.shapesize_src = (shape[1], shape[0])# 源图像四个顶点坐标pts1 = np.float32([[0, 0], [0, size_src[1]], [size_src[0], 0], [size_src[0], size_src[1]]])# 计算图片进行投影倾斜后的位置interval = abs(int(math.sin((float(angle) / 180) * math.pi) * shape[0]))# 目标图像上四个顶点的坐标if is_down:pts2 = np.float32([[interval, 0], [0, size_src[1]],[size_src[0] - interval, 0], [size_src[0], size_src[1]]])else:pts2 = np.float32([[0, 0], [interval, size_src[1]],[size_src[0], 0], [size_src[0] - interval, size_src[1]]])# 获取 3x3的投影映射/透视变换 矩阵matrix = cv2.getPerspectiveTransform(pts1, pts2)dst = cv2.warpPerspective(img, matrix, size_src)return dst, matrix, size_srcdef vertical_tilt_transfer(self, img, is_left_high=True):""" 添加按照指定角度进行垂直倾斜(上倾斜或下倾斜,最大倾斜角度self.angle_vertical一半):param img: 输入图像的numpy:param is_left_high: 图片投影的倾斜角度,左边是否相对右边高"""angle = self.rand_reduce(self.angle_vertical)shape = img.shapesize_src = [shape[1], shape[0]]# 源图像四个顶点坐标pts1 = np.float32([[0, 0], [0, size_src[1]], [size_src[0], 0], [size_src[0], size_src[1]]])# 计算图片进行上下倾斜后的距离,及形状interval = abs(int(math.sin((float(angle) / 180) * math.pi) * shape[1]))size_target = (int(math.cos((float(angle) / 180) * math.pi) * shape[1]), shape[0] + interval)# 目标图像上四个顶点的坐标if is_left_high:pts2 = np.float32([[0, 0], [0, size_target[1] - interval],[size_target[0], interval], [size_target[0], size_target[1]]])else:pts2 = np.float32([[0, interval], [0, size_target[1]],[size_target[0], 0], [size_target[0], size_target[1] - interval]])# 获取 3x3的投影映射/透视变换 矩阵matrix = cv2.getPerspectiveTransform(pts1, pts2)dst = cv2.warpPerspective(img, matrix, size_target)return dst, matrix, size_targetdef horizontal_tilt_transfer(self, img, is_right_tilt=True):""" 添加按照指定角度进行水平倾斜(右倾斜或左倾斜,最大倾斜角度self.angle_horizontal一半):param img: 输入图像的numpy:param is_right_tilt: 图片投影的倾斜方向(右倾,左倾)"""angle = self.rand_reduce(self.angle_horizontal)shape = img.shapesize_src = [shape[1], shape[0]]# 源图像四个顶点坐标pts1 = np.float32([[0, 0], [0, size_src[1]], [size_src[0], 0], [size_src[0], size_src[1]]])# 计算图片进行左右倾斜后的距离,及形状interval = abs(int(math.sin((float(angle) / 180) * math.pi) * shape[0]))size_target = (shape[1] + interval, int(math.cos((float(angle) / 180) * math.pi) * shape[0]))# 目标图像上四个顶点的坐标if is_right_tilt:pts2 = np.float32([[interval, 0], [0, size_target[1]],[size_target[0], 0], [size_target[0] - interval, size_target[1]]])else:pts2 = np.float32([[0, 0], [interval, size_target[1]],[size_target[0] - interval, 0], [size_target[0], size_target[1]]])# 获取 3x3的投影映射/透视变换 矩阵matrix = cv2.getPerspectiveTransform(pts1, pts2)dst = cv2.warpPerspective(img, matrix, size_target)return dst, matrix, size_targetdef sight_transfer(self, images, horizontal_sight_direction, vertical_sight_direction):"""对图片进行视角变换:param images::param horizontal_sight_direction: 水平视角变换方向:param vertical_sight_direction: 垂直视角变换方向:return:"""flag = 0img_num = len(images)# 左右视角if horizontal_sight_direction == 'left':flag += 1images[0], matrix, size = self.left_right_transfer(images[0], is_left=True)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)elif horizontal_sight_direction == 'right':flag -= 1images[0], matrix, size = self.left_right_transfer(images[0], is_left=False)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)else:pass# 上下视角if vertical_sight_direction == 'down':flag += 1images[0], matrix, size = self.up_down_transfer(images[0], is_down=True)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)elif vertical_sight_direction == 'up':flag -= 1images[0], matrix, size = self.up_down_transfer(images[0], is_down=False)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)else:pass# 左下视角 或 右上视角if abs(flag) == 2:images[0], matrix, size = self.vertical_tilt_transfer(images[0], is_left_high=True)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)images[0], matrix, size = self.horizontal_tilt_transfer(images[0], is_right_tilt=True)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)# 左上视角 或 右下视角elif abs(flag) == 1:images[0], matrix, size = self.vertical_tilt_transfer(images[0], is_left_high=False)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)images[0], matrix, size = self.horizontal_tilt_transfer(images[0], is_right_tilt=False)for i in range(1, img_num):images[i] = cv2.warpPerspective(images[i], matrix, size)else:passreturn images@staticmethoddef search_file(search_path, file_format='.jpg'):"""在指定目录search_path下,递归目录搜索指定尾缀的文件"""file_path_list = []for root_path, dir_names, file_names in os.walk(search_path):for filename in file_names:if filename.endswith(file_format):file_path_list.append(os.path.join(root_path, filename))return file_path_list@staticmethoddef rand_reduce(val):return int(np.random.random() * val)def add_gauss(self, img, level=None):""" 添加高斯模糊:param img: 待加噪图片:param level: 加噪水平"""if level is None:level = self.levelreturn cv2.blur(img, (level * 2 + 1, level * 2 + 1))def add_single_channel_noise(self, single):""" 添加高斯噪声:param single: 单一通道的图像数据"""diff = 255 - single.max()noise = np.random.normal(0, 1 + self.rand_reduce(6), single.shape)noise = (noise - noise.min()) / (noise.max() - noise.min())noise = diff * noisenoise = noise.astype(np.uint8)dst = single + noisereturn dstdef add_noise(self, img):"""添加噪声"""img[:, :, 0] = self.add_single_channel_noise(img[:, :, 0])img[:, :, 1] = self.add_single_channel_noise(img[:, :, 1])img[:, :, 2] = self.add_single_channel_noise(img[:, :, 2])return imgdef add_smudge(self, img, smu=None):"""添加污渍"""if smu is None:smu = self.smu# 截取某一部分rows = self.rand_reduce(smu.shape[0] - img.shape[0])cols = self.rand_reduce(smu.shape[1] - img.shape[1])add_smu = smu[rows:rows + img.shape[0], cols:cols + img.shape[1]]img = cv2.bitwise_not(img)img = cv2.bitwise_and(add_smu, img)img = cv2.bitwise_not(img)return imgdef rand_environment(self, img, env_data_paths=None):""" 添加自然环境的噪声:param img: 待加噪图片:param env_data_paths: 自然环境图片路径列表"""if env_data_paths is None:env_data_paths = self.env_data_paths# 随机选取环境照片index = self.rand_reduce(len(env_data_paths))env = cv2.imread(env_data_paths[index])env = cv2.resize(env, (img.shape[1], img.shape[0]))# 找到黑背景,反转为白bak = (img == 0)for i in range(bak.shape[2]):bak[:, :, 0] &= bak[:, :, i]for i in range(bak.shape[2]):bak[:, :, i] = bak[:, :, 0]bak = bak.astype(np.uint8) * 255# 环境照片用白掩码裁剪,然后与原图非黑部分合并inv = cv2.bitwise_and(bak, env)img = cv2.bitwise_or(inv, img)return imgdef rand_hsv(self, img):""" 添加饱和度光照的噪声:param img: BGR格式的图片:return 加了饱和度、光照噪声的BGR图片"""hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)# 色调,饱和度,亮度hsv[:, :, 0] = hsv[:, :, 0] * (self.hue_keep + np.random.random() * (1 - self.hue_keep))hsv[:, :, 1] = hsv[:, :, 1] * (self.saturation_keep + np.random.random() * (1 - self.saturation_keep))hsv[:, :, 2] = hsv[:, :, 2] * (self.value_keep + np.random.random() * (1 - self.value_keep))img = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)return imgdef augment(self, img, horizontal_sight_direction=None, vertical_sight_direction=None):"""综合上面的加载操作,进行全流程加噪:param img::param horizontal_sight_direction: 水平视角方向:param vertical_sight_direction: 垂直视角方向:return:"""if horizontal_sight_direction is None:horizontal_sight_direction = ImageAugmentation.horizontal_sight_directions[random.randint(0, 2)]if vertical_sight_direction is None:vertical_sight_direction = ImageAugmentation.vertical_sight_directions[random.randint(0, 2)]if not self.is_black_char:# 转为黑底白字img = cv2.bitwise_not(img)img = cv2.bitwise_or(img, self.template_image)# 基于视角的变换img = self.sight_transfer([img], horizontal_sight_direction, vertical_sight_direction)img = img[0]img = self.rand_environment(img)img = self.rand_hsv(img)else:# 底牌加车牌文字img = cv2.bitwise_and(img, self.template_image)# 基于视角的变换img = self.sight_transfer([img], horizontal_sight_direction, vertical_sight_direction)img = img[0]img = self.rand_environment(img)img = self.rand_hsv(img)img = self.add_gauss(img)img = self.add_noise(img)img = self.add_smudge(img)return imgclass LicensePlateGenerator(object):@staticmethoddef generate_license_plate_images(plate_type, plate_num_str_list, save_path):"""生成特定类型的的车牌图片,并保存到指定目录下:param plate_type: 车牌类型:param plate_num_str_list: 车牌号码列表:param save_path: 文件根目录:return:"""save_path = os.path.join(save_path, plate_type)if not os.path.exists(save_path):os.makedirs(save_path)print('\r>> 生成车牌号图片...')# 生成车牌号码,白底黑字chars_image_generator = CharsImageGenerator(plate_type)chars_images = chars_image_generator.generate_images(plate_num_str_list)# 生成车牌底牌license_template_generator = LicensePlateImageGenerator(plate_type)template_image = license_template_generator.generate_template_image(chars_image_generator.plate_width, chars_image_generator.plate_height)print('\r>> 生成车牌图片...')# 数据增强及车牌字符颜色修正,并保存augmentation = ImageAugmentation(plate_type, template_image)plate_height = 72plate_width = int(chars_image_generator.plate_width * plate_height / chars_image_generator.plate_height)i = 1for index, char_image in enumerate(chars_images):image_name = str(i) + "_" + plate_num_str_list[index] + ".jpg"image_path = os.path.join(save_path, image_name)image = augmentation.augment(char_image)image = cv2.resize(image, (plate_width, plate_height))cv2.imencode('.jpg', image)[1].tofile(image_path)print("\r>> {} done...".format(image_name))i += 1if __name__ == '__main__':# 保存文件夹名称file_path = os.path.join(os.getcwd(), 'plate_images')# 车牌号码列表plate_num_str_list = ["浙A5B5T3"]LicensePlateGenerator.generate_license_plate_images('single_blue', plate_num_str_list, file_path)
相关文章:

python+opencv生成较真实的车牌号码图片
本文参考github代码:https://github.com/loveandhope/license-plate-generator 效果: 一、代码目录结构: background目录下存放各种背景图片 font目录下存放车牌中文、字符的ttf字体 images目录下存放蓝色底牌、新能源绿色底牌、污渍&#…...

3.26周报
周报 代码行数: 周一 581 周二 601 周三 615 周四 591 周五 570 周六 561 周日 577 遇到的问题: 项目启动很慢,要将近5分钟才能开启项目,对开发造成很大困扰。 断点打在奇怪的地方,造成启动缓慢。断点…...

从0开始学python -69
Python math 模块 Python math 模块提供了许多对浮点数的数学运算函数。 math 模块下的函数,返回值均为浮点数,除非另有明确说明。 如果你需要计算复数,请使用 cmath 模块中的同名函数。 要使用 math 函数必须先导入: import…...

HashMap中HashCode的实现原理
代码 static final int hash(Object key) {int h;return (key null) ? 0 : (h key.hashCode()) ^ (h >>> 16);}1. h >>> 16 是什么,有什么用? h是hashcode。h >>> 16是用来取出h的高16,(>>>是无符号右移) 如下展…...

Redis —Set、ZSet介绍和应用场景
Set 概念 Redis的set是一个不重复、无序并唯一的键值集合。(方便管理无序集合)它支持交集、并集、差集等等 set和list区别 List 可以存储重复元素,Set 只能存储非重复元素;List 是按照元素的先后顺序存储元素的,而…...

【产品人卫朋】内容运营:文章点击量少的可怜,该怎么做?
今天来谈谈内容运营这个话题。 随着自媒体进入视播时代,也就是短视频的时代。 无论你打开任何一个短视频应用,每一个主题下面都会有成千上万个视频。 最为致命的是,大家停留的时间也越来越短了。 如果你不能在2秒的时间内吸引眼球,…...

【K8S系列】深入解析无状态服务
目录 序言 1. 无服务介绍 1.1 优点 1.2 使用场景 1.3 资源类型 1.4 总结 2 使用介绍 2.1 Deployment 使用场景: 2.2 ReplicaSet 使用场景 2.3 pod Pod 资源定义示例 2.4 service 创建一个Deployment: 创建一个Service: 总结…...

Node基础--命令窗口
1.Windows命令行窗口(叫做:小黑屏、cmd窗口、终端、shell) (1).如何打开命令行窗口 开始菜单 -- 运行 --- cmd --- enter win R -- cmd --- enter (2).cmd窗口常用指令 dir 列出当前目录下的所有文件 cd 目录名 进入到指定的目录 md 目录名 …...

一些有趣的项目
一个支持交互的展示卷积过程的可视化工具 https://github.com/pwwang/cnn-convoluter 一款简单易用基于 Python scikit 的推荐系统https://github.com/NicolasHug/Surprise 一个封装了 7 种启发式算法的 Python 代码库。分别是:差分进化算法、遗传算法、粒子群算法…...

教你精通JavaSE语法之第六章、数组的使用
一、数组的定义与使用 😁1.1数组的概念📌数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间,可以同来存储同种数据类型的多个值。但是数组容器在存储数据的时候,需要结合隐式转换考虑。比如࿱…...

基于51单片机AT89C51的小型音乐喷泉控制系统设计
wx供重浩:创享日记 对话框发送:单片机小喷泉 获取完整无水印论文报告(内含电路原理图和程序) 根据目前音乐喷泉的发展现状,介绍了一个以AT89C51单片机为核心的小型音乐喷泉控制系统。给出了一个简洁的单片机控制电路&a…...

【Nacos】Nacos原理详解(注册中心,配置中心)
文章目录一、背景二、CAP理论三、什么是NacosNacos 服务注册需要具备的能力:Nacos的实现原理:四、Nacos原理Nacos 服务注册与订阅的完整流程服务领域模型五、注册中心原理六、配置中心原理七、Nacos 的关键特性包括:八、 面试分析一、背景 服务注册中心…...

蓝桥杯刷题冲刺 | 倒计时11天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.质因子2.蓝桥王国1.质因子 题目 链接: 1545. 质因子 - AcWing题库 给定一个整数 N…...

【新】(2023Q2模拟题JAVA)华为OD机试 - 时间格式化
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为od机试,独家整理 已参加机试人员的实战技巧本篇题解:时间格式化 题目 运维工程师…...

MySQL函数
函数 MySQL函数与其存储过程类似,是一系列完成某种功能的SQL语句。函数一旦定义后,与过程一样是存储在MySQL的服务器上。调用函数就是一次性执行这些语句。所以函数可以降低语句重复。 MySQL本身提供了内置函数,这些函数的存在给我们日常的开…...

【Linux系统】开发工具(下) {调试器gdb,自动化构建工具make/Makefile,多文件编译,代码管理平台git}
【Linux系统】开发工具(上) {软件包管理器yum,更新yum源,文本编辑器vim,vim的三种基本模式,vim指令集,代码编译器gcc/g} 四、Linux调试器:gdb 4.1 debug模式 程序的编译模式有两种,debug模式和…...

线性代数——行列式
文章目录版权声明排列行列式行列式的由来行列式的概念行列式的性质重要公式克拉默法则补充知识版权声明 本文大部分内容皆来自李永乐老师考研教材和视频课。 排列 由1,2,…,n1,2,\ldots,n1,2,…,n组成的有序数组称为一个nnn阶排列,通常使用j1j2…jnj_1j_2\ldots …...

Spring注解-Spring-boot-SpingAOP
Spring各个模块 Test 对应spring-test.jar. Spring提供的测试工具, 可以整合JUnit测试, 简化测试环节. Core Container Spring的核心组件, 包含了Spring框架最基本的支撑. Beans, 对应spring-beans.jar. Spring进行对象管理时依赖的jar包. Core, 对应spring-core.jar,…...

使用Shell传参解决DataPhin中PySpark不支持中文的问题
使用Shell传参解决DataPhin中PySpark不支持中文的问题 背景 笔者开发PySpark任务时【别问为神马不用Java和Scala打Jar包的方式,PySpark不需要打包所以开发效率极高,早点搞完早点下班】,遇到一个令所有SQL Boy都很头疼的问题,那就…...

【CDH】cloudera manger 如何开启Debug 日志调试模式
前言 在安装 Cloudera Manger 时,遇到报错,需要开启Debug 日志级别来排查下问题原因。这里记录下 CM 如何开启 Debug 级别。 方法一:为整个服务启动DEBUG 如果 CM 无法启动,则可以为整个服务器启用 DEBUG 或 TRACE。 警告&…...

SQL Server 用户授权与回收
创建xxbbbb账号,账号可以在Company_report20221019.dbo.qfacccmprf表中进行select、 insert,update,delete --创建登录账号 create login xxbbbb with password12345#---创建用户 use Company_report20221019 create user xxbbbb for login xxbbbb---将qfacccmprf表…...

电脑出现乱码的原因以及解决方法
在日常使用电脑的过程中,经常会遇到电脑出现乱码,那么为什么会出现乱码呢?出现乱码又该怎么解决呢?下面我们一起来了解一下。 出现乱码的原因 系统乱码:主要是Windows中显示乱码,比如菜单、桌面、启动界面…...

网络工程师笔记
第一天: 编码就是转化为数字信号;调制就是转化为模拟信号; 调制: 1、基带调制(不改变频率,只改变波形) 2、带通调制(迁移到较高的频段进行传输) (1&…...

linux用户添加用户组与目录切换用户组的操作记录
linux用户添加到多个组 usermod -G groupname username (这种会把用户从其他组中去掉,只属于该组) 如:usermod -G git git (git只属于git组) usermod -a -G groupname username (把用户添加到这个组,之前所属组不影响) 如:usermod…...

在CentOS 7上使用二进制文件安装单节点Kubernetes的详细步骤:
确保您的系统已经安装了Docker和etcd。如果没有,请按照以下命令安装它们: yum install docker etcd 启动Docker服务并将其设置为开机自启: systemctl start docker systemctl enable docker 下载所需的Kubernetes二进制文件。您可以从以下网…...

iCollections for mac 8.0.6.80608 保持Mac桌面的整洁
应用介绍 iCollections允许您在桌面上创建区域,以便您可以排序和排列图标。这可以帮助您将相关项目保持在一起,以便文件(图片,文档,屏幕截图,应用程序等)井井有条且易于查找。 小麦测试可以按照…...

学习HM微博项目第8天
步骤:发微博01-导航栏内容 -> 发微博02-自定义TextView -> 发微博03-完善TextView和发送微博按钮 -> 发微博04-显示工具条 -> 发微博05-封装工具条和相册 -> 发微博06-发送微博 发微博01-导航栏内容 APP的演示操作: 从APP的演示操作中可…...

十五、存储过程与函数
一、存储过程概述 1、简介 含义:存储过程的英文是 Stored Procedure 。它的思想很简单,就是一组经过 预先编译 的 SQL 语句的封装 执行过程:存储过程预先存储在 MySQL 服务器上,需要执行的时候,客户端只需要向服务器…...

php实现助记词转TRX,ETH 私钥和钱包地址
TRX助记词转地址网上都是Java,js或其他语言开发的示例,一个简单的功能需要依赖其他环境来实现表示不能忍,毕竟php是世界上最好的语言。【狗头】 一、知识准备 要实现助记词转TRX私钥和地址,先需要知道助记词和私钥钱包地址之间的…...

浅析可观测系统中sdk的不同引入方式的利与弊
文章前提是不考虑sw的方式引入,同时不考虑在nginx等自动注入js脚本的方式,那么基本就是两种大的形式:cdn引入和本地引入其中cdn引入有两种:cdn同步cdn异步本地引入有两种:npm本地js文件参考知识提前先补充一张图片正文…...