从零开始详解OpenCV条形码区域分割

news2024/11/15 21:30:59

前言

在识别二维码之前,首先要划分出二维码的区域,在本篇文章中将从零开始实现二维码分割的功能,并详细介绍用到的方法。

我们需要处理的图像如下:
在这里插入图片描述

完整代码

首先我们先放出完整代码,然后根据整个分割流程介绍用到的函数和方法,完整代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt

class barCodes:
    def __init__(self, img_path, col_scale=800):
        self.image = cv2.imread(img_path)  # BGR图像
        self.gray_image = cv2.cvtColor(self.image.copy(), cv2.COLOR_RGB2GRAY)  # 灰度图
        self.col_scale = col_scale  # 根据列等比缩放图片
        self.scale = col_scale / self.image.shape[1]  # 缩放后图像宽与当前实际图像的宽的比值
        self.unscale = 1.0 / self.scale  # self.scale的倒值,用于还原缩放
        self.boxs = []  # 用于存储分割出来的框

    def scaleImage(self, image):
        # 根据比值来缩放图像
        im = image.copy()
        scale=self.scale
        im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale)))
        return im

    def blackHat(self, image, kernel = np.ones((1, 3), np.uint8)):
        # 黑帽操作
        im = image.copy()
        im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel=kernel, anchor=(1, 0))
        return im

    def threshold(self, image, low=10, heigh=255):
        # 根据阈值二值化
        im = image.copy()
        thresh, im = cv2.threshold(im, low, heigh, cv2.THRESH_BINARY)
        return im

    def morph_close(self, image, kernel=np.ones((1, 5), np.uint8), iterations=2):
        # 闭操作
        im = image.copy()
        im = cv2.morphologyEx(im, cv2.MORPH_CLOSE, kernel, iterations=iterations)
        return im

    def dilate(self, image, kernel = np.ones((1,3),np.uint8)):
        # 腐蚀操作
        im = image.copy()
        im = cv2.dilate(im, kernel)
        return im

    def getContours(self, image):
        # 获取边框
        im = image.copy()
        im_out = self.image.copy()
        unscale = self.unscale
        contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
        if contours != None:
            for contour in contours:
                if cv2.contourArea(contour) < 2000:
                    continue
                rect = cv2.minAreaRect(contour)
                rect = ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \
                       (int(rect[1][0] * unscale), int(rect[1][1] * unscale)),
                        rect[2]
                       )
        
                box = np.int0(cv2.boxPoints(rect))
                self.boxs.append(box)
                cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness=2)
        return im_out

    def forward(self, image, process_lst):
        im = image.copy()
        for i, process in enumerate(process_lst):
            im = process(im)
            self.plot_show(im, cmap=plt.cm.gray)

        return im

    def plot_show(self, image, cmap=None):
        # 显示图像
        if cmap is None:
            plt.imshow(image)
        else:
            plt.imshow(image, cmap)
        plt.show()
        
    def getBarRect(self):
        self.plot_show(self.image[:,:,::-1])
        process_lst = [self.scaleImage, self.blackHat, self.threshold, self.morph_close, self.dilate, self.getContours]
        image = self.forward(self.gray_image, process_lst)
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        self.plot_show(image)

barcode = barCodes('test.png')
barcode.getBarRect()

函数详解

初始化

def __init__(self, img_path, col_scale=800):
	self.image = cv2.imread(img_path)  # BGR图像
	self.gray_image = cv2.cvtColor(self.image.copy(), cv2.COLOR_RGB2GRAY)  # 灰度图
	self.col_scale = col_scale  # 根据列等比缩放图片
	self.scale = col_scale / self.image.shape[1]  # 缩放后图像宽与当前实际图像的宽的比值
	self.unscale = 1.0 / self.scale  # self.scale的倒值,用于还原缩放
	self.boxs = []  # 用于存储分割出来的框

在OpenCV中使用cv2.imread从文件中读入图像

语法:
	img = cv2.imread(filename[, flags])
参数:
	filename:要读取的图像的文件名或文件路径。
	flags(可选):读取图像时的标志。常用的标志有:	
		cv2.IMREAD_COLOR:以彩色模式加载图像。这是默认值。
		cv2.IMREAD_GRAYSCALE:以灰度模式加载图像。
		cv2.IMREAD_UNCHANGED:包括图像的 alpha 通道(如果存在)

