【Python实战】——Python+Opencv是实现车牌自动识别

🍉CSDN小墨&晓末:https://blog.csdn.net/jd1813346972

   个人介绍: 研一|统计学|干货分享
         擅长Python、Matlab、R等主流编程软件
         累计十余项国家级比赛奖项,参与研究经费10w、40w级横向

文章目录

  • 1 导入相关模块
  • 2 相关功能函数定义
    • 2.1 彩色图片显示函数(plt_show0)
    • 2.2 灰度图片显示函数(plt_show)
    • 2.3 图像去噪函数(gray_guss)
  • 2 图像预处理
    • 2.1 图片读取
    • 2.2 高斯去噪
    • 2.3 边缘检测
  • 2.4 阈值化
  • 3 车牌定位
    • 3.1 区域选择
    • 3.2 形态学操作
    • 3.3 轮廓检测
  • 4 车牌字符分割
    • 4.1 高斯去噪
    • 4.2 阈值化
    • 4.3 膨胀操作
    • 4.4 车牌号排序
    • 4.5 分割效果
  • 5 模板匹配
    • 5.1 准备模板
    • 5.2 匹配结果
    • 5.3 匹配效果展示
  • 6完整代码

该篇文章将以实战形式演示利用Python结合Opencv实现车牌识别,全程涉及图像预处理、车牌定位、车牌分割、通过模板匹配识别结果输出。该项目对于智能交通、车辆管理等领域具有实际应用价值。通过自动识别车牌号码,可以实现车辆追踪、违章查询、停车场管理等功能,提高交通管理的效率和准确性。可用于车牌识别技术学习。

技术要点:

  • OpenCV:用于图像处理和计算机视觉任务。
  • Python:作为编程语言,具有简单易学、资源丰富等优点。
  • 图像处理技术:如灰度化、噪声去除、边缘检测、形态学操作、透视变换等。

1 导入相关模块

import cv2
from matplotlib import pyplot as plt
import os
import numpy as np
from PIL import ImageFont, ImageDraw, Image

2 相关功能函数定义

2.1 彩色图片显示函数(plt_show0)

def plt_show0(img):b,g,r = cv2.split(img)img = cv2.merge([r, g, b])plt.imshow(img)plt.show()

cv2与plt的图像通道不同:cv2为[b,g,r];plt为[r, g, b]

2.2 灰度图片显示函数(plt_show)

def plt_show(img):plt.imshow(img,cmap='gray')plt.show()

2.3 图像去噪函数(gray_guss)

def gray_guss(image):image = cv2.GaussianBlur(image, (3, 3), 0)gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)return gray_image

此处演示使用高斯模糊去噪。

cv2.GaussianBlur参数说明:

  • src:输入图像,可以是任意数量的通道,这些通道可以独立处理,但深度应为 CV_8UCV_16UCV_16SCV_32FCV_64F
  • ksize:高斯核的大小,必须是正奇数,例如 (3, 3)、(5, 5) 等。如果 ksize 的值为零,那么它会根据 sigmaXsigmaY 的值来计算。
  • sigmaX:X 方向上的高斯核标准偏差。
  • dst:输出图像,大小和类型与 src 相同。
  • sigmaY:Y 方向上的高斯核标准偏差,如果 sigmaY 是零,那么它会与 sigmaX 的值相同。如果 sigmaY 是负数,那么它会从 ksize.widthksize.height 计算得出。
  • borderType:像素外插法,有默认值。

2 图像预处理

2.1 图片读取

origin_image = cv2.imread('D:/image/car3.jpg')

  此处演示识别车牌原图:

2.2 高斯去噪

origin_image = cv2.imread('D:/image/car3.jpg')
# 复制一张图片,在复制图上进行图像操作,保留原图
image = origin_image.copy()
gray_image = gray_guss(image)

2.3 边缘检测

Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
absX = cv2.convertScaleAbs(Sobel_x)
image = absX

