当前位置: 首页 > news >正文

OpenCV #以图搜图:均值哈希算法(Average Hash Algorithm)原理与实验

1. 介绍

均值哈希算法(Average Hash Algorithm) 是哈希算法的一种,主要用来做相似图片的搜索工作。

 

2. 原理

均值哈希算法(aHash)首先将原图像缩小成一个固定大小的像素图像,然后将图像转换为灰度图像,通过缩小图像的每个像素与平均灰度值的比较,生成一组哈希值。最后,利用两组图像的哈希值的汉明距离来评估图像的相似度。

魔法: 概括地讲,均值哈希算法一共可细分六步:

  1. 缩小图像: 将目标图像缩小为一个固定的大小,通常为8x8像素,总共64个像素。作用是去除各种图像尺寸和图像比例的差异,只保留结构、明暗等基本信息,目的是确保图像的一致性,降低计算的复杂度。
  2. 图像灰度化: 将缩小的图像转换为灰度图像。
  3. 灰度平均值: 计算灰度图像的平均灰度值。减少计算量。
  4. 比较平均值: 遍历灰度图像的每个像素,比较每个像素的灰度值是否大于或小于平均值。对于大于等于平均值的像素,将其表示为1,对于小于平均值的像素,将其表示为0。最后,得到一个64位的二进制值(8x8像素的图像)。
  5. 生成哈希值: 由于64位二进制值太长,所以按每4个字符为1组,由2进制转成16进制。这样就转为一个长度为16的字符串。这个字符串也就是这个图像可识别的哈希值,也叫图像指纹,即这个图像所包含的特征。
  6. 哈希值比较: 通过比较两个图像的哈希值的汉明距离(Hamming Distance),就可以评估图像的相似度,距离越小表示图像越相似。

 

3. 实验

第一步:缩小图像

将目标图像缩小为一个固定的大小,通常为8x8像素,总共64个像素。作用是去除各种图像尺寸和图像比例的差异,只保留结构、明暗等基本信息,目的是确保图像的一致性,降低计算的复杂度。

1)读取原图

# 测试图片路径
img_path = 'img_test/apple-01.jpg'# 通过OpenCV加载图像
img = cv2.imread(img_path)# 通道重排,从BGR转换为RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

aHash-0001

2)缩小原图

# 缩小图像:使用OpenCV的resize函数将图像缩放为8x8像素,采用Cubic插值方法进行图像重采样
img_resize = cv2.resize(img, (8, 8), cv2.INTER_CUBIC)

aHash-0002
OpenCV 的 cv2.resize() 函数提供了4种插值方法,以根据图像的尺寸变化来进行图像重采样。

  • cv2.INTER_NEAREST: 最近邻插值,也称为最近邻算法。它简单地使用最接近目标像素的原始像素的值。虽然计算速度快,但可能导致图像质量下降。
  • cv2.INTER_LINEAR: 双线性插值,通过对最近的4个像素进行线性加权来估计目标像素的值。比最近邻插值更精确,但计算成本略高。
  • cv2.INTER_CUBIC: 双三次插值,使用16个最近像素的加权平均值来估计目标像素的值。通常情况下,这是一个不错的插值方法,适用于图像缩小。
  • cv2.INTER_LANCZOS4: Lanczos插值,一种高质量的插值方法,使用Lanczos窗口函数。通常用于缩小图像,以保留图像中的细节和纹理。

第二步:图像灰度化

将缩小的图像转换为灰度图像。也就是说,所有像素点总共只有64种灰度颜色。

# 图像灰度化:将彩色图像转换为灰度图像。
img_gray = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)
print(f"缩放8x8的图像中每个像素的颜色=\n{img_gray}")

输出打印:

缩放8x8的图像中每个像素的颜色=
[[253 253 253 253 253 253 253 253][253 253 253 148 253 253 253 253][253 253 253 215 178 253 253 253][253 253 119  93 132 176 253 253][253 253  61  61  53 130 253 253][253 253 112  67  66 142 253 253][253 253 252  54  54 253 253 253][253 253 236  63 146 249 253 253]]

aHash-0003

