Python图像处理【1】图像与视频处理

news2024/12/29 9:46:39

图像与视频处理

    • 0. 前言
    • 1. 在 3D 空间中显示 RGB 图像颜色通道
      • 1.1 图像表示
      • 1.2 在 3D 空间中绘制颜色通道
    • 2. 使用 scikit-video 读/写视频文件
      • 2.1 scikit-video 库
      • 2.2 读/写视频文件
      • 2.3 提取视频文件属性
      • 2.4 读取并保存视频
    • 3. 使用 OpenCV 从相机捕获实时视频
    • 4. 实现 Gotham 图像滤镜
      • 4.1 Gotham 图像滤镜
      • 4.2 一维线性插值
      • 4.3 图像插值
    • 小结
    • 系列链接

0. 前言

图像处理是指在计算机上使用算法和代码对图像进行自动处理、操作和分析,而视频处理是图像处理的一种特殊情况(视频文件或视频流有连续的图像序列构成)。图像和视频处理在许多领域都有应用广泛的应用,如电视、摄影、机器人、遥感、医学诊断和工业检查等。
在本节中,我们将聚焦一些简单的图像和视频处理问题,用于帮助我们理解图像和视频的基本概念。在我们开始分析图像/视频之前,我们需要使用合适的数据结构将图像加载到内存中,并且能够将处理后的图像/视频保存到文件中;能够在计算机屏幕上实时可视化(绘制)图像能够帮助我们立即观察到图像处理算法对图像的处理结果。

1. 在 3D 空间中显示 RGB 图像颜色通道

1.1 图像表示

图像可以抽象为一个函数,并将其可视化,以进行进一步的分析/处理。灰度图像可以认为是像素位置的二元函数 f ( x , y ) f(x, y) f(x,y) f ( x , y ) f(x, y) f(x,y) 将每个像素映射到其相应灰度强度级别( [0, 255] 中的整数或 [0, 1] 中的浮点数),即:
f : ( x , y ) → R f:(x,y)→ R f:(x,y)R
对于 RGB 图像,有三个这样的函数,可以表示为:
f : ( x , y ) → R f : ( x , y ) → G f : ( x , y ) → B f:(x,y)→ R \\ f:(x,y)→ G \\ f:(x,y)→ B f:(x,y)Rf:(x,y)Gf:(x,y)B
其分别对应于每个通道及其色值,我们可以使用 matplotlib 库的三维绘图函数绘制以上函数,使用 Python 代码在 3D 空间中单独绘制每个 RGB 通道。

1.2 在 3D 空间中绘制颜色通道

(1) 首先,导入所有必需的包。为了读取图像,我们需要 scikit-image 库的 io 模块中的 imread() 函数;由于我们将图像加载为 array 类型,因此需要 Numpy 操作数据类型 array;为了显示图像,我们将使用 matplotlib.pyplot 函数;对于 3D 图像的显示,我们需要使用 mpl_toolkit 库的 mplt3d 模块以及 matplotlib 库中的其他模块:

from skimage.io import imread
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

(2) 使用 plot_surface() 函数绘制通道的像素值,这是绘制 3D 图像的关键函数:

Axes3D.plot_surface(X, Y, Z, *args, **kwargs)

接下来,我们实现 plot_3d() 的函数,在以下代码中,X 轴和 Y 轴分别用于显示水平轴和垂直轴,Z 轴用于显示图像的深度。需要注意的是,xyz 的尺寸必须相同,cmap 用于显示不同像素值的颜色映射:

def plot_3d(x, y, z, cmap='Reds', title=''):
    fig = plt.figure(figsize=(15,15))
    ax = fig.gca(projection='3d')
    # 曲面绘制
    surf = ax.plot_surface(x, y, z, cmap=cmap, linewidth=0, antialiased=False, rstride=2, cstride=2, alpha=0.5)
    ax.xaxis.set_major_locator(LinearLocator(10))
    ax.xaxis.set_major_formatter(FormatStrFormatter('%.02f'))
    ax.view_init(elev=10., azim=5)
    ax.set_title(title, size=20)
    plt.show()

(3) 从磁盘读取 RGB 图像,并使用 scikit-imageio 模块的 imread() 函数将其加载到内存中:

skimage.io.imread(fname, as_gray=False, plugin=None, flatten=None, **plugin_args)

使用 imread() 函数从文件加载图像:

im = imread('1.png')

(4) 然后,使用 Numpy 库的 arange()meshbrid() 函数创建像素坐标 ( x , y ) (x, y) (x,y) 的二维网格:

y = np.arange(im.shape[0])
x = np.arange(im.shape[1])
x, y = np.meshgrid(x, y)

(5) 最后,将图像的红色、绿色和蓝色通道分别分配给相应变量,这些通道使用 plot_3D() 函数以 3D 方式显示:

z1 = im[...,0]
z2 = im[...,1]
z3 = im[...,2]

(6)3D 空间中可视化图像,使用 plot_3d() 函数可视化 RGB 图像的颜色通道。使用 Z 轴作为深度轴,并从图像的高度中减去 y 轴值,以便将坐标原点从左上角移动到左侧中心点处。使用函数 plot_3d() 可视化红色通道:

plot_3d(z1, x, im.shape[1]-y, cmap='Reds', title='3D plot for the Red Channel')

红色通道的 3D 绘图结果如下所示:

红色通道

最后,再次使用函数 plot_3d() 分别可视化输入图像的绿色通道和蓝色通道:

plot_3d(z2, x, im.shape[1]-y, cmap='Greens', title='3D plot for the Green Channel')
plot_3d(z3, x, im.shape[1]-y, cmap='Blues', title='3D plot for the Blue Channel')

绿色通道蓝色通道

从以上绘图结果可以看出,每个通道中的颜色深度和 3D 绘图结果在视觉上与原始 2D 图像类似。

2. 使用 scikit-video 读/写视频文件

2.1 scikit-video 库

在本节中,我们将学习如何使用 scikit-video 库函数从磁盘加载视频,该库使用 FFmpeg 软件执行视频 I/O,因此首先需要安装 FFmpeg 后再安装 scikit-video 模块:

pip3 install scikit-video

2.2 读/写视频文件

首先导入所有必需的包:

import skvideo.io
import numpy as np
import matplotlib.pyplot as plt

接下来,使用 FFmpegReader() 函数从磁盘读取视频文件,并随机显示视频中的一些图像帧。函数 FFmpegReader() 的用法如下:

skvideo.io.FFmpegReader(*args, **kwargs)

使用 FFmpeg 读取视频帧:

inputparameters = {}
outputparameters = {}
reader = skvideo.io.FFmpegReader('example.mp4',
                inputdict=inputparameters,
                outputdict=outputparameters)

2.3 提取视频文件属性

使用 getShape() 方法以及 FFmpegReader() 函数返回的对象获取视频的帧数、高度、宽度和通道数等属性:

# 读取视频文件属性
num_frames, height, width, num_channels = reader.getShape()
print(num_frames, height, width, num_channels)

2.4 读取并保存视频

使用 nextFrame() 方法从视频中读取帧。通过使用 NumPyrandom.choice() 函数随机选择四个帧,并显示这些帧:

plt.figure(figsize=(20,10))

frame_list = np.random.choice(num_frames, 4)
i, j = 0, 1
for frame in reader.nextFrame():
    if i in frame_list:
        plt.subplot(2,2,j)
        plt.imshow(frame)
        plt.title("Frame {}".format(i), size=20)
        plt.axis('off')
        j += 1
    i += 1
plt.show()

视频读取
二值图像是只有两个不同灰度值(黑色和白色)的图像,二值图像处理通常是图像处理应用程序的主要过程之一,例如,形态学图像处理算法通常需要输入二值图像开始。要计算二值图像,最简单的方法是使用阈值算法,高于阈值的像素变为白色,低于阈值的像素均变为黑色。
filters 模块中的 threshold_otsu() 函数能够对视频中的帧进行阈值处理,threshold_otsu() 函数能够将灰度图像转换为二值图像(在之后的学习中,我们会对其进行详细介绍)。
对每个颜色通道应用阈值以从图像帧中获得二值图像帧。使用 FFmpegWriter() 函数保存二值化视频,方法是按读取视频帧顺序依次叠加二值图像帧:

from skimage.color import rgb2gray
from skimage.filters import threshold_otsu

