热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

视频提取关键帧提取

视频提取关键帧提取文章目录视频提取关键帧提取前言一、什么是关键帧和为什么要提取关键帧?二、关键帧提取方法三、整理结果参考资料:前言正所谓做工作要做好记

视频提取关键帧提取


文章目录

  • 视频提取关键帧提取
    • 前言
    • 一、什么是关键帧和为什么要提取关键帧?
    • 二、关键帧提取方法
    • 三、整理结果
    • 参考资料:


前言

正所谓做工作要做好记录,现在,我要开始记录啦。


一、什么是关键帧和为什么要提取关键帧?

1、每个视频都是一个图像序列,其内容比一张图像丰富很多,表现力强,信息量大。对视频的分析通常是基于视频帧,但视频帧通常存在大量冗余,对视频帧的提取也存在漏帧、冗余的现象。视频关键帧提取则主要体现视频中各个镜头的显著特征,通过视频关键帧提取能够有效减少视频检索所需要花费的时间,并能够增强视频检索的精确度。


2、关键帧定义:把图像坐标系中每个“视频帧”都叠加在一起,这时镜头中视频帧的特征矢量会在空间中呈现出一个轨迹的状态,而与轨迹中特征值进行对应的“帧”即可称之为关键帧[1]


3、视频具有层次化结构,由场景、镜头和帧三个逻辑单元组成。视频检索常基于帧进行,因此,提取视频的关键帧至关重要[2]


二、关键帧提取方法

1、关键帧提取思想:对视频序列采用镜头分割的方式,然后在镜头当中获得内容关键帧提取,接着利用“关键帧”来获得底层的形状、纹理和颜色等特征。

2、关键帧提取方法:

(1)全图像序列

​ 镜头边界方法是将镜头中的第一帧和最后一帧(或中间帧)作为关键帧。该方法简单易行,适于内容活动性小或内容保持不变的镜头,但未考虑镜头视觉内容的复杂性,限制了镜头关键帧的个数,提取的关键帧代表性不强,效果不够稳定。

(2)压缩视频

(3) 自定义k值聚类和内容分析的关键帧提取方法[2]

(4)a 基于抽样的关键帧提取[3]

​ 基于抽样的方法是通过随机抽取或在规定的时间间隔内随机抽取视频帧。这种方法简单不实用。

​ b 基于颜色特征的关键帧提取

​ c 基于运动分析的关键帧提取

​ d 基于镜头边界的关键帧提取(*)

e 基于视频内容的关键帧提取(*)

​ f 基于聚类的关键帧提取 (可能是最合适的一个了),我要识别的类别已经确定。

(5)使用3D-CNN提取关键帧[4]

​ 他提出了一种基于语义的视频关键帧提取算法,该算法首先使用层次聚类算法对视频关键帧进行初步提取;然后结合语义相关算法对初步提取的关键帧进行直方图对比去掉冗余帧,确定视频的关键帧;最后通过与其他算法比较,本文提出的算法提取的关键帧冗余度相对小。

(6)首先利用卷积自编码器提取视频帧的深度特征,对其进行 K-means 聚类,在每类视频帧中采用清晰度筛选取出最清晰的视频帧作为初次提取的关键帧;然后利用点密度方法对初次提取的关键帧进行二次优化,得到最终提取的关键帧进行手语识别.[5]

(7) 视频关键帧提取方法一般可分为四大类:

​ 第一类:基于图像内容的方法

​ 第二类:基于运动分析的方法

​ 第三类:基于轨迹曲线点密度特征的关键帧检测算法

​ 第四类:目前主流方法:基于聚类的方法

(8)帧间差法

​ 源自: 以下代码出自zyb_as的github