第三步:灰度平均值

计算灰度图像的平均灰度值。减少计算量。

img_average = np.mean(img_gray) 
print(f"灰度图像中所有像素的平均值={img_average}")

输出打印:

灰度图像中所有像素的平均值=209.890625

第四步:比较平均值

遍历灰度图像的每个像素,比较每个像素的灰度值是否大于或小于平均值。对于大于等于平均值的像素,将其表示为1;对于小于平均值的像素,将其表示为0。最后,得到一组长64位的二进制字符串(8x8像素的图像)。因为对于机器而言,只认识0和1,所以这组64位的二进制就可以表示这张图像的结构和亮度分布。

# 遍历图像像素:嵌套循环遍历图像的所有像素,对比灰度图像的平均灰度值,转换为二进制的图像哈希值
img_hash_binary = [] 
for i in range(img_gray.shape[0]): for j in range(img_gray.shape[1]): if img_gray[i,j] >= img_average: img_hash_binary.append(1)else: img_hash_binary.append(0)
print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)数组={img_hash_binary}")# 将列表中的元素转换为字符串并连接起来,形成一组64位的图像二进制哈希值字符串
img_hash_binary_str = ''.join(map(str, img_hash_binary))
print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)={img_hash_binary_str}")

代码分解和含义如下:

  1. 初始化空列表:创建一个空的列表 img_hash_binary,用于存储图像的哈希值。
  2. 遍历图像像素:嵌套循环遍历图像的所有像素,其中 img_gray 是输入的灰度图像,img_gray.shape[0] 和 img_gray.shape[1] 分别表示图像的高度和宽度。
  3. 计算平均值:代码中使用变量 img_average 存储了一个平均值,用于与图像像素的灰度值进行比较。
  4. 根据亮度值生成哈希值:对于每个像素,代码比较像素的灰度值与平均值 (img_gray[i, j] >= img_average)。如果像素的灰度值大于或等于平均值,就将数字1添加到 img_hash_binary 列表中,表示该像素是亮的。如果像素的灰度值小于平均值,就将数字0添加到 img_hash_binary 列表中,表示该像素是暗的。
  5. 最终哈希值:完成循环后,img_hash_binary 列表将包含图像的二进制哈希值,其中每个元素代表一个像素的明暗情况。

输出打印:

对比灰度图像的平均像素值降噪(图像的二进制形式)数组=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1]
对比灰度图像的平均像素值降噪(图像的二进制形式)=1111111111101111111101111100001111000011110000111110011111100111       

或者,使用等价的 lambda 表达式。效果一样。

# lambda表达式
img_hash_binary_str = ""
for i in range(8):img_hash_binary_str += ''.join(map(lambda i: '0' if i < img_average else '1', img_gray[i]))
print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)={img_hash_binary_str}")

输出打印:

对比灰度图像的平均像素值降噪(图像的二进制形式)=1111111111101111111101111100001111000011110000111110011111100111

第五步:生成哈希值

由于64位二进制值太长,所以按每4个字符为1组,由2进制转成16进制。这样就转为一个长度为16的字符串。这个字符串也就是这个图像可识别的哈希值,也叫图像指纹,即这个图像所包含的特征。

img_hash = ""
for i in range(0, 64, 4):img_hash += "".join('%x' % int(img_hash_binary_str[i : i + 4], 2))
print(f"图像可识别的哈希值={img_hash}")

代码分解和含义如下:

  1. 初始化为空字符串:创建一个空的字符串 img_hash,用于存储图像哈希值的十六进制表示。
  2. 遍历二进制哈希值:通过循环,代码以4位为一组遍历二进制哈希值 img_hash_binary_str。range(0, 64, 4) 确保代码在哈希值的每4位之间进行迭代。
  3. 将4位二进制转换为一个十六进制字符:在每次循环中,代码取出哈希值中的4位二进制(例如,img_hash_binary_str[i : i + 4]),然后使用’%x’ % int(…, 2) 将这4位二进制转换为一个十六进制字符。int(…, 2) 将二进制字符串转换为整数,‘%x’ 将整数转换为十六进制字符。
  4. 将十六进制字符追加到 img_hash:在每次循环中,得到的十六进制字符将被追加到 img_hash 字符串中。
  5. 最终哈希值:完成循环后,img_hash 将包含图像哈希值的十六进制表示,其中每个字符表示4位二进制。