writer = skvideo.io.FFmpegWriter("r2_binary.mp4", outputdict={})
for frame in skvideo.io.vreader("r3.mp4"):
    frame = rgb2gray(frame)
    thresh = threshold_otsu(frame)
    binary = np.zeros((frame.shape[0], frame.shape[1], 3), dtype=np.uint8)
    binary[...,0] = binary[...,1] = binary[...,2] = 255*(frame > thresh).astype(np.uint8)
    writer.writeFrame(binary)
writer.close()

最后,读取刚刚保存的二进制视频,然后显示一些随机帧:

plt.figure(figsize=(20,10))

reader = skvideo.io.FFmpegReader("example_binary.mp4")
num_frames, height, width, num_channels = reader.getShape()
frame_list = np.random.choice(num_frames, 4)
i, j = 0, 1
for frame in reader.nextFrame():
    if i in frame_list:
        plt.subplot(2,2,j)
        plt.imshow(frame)
        plt.title("Frame {}".format(i), size=20)
        plt.axis('off')
        j += 1
    i += 1
plt.show()

二值图像

3. 使用 OpenCV 从相机捕获实时视频

在本节中,我们将学习如何使用 OpenCV 库捕获视频并提取图像帧,同时我们将捕获摄像机(例如,笔记本电脑的内置网络摄像头或 USB 摄像头)录制的实时视频流。

(1) 首先导入所需的库:

import cv2
import matplotlib.pyplot as plt

(2) 要使用 OpenCV 捕获视频,我们需要创建一个 VideoCapture 对象,它的参数可以是设备索引(实时视频)或视频文件的名称(本地文件):

vc = cv2.VideoCapture(0)
plt.ion()
if vc.isOpened(): # 读取第一帧
    is_capturing, frame = vc.read()    
    webcam_preview = plt.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))    
else:
    is_capturing = False

设备索引是指定摄像机的整数数字,通常,如果只有一台相机连接到计算机,只需传递 0 作为参数即可,如果有两台相机,则可以通过传递 1 来选择第二台相机,依次类推。
我们可以使用 isOpened() 方法检查 VideoCapture 对象是否正确初始化,如果正确初始化则返回 true。如果返回 true,那么我们可以使用函数 read() 读取第一帧以及所有后续帧。
read() 函数是从设备捕获数据的最方便的方法,它返回捕获的视频帧。如果没有捕获到任何帧(摄像机已断开连接,或者视频文件中没有更多帧),则该方法返回 false;使用布尔变量 is_capturing 确定是否可以捕获帧。

(3) 一旦第一帧被正确读取,我们就可以在 while 循环中逐帧捕获,直到视频的最后一帧。最后,一定要调用 VideoCapture 对象上的 release() 函数来释放设备。以下代码演示了如何捕获实时视频流的前十帧。需要注意的是,OpenCV 使用 BGR 颜色格式,要显示具有真实 RGB 颜色的视频帧,必须使用转换函数 cv2.cvtColor(frame, cv2.color_BGR2RGB)

frame_index = 1
while is_capturing:
    if frame_index > 10: break

    is_capturing, frame = vc.read()
    image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    webcam_preview.set_data(image)
    plt.title('Frame {0:d} '.format(frame_index))
    plt.draw()
    frame_index += 1
    try:    # 避免由 plt.pause 引起的 NotImplementedError
        plt.pause(2)
    except Exception:
        Pass
vc.release()

如果连接到计算机的相机设备可以正常工作,那么运行以上代码时,就可以看到相机捕获到的实时图像。此外, cv2.VideoCapture() 函数也可用于从磁盘读取视频文件,相对应的,可以使用 cv2.VideoWriter() 函数可将视频文件保存到本地磁盘文件中。

4. 实现 Gotham 图像滤镜

4.1 Gotham 图像滤镜

在本节中,我们将学习如何实现 Gotham 图像滤镜用于增强图像效果,用于加强理解如何操作图像像素并执行插值操作。下图显示了我们将用于实现图像滤镜的输入图像:

示例图像

首先,导入所需的库。在本节中,我们将使用 PIL 库实现图像处理函数:

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

im = Image.open('images/Img_01_03.jpg')
print(np.max(im))

