【2】图像视频的加载和显示

news2024/11/18 4:34:57

文章目录

  • 【2】图像视频的加载和显示
  • 一、代码在哪写
  • 二、创建和显示窗口
    • (一)导入OpenCV的包`cv2`
    • (二)创建窗口
    • (三)更改窗口大小 & 显示窗口
    • (四)等待用户输入
        • 补充:ord()函数来返回ASCII值
    • (五)销毁窗口
    • (※)完整代码
  • 二、加载显示图片
    • (一)cv2.imread()返回值
    • (二)用matplotlib显示图片
    • (三)用OpenCV显示图片
      • (1)封装函数
      • (2)封装外部.py文件
    • (四)保存图片
  • 三、视频采集和录制
    • (一)视频采集
    • (二)视频录制
  • 四、控制鼠标
  • 五、TrackBar控件

【2】图像视频的加载和显示

一、代码在哪写

注:上一节中已经创建好了虚拟环境。

打开Anaconda Prompt,切换到我们已经创建好的opencv虚拟环境下。

image-20240910205759402

我们使用jupyter notebook来写代码。(输入jupyter notebook

image-20240910205949797

之后,就弹出一个控制台页面。

image-20240910210017744

弹出的这些东西就不太对了。

为什么会弹出这一堆东西,原因在于:你在哪个目录下执行的jupyter notebook命令,它就会以哪个目录作为根目录。

image-20240910210132157

可见,此时这一堆东西都是我的C:\Users\11202目录下的文件,这些文件肯定都是不能动的,我们也不应该以这里作为我们写代码的目录

也就是说,上述是一个错误的演示。

正确的应该怎么做呢?如下。

如果是继续刚才的命令往下写,那么需要按两下ctrl+C把刚才打开的jupyter notebook先退出。

如果是关掉,又新打开的Anaconda Prompt,则不要忘了使用activate opencv先跳转到需要的虚拟环境下

然后我们使用cd命令,打开到我们想要作为根目录的路径(我的是D:\ANACONDA\dirs\test2409),然后再使用命令jupyter notebook

image-20240910212613163

注意:从C盘跳转到D盘时,不要写成cd D:,而是直接输入D:。之后,跳转到D盘后,再使用cd去打开对应文件夹。

这时,再跳转到的控制页面就是我们想要的了。之后我们可以在里面新建一个notebook,就可以写代码了。

image-20240910222157917

image-20240910222233409

二、创建和显示窗口

  • namedWindow() 创建命名窗口
  • imshow() 显示窗口
  • destroyAllwindows() 摧毁窗口
  • resizeWindow() 改变窗口大小
  • waitKey() 等待用户输入

我们依次试一下其效果。

(一)导入OpenCV的包cv2

注意:OpenCV名字虽然叫OpenCV,但是在导包的时候,导入的包叫作cv2。(这是个历史遗留问题,很早的时候它就叫cv,之后进行了重构,于是又叫cv2了,并沿用至今)

image-20240910222645716

运行没有报错,说明正确导入此包。说明我们之前的环境配置、包的安装等操作都是顺利的。

(二)创建窗口

image-20240910223021704

注意:光标放在函数上,按shift+tab可以显示对该函数用法的说明(按一下是简洁版说明,按两下是详细版说明)。这个功能也是使用jupyter notebook所带来的一个好处。

注意:如果发现按shift+tab无效,则首先检查一下是否执行过import cv2代码,因为有时候你刚打开这个文件直接就去shift+tab,发现显示不出说明。实际上是因为没有导入cv2的包,导致它不认识这个函数,自然也就不会给出说明。

这个函数的用法是,括号的内的第一个参数,是窗口名字(注意,应当是一个字符串)。后面的参数是窗口标记(可以从函数用法说明中阅读到具体介绍)。

image-20240910224639146

可见,不同的窗口标记,可以使窗口以不同的风格进行显示;以及如果不注明窗口标记,则会有一个默认值。

注意:如果想要设置flag这一参数,仅仅输入对应标记名是不够的,还要在前面加上cv2.,如cv2.WINDOW_AUTOSIZE。(注意标记名不要写错)

image-20240910225901433

运行后,的确会出现一个窗口,说明代码没问题,但是是未响应状态,这是因为我们写的不是一个规范的写法。

注意:我们把import cv2创建窗口代码写在两个不同的代码框中,此时,务必要保证先运行了import cv2之后,再去运行创建窗口代码,否则会报错(报错原因是找不到cv2这个包)。或者你就把所有代码都写在同一个框里。

(三)更改窗口大小 & 显示窗口

cv2.resizeWindow()的第一个参数为要修改大小的窗口名,后两个参数为窗口大小尺寸

cv2.imshow()的第一个参数为要显示的窗口名,第二个参数为要显示的图片。此处我们没有什么要显示的图片,因此第二个参数设置为0。

此外,需要注意的是,对于我们创建窗口时设置的窗口标记,若设置的是cv2.WINDOW_AUTOSIZE(根据内容自动调节窗口尺寸),那么你修改窗口大小是没有效果的。

注意,注释单行代码的快捷键:ctrl+/

image-20240910231632608

(四)等待用户输入

cv2.waitKey()的作用是,等待接收用户按键,并返回该按键对应的ASCII码值。

其中参数设置为0,表示一直等待、接收任意按键。如果设置其他的整数,表示等待按键的时间(单位是毫秒)。比如设置为cv2.waitKey(5000),就表示它会等你5秒,在5秒之内你按键才有用,过了5秒就不等你了。

image-20240910232204977

注意,此时观察左侧,是In [*],是星号说明这段代码正在运行中,还没有运行结束。

实际上,cv2.waitKey(0)的作用就是等待用户按一个键。当然,焦点要在窗口上时才可以。

我按了一个键盘上的q键,它就会捕捉到并输出一个113113就是q的ASCII码值。(注意是小写q,不是大写Q)

image-20240910232058134

补充:ord()函数来返回ASCII值

image-20240910232736048

(五)销毁窗口

我们可以配合cv2.waitKey(0),先接收到用户按键的ASCII码值,然后就能根据用户按的是什么键,判断是否要销毁窗口了。(常用的比如q键、ESC键)。

image-20240910233703301

按下q键后,窗口直接被销毁(关闭),而不会再有窗口未响应的问题。

但是由于程序只接收一次按键,如果你按的不是q键,它还是会有窗口未响应的问题。

image-20240910233819979

注意,如果对于key == 'q'为什么有问题有疑问,则需要补一补python基础。

(※)完整代码

# ------------------------- 创建和显示窗口 -------------------------

# opencv名字叫opencv,但是导包的时候叫做cv2
import cv2

# 创建窗口
# 注意,cv2.WINDOW_AUTOSIZE则后续修改窗口大小无效
# cv2.namedWindow('myWindow01', cv2.WINDOW_AUTOSIZE)
cv2.namedWindow('myWindow01', cv2.WINDOW_NORMAL)

# 更改窗口大小
cv2.resizeWindow('myWindow01', 800, 600)

# 显示指定名字的窗口
cv2.imshow('myWindow01', 0)

# 等待按键
# 若用户按键为q键,则销毁窗口
key = cv2.waitKey(0)  # 先用变量key接收
# 注意,这样写更易读,而不要写key == 113,即使你知道q是113
# 注意,不要写成key == 'q'
if key == ord('q'):
    print('准备销毁窗口')
    cv2.destroyAllWindows()
    
# ------------------------- 创建和显示窗口 -------------------------

二、加载显示图片

  • imread(path, flag)

使用imread可以读取图片,默认读取的是彩色图片。

path是图片的路径(绝对路径、相对路径都可以)。

flag是以什么方式读取这个图片(比如读出来是黑白的)。

(一)cv2.imread()返回值

# 导入opencv包
import cv2

# 读取图片
cat = cv2.imread('./1.png')

# numpy的ndarray(多维数组)
cat

输出如下:

array([[[  1,  12,  90],
        [  2,  12,  91],
        [  1,  13,  91],
        ...,
        [  3,  10,  61],
        [  4,   9,  61],
        [  4,   9,  65]],

       [[  3,  13,  91],
        [  3,  13,  92],
        [  2,  14,  92],
        ...,
        [  2,  11,  60],
        [  2,  10,  60],
        [  2,   9,  63]],

       [[  2,  12,  91],
        [  2,  13,  91],
        [  2,  14,  92],
        ...,
        [  3,  10,  60],
        [  3,  10,  60],
        [  3,  10,  62]],

       ...,

       [[  4,  31, 111],
        [  4,  32, 112],
        [  4,  31, 113],
        ...,
        [119, 190, 208],
        [119, 190, 208],
        [119, 190, 208]],

       [[  5,  31, 111],
        [  5,  31, 111],
        [  5,  31, 112],
        ...,
        [119, 190, 208],
        [119, 190, 208],
        [119, 190, 208]],

       [[  6,  32, 111],
        [  6,  31, 111],
        [  6,  31, 111],
        ...,
        [118, 189, 207],
        [119, 190, 208],
        [119, 190, 208]]], dtype=uint8)

(二)用matplotlib显示图片

import matplotlib.pyplot as plt

plt.imshow(cat)

我的原图是:

image-20240911104705365

输出结果如下:

image-20240911104637344

发现这个猫的样子没变,但是颜色不太对。这是因为OpenCV读取的图片颜色通道是按照BGR(蓝绿红)排列的,一般的图片通道都是按照RGB来排列的。

为了正常显示图片,我们要使用OpenCV的图像显示方法。换句话说,用OpenCV读进来的图片一般不要用别的方式进行展示,比如matplotlib。

(三)用OpenCV显示图片

cv2.imshow('cat', cat)

# 按键以销毁窗口,避免每次都有窗口未响应的问题
key = cv2.waitKey(0)
if key == ord('q'):
    print('准备销毁窗口')
    cv2.destroyAllWindows()

这样就会弹出一个窗口,并正常显示该图片,我们可以按下q键以正常关闭窗口。

(1)封装函数

此外,我们可以把显示图片的方法封装成一个函数,方便我们显示图片:

# 把展示图片的代码封装成函数
def cv_show(name, img):
    cv2.imshow(name, img)
    key = cv2.waitKey(0)
    if key == ord('q'):
        cv2.destroyAllWindows()

之后想显示图片的时候,直接调用函数即可:

# 导入opencv包
import cv2

# 读取图片
cat = cv2.imread('./1.png')

cv_show('cat', cat)

(2)封装外部.py文件

我们可以在当前目录下创建一个.py文件,把封装的函数代码放进去。

image-20240911110226843

image-20240911110256307

注意,如果这样放代码,那么在调用的时候会报错。因为,在utils.py这个文件中,我们调用了cv2,但是并没有导入cv2,就会报错。

image-20240911111714180

需要在函数中调用cv2之前,先import cv2

image-20240911110636568

这样就可以正常运行了。

image-20240911111813648

注意:如果还是有问题,可以使用%run utils.py执行一下外部文件(这是在jupyter中执行外部文件的方法),看看外部文件本身是否运行不了。如果在执行外部文件时报错IndentationError: unindent does not match any outer indentation level,则是代码缩进问题,一般是tab和空格混用导致的缩进问题,这个问题仅凭肉眼是不容易看出来的(新手容易踩的坑)。(如果使用的是notepad++,可以通过View--Show Symbol--Show All Characters来检查这一问题)

image-20240911112039540

(四)保存图片

  • imwrite(path, img):使用imwrite保存图片。
import cv2

cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.resizeWindow('img', 320, 240)

img = cv2.imread('./1.png')

# 利用while循环优化退出逻辑
while True:
    cv2.imshow('img', img)
    key = cv2.waitKey(0)
    if(key & 0xFF == ord('q')):
        break
    elif(key & 0xFF == ord('s')):
        cv2.imwrite('./123.png', img)
    else:
        print(key)
        
cv2.destroyAllWindows()

三、视频采集和录制

(一)视频采集

  • 视频是由图片组成的,视频的每一帧就是一幅图片,一般是30帧,表示一秒显示30张图片。
  • cv2.VideoCapture可以捕获摄像头,用数字来表示不同的设备,比如0、1。
  • 如果是视频文件,可以直接指定路径即可。
# 打开视频文件
vc = cv2.VideoCapture('./1.mp4')

# 打开摄像头
vc = cv2.VideoCapture(0)

打开摄像头

  示例:

# 打开摄像头
import cv2

cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)

