python抽帧及生成高质量的GIF图
python抽帧及生成高质量的GIF图
对视频进行抽帧只需要两个模块即可:
opencv-python (cv2)
opencv-contrib-python
我们都知道视频有分辨率,即视频的宽度与高度,还有视频的帧速率,即每秒有多少帧。

对视频进行抽帧,有两种方式,一种是每秒抽取一帧,另一种是每秒所有帧的抽取。
import os
import cv2
import datetime
from pygifsicle import optimize def extract_frames(video_path, start_time, end_time, is_all=True):
"""
提取视频帧
:param video_path: 视频地址
:param start_time: 开始截取帧的时间
:param end_time: 结束截取帧的时间
:param is_all: 是否截图时间段所有帧,如果未来False,则每秒只截取1帧
:return: ideo_h, video_w, video_fps, out_path
""" first_frames = ''
filename = os.path.basename(video_path)
file_dir_name = os.path.dirname(video_path)
file_name = os.path.splitext(filename)[0]
cap = cv2.VideoCapture(video_path)
# 视频每秒帧数
video_fps = int(cap.get(cv2.CAP_PROP_FPS))
# 视频高度
video_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 视频宽度
video_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
# 视频时长
video_duration = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)/video_fps)
if start_time >= video_duration:
start_time = 1
if end_time >= video_duration:
end_time = video_duration
# 计算起始和结束帧
start_frame = int(start_time * video_fps)
end_frame = int(end_time * video_fps)
count = 0
proces_time = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
out_path = f"{file_dir_name}/{file_name}/{proces_time}/"
os.makedirs(out_path)
# 视频抽帧
while True:
ret, frame = cap.read()
if not ret:
break
if count == 0:
cv2.imwrite(out_path + f"frame_{count}.png", frame)
first_frames = out_path + f"frame_{count}.png"
# 如果已经超过结束帧,退出循环
if count >= end_frame:
break
# 如果当前帧在截取时间内,保存图片
if start_frame <= count:
# 如果需要抽取所有帧
if is_all is True:
cv2.imwrite(out_path + f"frame_{count}.png", frame)
# 如果是每秒只抽取一帧
if is_all is False and (count % video_fps == 0):
cv2.imwrite(out_path + f"frame_{count}.png", frame)
count += 1
cap.release()
return video_h, video_w, video_fps, out_path, first_frames
这里对视频的第一帧和指定的时间段做了抽帧,并返回视频的分辨率以及FPS。
接下来就是生成GIF图,图片都有了,合成GIF图很简单了:
用Pillow和imageio模块即可,如果还要压缩GIF的话,再安装pygifsicle这个模块即可:
def pic_to_gif(height, width, fps, pic_path, is_compress=True):
"""
图片转gif图
:param height: 生成gif图的高度
:param width: 生成gif图的宽度
:param fps: 生成gif图的帧率(每秒图片数)
:param pic_path: 需要生产gif图的图的地址
:param is_compress: 是否需要压缩
:return:
"""
img_path = []
for filename in os.listdir(pic_path):
if filename.endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tif', '.tiff')):
img_path.append(os.path.join(pic_path, filename))
images = [Image.open(file) for file in img_path]
cover_img = images[1].filename
# 设置 GIF 的尺寸和帧率
size = (width, height)
gif_file = f"{pic_path}01.gif"
with imageio.get_writer(gif_file, mode='I', fps=fps) as writer:
for image in images:
writer.append_data(image.resize(size))
# 步骤六:保存并关闭 GIF 文件
writer.close()
# def mimwrite(uri, ims, format=None, **kwargs):
# with imageio.mimsave(uri=gif_file, ims=images, fps=fps, loop=0) as write:
# 如果需要压缩GIF图
if is_compress is True:
optimize(gif_file, gif_file)
return gif_file, cover_img
imageio.get_writer 和 imageio.mimsave 方法都是一样的,是不是很简单!但对我来说,才开始。
因为用imageio生成GIF图,质量太不行,而且还比较大。
后来有找了很多生成GIF图的模块,比如moviepy,ImageMagick,都差强人意,值得说的是moviepy:
from moviepy.editor import VideoFileClip
video = VideoFileClip(video_path, verbose=True, has_mask=True)
clip = video.subclip(3, 6)
clip.write_gif("00.gif", program='ffmpeg', fps=4, tempfiles=False, fuzz=0)
"""
def write_gif(self, filename, fps=None, program='imageio',
                  opt='nq', fuzz=1, verbose=True,
                  loop=0, dispose=False, colors=None, tempfiles=False,
                  logger='bar'):
program
          Software to use for the conversion, either 'imageio' (this will use
          the library FreeImage through ImageIO), or 'ImageMagick', or 'ffmpeg'.
opt
          Optimalization to apply. If program='imageio', opt must be either 'wu'
          (Wu) or 'nq' (Neuquant). If program='ImageMagick',
          either 'optimizeplus' or 'OptimizeTransparency'.
"""
moviepy 里的write_gif函数,可以传生成gif图的程序,比如imageio,ffmpeg,ImageMagick
也就是通过moviepy找到了解决方案,这几个程序我都尝试了一遍,当然,ffmpeg,ImageMagick都需要自己安装一下。
发现ffmpeg生成GIF图比imageio要好很多,imageio特别是遇到人脸等啥的,就像打了马赛克一样的。但ffmpeg整体均匀的模糊一样,马赛克不见了,但整体的GIF图质量还是没达到预期。ImageMagick也不行。
找了很多资料,还是在ffmpeg上找到了解决方案:
测试代码:
import subprocess as sp
from moviepy.compat import DEVNULL globalPalettePicPath = "D:\\thecover_project\\video_to_picture\\video_path\\000.png"
video_path = r"D:\thecover_project\video_to_picture\video_path\video1625112445881755141.mp4"
outFilePath = "D:\\thecover_project\\video_to_picture\\video_path\\1111111.gif" # video = VideoFileClip(video_path, verbose=True, has_mask=True)
# clip = video.subclip(3, 6)
# clip.write_gif("00.gif", program='ffmpeg', fps=4, tempfiles=False, fuzz=0)
popen_params = {"stdout": DEVNULL, "stderr": DEVNULL, "stdin": sp.PIPE}
command = f"ffmpeg -ss 3 -t 2 -i {video_path} -b:v 520k -r 29 -vf fps=29,scale=337:-1:flags=lanczos,palettegen -y {globalPalettePicPath}"
proc = sp.Popen(command, **popen_params)
proc.communicate()
proc.stdin.close()
command1 = f"ffmpeg -v error -ss 3 -t 2 -i {video_path} -i {globalPalettePicPath} -r 29 -lavfi fps=29,scale=337:-1:flags=lanczos[x];[x][1:v]paletteuse -y {outFilePath}"
# command1 = f"ffmpeg -ss 3 -t 2 -i {video_path} -r 29 -vf fps=29,scale=337:-1 {outFilePath}"
proc = sp.Popen(command1, **popen_params)
proc.communicate()
proc.stdin.close()
在生成GIF图前,先对视频进行全局采样,对每一帧的所有颜色制作一个直方图,并且基于这些生成一个调色板,原文详细介绍见这个地址:https://blog.pkh.me/p/21-high-quality-gif-with-ffmpeg.html
if video_h >= video_w:
video_w = 337
# video_w = 720
else:
video_w = 600
# video_w = 1280
global_palette_pic_path = f"{out_path}00.png"
gif_file = f"{out_path}01.gif"
# 命令通道参数,比如不打印显示日志信息等
popen_params = {"stdout": DEVNULL, "stderr": DEVNULL, "stdin": sp.PIPE}
# 定义全局调色板
command = f"ffmpeg -ss {start_time} -t {end_time-start_time} -i {video_path} -b:v 520k -r {video_fps} -vf fps={video_fps},scale={video_w}:-1:flags=lanczos,palettegen -y {global_palette_pic_path}"
proc = sp.Popen(command, **popen_params)
proc.communicate()
proc.stdin.close()
# 通过ffmpeg生成gif图
command1 = f"ffmpeg -v error -ss {start_time} -t {end_time-start_time} -i {video_path} -i {global_palette_pic_path} -r {video_fps} -lavfi fps={video_fps},scale={video_w}:-1:flags=lanczos[x];[x][1:v]paletteuse -y {gif_file}"
proc = sp.Popen(command1, **popen_params)
proc.communicate()
proc.stdin.close()
return first_frames, img_cover, gif_file
这里生成的GIF图,都进行了宽度压缩,竖屏就以宽度337来等比压缩。横屏就以600宽度等比压缩。比较符合网络传播。
好了,生成高质量的GIF图,摸索就到这!
以下是连接原文的转载:
使用 FFmpeg 的高品质 GIF
大约两年前,我尝试改进 FFmpeg 中对 GIF 编码的支持,使其至少像样。这尤其导致了 GIF 编码器中添加透明机制。虽然根据您的来源,这并不总是最佳的,但在最常见的情况下是这样。尽管如此,这只是为了防止编码器受到过多的羞辱。
但最近在Stupeflix ,我们需要一种为Legend 应用程序生成高质量 GIF 的方法,所以我决定再次致力于此。
本博文中介绍的所有功能都在FFmpeg 2.6中可用,并将在 Legend 应用程序的下一版本中使用(可能在 3 月 26 日左右)。
TL;DR:转到“用法”部分查看如何使用它。
初步改进(2013)
我们来观察一下2013年引入的透明机制在GIF编码器中的效果:
% ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale=300:-1 -gifflags -transdiff -y bbb-notrans.gif
% ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale=300:-1 -gifflags +transdiff -y bbb-trans.gif
% ls -l bbb-*.gif
-rw-r--r-- 1 ux ux 1.1M Mar 15 22:50 bbb-notrans.gif
-rw-r--r-- 1 ux ux 369K Mar 15 22:50 bbb-trans.gif