创建 Gotham 滤波器需要在输入图像上应用中间色调(红色)对比度增强,这需要通过使用 Numpy 库的 interp() 函数完成的,利用 该函数实现通道插值。接下来,我们首先了解 NumPy 插值在一维情况空间中的工作原理。

4.2 一维线性插值

当图像按缩放因子调整大小时,需要执行一些像素插值,以便在现有像素之间填充新像素值,我们可以使用 NumPy interp() 函数执行插值操作。从 NumPy 文档中可以看到,interp() 函数的一维线性插值基本用法如下:

numpy.interp(x, left=None, right=None, period=None)

interp() 会返回具有给定离散数据点的函数的一维分段线性插值:

x_p = np.linspace(0, 2*np.pi, 10) # 在间隔[0,2π]中生成10个均匀间隔的数字序列
y_p = np.cos(x_p)
x = np.linspace(0, 2*np.pi, 50) # 在间隔[0,2π]中生成50个均匀间隔的数字序列
y = np.cos(x)
y_interp = np.interp(x, x_p, y_p)

plt.figure(figsize=(20,10))
plt.plot(x_p, y_p, 'o', label='reference points')
plt.plot(x, y_interp, '-x', label='interpolated')
plt.plot(x, y, '--', label='true')
plt.legend(prop={'size': 16})
plt.show()

假设我们希望(线性)插值区间 [ 0 , 2 π ] [0, 2π] [0,2π] 中余弦函数的值,最初区间中仅包含十个参考点。我们可以使用 interp() 函数计算剩余点处函数的值,从给定点处函数值开始,然后应用线性插值。橙色曲线表示由 interp() 函数估计的曲线,绿色曲线显示真实的余弦曲线:

一维线性插值

4.3 图像插值

可以以类似的方式扩展以上代码,使用 interp() 函数计算 R (红色)通道的通道内插值结果,由于图像的红色通道值本质上是一个 2D 阵列(矩阵),因此在将该函数应用于通道之前,需要执行以下操作:

  • 2D 阵列展平为 1D 阵列(使用 NumPyravel() 函数)
  • 使用 interp() 函数应用通道插值
  • 1D 阵列重新整形为图像矩阵(使用 NumPy 的整形函数)

(1) 使用 np.interp() 函数,用 11 个参考点拉伸红色通道直方图:

r, g, b = im.split() # 分割图像通道为R、G和B
r_old = np.linspace(0,255,11)   # 参考点
r_new = [0., 12.75, 25.5, 51., 76.5, 127.5, 178.5, 204., 229.5, 242.25, 255.] # 参考点的新值

r1 = Image.fromarray((np.reshape(np.interp(np.array(r).ravel(), r_old, r_new),
                                 (im.height, im.width))).astype(np.uint8), mode='L')

(2) 然后,绘制图像和红色通道直方图:

plt.figure(figsize=(20,15))
plt.subplot(221)
plt.imshow(im)
plt.title('original', size=20)
plt.axis('off')
plt.subplot(222)
im1 = Image.merge('RGB', (r1, g, b))
plt.imshow(im1)
plt.axis('off')
plt.title('with red channel interpolation', size=20)
plt.subplot(223)
plt.hist(np.array(r).ravel())
plt.subplot(224)
plt.hist(np.array(r1).ravel())
plt.show()

下图显示了插值变换前后的图像:

插值变换前后的图像

(3) 通过使用以下代码,令黑色更接近蓝色值,我们将蓝色值增加了 7.65,并且使用函数 np.clip() 来确保新值保持在 0255 区间内:

plt.figure(figsize=(20,10))
plt.subplot(121)
plt.imshow(im1)
plt.title('last image', size=20)
plt.axis('off')
b1 = Image.fromarray(np.clip(np.array(b) + 7.65, 0, 255).astype(np.uint8))
im1 = Image.merge('RGB', (r1, g, b1))
plt.subplot(122)
plt.imshow(im1)
plt.axis('off')
plt.title('with transformation', size=20)
plt.tight_layout()
plt.show()

添加蓝色值
其中,matplotlib 库的 subplot 模块用于显示子图,向当前图像中添加子图:

subplot(nrows, ncols, index, **kwargs)

如上图所示,使用 plt.subplot(121) 创建具有一行和两列子图的图像,并使用索引参数 index 指定绘图位置。