# 如果打开失败(比如没有摄像头),不会报错
# cap = cv2.VideoCapture(1) # 我只有摄像头0,没有摄像头1
cap = cv2.VideoCapture(0)

# 循环读取摄像头的每一帧
# while True:
while cap.isOpened():
    # 读一帧数据,返回标记和这一帧数据,标记为True表示读到了数据,False表示没读到数据
    ret, frame = cap.read()
    
    # 可以根据ret做个判断
    if not ret:
        # 没读到数据,直接退出
        break
        
    # 显示数据
    cv2.imshow('video', frame)
    
    key = cv2.waitKey(1)
    # 注意,此处就不要再写0了,因为写0表示无限等待,也就是显示一帧数据然后一直等待用户按键
    # 写个1,表示等1毫秒,若等不到按键就继续处理了
    
    if key == ord('q'):
        break
        
# 别忘了释放资源
cap.release()
cv2.destroyAllWindows()

打开视频文件

  示例:

# 打开摄像头
import cv2

cv2.namedWindow('video', cv2.WINDOW_NORMAL)
cv2.resizeWindow('video', 640, 480)

# 打开视频,传入视频路径即可
cap = cv2.VideoCapture('./1.mp4')

# 循环读取摄像头的每一帧
# while True:
while cap.isOpened():
    # 读一帧数据,返回标记和这一帧数据,标记为True表示读到了数据,False表示没读到数据
    ret, frame = cap.read()
    
    # 可以根据ret做个判断
    if not ret:
        # 没读到数据,直接退出
        break
        
    # 显示数据
    cv2.imshow('video', frame)
    
    key = cv2.waitKey(1)
    # 注意,此处就不要再写0了,因为写0表示无限等待,也就是显示一帧数据然后一直等待用户按键
    # 写个1,表示等1毫秒,若等不到按键就继续处理了
    
    # key = cv2.waitKey(1000 // 30)  # 让视频以30帧播放
    
    if key == ord('q'):
        break
        