默认情况下启用此选项,因此您只需在图像有大量运动或颜色变化时才需要禁用它。
另一种实现的压缩机制是裁剪,这基本上是一种只允许重绘 GIF 的子矩形并保持周围不变的方法。对于电影来说,它很少有用。我稍后会再讨论这个问题。
但无论如何,从那时起,我在这方面就没有任何进展。虽然在上图中可能不太明显,但在质量方面存在不少缺陷。
256 色限制
您可能知道,GIF 的调色板仅限于 256 种颜色。默认情况下,FFmpeg 仅使用通用调色板,尝试覆盖整个颜色空间以支持最多种内容:

有序和误差扩散抖动
为了避免这个问题,使用了抖动。在上面的 Big Buck Bunny GIF 中,应用了有序拜耳抖动。它很容易通过其8x8交叉阴影线图案来识别。虽然它不是最漂亮的,但它有很多好处,例如可预测、快速,并且实际上可以防止条带效应和类似的视觉故障。
您会发现大多数其他抖动方法都是基于错误的。其原理是,单一颜色错误(调色板中选取的颜色与预期颜色之间的差异)将遍布整个图像,导致帧之间出现“蜂拥效应”,即使在帧之间源完全相同的区域中也是如此。虽然这通常可以提供更好的质量,但它完全破坏了 GIF 的压缩:
% ffmpeg -v warning -ss 45 -t 2 -i big_buck_bunny_1080p_h264.mov -vf scale=300:-1:sws_dither=ed -y bbb-error-diffusal.gif
% ls -l bbb-error-diffusal.gif
-rw-r--r-- 1 ux ux 1.3M Mar 15 23:10 bbb-error-diffusal.gif
更好的调色板
提高 GIF 质量的第一步是定义更好的调色板。 GIF格式存储了一个全局调色板,您可以为一张图片(或子图片;每一帧叠加在前一帧上,但可以以更小的尺寸以特定偏移量叠加)重新定义调色板。每帧调色板仅取代一帧的全局调色板。一旦您停止定义调色板,它就会退回到全局调色板。这意味着您无法像您想做的那样为一系列帧定义调色板(通常在每个场景更改时定义一个新调色板)。
换句话说,您必须遵循一个全局调色板或每帧一个调色板的模型。
每帧一个调色板(未实现)
我最初是从实现每帧调色板的计算开始的,但这有以下缺点:
- 开销:256 色调色板为 768B,它不是 LZW算法机制的一部分,因此不会被压缩。由于必须按每一帧存储它,这意味着 25 FPS 素材的开销为 150 kbits/sec。但它大多可以忽略不计。
- 我最初的测试是由于这些调色板的变化而产生亮度闪烁效果,这根本不漂亮。
这是我没有遵循该路径并决定计算全局调色板的两个原因。现在我回想起来,可能需要重试该方法,因为颜色量化的状态比我最初的测试更好。
还可以在帧范围的每个帧处存储相同的调色板(通常在场景变化时,如前面提到的)。或者更好,仅针对发生变化的子矩形。
所有这些都留给读者作为练习,欢迎补丁。如果您对此感兴趣,请随时与我联系。
一个全局调色板(已实现)
拥有一个全局调色板意味着 2 遍机制(除非您愿意将所有视频帧存储在内存中)。
第一遍是计算整个演示文稿的调色板。这就是新的调色板生成过滤器发挥作用的地方。该滤镜对每帧的所有颜色制作直方图,并从中生成调色板。
关于技术方面的一些琐事:过滤器正在实现 Paul Heckbert 的帧缓冲区显示彩色图像量化 (1982)论文中的算法的变体。以下是我记得所做的差异(或论文中未定义行为的特殊性):
- 它使用全分辨率颜色直方图。因此,该过滤器没有像论文中建议的那样使用下采样 RGB 5:5:5 直方图作为关键,而是使用哈希表来存储 1600 万种可能的 RGB 8:8:8 颜色。
- 盒子的分割仍然是在中点处进行,但是根据盒子中颜色的方差来选择要分割的盒子(颜色方差较大的盒子将被优先选择为截止) )。
- 据我所知,这在论文中没有定义,但框中颜色的平均值是根据颜色的重要性来完成的。
- 当沿轴(红、绿或蓝)分割盒子时,在相等的情况下,绿色优先于红色,而红色又优先于蓝色。
所以无论如何,这个过滤器会进行颜色量化,并生成调色板(通常保存到文件中PNG)。
它通常看起来像这样(放大):