x方向上的边缘检测(增强边缘信息)

2.4 阈值化

# 图像阈值化操作——获得二值化图
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
# 显示灰度图像
plt_show(image)

  运行结果:

3 车牌定位

3.1 区域选择

kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1)
# 显示灰度图像
plt_show(image)

从图像中提取对表达和描绘区域形状有意义的图像分量。

  运行结果:

3.2 形态学操作

# 腐蚀(erode)和膨胀(dilate)
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
#x方向进行闭操作(抑制暗细节)
image = cv2.dilate(image, kernelX)
image = cv2.erode(image, kernelX)
#y方向的开操作
image = cv2.erode(image, kernelY)
image = cv2.dilate(image, kernelY)
# 中值滤波(去噪)
image = cv2.medianBlur(image, 21)
# 显示灰度图像
plt_show(image)

使用膨胀和腐蚀操作来突出车牌区域。

   运行结果:

3.3 轮廓检测

contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for item in contours:rect = cv2.boundingRect(item)x = rect[0]y = rect[1]weight = rect[2]height = rect[3]# 根据轮廓的形状特点,确定车牌的轮廓位置并截取图像if (weight > (height * 3)) and (weight < (height * 4.5)):image = origin_image[y:y + height, x:x + weight]plt_show(image)

4 车牌字符分割

4.1 高斯去噪

# 图像去噪灰度处理
gray_image = gray_guss(image)

4.2 阈值化

ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)
plt_show(image)

  运行结果:

4.3 膨胀操作

#膨胀操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4))
image = cv2.dilate(image, kernel)
plt_show(image)

  运行结果:

4.4 车牌号排序

words = sorted(words,key=lambda s:s[0],reverse=False)
i = 0
#word中存放轮廓的起始点和宽高
for word in words:# 筛选字符的轮廓if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 5.5)) and (word[2] > 10):i = i+1if word[2] < 15:splite_image = image[word[1]:word[1] + word[3], word[0]-word[2]:word[0] + word[2]*2]else:splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]]word_images.append(splite_image)print(i)
print(words)

  运行结果:

1
2
3
4
5
6
7
[[2, 0, 7, 70], [12, 6, 30, 55], [15, 7, 7, 9], [46, 6, 32, 55], [83, 30, 9, 9], [96, 7, 32, 55], [132, 8, 32, 55], [167, 8, 30, 54], [202, 62, 7, 6], [203, 7, 30, 55], [245, 7, 12, 54], [266, 0, 12, 70]]

4.5 分割效果

for i,j in enumerate(word_images):  plt.subplot(1,7,i+1)plt.imshow(word_images[i],cmap='gray')
plt.show()

  运行结果:

5 模板匹配

5.1 准备模板

# 准备模板(template[0-9]为数字模板;)
template = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z','藏','川','鄂','甘','赣','贵','桂','黑','沪','吉','冀','津','晋','京','辽','鲁','蒙','闽','宁','青','琼','陕','苏','皖','湘','新','渝','豫','粤','云','浙']# 读取一个文件夹下的所有图片,输入参数是文件名,返回模板文件地址列表
def read_directory(directory_name):referImg_list = []for filename in os.listdir(directory_name):referImg_list.append(directory_name + "/" + filename)return referImg_list# 获得中文模板列表(只匹配车牌的第一个字符)
def get_chinese_words_list():chinese_words_list = []for i in range(34,64):#将模板存放在字典中c_word = read_directory('D:/refer1/'+ template[i])chinese_words_list.append(c_word)return chinese_words_list
chinese_words_list = get_chinese_words_list()# 获得英文模板列表(只匹配车牌的第二个字符)
def get_eng_words_list():eng_words_list = []for i in range(10,34):e_word = read_directory('D:/refer1/'+ template[i])eng_words_list.append(e_word)return eng_words_list
eng_words_list = get_eng_words_list()# 获得英文和数字模板列表(匹配车牌后面的字符)
def get_eng_num_words_list():eng_num_words_list = []for i in range(0,34):word = read_directory('D:/refer1/'+ template[i])eng_num_words_list.append(word)return eng_num_words_list
eng_num_words_list = get_eng_num_words_list()