# -*- coding: utf-8 -*-
"""
帧间最大值法
Created on Tue Dec 4 16:48:57 2018
keyframes extract tool
this key frame extract algorithm is based on interframe difference.
The principle is very simple
First, we load the video and compute the interframe difference between each frames
Then, we can choose one of these three methods to extract keyframes, which are
all based on the difference method:1. use the difference orderThe first few frames with the largest average interframe difference are considered to be key frames.
2. use the difference thresholdThe frames which the average interframe difference are large than the threshold are considered to be key frames.
3. use local maximumThe frames which the average interframe difference are local maximum are considered to be key frames.It should be noted that smoothing the average difference value before calculating the local maximum can effectively remove noise to avoid repeated extraction of frames of similar scenes.
After a few experiment, the third method has a better key frame extraction effect.
The original code comes from the link below, I optimized the code to reduce
unnecessary memory consumption.
https://blog.csdn.net/qq_21997625/article/details/81285096
@author: zyb_as
"""
import cv2
import operator
import numpy as np
import matplotlib.pyplot as plt
import sys
from scipy.signal import argrelextremadef smooth(x, window_len=13, window='hanning'):"""smooth the data using a window with requested size.This method is based on the convolution of a scaled window with the signal.The signal is prepared by introducing reflected copies of the signal (with the window size) in both ends so that transient parts are minimizedin the begining and end part of the output signal.input:x: the input signal window_len: the dimension of the smoothing windowwindow: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'flat window will produce a moving average smoothing.output:the smoothed signalexample:import numpy as np t = np.linspace(-2,2,0.1)x = np.sin(t)+np.random.randn(len(t))*0.1y = smooth(x)see also: numpy.hanning, numpy.hamming, numpy.bartlett, numpy.blackman, numpy.convolvescipy.signal.lfilterTODO: the window parameter could be the window itself if an array instead of a string """print(len(x), window_len)# if x.ndim != 1:# raise ValueError, "smooth only accepts 1 dimension arrays."## if x.size = THRESH):keyframe_id_set.add(frames[i].id) if USE_LOCAL_MAXIMA:print("Using Local Maxima")diff_array = np.array(frame_diffs)sm_diff_array = smooth(diff_array, len_window)frame_indexes = np.asarray(argrelextrema(sm_diff_array, np.greater))[0]for i in frame_indexes:keyframe_id_set.add(frames[i - 1].id)plt.figure(figsize=(40, 20))plt.locator_params(numticks=100)plt.stem(sm_diff_array)plt.savefig(dir + 'plot.png')# save all keyframes as imagecap = cv2.VideoCapture(str(videopath))curr_frame = Nonekeyframes = []success, frame = cap.read()idx = 0while(success):if idx in keyframe_id_set:name = "keyframe_" + str(idx) + ".jpg"cv2.imwrite(dir + name, frame)keyframe_id_set.remove(idx)idx = idx + 1success, frame = cap.read()cap.release()

运动分析流光法进行关键帧提取

源自:AillenAnthony的github