颜色映射和抖动
然后,第二遍由调色板使用过滤器处理,正如您从名称中猜测的那样,它将使用该调色板生成最终的颜色量化流。它的任务是在生成的调色板中找到最合适的颜色来表示输入颜色。您也可以在此处决定使用哪种抖动方法。
再说一些技术方面的琐事:
- 虽然原始论文仅提出了一种抖动方法,但滤波器实现了其中 5 种。
- 就像 一样palettegen,颜色分辨率(将 24 位输入颜色映射到调色板条目)是在不破坏输入的情况下完成的。它是通过Kd Tree的迭代实现(显然 K=3,每个 RGB 分量一个维度)和缓存系统来实现的。
使用这两个过滤器将允许您像这样编码 GIF(单个全局调色板,无抖动):

用法
使用相同的参数手动运行 2 个通道可能会有点烦人,需要调整每个通道的参数,因此我建议编写一个简单的脚本,例如:
#!/bin/sh
palette="/tmp/palette.png"
filters="fps=15,scale=320:-1:flags=lanczos"
ffmpeg -v warning -i $1 -vf "$filters,palettegen" -y $palette
ffmpeg -v warning -i $1 -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $2
...可以这样使用:
% ./gifenc.sh video.mkv anim.gif
该filters变量包含在这里:
- 每秒帧数的调整(减少到 15 可能会导致视觉上的抖动,但会使最终的 GIF 更小)
- 使用lanczos缩放器而不是默认的缩放器(bilinear当前)。建议您使用lanczos或重新缩放,bicubic因为它们远远优于bilinear。如果不这样做,您的输入很可能会更加模糊。
仅提取样本
您不太可能对完整的电影进行编码,因此您可能会想使用-ss和-t(或类似)选项来选择片段。如果您这样做,请务必将两者都作为输入选项(在 之前-i)。例如:
#!/bin/sh
start_time=12:23
duration=35
palette="/tmp/palette.png"
filters="fps=15,scale=320:-1:flags=lanczos"
ffmpeg -v warning -ss $start_time -t $duration -i $1 -vf "$filters,palettegen" -y $palette
ffmpeg -v warning -ss $start_time -t $duration -i $1 -i $palette -lavfi "$filters [x]; [x][1:v] paletteuse" -y $2
如果不这样做,至少在第一遍中会导致问题,其中输出永远不会超过一帧(调色板),因此不会达到您想要的效果。
一种替代方法是使用流复制来预提取要编码的样本,例如:
% ffmpeg -ss 12:23 -t 35 -i full.mkv -c:v copy -map 0:v -y video.mkv
如果流副本不够准确,您可以添加修剪 过滤器。例如:
filters="trim=start_frame=12:end_frame=431,fps=15,scale=320:-1:flags=lanczos"
充分利用调色板一代
现在我们可以开始看看有趣的部分了。在palettegen过滤器中,您想要进行的主要且可能唯一的调整是选项stats_mode 。
此选项基本上允许您指定您是对整个/整体视频更感兴趣,还是仅对正在移动的内容更感兴趣。如果使用stats_mode=full (默认),所有像素都将成为颜色统计的一部分。如果使用 stats_mode=diff,则仅考虑与前一帧不同的像素。
注意:要向过滤器添加选项,请像这样使用它: thefilter=opt1=value1:opt2=value2
以下是一个示例来说明它如何影响最终输出:
 
 
第一个 GIF 正在使用stats_mode=full(默认)。整个演示文稿的背景不会改变,因此天空的颜色受到了很多关注。另一方面,移动文本最终的颜色子集非常有限。结果,文本的淡出受到了影响:

另一方面,第二个 GIF 使用stats_mode=diff,这有利于移动的内容。事实上,文本的淡出要好得多,但代价是天空中出现抖动故障:

充分利用颜色映射
该paletteuse过滤器有更多的选项可供使用。最明显的一个是抖动(dither选项)。唯一可用的可预测抖动是bayer,所有其他抖动都是基于误差扩散的。
如果您确实想使用bayer(因为您有高速或尺寸问题),您可以使用bayer_scale降低或增加其剖面线图案的选项。
当然,您也可以使用 来完全禁用抖动 dither=none。
关于误差扩散抖动,您需要使用 floyd_steinberg、sierra2和sierra2_4a。有关这些的更多详细信息,我将您重定向到DHALF.TXT。
对于懒人来说,floyd_steinberg是最流行的之一,并且sierra2_4a是(并且是默认的)的快速/较小版本sierra2,通过 3 个像素而不是 7 个像素进行扩散。heckbert是我之前提到的论文中记录的一个,并且只是包含为一个参考(你可能不需要它)。
以下是不同抖动模式的小预览:
原始(31.82K): 
dither=bayer:bayer_scale=1(132.80K): 
dither=bayer:bayer_scale=2(118.80K): 
dither=bayer:bayer_scale=3(103.11K): 
dither=floyd_steinberg(101.78K): 
dither=sierra2(89.98K): 
dither=sierra2_4a(109.60K): 
dither=none(73.10K): 
最后,在尝试了抖动之后,您可能有兴趣了解该选项diff_mode。引用文档:
只有变化的矩形才会被重新处理。这类似于 GIF 裁剪/偏移压缩机制。如果仅图像的一部分发生变化,则此选项对于提高速度很有用,并且具有一些用例,例如将误差扩散抖动的范围限制为限制移动场景的矩形(如果场景不发生变化,则它会导致更具确定性的输出)变化不大,因此移动噪音更少,GIF 压缩效果更好)。
或者换句话说:如果您想在图像上使用误差扩散抖动作为背景,即使它是静态的,请启用此选项来限制误差在整个图片上的传播。这是一个相关的典型案例:

请注意,只有当顶部和底部文本同时移动时(即,在此处的最后一帧中),猴子脸上的抖动才会发生变化。
python抽帧及生成高质量的GIF图的更多相关文章
- C#放缩、截取、合并图片并生成高质量新图的类
		原文:C#放缩.截取.合并图片并生成高质量新图的类 using System;using System.Drawing;using System.Drawing.Imaging;using Syste ... 
- atitit.thumb生成高质量缩略图 php .net c++  java
		atitit.java thumb生成高质量缩略图 php .net c++ 1. 图像缩放(image scaling)---平滑度(smoothness)和清晰度(sharpness) 1 2. ... 
- Python高质量缩放切图,抗锯齿
		最近刚接触Python,以迅雷不及掩耳盗铃之势(只是迫不及待)应用到工作中去了之前用 cmd+photoshop做批量图像处理(缩放切片),在执行效率(速度)上和灵活度上有很大限制,遂转战Python ... 
- C#剪切生成高质量缩放图片
		/// <summary> /// 高质量缩放图片 /// </summary> /// <param name="OriginFilePath"&g ... 
- <1>Python生成高质量Html文件:Pyh模块+Bootstrap框架
		一,介绍 QQ交流群:585499566 本文的目的是怎么使用Pyh+Bootstrap快速生成简约,大方,清新的Html页面,涉及到的技能:Python小白技能,Pyh会阅读中文文档,Html基础, ... 