此处需提前准备各类字符模板。

5.2 匹配结果

# 获得英文和数字模板列表(匹配车牌后面的字符)
def get_eng_num_words_list():eng_num_words_list = []for i in range(0,34):word = read_directory('D:/refer1/'+ template[i])eng_num_words_list.append(word)return eng_num_words_list
eng_num_words_list = get_eng_num_words_list()# 读取一个模板地址与图片进行匹配,返回得分
def template_score(template,image):#将模板进行格式转换template_img=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1)template_img = cv2.cvtColor(template_img, cv2.COLOR_RGB2GRAY)#模板图像阈值化处理——获得黑白图ret, template_img = cv2.threshold(template_img, 0, 255, cv2.THRESH_OTSU)
#     height, width = template_img.shape
#     image_ = image.copy()
#     image_ = cv2.resize(image_, (width, height))image_ = image.copy()#获得待检测图片的尺寸height, width = image_.shape# 将模板resize至与图像一样大小template_img = cv2.resize(template_img, (width, height))# 模板匹配,返回匹配得分result = cv2.matchTemplate(image_, template_img, cv2.TM_CCOEFF)return result[0][0]# 对分割得到的字符逐一匹配
def template_matching(word_images):results = []for index,word_image in enumerate(word_images):if index==0:best_score = []for chinese_words in chinese_words_list:score = []for chinese_word in chinese_words:result = template_score(chinese_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[34+i])r = template[34+i]results.append(r)continueif index==1:best_score = []for eng_word_list in eng_words_list:score = []for eng_word in eng_word_list:result = template_score(eng_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[10+i])r = template[10+i]results.append(r)continueelse:best_score = []for eng_num_word_list in eng_num_words_list:score = []for eng_num_word in eng_num_word_list:result = template_score(eng_num_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[i])r = template[i]results.append(r)continuereturn resultsword_images_ = word_images.copy()
# 调用函数获得结果
result = template_matching(word_images_)
print(result)
print( "".join(result))

  运行结果:

['渝', 'B', 'F', 'U', '8', '7', '1']
渝BFU871

“”.join(result)函数将列表转换为拼接好的字符串,方便结果显示

5.3 匹配效果展示

height,weight = origin_image.shape[0:2]
print(height)
print(weight)image_1 = origin_image.copy()
cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5)#设置需要显示的字体
fontpath = "font/simsun.ttc"
font = ImageFont.truetype(fontpath,64)
img_pil = Image.fromarray(image_1)
draw = ImageDraw.Draw(img_pil)
#绘制文字信息
draw.text((int(0.2*weight)+25, int(0.75*height)),  "".join(result), font = font, fill = (255, 255, 0))
bk_img = np.array(img_pil)
print(result)
print( "".join(result))
plt_show0(bk_img)

  运行结果:

6完整代码