# Scripts to try and detect key frames that represent scene transitions
# in a video. Has only been tried out on video of slides, so is likely not
# robust for other types of video.# 1. 基于图像信息
# 2. 基于运动分析(光流分析)import cv2
import argparse
import json
import os
import numpy as np
import errnodef getInfo(sourcePath):cap = cv2.VideoCapture(sourcePath)info = {"framecount": cap.get(cv2.CAP_PROP_FRAME_COUNT),"fps": cap.get(cv2.CAP_PROP_FPS),"width": int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)),"heigth": int(cap.get(cv2.CAP_PROP_FRAME_Heigth)),"codec": int(cap.get(cv2.CAP_PROP_FOURCC))}cap.release()return infodef scale(img, xScale, yScale):res = cv2.resize(img, None,fx=xScale, fy=yScale, interpolation = cv2.INTER_AREA)return resdef resize(img, width, heigth):res = cv2.resize(img, (width, heigth), interpolation = cv2.INTER_AREA)return res#
# Extract [numCols] domninant colors from an image
# Uses KMeans on the pixels and then returns the centriods
# of the colors
#
def extract_cols(image, numCols):# convert to np.float32 matrix that can be clusteredZ = image.reshape((-1,3))Z = np.float32(Z)# Set parameters for the clusteringmax_iter = 20epsilon = 1.0K = numColscriteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, max_iter, epsilon)labels = np.array([])# clustercompactness, labels, centers = cv2.kmeans(Z, K, labels, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)clusterCounts = []for idx in range(K):count = len(Z[labels == idx])clusterCounts.append(count)#Reverse the cols stored in centers because cols are stored in BGR#in opencv.rgbCenters = []for center in centers:bgr = center.tolist()bgr.reverse()rgbCenters.append(bgr)cols = []for i in range(K):iCol = {"count": clusterCounts[i],"col": rgbCenters[i]}cols.append(iCol)return cols#
# Calculates change data one one frame to the next one.
#
def calculateFrameStats(sourcePath, verbose=False, after_frame=0): # 提取相邻帧的差别cap = cv2.VideoCapture(sourcePath)#提取视频data = {"frame_info": []}lastFrame = Nonewhile(cap.isOpened()):ret, frame = cap.read()if frame == None:breakframe_number = cap.get(cv2.CAP_PROP_POS_FRAMES) - 1# Convert to grayscale, scale down and blur to make# calculate image differences more robust to noisegray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 提取灰度信息gray = scale(gray, 0.25, 0.25) # 缩放为原来的四分之一gray = cv2.GaussianBlur(gray, (9,9), 0.0) # 做高斯模糊if frame_number data["stats"]["mean"]]greater_than_median = [fi for fi in data["frame_info"] if fi["diff_count"] > data["stats"]["median"]]greater_than_one_sd = [fi for fi in data["frame_info"] if fi["diff_count"] > data["stats"]["sd"] + data["stats"]["mean"]]greater_than_two_sd = [fi for fi in data["frame_info"] if fi["diff_count"] > (data["stats"]["sd"] * 2) + data["stats"]["mean"]]greater_than_three_sd = [fi for fi in data["frame_info"] if fi["diff_count"] > (data["stats"]["sd"] * 3) + data["stats"]["mean"]]# 统计其他信息data["stats"]["greater_than_mean"] = len(greater_than_mean)data["stats"]["greater_than_median"] = len(greater_than_median)data["stats"]["greater_than_one_sd"] = len(greater_than_one_sd)data["stats"]["greater_than_three_sd"] = len(greater_than_three_sd)data["stats"]["greater_than_two_sd"] = len(greater_than_two_sd)return data#
# Take an image and write it out at various sizes.
#
# TODO: Create output directories if they do not exist.
#
def writeImagePyramid(destPath, name, seqNumber, image):fullPath = os.path.join(destPath, "full", name + "-" + str(seqNumber) + ".png")halfPath = os.path.join(destPath, "half", name + "-" + str(seqNumber) + ".png")quarterPath = os.path.join(destPath, "quarter", name + "-" + str(seqNumber) + ".png")eigthPath = os.path.join(destPath, "eigth", name + "-" + str(seqNumber) + ".png")sixteenthPath = os.path.join(destPath, "sixteenth", name + "-" + str(seqNumber) + ".png")hImage = scale(image, 0.5, 0.5)qImage = scale(image, 0.25, 0.25)eImage = scale(image, 0.125, 0.125)sImage = scale(image, 0.0625, 0.0625)cv2.imwrite(fullPath, image)cv2.imwrite(halfPath, hImage)cv2.imwrite(quarterPath, qImage)cv2.imwrite(eigthPath, eImage)cv2.imwrite(sixteenthPath, sImage)#
# Selects a set of frames as key frames (frames that represent a significant difference in
# the video i.e. potential scene chnges). Key frames are selected as those frames where the
# number of pixels that changed from the previous frame are more than 1.85 standard deviations
# times from the mean number of changed pixels across all interframe changes.
#
def detectScenes(sourcePath, destPath, data, name, verbose=False):destDir = os.path.join(destPath, "images")# TODO make sd multiplier externally configurable#diff_threshold = (data["stats"]["sd"] * 1.85) + data["stats"]["mean"]diff_threshold = (data["stats"]["sd"] * 2.05) + (data["stats"]["mean"])cap = cv2.VideoCapture(sourcePath)for index, fi in enumerate(data["frame_info"]):if fi["diff_count"] 2.5if exc.errno == errno.EEXIST and os.path.isdir(path):passelse: raiseif __name__ == '__main__':parser = argparse.ArgumentParser()# parser.add_argument('-s','--source', help='source file', required=True)# parser.add_argument('-d', '--dest', help='dest folder', required=True)# parser.add_argument('-n', '--name', help='image sequence name', required=True)# parser.add_argument('-a','--after_frame', help='after frame', default=0)# parser.add_argument('-v', '--verbose', action='store_true')# parser.set_defaults(verbose=False)parser.add_argument('-s','--source', help='source file', default="dataset/video/wash_hand/00000.mp4")parser.add_argument('-d', '--dest', help='dest folder', default="dataset/video/key_frame")parser.add_argument('-n', '--name', help='image sequence name', default="")parser.add_argument('-a','--after_frame', help='after frame', default=0)parser.add_argument('-v', '--verbose', action='store_true')parser.set_defaults(verbose=False)args = parser.parse_args()if args.verbose:info = getInfo(args.source)print("Source Info: ", info)makeOutputDirs(args.dest)# Run the extractiondata = calculateFrameStats(args.source, args.verbose, int(args.after_frame))data = detectScenes(args.source, args.dest, data, args.name, args.verbose)keyframeInfo = [frame_info for frame_info in data["frame_info"] if "dominant_cols" in frame_info]# Write out the resultsdata_fp = os.path.join(args.dest, "metadata", args.name + "-meta.json")with open(data_fp, 'w') as f:data_json_str = json.dumps(data, indent=4)f.write(data_json_str)keyframe_info_fp = os.path.join(args.dest, "metadata", args.name + "-keyframe-meta.json")with open(keyframe_info_fp, 'w') as f:data_json_str = json.dumps(keyframeInfo, indent=4)f.write(data_json_str)