(4) 通过使用 PIL 库的 ImageEnhance 类中的 Enhance() 方法对图像执行较小的锐化:

class PIL.ImageEnhance.Sharpness(image)

ImageEnhance 类可用于调整图像的清晰度,

from PIL.ImageEnhance import Sharpness

plt.figure(figsize=(20,10))
plt.subplot(121)
plt.imshow(im1)
plt.title('last image', size=20)
plt.axis('off')
im2 = Sharpness(im1).enhance(3.0)
plt.subplot(122)
plt.imshow(im2)
plt.axis('off')
plt.title('with transformation', size=20)
plt.tight_layout()
plt.show()

图像锐化

(5) 减少蓝色通道的色调值,我们同样使用通道插值完成,但这次需要在 RGB 图像的蓝色通道上进行:

blue_old = np.linspace(0,255,17) # 参考点的像素值
blue_new = [0., 11.985, 30.09, 64.005, 81.09, 99.96, 107.1, 111.945, 121.125, 143.055, 147.9, 159.885, 171.105,
               186.915, 215.985, 235.875, 255.] # 参考点的新像素值

b2 = Image.fromarray((np.reshape(np.interp(np.array(b1).ravel(), blue_old, blue_new),
                                 (im.height, im.width))).astype(np.uint8), mode='L')

绘制图像以及蓝色通道直方图如下:

plt.figure(figsize=(20,15))
plt.subplot(221)
plt.imshow(im2)
plt.title('last image', size=20)
plt.axis('off')
plt.subplot(222)
im3 = Image.merge('RGB', (r1, g, b2))
plt.imshow(im3)
plt.axis('off')
plt.title('with blue channel interpolation', size=20)
plt.subplot(223)
plt.hist(np.array(b1).ravel(), normed=True)
plt.subplot(224)
plt.hist(np.array(b2).ravel(), normed=True)
plt.show()

减小蓝色色调
(5) 最后,我们展示应用 Gotham 滤镜生成的最终输出图像:

plt.figure(figsize=(20,15))
plt.imshow(im3)
plt.axis('off')
plt.show()

结果图像

小结

图像和视频是大数据时代重要的交流媒介,图像和视频处理是当今人工智能技术重点的研究领域。在本节中,我们学习了如何使用 Python 执行基本的图像/视频处理,我们首先学习在 3D 空间可视化 RGB 图像的三个通道;然后,介绍了如何捕获视频并提取图像帧;最后,我们展示了如何实现一种流形的图像滤镜 Gotham,用于理解如何操作图像像素并执行插值操作。

系列链接

Python图像处理【2】探索Python图像处理库
Python图像处理【3】探索Python图像处理库

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

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

相关文章

[附源码]计算机毕业设计springboot葡萄酒销售管理系统论文

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

Python jupyter notebook Katex|Latex

目录 1.行内公式编辑 2.矩阵公式编辑 3.添加括号 4.添加图片 1.行内公式编辑 $\alpha\beta \gamma$点击control回车; 运行结果: 2.矩阵公式编辑 \begin{matrix} a & b &c \\ d & e & f \\ j & h & i \end{matrix} 点击…

基于随机森林实现特征选择降维及回归预测(Matlab代码实现)

目录 摘要: 1.随机森林: 2.随机森林的特征选取: 3.基于Matlab自带的随机森林函数进行特征选取具体步骤 (1)加载数据 (2)首先建立随机森林并使用全部特征进行车辆经济性预测 (3&#…

Shell脚本学习指南(五)——变量、判断、重复动作

文章目录前言变量与算术变量赋值与环境参数展开展开运算符位置参数特殊变量算术展开退出状态退出状态值if-else-else-fi语句逻辑的NOT、AND与ORtest命令case语句循环for循环while与until循环break与continueshift与选项处理函数前言 变量对于正规程序而言很重要。处理维护有用…

Android: SimpleAdapter+GridView 简单图片展示

1:原理解析: 一个xml放总布局,一个xml放适配器要加载的模板(我喜欢这样理解); java中写适配事件; 2:目录: 3:主布局:最重要的是要放一个GridView …

[附源码]Python计算机毕业设计Django港口集团仓库管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

Google单元测试框架gtest之官方sample笔记3--值参数化测试

1.7 sample7--接口测试 值参数不限定类型,也可以是类的引用,这就可以实现对类接口的测试,一个基类可以有多个继承类,那么可以测试不同的子类功能,但是只需要写一个测试用例,然后使用参数列表实现对每个子类…

m基于可见光通信系统的RFID接口过程以及ALOHA防碰撞算法的matlab仿真

目录 1.算法描述 2.matlab算法仿真效果 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 射频识别技术(Radio Frequency Identification,RFID)是一种非接触式自动识别技术,与传统的识别方式相比,它无需直接接触、无需光学可视、无需人工干预即…

产品经理的七大定律的总结

最近学习了产品经理的七大定律,这些设计准则都基于人类心理学:人们如何感知、学习、推理、记忆,以及把意图转换为行动。 1、菲茨(Paul Fitt)定律 菲茨定律的对于产品设计时的启示: 1)按钮等可…