# 导入所需模块
import cv2
from matplotlib import pyplot as plt
import os
import numpy as np
from PIL import ImageFont, ImageDraw, Image
# plt显示彩色图片
def plt_show0(img):b,g,r = cv2.split(img)img = cv2.merge([r, g, b])plt.imshow(img)plt.show()# plt显示灰度图片
def plt_show(img):plt.imshow(img,cmap='gray')plt.show()# 图像去噪灰度处理
def gray_guss(image):image = cv2.GaussianBlur(image, (3, 3), 0)gray_image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)return gray_image# 读取待检测图片
origin_image = cv2.imread('D:/image/car3.jpg')
# 复制一张图片,在复制图上进行图像操作,保留原图
image = origin_image.copy()
# 图像去噪灰度处理
gray_image = gray_guss(image)
# x方向上的边缘检测(增强边缘信息)
Sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
absX = cv2.convertScaleAbs(Sobel_x)
image = absX# 图像阈值化操作——获得二值化图
ret, image = cv2.threshold(image, 0, 255, cv2.THRESH_OTSU)
# 显示灰度图像
plt_show(image)
# 形态学(从图像中提取对表达和描绘区域形状有意义的图像分量)——闭操作
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
image = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernelX,iterations = 1)
# 显示灰度图像
plt_show(image)# 腐蚀(erode)和膨胀(dilate)
kernelX = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
kernelY = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
#x方向进行闭操作(抑制暗细节)
image = cv2.dilate(image, kernelX)
image = cv2.erode(image, kernelX)
#y方向的开操作
image = cv2.erode(image, kernelY)
image = cv2.dilate(image, kernelY)
# 中值滤波(去噪)
image = cv2.medianBlur(image, 21)
# 显示灰度图像
plt_show(image)# 获得轮廓
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)for item in contours:rect = cv2.boundingRect(item)x = rect[0]y = rect[1]weight = rect[2]height = rect[3]# 根据轮廓的形状特点,确定车牌的轮廓位置并截取图像if (weight > (height * 3)) and (weight < (height * 4.5)):image = origin_image[y:y + height, x:x + weight]plt_show(image)#车牌字符分割
# 图像去噪灰度处理
gray_image = gray_guss(image)# 图像阈值化操作——获得二值化图   
ret, image = cv2.threshold(gray_image, 0, 255, cv2.THRESH_OTSU)
plt_show(image)#膨胀操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (4, 4))
image = cv2.dilate(image, kernel)
plt_show(image)# 查找轮廓
contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
words = []
word_images = []
#对所有轮廓逐一操作
for item in contours:word = []rect = cv2.boundingRect(item)x = rect[0]y = rect[1]weight = rect[2]height = rect[3]word.append(x)word.append(y)word.append(weight)word.append(height)words.append(word)
# 排序,车牌号有顺序。words是一个嵌套列表
words = sorted(words,key=lambda s:s[0],reverse=False)
i = 0
#word中存放轮廓的起始点和宽高
for word in words:# 筛选字符的轮廓if (word[3] > (word[2] * 1.5)) and (word[3] < (word[2] * 5.5)) and (word[2] > 10):i = i+1if word[2] < 15:splite_image = image[word[1]:word[1] + word[3], word[0]-word[2]:word[0] + word[2]*2]else:splite_image = image[word[1]:word[1] + word[3], word[0]:word[0] + word[2]]word_images.append(splite_image)print(i)
print(words)for i,j in enumerate(word_images):  plt.subplot(1,7,i+1)plt.imshow(word_images[i],cmap='gray')
plt.show()#模版匹配
# 准备模板(template[0-9]为数字模板;)
template = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z','藏','川','鄂','甘','赣','贵','桂','黑','沪','吉','冀','津','晋','京','辽','鲁','蒙','闽','宁','青','琼','陕','苏','皖','湘','新','渝','豫','粤','云','浙']# 读取一个文件夹下的所有图片,输入参数是文件名,返回模板文件地址列表
def read_directory(directory_name):referImg_list = []for filename in os.listdir(directory_name):referImg_list.append(directory_name + "/" + filename)return referImg_list# 获得中文模板列表(只匹配车牌的第一个字符)
def get_chinese_words_list():chinese_words_list = []for i in range(34,64):#将模板存放在字典中c_word = read_directory('D:/refer1/'+ template[i])chinese_words_list.append(c_word)return chinese_words_list
chinese_words_list = get_chinese_words_list()# 获得英文模板列表(只匹配车牌的第二个字符)
def get_eng_words_list():eng_words_list = []for i in range(10,34):e_word = read_directory('D:/refer1/'+ template[i])eng_words_list.append(e_word)return eng_words_list
eng_words_list = get_eng_words_list()# 获得英文和数字模板列表(匹配车牌后面的字符)
def get_eng_num_words_list():eng_num_words_list = []for i in range(0,34):word = read_directory('D:/refer1/'+ template[i])eng_num_words_list.append(word)return eng_num_words_list
eng_num_words_list = get_eng_num_words_list()# 读取一个模板地址与图片进行匹配,返回得分
def template_score(template,image):#将模板进行格式转换template_img=cv2.imdecode(np.fromfile(template,dtype=np.uint8),1)template_img = cv2.cvtColor(template_img, cv2.COLOR_RGB2GRAY)#模板图像阈值化处理——获得黑白图ret, template_img = cv2.threshold(template_img, 0, 255, cv2.THRESH_OTSU)
#     height, width = template_img.shape
#     image_ = image.copy()
#     image_ = cv2.resize(image_, (width, height))image_ = image.copy()#获得待检测图片的尺寸height, width = image_.shape# 将模板resize至与图像一样大小template_img = cv2.resize(template_img, (width, height))# 模板匹配,返回匹配得分result = cv2.matchTemplate(image_, template_img, cv2.TM_CCOEFF)return result[0][0]# 对分割得到的字符逐一匹配
def template_matching(word_images):results = []for index,word_image in enumerate(word_images):if index==0:best_score = []for chinese_words in chinese_words_list:score = []for chinese_word in chinese_words:result = template_score(chinese_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[34+i])r = template[34+i]results.append(r)continueif index==1:best_score = []for eng_word_list in eng_words_list:score = []for eng_word in eng_word_list:result = template_score(eng_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[10+i])r = template[10+i]results.append(r)continueelse:best_score = []for eng_num_word_list in eng_num_words_list:score = []for eng_num_word in eng_num_word_list:result = template_score(eng_num_word,word_image)score.append(result)best_score.append(max(score))i = best_score.index(max(best_score))# print(template[i])r = template[i]results.append(r)continuereturn resultsword_images_ = word_images.copy()
# 调用函数获得结果
result = template_matching(word_images_)
print(result)
# "".join(result)函数将列表转换为拼接好的字符串,方便结果显示
print( "".join(result))height,weight = origin_image.shape[0:2]
print(height)
print(weight)image_1 = origin_image.copy()
cv2.rectangle(image_1, (int(0.2*weight), int(0.75*height)), (int(weight*0.9), int(height*0.95)), (0, 255, 0), 5)#设置需要显示的字体
fontpath = "font/simsun.ttc"
font = ImageFont.truetype(fontpath,64)
img_pil = Image.fromarray(image_1)
draw = ImageDraw.Draw(img_pil)
#绘制文字信息
draw.text((int(0.2*weight)+25, int(0.75*height)),  "".join(result), font = font, fill = (255, 255, 0))
bk_img = np.array(img_pil)
print(result)
print( "".join(result))
plt_show0(bk_img)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/509791.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MYSQL---日志