为了方便显示,我们首先选择cv2.IMREAD_COLOR读取彩色BGR图片,因为随后的处理过程需要用到灰度图,所以我们需要将彩色图片转换成灰度图。

cv2.cvtColor 用于颜色空间转换。将图像从一个颜色空间转换到另一个颜色空间。

语法:
	dst = cv2.cvtColor(src, code[, dst[, dstCn]])
参数:
	src:输入图像,即要进行颜色空间转换的原始图像。
	code:转换类型。OpenCV 提供了多种预定义的颜色空间转换类型
		cv2.COLOR_BGR2GRAY:BGR 到灰度图。
		cv2.COLOR_BGR2HSV:BGR 到 HSV(色相、饱和度、亮度)。
		cv2.COLOR_BGR2HLS:BGR 到 HLS(色相、亮度、饱和度,与 HSV 类似,但计算方式不同)。
		cv2.COLOR_HSV2BGR:HSV 到 BGR。
		cv2.COLOR_GRAY2BGR:灰度图到 BGR(结果图像的每个通道都将具有相同的灰度值)
	dst(可选):输出图像,即颜色空间转换后的图像。
	dstCn(可选):目标图像的通道。

有时我们需要处理的图像过大,会影响到处理的速度,所以我们一般需要对图像进行缩放。但是如果直接对图像reshape,会影响到图像的比例导致图像失真,所以我们最好根据比例进行缩放。

我们设置了一个名为scale的变量,来保存我们需要的宽度与图像实际宽度的比,后续可以通过scale与图像的实际宽高相乘获取到等比例缩小后的长和宽。

显示图像

def plot_show(self, image, cmap=None):
	# 显示图像
    if cmap is None:
        plt.imshow(image)
    else:
        plt.imshow(image, cmap)
    plt.show()

在本篇中使用matplotlib显示图像。

按比例缩放

def scaleImage(self, image):
	# 根据比值来缩放图像
	im = image.copy()
	scale=self.scale
	im = cv2.resize(im, (int(im.shape[1] * scale), int(im.shape[0] * scale)))
	return im

这个功能还是很简单的,获取到缩小后的长和宽之后调用cv2.resize对图像比例缩放。

语法:
	dst = cv2.resize(src, dsize[, fx[, fy[, interpolation]]])
参数:
	src:输入图像。
	dsize:目标图像的大小(宽度,高度)。
	fx(可选):水平轴(宽度)的缩放因子。当 dsize 为(0, 0)时,它才有效。
	fy(可选):垂直轴(高度)的缩放因子。当 dsize 为(0, 0) 时,它才有效。
		通常设置为与 fx 相同,以保持图像的纵横比。
	interpolation(可选):插值方法。常用的插值方法有:
		cv2.INTER_LINEAR:线性插值(默认)。
		cv2.INTER_NEAREST:最近邻插值。
		cv2.INTER_AREA:区域插值(当缩小图像时使用)。
		cv2.INTER_CUBIC:三次样条插值(当放大图像时使用)。
		cv2.INTER_LANCZOS4:Lanczos 插值。

黑帽操作

def blackHat(self, image, kernel = np.ones((1, 3), np.uint8)):
	# 黑帽操作
	im = image.copy()
	im = cv2.morphologyEx(im, cv2.MORPH_BLACKHAT, kernel=kernel, anchor=(1, 0))
	return im
黑帽操作(Black Hat)是形态学操作中的一种常见操作。
原理:	
	闭运算结果与原始图像之间的差别。
	闭运算:先膨胀,再腐蚀。
	膨胀:白色像素占据黑色像素
	腐蚀:黑色像素占据白色像素
作用:
	黑帽操作可以得到图像中较亮的小区域,而不考虑更暗的大区域。
	通常用于提取图像中的大型结构、背景或者光照不均匀造成的影响。

在黑帽操作中,第一步是先膨胀再腐蚀然后与原始图像相减,这个步骤使得处理后的图像白色区域比黑色区域更多,即黑色区域被白色区域侵蚀;第二步是与原本图像相减,经过这个步骤,处理的结果中就只剩下了边缘轮廓的线条,而条形码区域的边缘轮廓线条较为密集,经过这一步骤可以除去图像中的大部分背景。