输出打印:

图像可识别的哈希值=ffeff7c3c3c3e7e7

第六步:哈希值比较

通过比较两个图像的哈希值的汉明距离(Hamming Distance),就可以评估图像的相似度,距离越小表示图像越相似。

def hamming_distance(s1, s2):# 检查这两个字符串的长度是否相同。如果长度不同,它会引发 ValueError 异常,因为汉明距离只适用于等长的字符串if len(s1) != len(s2):raise ValueError("Input strings must have the same length")distance = 0for i in range(len(s1)):# 遍历两个字符串的每个字符,比较它们在相同位置上的值。如果发现不同的字符,将 distance 的值增加 1if s1[i] != s2[i]:distance += 1return distance

 

4. 测试

我们来简单测试一下基于均值哈希算法的以图搜图 – 基于一张原图找最相似图片,看看效果如何。
这里,我准备了10张图片,其中9张是苹果,但形态不一,1张是梨子。
aHash-0004
输出打印:

图片名称:img_test/apple-01.jpg,图片HASH:ffeff7c3c3c3e7e7,与图片1的近似值(汉明距离):0
图片名称:img_test/apple-02.jpg,图片HASH:ffcfc3e3e3e3e7ff,与图片1的近似值(汉明距离):8
图片名称:img_test/apple-03.jpg,图片HASH:ffe7c3c3c3c7c7ff,与图片1的近似值(汉明距离):7
图片名称:img_test/apple-04.jpg,图片HASH:e7e7c3c3c3eff7ff,与图片1的近似值(汉明距离):10
图片名称:img_test/apple-05.jpg,图片HASH:f3f3e7c7c3c7c7e7,与图片1的近似值(汉明距离):7
图片名称:img_test/apple-06.jpg,图片HASH:ffffd981818189dd,与图片1的近似值(汉明距离):13
图片名称:img_test/apple-07.jpg,图片HASH:fff7f3e3e3e3f0ff,与图片1的近似值(汉明距离):10
图片名称:img_test/apple-08.jpg,图片HASH:000006fdf171f9f8,与图片1的近似值(汉明距离):16
图片名称:img_test/apple-09.jpg,图片HASH:ffcfe7c1c1c3e7ff,与图片1的近似值(汉明距离):6
图片名称:img_test/pear-001.jpg,图片HASH:fffbe5c1c3c3c3ef,与图片1的近似值(汉明距离):8
耗时:0.09571695327758789

汉明距离:两个长度相同的字符串在相同位置上的字符不同的个数。
aHash-0005

简单的测试分析:

原图相似图片相似值(汉明距离)相似图片特点相似图片与原图Hash对比结果
图片01图片010自己自己与自己相似度100%
图片01图片096青苹果最相似。相同背景相同物体位置下最相似。
图片01图片03、图片057红蛇果(苹果)、青苹果(2D)次相似。同上,单物体对比时,背景、物体位置越近越相似。
图片01图片028两者几乎相似比较相似。影响相似距离的似乎是苹果下方的阴影有无。
图片01图片pear-0018黄色的梨子意外相似。相似搜索并不能识别物体/内容,因为工作原理是通过图片灰度后的灰色像素点位置与对比。
图片01图片0410原图像的180度旋转图相差甚远。对于原图旋转变换相对不敏感,因为均值哈希算法只捕获了图像的平均亮度和粗略结构。
图片01图片06、07、0810以上复杂、多主体、多色调较难分辨。复杂、多主体、多色调的图片较难与原图相似。

10张测试图片中,汉明距离在5以内1张;汉明距离在5以外9张。
从抽样简单测试结果看,平均哈希简单且计算速度快,但它对图像的细节变化比较敏感,容易受到局部图像的特性的干扰。

备注:如果汉明距离0,则表示这两张图片非常相似;如果汉明距离小于5,则表示有些不同,但比较相近;如果汉明距离大于10,则表明是完全不同的图片。

 