1.日志的概述 日志是MySQL数据库的重要组成部分。日志文件中记录着MySQL数据库运行期间发生的变化&#xff1b;也就是说用来记录MySQL数据库的客户端连接状况、SQL语句的执行情况和错误信息等。当数据库遭到意外的损坏时&#xff0c;可以通过日志查看文件出错的原因&#xff0…

Ambari动态给YARN分配计算节点

1.前言 YARN可用的计算节点数量并不总是等于 Hadoop集群节点数量&#xff0c;可以根据业务需求分配 YARN计算节点数量。 这里首先介绍一些前置知识&#xff1a; YARN中 ResourceManager 和 NodeManager是两个核心组件&#xff0c;其中 ResourceManager负责集群资源的统一管理…

2023下半年主品牌锋芒依旧,江南布衣打破既定天花板?

在过去的2023年里&#xff0c;服装板块令人意外的领涨消费大盘&#xff0c;国家统计局数据显示&#xff0c;上半年服装零售额同比增长12.8%&#xff0c;远超商品零售大盘的增速6.8%。 整体表现强劲的同时&#xff0c;“局部”表现是否也尽如人意。近日&#xff0c;作为时尚服装…

Arduino与processing之间的通信——进阶版

本次需要实现Arduino获取板子的偏转角度并通过串口发送给processing&#xff0c;processing部分根据传输过来的各个轴的偏转角度建立对应偏转角度的3D模型。 这就涉及了两个轴正负方向的偏转&#xff0c;我的实现思路是使用串口传输 字母数字 格式的信息&#xff0c;字母用来判…