# 别忘了释放资源
cap.release()
cv2.destroyAllWindows()

  注意,上述代码,和刚才“打开摄像头”的代码只有一行不同,即第8行的cap = cv2.VideoCapture('./1.mp4'),其他地方都相同。

  运行此代码时,发现其播放的视频好像加速了一样,这是因为,第24行代码的key = cv2.waitKey(1)造成的效果是每等待1毫秒显示一帧数据,所以播放的比较快。

  假如我们想让视频是30帧,那么每张图片要间隔多少毫秒?

  答:理论上来说,是1000 / 30ms,但此处传递的参数必须是整数,所以我们代码写成1000 // 30。(Python语法,//表示向下取整)

  另外,我们此处处理的是视频中每一帧的图片,所以没有声音。

(二)视频录制

  • VideoWriter:参数1为输出文件,参数2为多媒体文件格式(VideoWriter_fourcc),参数3为帧率,参数4为分辨率;
  • write编码并写入缓存;
  • release缓存内容写入磁盘,并释放资源。
import cv2

cap = cv2.VideoCapture(0)

# *mp4v 就是解包操作,等同于 'm','p','4','v'
# fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# avi格式的视频
fourcc = cv2.VideoWriter_fourcc(*'XVID')

# (640, 480)表示摄像头拍视频的分辨率,这个大小搞错了也不行
# vw = cv2.VideoWriter('output.mp4', fourcc, 20, (640, 480))