5. 总结

经过实验和测试,平均哈希算法优缺点明显。

特点: 传统
优点: 简单、计算效率高,适用于快速图像相似性比较。
缺点: 对于图片的旋转和主体内容变换相对不敏感;对于复杂、多主体、多色调的图片较难相似,因为它只捕获了图片的平均亮度和粗略结构。

 

6. 实验代码

"""
以图搜图:均值哈希算法(Average Hash Algorithm)的原理与实现
测试环境:win10 | python 3.9.13 | OpenCV 4.4.0 | numpy 1.21.1
实验时间:2023-10-20
"""import cv2
import time
import numpy as np
import matplotlib.pyplot as pltdef get_hash(img_path):# 读取图像:通过OpenCV的imread加载图像# 缩小图像:使用OpenCV的resize函数将图像缩放为8x8像素,采用Cubic插值方法进行图像重采样img_rgb = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)# 使用OpenCV的resize函数将图像缩放为8x8像素,采用Cubic插值方法进行图像重采样img_resize = cv2.resize(img_rgb, (8, 8), cv2.INTER_CUBIC)# 图像灰度化:将彩色图像转换为灰度图像。较少计算量。img_gray = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)# print(f"缩放8x8的图像中每个像素的颜色=\n{img_gray}")# 灰度平均值:计算灰度图像的平均灰度值img_average = np.mean(img_gray) # print(f"灰度图像中所有像素的平均值={img_average}")"""# # 比较平均值:嵌套循环遍历图像的所有像素,对比灰度图像的平均灰度值,转换为二进制的图像哈希值# # img_gray:是灰度图像# # img_gray.shape[0] 和 img_gray.shape[1] 分别表示图像的高度和宽度# img_hash_binary = [] # for i in range(img_gray.shape[0]): #     for j in range(img_gray.shape[1]): #         if img_gray[i,j] >= img_average: #             img_hash_binary.append(1)#         else: #             img_hash_binary.append(0)# print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)数组={img_hash_binary}")# # 将列表中的元素转换为字符串并连接起来,形成一组64位的图像二进制哈希值字符串# img_hash_binary_str = ''.join(map(str, img_hash_binary))# print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)={img_hash_binary_str}")# # 生成哈希值# img_hash = ""# # 遍历二进制哈希值:通过循环,代码以4位为一组遍历二进制哈希值 img_hash_binary_str。# # range(0, 64, 4) 确保代码在哈希值的每4位之间进行迭代。# for i in range(0, 64, 4):#     # 将4位二进制转换为一个十六进制字符#     # 在每次循环中,代码取出哈希值中的4位二进制(例如,img_hash_binary_str[i : i + 4])#     # 然后使用'%x' % int(..., 2)将这4位二进制转换为一个十六进制字符。#     # int(..., 2)将二进制字符串转换为整数,'%x'将整数转换为十六进制字符。#     # 将十六进制字符追加到 img_hash:在每次循环中,得到的十六进制字符将被追加到 img_hash 字符串中。#     img_hash += "".join('%x' % int(img_hash_binary_str[i : i + 4], 2))# print(f"图像可识别的哈希值={img_hash}")"""# 图像二进制哈希值img_hash_binary_str = ''for i in range(8):img_hash_binary_str += ''.join(map(lambda i: '0' if i < img_average else '1', img_gray[i]))# print(f"对比灰度图像的平均像素值降噪(图像的二进制哈希值)={img_hash_binary_str}")# 图像可识别哈希值img_hash = ''.join(map(lambda x:'%x' % int(img_hash_binary_str[x : x + 4], 2), range(0, 64, 4)))# print(f"图像可识别的哈希值={img_hash}")return img_hash# 汉明距离:计算两个等长字符串(通常是二进制字符串或位字符串)之间的汉明距离。用于确定两个等长字符串在相同位置上不同字符的数量。
def hamming_distance(s1, s2):# 检查这两个字符串的长度是否相同。如果长度不同,它会引发 ValueError 异常,因为汉明距离只适用于等长的字符串if len(s1) != len(s2):raise ValueError("Input strings must have the same length")distance = 0for i in range(len(s1)):# 遍历两个字符串的每个字符,比较它们在相同位置上的值。如果发现不同的字符,将 distance 的值增加 1if s1[i] != s2[i]:distance += 1return distance# --------------------------------------------------------- 测试 ---------------------------------------------------------time_start = time.time()img_1 = 'img_test/apple-01.jpg'
img_2 = 'img_test/apple-02.jpg'
img_3 = 'img_test/apple-03.jpg'
img_4 = 'img_test/apple-04.jpg'
img_5 = 'img_test/apple-05.jpg'
img_6 = 'img_test/apple-06.jpg'
img_7 = 'img_test/apple-07.jpg'
img_8 = 'img_test/apple-08.jpg'
img_9 = 'img_test/apple-09.jpg'
img_10 = 'img_test/pear-001.jpg'img_hash1 = get_hash(img_1)
img_hash2 = get_hash(img_2)
img_hash3 = get_hash(img_3)
img_hash4 = get_hash(img_4)
img_hash5 = get_hash(img_5)
img_hash6 = get_hash(img_6)
img_hash7 = get_hash(img_7)
img_hash8 = get_hash(img_8)
img_hash9 = get_hash(img_9)
img_hash10 = get_hash(img_10)distance1 = hamming_distance(img_hash1, img_hash1)
distance2 = hamming_distance(img_hash1, img_hash2)
distance3 = hamming_distance(img_hash1, img_hash3)
distance4 = hamming_distance(img_hash1, img_hash4)
distance5 = hamming_distance(img_hash1, img_hash5)
distance6 = hamming_distance(img_hash1, img_hash6)
distance7 = hamming_distance(img_hash1, img_hash7)
distance8 = hamming_distance(img_hash1, img_hash8)
distance9 = hamming_distance(img_hash1, img_hash9)
distance10 = hamming_distance(img_hash1, img_hash10)time_end = time.time()print(f"图片名称:{img_1},图片HASH:{img_hash1},与图片1的近似值(汉明距离):{distance1}")
print(f"图片名称:{img_2},图片HASH:{img_hash2},与图片1的近似值(汉明距离):{distance2}")
print(f"图片名称:{img_3},图片HASH:{img_hash3},与图片1的近似值(汉明距离):{distance3}")
print(f"图片名称:{img_4},图片HASH:{img_hash4},与图片1的近似值(汉明距离):{distance4}")
print(f"图片名称:{img_5},图片HASH:{img_hash5},与图片1的近似值(汉明距离):{distance5}")
print(f"图片名称:{img_6},图片HASH:{img_hash6},与图片1的近似值(汉明距离):{distance6}")
print(f"图片名称:{img_7},图片HASH:{img_hash7},与图片1的近似值(汉明距离):{distance7}")
print(f"图片名称:{img_8},图片HASH:{img_hash8},与图片1的近似值(汉明距离):{distance8}")
print(f"图片名称:{img_9},图片HASH:{img_hash9},与图片1的近似值(汉明距离):{distance9}")
print(f"图片名称:{img_10},图片HASH:{img_hash10},与图片1的近似值(汉明距离):{distance10}")print(f"耗时:{time_end - time_start}")

 