(9) 使用ffmpeg进行关键帧提取

代码见于此处

(10) 使用K-means聚类法

源代码见于此处

filenames=dir('images/*.jpg');
%file_name = fly-1;
num=size(filenames,1); %输出filenames中文件图片的个数
key=zeros(1,num); %一行,num列都是0 [0,0,0,0,0,0,0,0,0,0,0,0,....0,0,0,0]
cluster=zeros(1,num); %[0,0,0,0,0,0,0,0,0,0,0,0,....0,0,0,0]
clusterCount=zeros(1,num); %各聚类有的帧数 [0,0,0,0,0,0,0,0,0,0,0,0,....0,0,0,0]
count=0; %聚类的个数 %threshold=0.75; %阈值越大帧越多
%airplane这个视频阈值设为0.93比较合适 0.95更好
%********************************************************阈值**************************************************************%
threshold=0.91; %阈值
centrodR=zeros(num,256); %聚类质心R的直方图 第一帧图片256个初始化全部为0,第二帧也是,其余帧都是 %%%后面相似度大加入一帧后会对其进行调整
centrodG=zeros(num,256); %聚类质心G的直方图
centrodB=zeros(num,256); %聚类质心B的直方图if num==0error('Sorry, there is no pictures in images folder!');
else%令首帧形成第一个聚类img=imread(strcat('images/',filenames(1).name));count=count+1; %产生第一个聚类[preCountR,x]=imhist(img(:,:,1)); %red histogram 得到红色的直方图一共256个数值,每个数值有多少作为直方图的高度[preCountG,x]=imhist(img(:,:,2)); %green histogram[preCountB,x]=imhist(img(:,:,3)); %blue histogramcluster(1)=1; %设定第一个聚类选取的关键帧初始为首帧 cluster变为了(1,0,0,0,0,......,0,0,0)cluster(1)是改变了第一个元素clusterCount(1)=clusterCount(1)+1;%clusterCount(1)为0,加1,变为1,最终 clusterCount(1)为[1,0,0,0,.....,0,0,0]centrodR(1,:)=preCountR; % centrodR本来是num(帧个数)行,256列,全部为0.。现在第一行为第一帧的红色直方图各个数值的高度centrodG(1,:)=preCountG;centrodB(1,:)=preCountB;visit = 1;for k=2:numimg=imread(strcat('images/',filenames(k).name)); %循环读取每一帧,首先是第2帧[tmpCountR,x]=imhist(img(:,:,1)); %red histogram 得到红色分量直方图 第二幅图片的红色直方图[tmpCountG,x]=imhist(img(:,:,2)); %green histogram[tmpCountB,x]=imhist(img(:,:,3)); %blue histogramclusterGroupId=1; %新定义的一个变量clusterGroupId为1maxSimilar=0; %新定义,相似度for clusterCountI= visit:count %目前 count为1 定义新变量clusterCountI I来确定这一帧归属于第一个聚类还是第二个聚类sR=0;sG=0;sB=0;%运用颜色直方图法的差别函数for j=1:256sR=min(centrodR(clusterCountI,j),tmpCountR(j))+sR;%,j从1到256,第一帧中R的所有值256个亮度 以及第二帧的红色直方图所有高度值 进行比较选最小的sG=min(centrodG(clusterCountI,j),tmpCountG(j))+sG;sB=min(centrodB(clusterCountI,j),tmpCountB(j))+sB;enddR=sR/sum(tmpCountR);dG=sG/sum(tmpCountG);dB=sB/sum(tmpCountB);%YUV,persons are sensitive to Yd=0.30*dR+0.59*dG+0.11*dB; %运用颜色直方图法的差别函数 定义了d 差别函数if d>maxSimilarclusterGroupId=clusterCountI;maxSimilar=d;endendif maxSimilar>threshold%相似度大,与该聚类质心距离小%加入该聚类,并调整质心for ii=1:256 centrodR(clusterGroupId,ii)=centrodR(clusterGroupId,ii)*clusterCount(clusterGroupId)/(clusterCount(clusterGroupId)+1)+tmpCountR(ii)*1.0/(clusterCount(clusterGroupId)+1);centrodG(clusterGroupId,ii)=centrodG(clusterGroupId,ii)*clusterCount(clusterGroupId)/(clusterCount(clusterGroupId)+1)+tmpCountG(ii)*1.0/(clusterCount(clusterGroupId)+1);centrodB(clusterGroupId,ii)=centrodB(clusterGroupId,ii)*clusterCount(clusterGroupId)/(clusterCount(clusterGroupId)+1)+tmpCountB(ii)*1.0/(clusterCount(clusterGroupId)+1);endclusterCount(clusterGroupId)=clusterCount(clusterGroupId)+1;cluster(k)=clusterGroupId; %第k帧在第clusterGroupId个聚类里面 cluster(3)等于1或者2,,也就是属于第一个聚类或者第二个聚类else%形成新的聚类,增加一个聚类质心count=count+1;visit = visit+1;clusterCount(count)=clusterCount(count)+1;centrodR(count,:)=tmpCountR;centrodG(count,:)=tmpCountG;centrodB(count,:)=tmpCountB;cluster(k)=count; %第k帧在第count个聚类里面 否则 cluster(k)就在新建的聚类中endend%至此,所有帧都划进相应的聚类,一共有count个聚类,第k帧在第cluster(k)聚类中%现欲取出每个聚类中离质心距离最近,即相似度最大的作为该聚类的关键帧maxSimilarity=zeros(1,count);frame=zeros(1,count);for i=1:numsR=0;sG=0;sB=0;%运用颜色直方图法的差别函数for j=1:256sR=min(centrodR(cluster(i),j),tmpCountR(j))+sR;%每一帧和聚类质心进行比较,取最小值 sG=min(centrodG(cluster(i),j),tmpCountG(j))+sG;sB=min(centrodB(cluster(i),j),tmpCountB(j))+sB;enddR=sR/sum(tmpCountR);dG=sG/sum(tmpCountG);dB=sB/sum(tmpCountB);%YUV,persons are sensitive to Yd=0.30*dR+0.59*dG+0.11*dB;if d>maxSimilarity(cluster(i))maxSimilarity(cluster(i))=d;frame(cluster(i))=i;endendfor j=1:countkey(frame(j))=1;figure(j);imshow(strcat('images/',filenames(frame(j)).name));end
endkeyFrameIndexes=find(key)