# 如果前面写的是avi,这里要改成avi格式
vw = cv2.VideoWriter('output.avi', fourcc, 20, (640, 480))

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        print('can not receive frame, Exiting...')
        break
        
    vw.write(frame)
    cv2.imshow('frame', frame)
    
    if cv2.waitKey(1) == ord('q'):
        break
        
cap.release()

vw.release()

cv2.destroyAllWindows()

四、控制鼠标

  OpenCV允许我们对窗口上的鼠标动作做出响应。

  • setMouseCallback(winname, callback, userdata):winname是窗口名字,callback是回调函数,userdata是给回调函数的参数。
  • callback(event, x, y, flags, userdata):回调函数必须包含这5个参数。event是事件(鼠标移动、左键、右键),xy是点鼠标的坐标点,flags主要用于组合键,userdata就是上面的setMouseCallback的userdata。
鼠标事件:
EVENT_MOUSEMOVE 0 鼠标移动
EVENT_LBUTTONDOWN 1 按下鼠标左键
EVENT_RBUTTONDOWN 2 按下鼠标右键
EVENT_MBUTTONDOWN 3 按下鼠标中键
EVENT_LBUTTONUP 4 左键释放
EVENT_RBUTTONUP 5 右键释放
EVENT_MBUTTONUP 6 中键释放
EVENT_LBUTTONDBLCLK 7 左键双击
EVENT_RBUTTONDBLCLK 8 右键双击
EVENT_MBUTTONDBLCLK 9 中键双击
EVENT_MOUSEWHEEL 10 鼠标滚轮上下滚动
EVENT_MOUSEHWHEEL 11 鼠标左右滚动