7. 疑难杂症

问题1: 为什么通过 cv2.imread(img_path) 加载的图像,显示出来之后,原图由红色变成了蓝色?
aHash-0006
问题原因: 如果原图是红色的,但通过OpenCV加载显示的图像是蓝色的,这可能是由于图像的通道顺序不同导致的。在OpenCV中,图像的通道顺序通常是BGR(蓝绿红),而在一些其他库(如matplotlib)中,通常使用RGB(红绿蓝)通道顺序。
解决方案: 使用OpenCV的通道重排功能,将图像的通道顺序从BGR转换为RGB,然后再显示图像。以下是修改后的代码:

# 通过OpenCV加载图像
img = cv2.imread(img_path)# 通道重排,从BGR转换为RGB
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

问题2: 为什么使用了 cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) ,但显示出来图像是彩色的?
aHash-0007
问题原因: 这可能是由于你使用了 matplotlib 来显示图像,而 matplotlib 默认将灰度图像显示为伪彩色图像。Matplotlib会将单通道的灰度图像(每个像素只有一个亮度值)显示为伪彩色图像以便于可视化。
解决方案: 在使用 imshow 函数显示图像时,添加 cmap 参数,并将其设置为 ‘gray’,以确保图像以灰度形式显示。例如:

# 测试图片路径
img_path = 'img_test/apple-01.jpg'# 通过OpenCV加载图像
img = cv2.imread(img_path)# 通道重排,从BGR转换为RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)# 使用OpenCV的resize函数将图像缩放为8x8像素,采用Cubic插值方法
img_resize = cv2.resize(img_rgb, (8, 8), cv2.INTER_CUBIC)# 灰度化:将彩色图像转换为灰度图像。
img_gray = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY)# 灰度形式查看图像
plt.imshow(img_gray, cmap='gray')
# 显示图像
plt.show()