这种方法在878帧图片中提取出198帧,冗余度还是比较高。

(11) 使用CNN来保存图片在使用聚类法提取关键帧,这种方法由于TensorFlow环境搭配的有问题,没有实际运行,在这给出链接

和这个


三、整理结果

博主使用一分十五秒00000.MP4视频, 共1898帧,分为七类,帧差最大值帧间差法提取的效果很好。k-means聚类法效果不好,原因在于(1)代码是copy 别人的,没有进行优化,(2)博主对帧间聚类方法理论研究浅薄,指导不了实践。

k-means聚类 提出484帧

帧差最大值帧间差法提取出35帧


参考资料:

[1]苏筱涵.深度学习视角下视频关键帧提取与视频检索研究[J].网络安全技术与应用,2020(05):65-66.

[2]王红霞,王磊,晏杉杉.视频检索中的关键帧提取方法研究[J].沈阳理工大学学报,2019,38(03):78-82.

[3]王俊玲,卢新明.基于语义相关的视频关键帧提取算法[J/OL].计算机工程与应用:1-10[2020-11-04].http://kns.cnki.net/kcms/detail/11.2127.TP.20200319.1706.018.html.

[4] 张晓宇,张云华.基于融合特征的视频关键帧提取方法.计算机系统应用,2019,28(11):176–181. http://www.c-s-a.org.cn/1003-3254/7163.html

[5] [1]周舟,韩芳,王直杰.面向手语识别的视频关键帧提取和优化算法[J/OL].华东理工大学学报(自然科学版):1-8[2020-11-05].https://doi.org/10.14135/j.cnki.1006-3080.20191201002.

附录:

1、数字视音频处理知识点小结

[2020-11-04].http://kns.cnki.net/kcms/detail/11.2127.TP.20200319.1706.018.html.

[4] 张晓宇,张云华.基于融合特征的视频关键帧提取方法.计算机系统应用,2019,28(11):176–181. http://www.c-s-a.org.cn/1003-3254/7163.html