flags:
EVENT_FLAG_LBUTTON 1 按下左键
EVENT_FLAG_RBUTTON 2 按下右键
EVENT_FLAG_MBUTTON 4 按下中键
EVENT_FLAG_CTRLKEY 8 按下ctrl键
EVENT_FLAG_SHIFTKEY 16 按下shift键
EVENT_FLAG_ALTKEY 32 按下alt键

  示例:

import cv2
import numpy as np

# 函数名可以随便取,但是参数必须是5个(参数名也可以随便取)
# event表示鼠标事件
# x, y是发生鼠标事件的坐标
# flags是鼠标的组合操作
def mouse_callback(event, x, y, flags, userdata):
    print(event, x, y, flags, userdata)
    # 按下鼠标右键退出
    if event == 2:
        cv2.destroyAllWindows()
    
# 创建窗口
cv2.namedWindow('mouse', cv2.WINDOW_NORMAL)
cv2.resizeWindow('mouse', 640, 360)

# 设置鼠标的回调函数
cv2.setMouseCallback('mouse', mouse_callback, '123')

# 生成全黑的图片
img = np.zeros((360, 640, 3), np.uint8)

while True:
    cv2.imshow('mouse', img)
    key = cv2.waitKey(1)
    if key == ord('q'):
        break
        
cv2.destroyAllWindows()

五、TrackBar控件

image-20240926102921673

  • createTrackbar(trackbarname, winname, value, count, onChange):创建TrackBar控件,value为trackbar的默认值,count为bar的最大值,最小为0。
  • getTrackbarPos(trackbarname, winname):获取TrackBar当前值。

  示例:

import cv2
import numpy as np

# 创建窗口
cv2.namedWindow('trackbar', cv2.WINDOW_NORMAL)
cv2.resizeWindow('trackbar', 640, 480)

# 定义回调函数
def callback(value):
    print(value)
    
# 创建trackbar
cv2.createTrackbar('R', 'trackbar', 0, 255, callback)
cv2.createTrackbar('G', 'trackbar', 0, 255, callback)
cv2.createTrackbar('B', 'trackbar', 0, 255, callback)