SpringBoot 3.0 新特性,内置声明式HTTP客户端

http interface 从 Spring 6 和 Spring Boot 3 开始,Spring 框架支持将远程 HTTP 服务代理成带有特定注解的 Java http interface。类似的库,如 OpenFeign 和 Retrofit 仍然可以使用,但 http interface 为 Spring 框架添加内置支持。 什么是…

steam deck科普、上手教程及模拟器配置指南

steam_deck前言 早在2021年得时候,坊间就开始流传steam deck这个东西要问世了。但是中途跳了几次票,直到2022年2月,第一批steam deck才正式面向大众玩家。在熟悉steam deck之前,我们有必要了解如下的知识: Steam 准确来说&…

G1D27-deberta右键创建md文档

回家啦!!!中午的炒饭太好吃了!!吃的好撑!!回家后和mm去了超市,买了冰淇淋、薯片和水果,好开心!!! 下午睡了一会觉,真的好舒…

Spring MVC处理用户请求的完整流程

Spring MVC 框架是高度可配置的,包含多种视图技术,例如 JSP 技术、Velocity、Tiles、iText 和 POI。 Spring MVC 框架并不关心使用的视图技术,也不会强迫开发者只使用 JSP 技术,但教程中使用的视图是 JSP,本节主要介绍…

猿如意 | 带你手把手安装 Visual Studio Code

目录 一、什么是猿如意 二、借助猿如意安装Visual Studio Code 1、安装猿如意 2、安装Visual Studio Code 三、总结 一、什么是猿如意 猿如意是CSDN推出来的一款面向开发者的工具,他能够帮助开发者,找到自己心仪的开发工具提高自己的开发效率。 目标…

华为云两台机器内网互联

文章目录1. 前言2. ping公网ip3. 不同账号需要在同一大区4. 创建虚拟私有云5. 更换服务器所属的VPC网段6. 创建对等连接7. 填写对端项目ID和对端VPC ID8. 配置对等连接9. 添加对等连接路由10. 测试是否联通11. 后记1. 前言 最近在华为云买了两台低配Linux机器,35一…

聚焦出海 长城汽车50多国家和地区经销商集团齐聚泰国车博会

11月30日,长城汽车携新能源豪华阵容登陆第39届泰国国际汽车博览会(简称“泰国车博会”)。以“GWM Light the Future”(长城汽车点亮未来)为参展主题,长城汽车旗下中大型商务豪华SUV坦克500 HEV量产版、欧拉…

[附源码]Python计算机毕业设计SSM留守儿童管理平台(程序+LW)

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

英文Paper写作如何正确掌握质量情况?

在国外留学的学子们要想完成高质量高水平的作业(assignment与Paper),那么首先就要在心里想想这些基本必要的问题,等有了这些问题的轮廓之后,相信留学的朋友都能够写出满意自足的Paper或assignment。 1.Why …

TypeError: can only concatenate list (not “int“) to list

参考 TypeError: can only concatenate list (not "int") to list - 云社区 - 腾讯云 观察是否将列表和非列表的类型相连。 入队enqueue_op 5会报错,改成乘5就不会了。

Springboot整合策略模式概念->使用场景->优缺点->企业级实战

一、前言 策略模式可能是在工作中使用最多的,也是在面试中最常提到的,代码重构和优化的必备! 小编之前也是一直说,其实没有真正的实战;最近有了机会实战了一下,来分享一下使用心得和在企业级的使用&#x…