[5] [1]周舟,韩芳,王直杰.面向手语识别的视频关键帧提取和优化算法[J/OL].华东理工大学学报(自然科学版):1-8[2020-11-05].https://doi.org/10.14135/j.cnki.1006-3080.20191201002.
[6] https://me.csdn.net/cungudafa这位小姐姐的博客

附录:

1、数字视音频处理知识点小结


推荐阅读
  • PyTorch实用技巧汇总(持续更新中)
    空洞卷积(Dilated Convolutions)在卷积操作中通过在卷积核元素之间插入空格来扩大感受野,这一过程由超参数 dilation rate 控制。这种技术在保持参数数量不变的情况下,能够有效地捕捉更大范围的上下文信息,适用于多种视觉任务,如图像分割和目标检测。本文将详细介绍空洞卷积的计算原理及其应用场景。 ... [详细]
  • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
    在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • 本文探讨了一种高效的算法,用于生成所有数字(0-9)的六位组合,允许重复使用数字,并确保这些组合的和等于给定的整数N。该算法通过优化搜索策略,显著提高了计算效率,适用于大规模数据处理和组合优化问题。 ... [详细]
  • 在《数字图像处理及应用(MATLAB)第4章》中,详细探讨了“逢七必过”游戏规则的实现方法,并结合数字图像处理技术进行了深入分析。本章通过丰富的实例和代码示例,展示了如何利用MATLAB实现这一游戏规则,并介绍了数字图像处理的基本原理和技术应用。内容涵盖了图像增强、滤波、边缘检测等多个方面,为读者提供了全面的技术支持和实践指导。 ... [详细]
  • 如何使用 `org.eclipse.rdf4j.query.impl.MapBindingSet.getValue()` 方法及其代码示例详解 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • 优化后的标题:深入探讨网关安全:将微服务升级为OAuth2资源服务器的最佳实践
    本文深入探讨了如何将微服务升级为OAuth2资源服务器,以订单服务为例,详细介绍了在POM文件中添加 `spring-cloud-starter-oauth2` 依赖,并配置Spring Security以实现对微服务的保护。通过这一过程,不仅增强了系统的安全性,还提高了资源访问的可控性和灵活性。文章还讨论了最佳实践,包括如何配置OAuth2客户端和资源服务器,以及如何处理常见的安全问题和错误。 ... [详细]
  • 当使用 `new` 表达式(即通过 `new` 动态创建对象)时,会发生两件事:首先,内存被分配用于存储新对象;其次,该对象的构造函数被调用以初始化对象。为了确保资源管理的一致性和避免内存泄漏,建议在使用 `new` 和 `delete` 时保持形式一致。例如,如果使用 `new[]` 分配数组,则应使用 `delete[]` 来释放内存;同样,如果使用 `new` 分配单个对象,则应使用 `delete` 来释放内存。这种一致性有助于防止常见的编程错误,提高代码的健壮性和可维护性。 ... [详细]
  • 本文探讨了利用JavaScript实现集合的对称差集算法的方法。该算法旨在处理多个数组作为输入参数,同时保留每个数组中元素的原始顺序。算法不会移除单个数组内的重复元素,但会删除在不同数组之间出现的重复项。通过这种方式,能够有效地计算出多个数组的对称差集。 ... [详细]
  • 使用 `git stash` 可以将当前未提交的修改保存到一个临时存储区,以便在后续恢复工作目录时使用。例如,在处理中间状态时,可以通过 `git stash` 命令将当前的所有未提交更改推送到一个新的储藏中,从而保持工作目录的整洁。此外,本文还将详细介绍如何解决 `git stash pop` 时可能出现的冲突问题,帮助用户高效地管理代码变更。 ... [详细]
  • #30 序列压缩算法优化与实现
    本文探讨了序列压缩算法的优化与实现,旨在提高数据存储效率和处理速度。通过对现有算法的深入分析,提出了一种新的优化方法,该方法在保持高压缩比的同时,显著降低了计算复杂度。实验结果表明,新方法在多种数据集上均表现出色,具有广泛的应用前景。 ... [详细]
  • 本文介绍了一种算法,用于计算当前日期在本年度的具体周数。该方法由作者王峰提出,通过私有函数 `weekOfYear` 实现,能够准确地确定当前日期在一年中的周位置。此算法在日历计算和时间管理中具有广泛应用,适用于各种编程语言和应用场景。 ... [详细]
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
author-avatar
那一年2502931247
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有