# 创建一个背景图片
img = np.zeros((480, 640, 3), np.uint8)

while True:
    # 获取当前trackbar的值
    r = cv2.getTrackbarPos('R', 'trackbar')
    g = cv2.getTrackbarPos('G', 'trackbar')
    b = cv2.getTrackbarPos('B', 'trackbar')
    
    # 改变背景图颜色
    img[:] = [b, g, r]
    cv2.imshow('trackbar', img)
    
    key = cv2.waitKey(1)
    if key & 0xFF == ord('q'):
        break
        
cv2.destroyAllWindows()

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

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

相关文章

24最新ComfyUI搭建使用教程

前言 ComfyUI 是一个基于节点流程式的stable diffusion AI 绘图工具WebUI, 通过将stable diffusion的流程拆分成节点,实现了更加精准的工作流定制和完善的可复现性。 ComfyUI因为内部生成流程做了优化,生成图片时的速度相较于WebUI有10%~25…

关于字节 c++

字节的介绍 字节是计算机中最小的存储单位,通常由8个二进制位组成,用来存储一个字符。在C中,字节也是基本数据类型之一,用关键字"byte"来表示。字节主要用于存储一些较小的数据,如整数、字符等。字节的大小…

音频转MP3格式困难?如何轻松实现wav转mp3?

格式多样化为我们带来了灵活性和创意的无限可能,但同时,不同格式间的转换也成为了不少用户面临的难题。尤其是当你手握珍贵的WAV音频文件,却希望它们能在更多设备上流畅播放或节省存储空间时,wav转mp3的需求便应运而生。WAV以其无…

网络安全中的 EDR 是什么:概述和功能

专业知识:EDR、XDR、NDR 和 MDR_xdr edr ndr-CSDN博客 端点检测和响应 (EDR) 是一种先进的安全系统,用于检测、调查和解决端点上的网络攻击。它可以检查事件、检查行为并将系统恢复到攻击前的状态。EDR 使用人工智能、机器学习和威胁情报来避免再次发生攻…

c语言实现:链表创建、插入、删除、翻转

#include <stdio.h> #include <stdlib.h>// 链表创建 typedef struct Node{int data;struct Node* next; } Node;// 创建一个节点 Node* createNode(int data){Node* newNode (Node* )malloc(sizeof(Node));newNode->data data;newNode->next NULL;return…

35岁java转大模型笔记,大模型智能体(LLM Agent)学习笔记

\1. 什么是大模型&#xff1f; 大模型对应的英文是Large Language Model&#xff08;LLM&#xff09;&#xff0c;即大语言模型&#xff0c;简称大模型。技术层面讲&#xff0c;大模型是一种基于深度学习技术的机器学习模型。 为什么叫大模型呢&#xff1f;它是相对于小模型而…

万界星空科技铜拉丝行业MES系统,实现智能化转型

一、铜拉丝行业生产管理的难点主要体现在以下几个方面&#xff1a; 1、标准严格&#xff1a;铜线产品对质量的要求极高&#xff0c;特别是在电气性能、导电性、耐腐蚀性等方面&#xff0c;任何微小的瑕疵都可能影响产品的使用效果和安全性。 2、过程监控&#xff1a;生产过程…

点赞10万+,1分钟教会你,用AI生成的宠物带娃视频

今天刷到了这样的宠物带娃视频&#xff0c;最近这种视频爆火&#xff0c;出现了很多爆款&#xff0c;今天就拆解一下&#xff0c;教大家学会这种视频用AI如何生成。 我们先看一下这类视频的数据&#xff0c;很多账号都在做&#xff0c;对于不了解AI的人来说&#xff0c;会觉得…

轻松构建便民平台小程序源码系统 带完整的安装代码包以及搭建部署教程