- Highcharts结合PhantomJS在服务端生成高质量的图表图片
		项目背景 最近忙着给部门开发一套交互式的报表系统,来替换原有的静态报表系统. 老系统是基于dotnetCHARTING开发的,dotnetCHARTING的优势是图表类型丰富,接口调用简单,使用时只需 ... 
- MPlayer-ww 增加边看边剪切功能+生成高质量GIF功能
		http://pan.baidu.com/s/1eQm5a74 下载FFmpeg palettegen paletteuse documentation 需要下载 FFmpeg2.6 以上 并FFmp ... 
- ASP.NET 画图与图像处理-生成高质量缩略图
		http://www.cftea.com/c/2007/08/SG9WFLZJD62Z2D0O.asp 
- 编写高质量代码--改善python程序的建议(六)
		原文发表在我的博客主页,转载请注明出处! 建议二十八:区别对待可变对象和不可变对象 python中一切皆对象,每一个对象都有一个唯一的标识符(id()).类型(type())以及值,对象根据其值能否修 ... 
- Effective Python之编写高质量Python代码的59个有效方法
		这个周末断断续续的阅读完了<Effective Python之编写高质量Python代码 ... 
随机推荐
- 14 CodeTON Round 5 (Div. 1 + Div. 2, Rated, Prizes!)C. Tenzing and Balls(dp+前缀最大值优化)
			思路: dp还是挺明显的,思路可以参考最长上升子序列 有点dp的感觉 \(f[i]\)表示考虑前\(i\)个数,的最大值 当前数有两种删或不删 不删:\(f[i]=f[i-1]\); 删:\(f[i] ... 
- 文心一言 VS 讯飞星火 VS chatgpt (210)-- 算法导论16.1 1题
			一.根据递归式(16.2)为活动选择问题设计一个动态规划算法.算法应该按前文定义计算最大兼容活动集的大小 c[i,j]并生成最大集本身.假定输入的活动已按公式(16.1)排好序.比较你的算法和GREE ... 
- vscode 格式化空格,constructor 构造函数的空格 会有问题,找到一个配置文件好使
			Ctrl+Shift+P "javascript.format.enable": false, "javascript.format.insertSpaceAfterCo ... 
- 关于easyExcel导出文字合并居中和服务器导出失败踩了一天的坑
			参考:https://blog.csdn.net/hanyi_/article/details/118117484,https://blog.csdn.net/sunyuhua_keyboard/ar ... 
- 熬夜的JaVa
			1 import java.util.Scanner; 2 3 public class viovo { 4 static int number = 5;//五个商品信息 5 static oppo[ ... 
- 记录--开局一张图,构建神奇的 CSS 效果
			这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 假设,我们有这样一张 Gif 图: 利用 CSS,我们尝试来搞一些事情. 图片的 Glitch Art 风 在这篇文章中 --CSS 故障 ... 
- C# 剪裁图片
			/// <summary> /// 剪裁图片 /// </summary> /// <param name="src">原图片</para ... 
- C# WinForm 获取执行路径的几种常见方法
			//1.获取模块的完整路径. string path1 = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; Co ... 
- KingbaseES 的oracle兼容性参数
			KingbaseES用户可通过设置相关的数据库兼容参数,部分或全部启用Oracle兼容特性. 常用的兼容性参数有以下这些: 参数名称 参数说明 ora_forbid_func_polymorphism ... 
- HashMap的三种遍历方式--Java--小白必懂
			初学Hash Map总感觉它的遍历很麻烦,其实看懂后总结一下就是:集合+泛型,没啥特别的 总结一下HashMap的三种遍历方法如下: 保证一看就会>>> 1 // 对HashMap的 ... 