在OpenCV中cv2.morphologyEx用于执行形态学操作,我们可以通过cv2.morphologyEx实现黑帽操作

语法:
	dst = cv2.morphologyEx(src, op, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]])

参数
	src:源图像,必须是单通道的灰度图像。
	op:形态学操作的类型,可以是以下几种之一:
		cv2.MORPH_ERODE:腐蚀操作。
		cv2.MORPH_DILATE:膨胀操作。
		cv2.MORPH_OPEN:开运算(先腐蚀后膨胀)。
		cv2.MORPH_CLOSE:闭运算(先膨胀后腐蚀)。
		cv2.MORPH_GRADIENT:形态学梯度(膨胀后减去腐蚀)。
		cv2.MORPH_TOPHAT:顶帽运算(原图像减去开运算结果)。
		cv2.MORPH_BLACKHAT:黑帽运算(闭运算结果减去原图像)。
		kernel:结构元素或卷积核,用于定义形态学操作的结构和大小。
			它通常是一个奇数大小的二维数组(矩阵)。
		dst(可选):输出图像,如果未指定,则函数会创建一个新的输出图像。
		anchor(可选):锚点位置,指定了卷积核的基准点,
			默认为(-1, -1),表示位于卷积核的中心。
		iterations(可选):操作迭代的次数,默认为1。
			对于腐蚀和膨胀操作,增加迭代次数可以加大效果。
		borderType(可选):像素外推法选择标志,默认为cv2.BORDER_CONSTANT。
		borderValue(可选):当使用cv2.BORDER_CONSTANT时,此值指定了边界像素的值。

经过这一过程后图像变为
在这里插入图片描述

阈值二值化

def threshold(self, image, low=10, heigh=255):
	# 根据阈值二值化
	im = image.copy()
	thresh, im = cv2.threshold(im, low, heigh, cv2.THRESH_BINARY)
	return im

经过黑帽操作后的图像显然还不够清晰,我们可以通过阈值二值化操作将图像的像素点变为纯黑和纯白两种颜色。

在opencv中可以使用cv2.threshold完成这一操作

语法:
	retval, dst = cv2.threshold(src, thresh, maxval, type[, dst])
参数:
	src:源图像(必须是灰度图像)。
	thresh:阈值。
	maxval:用于替换超过阈值的像素的最大值。
	type:阈值处理的类型。OpenCV 提供了几种不同的类型,
		其中最常见的有:
		cv2.THRESH_BINARY:二值化阈值处理(0~maxval)
		cv2.THRESH_BINARY_INV:反二值化阈值处理(0~maxval)
		cv2.THRESH_TRUNC:截断阈值处理,如果像素值大于阈值,则像素值设置为阈值。
		cv2.THRESH_TOZERO:低阈值归零处理,如果像素值小于或等于阈值,则像素值设置为0。
		cv2.THRESH_TOZERO_INV:高阈值归零处理,如果像素值大于阈值,则像素值设置为0。
		cv2.THRESH_OTSU(结合此值,函数会计算并选择一个最佳的全局阈值)
		cv2.THRESH_TRIANGLE(结合此值,函数会计算并选择一个基于三角形方法的最佳全局阈值)
	dst(可选):输出图像。如果省略,则使用一个新的图像。
返回值:
	retval:分割的阈值
	dst:阈值处理后的图像。

经过这一操作,图像变为
在这里插入图片描述

闭操作

def morph_close(self, image, kernel=np.ones((1, 5), np.uint8), iterations=2):
	# 闭操作
	im = image.copy()
	im = cv2.morphologyEx(im, cv2.MORPH_CLOSE, kernel, iterations=iterations)
	return im

通过闭操作,先膨胀(白色像素吞噬黑色像素)后腐蚀(黑色像素吞噬白色像素),可以使得条形码分散的各部分合并在一起。

经过操作后图像效果如下
在这里插入图片描述

腐蚀操作

def dilate(self, image, kernel = np.ones((1,3),np.uint8)):
	# 腐蚀操作
	im = image.copy()
	im = cv2.dilate(im, kernel)
    return im

通过腐蚀操作(黑色像素吞噬白色像素)可以进一步去除非条形码的线条干扰。