相关文章:

OpenCV #以图搜图:均值哈希算法(Average Hash Algorithm)原理与实验

1. 介绍 均值哈希算法&#xff08;Average Hash Algorithm&#xff09; 是哈希算法的一种&#xff0c;主要用来做相似图片的搜索工作。 2. 原理 均值哈希算法&#xff08;aHash&#xff09;首先将原图像缩小成一个固定大小的像素图像&#xff0c;然后将图像转换为灰度图像&am…...

博通BCM575系列RDMA网卡驱动bnxt_re分析(一)

简介 整个BCM系列驱动分成以太网部分(bnxt_en.ko)和RDMA部分(bnxt_re.ko), 两个模块之间通过内核的auxiliary_bus进行管理.我们主要分析下bnxt_re驱动. 代码结构 这个驱动的核心是 qplib_fp.c, 这个文件主要包含了驱动的数据路径, 包括Post Send, Post Recv, Poll CQ流程的实…...

集合总结-

Collection 常用方法 package com.test01;import java.util.ArrayList; import java.util.Collection; /*添加元素---boolean add(E e);移除元素---boolean remove(Object c);判断元素是否存在---boolean contains(Object c);*/ public class S {public static void main(Str…...

【知识串联】概率论中的值和量(随机变量/数字特征/参数估计)【考研向】【按概率论学习章节总结】

就我的概率论学习经验来看&#xff0c;这两个概念极易混淆&#xff0c;并且极为重点&#xff0c;然而&#xff0c;在概率论的前几章学习中&#xff0c;如果只是计算&#xff0c;对这方面的辨析不清并没有问题。然而&#xff0c;到了后面的参数估计部分&#xff0c;却可能出现问…...

上游服务不可用了,下游服务如何应对?

上游服务不可用了&#xff0c;下游服务如何应对&#xff1f; 引言 在系统中&#xff0c;上游服务和下游服务是两个关键概念。上游服务通常指的是提供某种功能或数据的服务端&#xff0c;它接收来自下游服务的请求&#xff0c;并根据请求进行处理和响应。下游服务通常指的是发…...

WebGL笔记:矩阵的变换之平移的实现

矩阵的变换 变换 变换有三种状态&#xff1a;平移、旋转、缩放。当我们变换一个图形时&#xff0c;实际上就是在移动这个图形的所有顶点。解释 webgl 要绘图的话&#xff0c;它是先定顶点的&#xff0c;就比如说我要画个三角形&#xff0c;那它会先把这三角形的三个顶点定出来…...

XTU-OJ 1187-Candy

WCB某天买了非常多的糖果并把它们分成N份&#xff0c;依次分别有1&#xff0c;2&#xff0c;3…,N个糖果。他想拿出其中的3份分给他的室友&#xff0c; 为了不让室友们闹意见&#xff0c;必须让这三份的糖果总数恰好能被三人均分。请问他一共有多少种不同的组合方案数&#xff…...

基于 nodejs+vue城市轨道交通线路查询系统mysql

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…...

电商时代,VR全景如何解决实体店难做没流量?

近日&#xff0c;电商和实体经济的对立成为了热门话题&#xff0c;尽管电商的兴起确实对线下实体店造成了一定的冲击&#xff0c;但实体店也不是没有办法挽救。VR全景助力线下实体店打造线上店铺&#xff0c;打通流量全域布局&#xff0c;还能实现打开产品、查看产品内部细节等…...

操作系统-浅谈CPU与内存

目录 计算机的基本组成CPU内存虚拟内存内存分段内存分页 CPU与内存的交互过程高速缓存cache 所有图片均来自&#xff1a;小林coding 计算机的基本组成 计算机由软件和硬件组成 硬件由CPU(中央处理器&#xff09;存储器(内存外存&#xff09;外部设备组成。 软件由应用软件和系…...

K8s 部署 CNI 网络组件+k8s 多master集群部署+负载均衡

------------------------------ 部署 CNI 网络组件 ------------------------------ ---------- 部署 flannel ---------- K8S 中 Pod 网络通信&#xff1a; ●Pod 内容器与容器之间的通信 在同一个 Pod 内的容器&#xff08;Pod 内的容器是不会跨宿主机的&#xff09;共享同一…...

若依微服务上传图片文件代理配置

在使用若依微服务文件上传时候,文件上传成功会上传到D:/ruoyi/uploadPath目录下。默认使用9300端口进行访问图片文件,现在我想把它代理到80端口应该怎么做呢? 配置前:http://localhost:9300/statics/2023/09/24/test.jpg 配置后:http://localhost/statics/2023/09/24/test…...

物联网与 Linux 的相爱相生

Linux 无疑将在物联网中扮演一个关键角色&#xff0c;但是其光彩将与其它的一些分享。 随着 Canonical 重新关注于赢利和新技术&#xff0c;我们中的一些人发现我们正在思考 Linux 未来将走向何方&#xff0c;IoT&#xff08;物联网&#xff09;是否是 Linux 的未来&#xff1…...

python自动化测试(一):操作浏览器

通过Python的代码去操作浏览器的操作 目录 目录 1、导入自动化模块 2、定义打开的浏览器驱动、声明一个url变量保存打开的地址 3、使用函数&#xff1a;driver.get(url)打开浏览器的指定页面 4、最大化浏览器窗口&#xff1a;driver.maximize_window() 5、添加全局的等待…...

NReco.LambdaParser使用案例

使用案例集合&#xff1a; private async void RuleEngine_Click(object sender, EventArgs e){#region 获取变量string expression this.Rule.Text.Trim();string pattern "\$(.*?)\$";MatchCollection matches Regex.Matches(expression, pattern);foreach (Ma…...

苹果IOS安装IPA, plist形式 Safari 浏览器点击安装

快速链接 苹果开发者账号链接 网址: https://developer.apple.com/account 苹果应用上架链接 网址: https://appstoreconnect.apple.com/ 应用证书文件及打包 参考教程: 最新uniapp打包IOS详细步骤&#xff08;2022&#xff09; 证书在线制作工具 网址: https://app.121xuexi.…...

Django 注册及创建订单商品

注册功能的实现 user/views from rest_framework.generics import GenericAPIView from rest_framework.views import APIViewfrom apps.user.models import User from apps.user.serializers import UserSerializer from utils import ResponseMessage from utils.jwt_auth …...

15、Python -- 阶段总结:变量与流程控制

目录 变量变量没有类型&#xff0c;数据有类型 表达式程序流程 变量 变量&#xff1a;编程的本质就是处理数据&#xff0c;数据需要用变量保存 Python语言的特征&#xff1a; 所有变量无需声明&#xff0c;即可使用 变量没有类型 变量没有类型&#xff0c;数据有类型 已学过…...

信息检索与数据挖掘 | 【实验】排名检索模型

文章目录 &#x1f4da;实验内容&#x1f4da;相关概念&#x1f4da;实验步骤&#x1f407;分词预处理&#x1f407;构建倒排索引表&#x1f407;计算query和各个文档的相似度&#x1f407;queries预处理及检索函数&#x1f525;对输入的文本进行词法分析和标准化处理&#x1f…...

玩转AIGC:打造令人印象深刻的AI对话Prompt

玩转AIGC&#xff1a;打造令人印象深刻的AI对话Prompt 《玩转AIGC&#xff1a;打造令人印象深刻的AI对话Prompt》摘要引言正文良好的Prompt&#xff1a;引发AI深度交流的法宝 ✨探讨不同的提问方式1. 常规提问2. 创意提问 对话交流的艺术&#xff1a;倾听与引导的巧妙平衡 ⚖️…...

uniapp vue国际化 i18n

一、安装 vue-i18n npm i vue-i18n 二、新建i18n目录 1、en.json 内容 {"loginPage":{"namePh":"Please enter your login account","passwordPh":"Please enter password"} } 2、zh-CN.json 内容 {"loginPage&qu…...

Docker 启动远程服务访问不了

今天一下午在弄这个 1、防火墙是否关了 firewall-cmd --state2、ip转发开没开 sysctl net.ipv4.ip_forward3、service iptables是不是打开并拦截了 4、检查docker启动的端口号是否一致&#xff0c;或者启动时对不对 5、检查docker的服务是否起来了&#xff0c;比如你的端口号…...

[ACTF2020 新生赛]Exec

【解题过程】 1.打开链接 得到一个能ping 的网站&#xff0c;可以推测这个可以在终端运行的网站。 2.解题思路 在执行的时候我们可以想到命令执行的“&#xff1b;”分号的作用&#xff1a;命令用分号分隔开来&#xff0c;表示它们是两个独立的命令&#xff0c;需要依次执行。…...

Git(三).git 文件夹详解

目录 一、初始化新仓库二、.git 目录2.1 hooks 文件夹2.2 info 文件夹2.3 logs 文件夹2.4 objects 文件夹【重要】2.5 refs 文件夹【重要】2.6 COMMIT_EDITMSG2.7 config2.8 description2.9 FETCH_HEAD2.10 HEAD【重要】2.11 index【重要】2.12 ORIG_HEAD2.13 packed-refs 官网…...

esp32-S3 + visual studio code 开发环境搭建

一、首先在下面链接网页中下载esp-idf v5.1.1离线安装包 &#xff0c;并安装到指定位置。dl.espressif.cn/dl/esp-idf/https://dl.espressif.cn/dl/esp-idf/ 安装过程中会提示需要长路径支持&#xff0c;所以windows系统需要开启长路径使能 Step 1&#xff1a; 打开运行&…...

4.1 网络基础之网络IO

一、编写基本服务程序流程 1、创建套接字 #include <sys/types.h> #include <sys/socket.h>int socket(int domain, int type, int protocol);/* * 参数domain通讯协议族&#xff1a; * PF_INET IPv4互联网协议族&#xff08;常用&#xff09; * PF_INET6 …...

[100天算法】-和为 K 的子数组(day 39)

题目描述 给定一个整数数组和一个整数 k&#xff0c;你需要找到该数组中和为 k 的连续的子数组的个数。示例 1 :输入:nums [1,1,1], k 2 输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。 说明 :数组的长度为 [1, 20,000]。 数组中元素的范围是 [-1000, 1000] &#xff0c;且整…...

Leo赠书活动-02期 【信息科技风险管理:合规管理、技术防控与数字化】

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…...

L2-026 小字辈 - java

L2-026 小字辈 时间限制 400 ms 内存限制 64 MB 题目描述&#xff1a; 本题给定一个庞大家族的家谱&#xff0c;要请你给出最小一辈的名单。 输入格式&#xff1a; 输入在第一行给出家族人口总数 N&#xff08;不超过 100 000 的正整数&#xff09; —— 简单起见&#xff0c…...

排序算法-堆积树排序法(HeapSort)

目录 排序算法-堆积树排序法&#xff08;HeapSort&#xff09; 1、说明 2、算法分析 3、C代码 排序算法-堆积树排序法&#xff08;HeapSort&#xff09; 1、说明 堆积树排序法是选择排序法的改进版&#xff0c;可以减少在选择排序法中的比较次数&#xff0c;进而减少排序…...