Java和JavaScript之间的主要区别与联系

目录 概况 主要区别 联系 总结 概况 Java和JavaScript&#xff0c;尽管名字相似&#xff0c;但它们在编程世界中却扮演着截然不同的角色。Java&#xff0c;一种强类型、面向对象的编程语言&#xff0c;广泛应用于企业级应用和安卓应用开发。它的设计理念是一次编写&#x…

HLS的硬件加速器设计

完整可点击跳转 目录 硬件加速器的设计方法高层次综合HLSHLS与电路地对应关系HLS的设计规范HLS优化延迟优化降低单个循环的延迟循环展开(Unroll)循环展平(Flatten)多个循环的并行化循环合并循环函数化数据流执行(Dataflow)吞吐量优化循环/函数流水线数据流优化调试硬件加…

每日一练:LeeCode-203. 移除链表元素 【链表+虚拟头结点】

每日一练&#xff1a;LeeCode-203. 移除链表元素 【链表虚拟头结点】 思路设置虚拟头结点 本文是力扣 每日一练&#xff1a;LeeCode-203. 移除链表元素 【链表虚拟头结点】 学习与理解过程&#xff0c;本文仅做学习之用&#xff0c;对本题感兴趣的小伙伴可以出门左拐LeeCode-20…

BUUCTF---[极客大挑战 2019]Upload1

1.题目描述 2.点开链接&#xff0c;需要上传文件&#xff0c;要求是image&#xff0c;上传文件后缀为jpg的一句话木马&#xff0c;发现被检测到了 3.换另一个木马试试 GIF89a? <script language"php">eval($_REQUEST[1])</script> 发现可以上传成功 4…

服务器硬件基础知识

1. 服务器分类 服务器分类 服务器的分类没有一个统一的标准。 从多个多个维度来看服务器的分类可以加深我们对各种服务器的认识。 N.B. CISC: complex instruction set computing 复杂指令集计算 RISC: reduced instruction set computer 精简指令集计算 EPIC: explicitly p…

骨传导耳机哪个牌子好?简单6招教你选到高品质机型!

作为一名有着十几年工作经验的资深数码产品测评师&#xff0c;多年来见过太多因为选购劣质骨传导耳机而踩雷的情况&#xff0c;对此&#xff0c;我想要提醒大家的是&#xff0c;在选择骨传导耳机时不要一味地追求外观颜值、品牌知名度&#xff0c;而应该更加重视产品的专业技术…

黑马点评-短信登录业务

原理 模型如下 nginx nginx基于七层模型走的事HTTP协议&#xff0c;可以实现基于Lua直接绕开tomcat访问redis&#xff0c;也可以作为静态资源服务器&#xff0c;轻松扛下上万并发&#xff0c; 负载均衡到下游tomcat服务器&#xff0c;打散流量。 我们都知道一台4核8G的tomca…

史上最全的大数据开发八股文【自己的吐血总结】

自我介绍 我本硕都是双非计算机专业&#xff0c;从研一下开始学习大数据开发的相关知识&#xff0c;从找实习到秋招&#xff0c;我投递过100公司&#xff0c;拿到过10的offer&#xff0c;包括滴滴、字节、蚂蚁、携程、蔚来、去哪儿等大厂&#xff08;岗位都是大数据开发&#…