经过操作后图像效果如下,在这里效果并不明显,可以再多尝试一些参数组合。
在这里插入图片描述

获取边框

 def getContours(self, image):
 	# 获取边框
 	im = image.copy()
 	im_out = self.image.copy()
 	unscale = self.unscale
 	contours, hierarchy = cv2.findContours(im, cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
 	if contours != None:
 		for contour in contours:
 			if cv2.contourArea(contour) < 2000:
 				continue
 			rect = cv2.minAreaRect(contour)
 			rect = ((int(rect[0][0] * unscale), int(rect[0][1] * unscale)), \
                       (int(rect[1][0] * unscale), int(rect[1][1] * unscale)),
                        rect[2]
                       )
        	box = np.int0(cv2.boxPoints(rect))
        	self.boxs.append(box)
        	cv2.drawContours(im_out, [box], 0, (0, 255, 0), thickness=2)
	return im_out

根据之前的处理结果已经可以看到一些雏形了,接下来我们将直接使用 cv2.findContours直接获取条形码轮廓区域。
cv2.findContours的用法:

语法:
	contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
参数:
	image: 源图像,必须是8位单通道二值图像。
	mode: 轮廓检索模式。可选参数:
		cv2.RETR_EXTERNAL: 只检索最外层的轮廓。
		cv2.RETR_LIST: 检索所有的轮廓,但不建立父子关系。
		cv2.RETR_CCOMP: 检索所有的轮廓,并建立两个级别的关系
			(即,谁是谁的外部轮廓,谁是谁的孔)。
		cv2.RETR_TREE: 检索所有的轮廓,并重新建立嵌套的轮廓关系。
	method: 轮廓近似方法。可以是以下之一:
		cv2.CHAIN_APPROX_NONE: 存储轮廓的每个点。
		cv2.CHAIN_APPROX_SIMPLE: 压缩水平、垂直和对角线段,只留下它们的端点。
		cv2.CHAIN_APPROX_TC89_L1, cv2.CHAIN_APPROX_TC89_KCOS: 使用 Teh-Chinl 的近似算法。
	contours: 检测到的轮廓。每个轮廓都是图像边界点的一个点集。
	hierarchy: 可选的输出向量,其中包含了有关图像拓扑的信息。
返回值:
	contours和hierarchy。

上述代码中首先获取了条形码所有的轮廓区域,随后遍历所有轮廓区域,通过cv2.contourArea检测轮廓面积大小,当轮廓面积过小时,很显然并不是我们所需的条形码区域,所以我们直接跳过处理。如果大于设定的轮廓面积,使用cv2.minAreaRect获取符合轮廓形状的最小矩形,获取的矩形就是条形码的区域。随后就可以画图了。

cv2.drawContours用法

语法:
	cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
参数:
	image:源图像,可以是二值图像或彩色图像。
		注意,cv2.drawContours 会在图像上直接绘制轮廓。
	contours:要绘制的轮廓。
	contourIdx:要绘制的轮廓的索引。如果为 -1,则绘制所有轮廓。
	color:轮廓的颜色,是一个三元组,表示 BGR颜色。
	thickness:线条的粗细。如果为负数,则轮廓将被填充。
	lineType:线条类型。默认cv2.LINE_8(8连通线)。
	hierarchy:轮廓的层次关系,是一个 NumPy 数组。通常这个参数可以省略。
	maxLevel:最多绘制的轮廓层次级别。如果未指定,则绘制所有级别。
	offset:轮廓点相对于图像原点的偏移量。通常这个参数可以省略。

这一步骤后图像效果是蓝色的,因为opencv是BGR格式而matplotlib是RGB格式的
在这里插入图片描述
如果BGR转RGB,结果如下
在这里插入图片描述

流程化

根据之前的步骤我们可以看出,执行的过程是线性的,所以我们可以将代码流程化

def forward(self, image, process_lst):
	im = image.copy()
    for i, process in enumerate(process_lst):
        im = process(im)
        self.plot_show(im, cmap=plt.cm.gray)
    return im

其中process_lst是执行过程组成的列表,image是图像,每步执行后调用plot_show显示结果。

def getBarRect(self):
	self.plot_show(self.image[:,:,::-1])
	process_lst = [self.scaleImage, self.blackHat, self.threshold, self.morph_close, self.dilate, self.getContours]
	image = self.forward(self.gray_image, process_lst)
	image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
	self.plot_show(image)

在使用时传入图像路径后调用getBarRect即可完成条码区域区分功能

barcode = barCodes('test.png')
barcode.getBarRect()

视频讲解

从零开始详解OpenCV条形码区域分割


从零开始详解OpenCV条形码区域分割

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

英伟达的GDS

英伟达的GDS&#xff0c;即GPUDirect Storage&#xff0c;是英伟达开发的一种技术&#xff0c;它允许GPU直接访问存储设备&#xff0c;从而显著提高数据传输效率和性能。 以下是对英伟达GDS的详细介绍&#xff1a; 一、GDS技术的主要特点和优势 直接内存存取&#xff1a;GDS通…

【设计模式】JAVA Design Patterns——Acyclic Visitor(非循环访问者模式)

&#x1f50d;目的 允许将新功能添加到现有的类层次结构中&#xff0c;而不会影响这些层次结构&#xff0c;也不会有四人帮访客模式中那样循环依赖的问题。 &#x1f50d;解释 真实世界例子 我们有一个调制解调器类的层次结构。 需要使用基于过滤条件的外部算法&#xff08;是…

使用 python 整理 latex 的 bib 文献列表

目录 bib 文献整理脚本前提条件与主要功能原理编程语言与宏包基础完整程序 bib 文献整理脚本 本文主要用于解决 Latex 写作过程中遇到的 bib 文献整理问题&#xff0c;可处理中文文献。 LaTeX是一种基于ΤΕΧ的排版系统&#xff0c;它非常适用于生成高印刷质量的科技和数学类…

八大设计模式:适配器模式实现栈的泛型编程 | 通用数据结构接口的秘诀(文末送书)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 哈喽各位铁汁们好啊&#xff0c;我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发&#xff0c;不知道各位的…

pyautogui 基本用法

pyautogui 是一个 Python 库&#xff0c;可以让你用 Python 脚本控制鼠标和键盘。它适用于自动化桌面图形用户界面&#xff08;GUI&#xff09;的任务&#xff0c;比如自动化测试、游戏脚本或任何需要模拟用户输入的程序。 以下是使用 pyautogui 的一些基础示例&#xff1a; 安…

地平线旭日X3开发板编译USB网卡驱动 AX88772B

由于使用的激光雷达是网口输出的&#xff0c; 为了不占用X3派已有的网口&#xff0c;接上去了一个绿联的usb网卡&#xff0c; 发现系统没有驱动&#xff0c;所以动手看看能不能自己编译一个 首先lsusb查看一下网卡型号 发现型号是AX88772B&#xff0c;去官网看了一下&#x…

低空经济之无人机

朋友们&#xff0c;今天来聊聊个超酷的话题——低空经济之无人机&#xff01; 无人机不仅让天空变得触手可及&#xff0c;还带来了无尽的商业可能&#xff0c;简直就是新时代的“空中小助手”啊&#xff01; 说到无人机&#xff0c;你们是不是也和我一样&#xff0c;脑海里立马…

【数据结构】队列的实现(链式)

文章目录 队列1.队列的概念及结构概念结构 2.队列的实现&#xff08;链式结构&#xff09;队列定义初始化队列入队出队获取队头元素获取队尾元素销毁队列判断队列是否为空队列有效个数 完整代码&#xff08;包含测试代码&#xff09;Queue.hQueue.ctest.c 队列 1.队列的概念及…

nodemon运行ts文件

https://juejin.cn/post/7035637086451400734 nodemon经常用来调试js文件&#xff0c;大家都是知道的&#xff0c;但是用nodemon来调试ts文件&#xff0c;大家试过吗&#xff1f; 如果直接运行nodemon index.ts是会报错的。 ts 复制代码 //index.ts console.log(1) 需要全局…

安全设备篇——抗DDOS设备

写在前面&#xff1a;up初研究这个设备的时候以为很容易&#xff0c;毕竟ddos嘛大家都懂&#xff0c;但是实际去找资料和研究的时候发现资料少的可怜&#xff0c;再加上大家知道ddos但大多没见过&#xff0c;万幸up的老东家某普有这类设备&#xff0c;和之前的同事沟通了一下还…

百望云钉钉:重塑财务智能化管理,助力企业实现数字化飞跃

近年来&#xff0c;数字技术正在深刻改变着企业生产方式和组织模式&#xff0c;企业面连着业务流程再造、经营模式创新等一系列建设挑战。 其中&#xff0c;财务部门从价值守护走向价值创造的过程中&#xff0c;展现出对企业经营与业务发展的巨大影响力。叠加金税四期税务改革&…

【稳定检索|主题广泛】2024年人文发展、媒体传播与文化交流国际会议(DMCCE 2024)

2024年人文发展、媒体传播与文化交流国际会议&#xff08;DMCCE 2024&#xff09; 2024 International Conference on Cultural Development, Media Communication, and Cultural Exchange 【会议简介】 2024年人文发展、媒体传播与文化交流国际会议将于成都举行。此次会议将…

计算机考研|408备考,如何6个月顺利上岸?经验+资料分享

如果是跨考的话&#xff0c;现在已经快六月份了&#xff0c;备考408时间真的很紧张 u1s1&#xff0c;我虽然一直推荐大家考408&#xff0c;但是也看情况&#xff0c;这种跨考&#xff0c;并且时间不充足的情况下&#xff0c;就最好不要去硬刚408了。408的复习量很大&#xff0…

【python数据预处理系列】使用Pandas的factorize()函数进行类别编码(整数编码)

在Pandas中&#xff0c;factorize()函数主要用于将分类变量转换为整数编码&#xff0c;这对于减少内存使用或准备数据进行某些统计分析非常有用。 它实际上是将列的唯一值映射到从0开始的整数序列上。 假设有一个DataFrame&#xff0c;其中一列包含一些类别值&#xff0c;你希望…

运筹说 第114期 | 其他排队模型简介

前面我们已经学习了一些排队模型&#xff0c;对排队系统有了基本认知&#xff0c;本期小编带大家继续来学习其他排队模型的内容。 一、有限源排队模型 顾客源为有限的这类排队问题的主要特征是顾客总数是有限的&#xff0c;如只有m个顾客。每个顾客来到系统中接受服务后仍回到…

jmeter指南:JMeter 安装、配置和性能测试

使用 JMeter 进行性能测试 1. Java 版本要求 JMeter 要求与 Java 8 或更高版本兼容。为了确保安全性和性能&#xff0c;建议安装最新次要版本的主要 Java 版本。鉴于 JMeter 仅使用标准 Java API&#xff0c;如果由于 JRE 实现问题而无法运行 JMeter&#xff0c;请不要提交错…

为Akamai 云平台上部署的资源配置2FA跳板机-上

为重要账户启用2FA&#xff0c;这几乎已经成为保护账户和数据安全的一种标准做法。无论登录常见应用或服务&#xff0c;或是访问企业内部资源&#xff0c;时不时都会需要进行2FA验证。那么当你在Akamai Connected Cloud云平台中部署了各类资源&#xff08;云计算、云存储、SaaS…

Java面试八股之float和double的区别

Java中float和double的区别 存储空间与精度&#xff1a; double&#xff1a;占据64位&#xff08;8字节&#xff09;存储空间&#xff0c;属于双精度浮点数。它可以提供较高的精度&#xff0c;通常能够精确表示大约15到17位十进制数字&#xff0c;适合用于需要较高精度计算或…

【面试必看】MyBatis部分

MyBatis 必读 Mybatis系列全解 MyBatis最全使用指南 MyBatis最全使用指南 1. JDBC java 操作数据库的原始方式就是 JDBC。 但是存在以下问题&#xff1a; 每次操作我们都要创建 connection、Statement 等一些对象&#xff0c;操作完还要关闭、销毁这些对象。 ResultSet …

【OSM】RDP资源无法访问

发布windows的远程桌面资源&#xff0c;web和rdp方式都不能访问&#xff0c;端口测试都正常&#xff0c;不经过堡垒机能正常连接服务器 1、将资源中rdp安全模式指定为rdp&#xff0c;并直接登录到服务器&#xff0c;打开【组策略】&#xff0c;依次展开计算机配置→Windows组件…