系统概述 轻松构建便民平台小程序源码系统是一款集成了多项实用功能的模块化小程序开发框架。它基于当前最流行的小程序开发技术栈&#xff0c;如微信小程序、支付宝小程序等&#xff0c;通过预制的组件和模块&#xff0c;极大地简化了开发流程&#xff0c;降低了技术门槛。无…

Google BigTable架构详解

文章目录 什么是BigTable?架构图一、整体架构二、数据存储与索引存储模型 三、数据拆分与存储四、元数据管理五、读写流程 其他内容概览负载平衡其他存储和数据库选项 什么是BigTable? Bigtable是Google开发的一个高性能、可扩展的分布式存储系统&#xff0c;用于管理大规模…

Error running Application.Command line is too long

问题解析 本质上就是执行启动类Application的时候&#xff0c;执行的指令太长了&#xff0c;所以运行失败。 解决方案 1.打开Edit Configuration。 2.点击Modify options 3.勾选 Shorten command line 4.选择classpath file。 最终解决问题。

深入理解包管理工具

目录 引入npm配置文件常见属性版本理解package-lock.jsonnpm install其他命令发布自己的包 yarncnpmnpxpnpm安装和使用硬链接和软链接非扁平node\_modules存储store 引入 随着前端技术的发展&#xff0c;项目依赖的第三方库和工具越来越多&#xff08;例如&#xff1a;React、V…

信用卡验证-卢恩算法

卢恩算法 什么是 Luhn 算法&#xff1f; Luhn算法&#xff0c;也称为“模10算法”&#xff0c;是一种用于确定用户提供的标识号是否准确的公式。它广泛应用于验证信用卡号码以及其他数字序列&#xff0c;例如政府的社会安全号码 (SSN)。如今&#xff0c;Luhn算法是电子支付系…

详细分析SpringMvc中HandlerInterceptor拦截器的基本知识(附Demo)

目录 前言1. 基本知识2. Demo3. 实战解析 前言 对于Java的基本知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09; 1. 基本知识 HandlerInter…

OJ在线评测系统 前端创建题目(增) 更新题目(改) 题目列表(查) 以及做题页面的开发 基于VUECLI脚手架画界面

目录 前端创建页面的开发一 创建一个路由 用acro design写 前端创建页面的开发二 题目管理页面 搜索 最終效果 题目更新页面的开发 携带参数的那种 修改路由 页码更新细节 我们先处理菜单项的权限控制和权限隐藏 在这里改 属性绑定一个函数 可以参考聚合搜索项目…

金属增材制造咋突破?纳米纹理粉末如何助力金属增材制造?

大家好&#xff0c;今天我们来了解一篇金属增材制造文章——《High absorptivity nanotextured powders for additive manufacturing》发表于《Science Advances》。金属增材制造在医疗、航空航天等领域&#xff0c;它潜力巨大&#xff0c;但目前可打印的金属材料有限&#xff…

word中的表格全部设置宽度100%

1、背景 我们用工具将数据库或其他的数据导出成word时&#xff0c;表格有的会大于100%&#xff0c;超过了边界。word没有提供全局修改的方法。如果我们想改成100%。 一种方式是通过宏&#xff0c;全局改。一种是手动改。 2、宏修改 如果表格多&#xff0c;可以通过这种方式。…

文献阅读——基于拉格朗日乘子的电力系统安全域边界通用搜索方法

摘要 为提升电力系统安全域(security region&#xff0c;SR)的构建效 率&#xff0c;提出一种基于拉格朗日乘子(Lagrange multiplier&#xff0c;LM) 的电力系统安全域边界(security region boundary&#xff0c;SRB)通用搜索方法。 首先&#xff0c;根据电力系统静态安全性问…

15.面试算法-树基础

1. 树基础 树在工程中有非常广泛的应用&#xff0c;在算法中也是一个极为庞大的体系&#xff0c;我们前面链表的文章中说过“没学会反转&#xff0c;链表相当于白学”&#xff0c;现在再加一句“没学会树的问题&#xff0c;算法相当于没学”。 本文我们将系统地学习相关问题。…