All basketball teams have a camera system called SportVU installed in their arenas. These camera systems track players and the ball throughout a basketball game.

所有篮球队在赛场上都安装了名为SportVU的摄像头系统。 这些摄像机系统在整个篮球比赛中跟踪球员和球。

The data produced by sportsvu camera systems used to be freely available on NBA.com, but was recently removed (I have no idea why). Luckily, the data for about 600 games are available on neilmj’s github. In this post, I show how to create a video recreation of a given basketball play using the sportsvu data.

sportsvu摄像机系统产生的数据曾经可以在NBA.com上免费获得,但是最近被删除了(我不知道为什么)。 幸运的是,可以在neilmj的github上找到大约600场比赛的数据。 在本文中,我将展示如何使用sportsvu数据为给定的篮球比赛创建视频娱乐。

This code is also available as a jupyter notebook on my github.

此代码也可以在我的github上作为jupyter笔记本使用。

1
1
2
2
3
3
4
4
5
5

The data is provided as a json. Here’s how to import the python json library and load the data. I’m a T-Wolves fan, so the game I chose is a wolves game.

数据作为json提供。 这是导入python json库和加载数据的方法。 我是T-狼队的球迷,所以我选择的游戏是狼队游戏。

1
1
2
2
3
3

Let’s take a quick look at the data. It’s a dictionary with three keys: gamedate, gameid, and events. Gamedate and gameid are the date of this game and its specific id number, respectively. Events is the structure with data we’re interested in.

让我们快速看一下数据。 这是一本具有三个键的字典:gamedate,gameid和events。 Gamedate和gameid分别是该游戏的日期及其特定的ID号。 事件是我们感兴趣的数据结构。

1
1
[u'gamedate', u'gameid', u'events']
[u'gamedate', u'gameid', u'events']
 

Lets take a look at the first event. The first event has an associated eventid number. We will use these later. There’s also data for each player on the visiting and home team. We will use these later too. Finally, and most importantly, there’s the “moments.” There are 25 moments for each second of the “event” (the data is sampled at 25hz).

让我们看一下第一个事件。 第一个事件具有关联的事件ID号。 我们稍后将使用它们。 还有来访和主队中每个球员的数据。 我们也将在以后使用它们。 最后,最重要的是,存在“时刻”。 “事件”的每一秒有25个瞬间(数据以25hz采样)。

data['events'][0].keys()
data [ 'events' ][ 0 ] . keys ()
 

Here’s the first moment of the first event. The first number is the quarter. The second number is the time of the event in milliseconds. The third number is the number of seconds left in the quarter (the 1st quarter hasn’t started yet, so 12 * 60 = 720). The fourth number is the number of seconds left on the shot clock. I am not sure what fourth number (None) represents.

这是第一场比赛的第一刻。 第一个数字是四分之一。 第二个数字是事件的时间(以毫秒为单位)。 第三个数字是该季度剩余的秒数(第一个季度尚未开始,因此12 * 60 = 720)。 第四个数字是射击时钟上剩余的秒数。 我不确定第四个数字(无)代表什么。

The final matrix is 11×5 matrix. The first row describes the ball. The first two columns are the teamID and the playerID of the ball (-1 for both because the ball does not belong to a team and is not a player). The 3rd and 4th columns are xy coordinates of the ball. The final column is the height of the ball (z coordinate).

最终矩阵是11×5矩阵。 第一行描述了球。 前两列是球的teamID和玩家ID(对于两个都为-1,因为球不属于团队且不是玩家)。 第三和第四列是球的xy坐标。 最后一列是球的高度(z坐标)。

The next 10 rows describe the 10 players on the court. The first 5 players belong to the home team and the last 5 players belong to the visiting team. Each player has his teamID, playerID, xy&z coordinates (although I don’t think players’ z coordinates ever change).

接下来的10行描述了球场上的10位玩家。 前5名球员属于主队,后5名球员属于客队。 每个玩家都有自己的teamID,playerID,xy&z坐标(尽管我认为玩家的z坐标不会改变)。

1
1
[1,1452903036782,720.0,24.0,None,[[-1, -1, 44.16456, 26.34142, 5.74423],[1610612760, 201142, 45.46259, 32.01456, 0.0],[1610612760, 201566, 10.39347, 24.77219, 0.0],[1610612760, 201586, 25.86087, 25.55881, 0.0],[1610612760, 203460, 47.28525, 17.76225, 0.0],[1610612760, 203500, 43.68634, 26.63098, 0.0],[1610612750, 708, 55.6401, 25.55583, 0.0],[1610612750, 2419, 47.95942, 31.66328, 0.0],[1610612750, 201937, 67.28725, 25.10267, 0.0],[1610612750, 203952, 47.28525, 17.76225, 0.0],[1610612750, 1626157, 49.46814, 24.24193, 0.0]]]
[1,1452903036782,720.0,24.0,None,[[-1, -1, 44.16456, 26.34142, 5.74423],[1610612760, 201142, 45.46259, 32.01456, 0.0],[1610612760, 201566, 10.39347, 24.77219, 0.0],[1610612760, 201586, 25.86087, 25.55881, 0.0],[1610612760, 203460, 47.28525, 17.76225, 0.0],[1610612760, 203500, 43.68634, 26.63098, 0.0],[1610612750, 708, 55.6401, 25.55583, 0.0],[1610612750, 2419, 47.95942, 31.66328, 0.0],[1610612750, 201937, 67.28725, 25.10267, 0.0],[1610612750, 203952, 47.28525, 17.76225, 0.0],[1610612750, 1626157, 49.46814, 24.24193, 0.0]]]
 

Alright, so we have the sportsvu data, but its not clear what each event is. Luckily, the NBA also provides play by play (pbp) data. I write a function for acquiring play by play game data. This function collects (and trims) the play by play data for a given sportsvu data set.

好了,所以我们有了sportsvu数据,但不清楚每个事件是什么。 幸运的是,NBA还提供逐场比赛(pbp)数据。 我编写了一个通过玩游戏数据获取玩游戏的功能。 此功能针对给定的sportsvu数据集按播放数据收集(和修剪)该播放。

def acquire_gameData(data):
    import requests
    header_data = { #I pulled this header from the py goldsberry library
        'Accept-Encoding': 'gzip, deflate, sdch',
        'Accept-Language': 'en-US,en;q=0.8',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64)'
        ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 '
        'Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9'
        ',image/webp,*/*;q=0.8',
        'Cache-Control': 'max-age=0',
        'Connection': 'keep-alive'
    }
    game_url = 'http://stats.nba.com/stats/playbyplayv2?EndPeriod=0&EndRange=0&GameID='+data['gameid']+
                '&RangeType=0&StartPeriod=0&StartRange=0' #address for querying the data
    response = requests.get(game_url,headers = header_data) #go get the data
    headers = response.json()['resultSets'][0]['headers'] #get headers of data
    gameData = response.json()['resultSets'][0]['rowSet'] #get actual data from json object
    df = pd.DataFrame(gameData, columns=headers) #turn the data into a pandas dataframe
    df = df[[df.columns[1], df.columns[2],df.columns[7],df.columns[9],df.columns[18]]] #there's a ton of data here, so I trim  it doown
    df['TEAM'] = df['PLAYER1_TEAM_ABBREVIATION']
    df = df.drop('PLAYER1_TEAM_ABBREVIATION', 1)
    return df
def acquire_gameData ( data ):import requestsheader_data = { #I pulled this header from the py goldsberry library'Accept-Encoding' : 'gzip, deflate, sdch' ,'Accept-Language' : 'en-US,en;q=0.8' ,'Upgrade-Insecure-Requests' : '1' ,'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; WOW64)'' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.82 ''Safari/537.36' ,'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9'',image/webp,*/*;q=0.8' ,'Cache-Control' : 'max-age=0' ,'Connection' : 'keep-alive'}game_url = 'http://stats.nba.com/stats/playbyplayv2?EndPeriod=0&EndRange=0&GameID=' + data [ 'gameid' ] +'&RangeType=0&StartPeriod=0&StartRange=0' #address for querying the dataresponse = requests . get ( game_url , headers = header_data ) #go get the dataheaders = response . json ()[ 'resultSets' ][ 0 ][ 'headers' ] #get headers of datagameData = response . json ()[ 'resultSets' ][ 0 ][ 'rowSet' ] #get actual data from json objectdf = pd . DataFrame ( gameData , columns = headers ) #turn the data into a pandas dataframedf = df [[ df . columns [ 1 ], df . columns [ 2 ], df . columns [ 7 ], df . columns [ 9 ], df . columns [ 18 ]]] #there's a ton of data here, so I trim  it doowndf [ 'TEAM' ] = df [ 'PLAYER1_TEAM_ABBREVIATION' ]df = df . drop ( 'PLAYER1_TEAM_ABBREVIATION' , 1 )return df
 

Below I show what the play by play data looks like. There’s a column for event number (eventnum). These event numbers match up with the event numbers from the sportsvu data, so we will use this later for seeking out specific plays in the sportsvu data. There’s a column for the event type (eventmsgtype). This column has a number describing what occured in the play. I list these number codes in the comments below.

在下面,我显示了逐次播放数据的样子。 有一个事件号(eventnum)列。 这些事件编号与来自sportsvu数据的事件编号匹配,因此我们稍后将使用它来查找sportsvu数据中的特定比赛。 这里有一个事件类型列(eventmsgtype)。 此列中有一个数字,描述剧中发生的事情。 我在下面的评论中列出了这些数字代码。

There’s also short text descriptions of the plays in the home description and visitor description columns. Finally, I use the team column to represent the primary team involved in a play.

在首页说明和访客说明列中也有关于剧本的简短文字说明。 最后,我使用“团队”列来表示比赛中涉及的主要团队。

I stole the idea of using play by play data from Raji Shah.

我偷走了拉吉·沙 ( Raji Shah)的逐次使用比赛数据的想法。

df = acquire_gameData(data)
df.head()
#EVENTMSGTYPE
#1 - Make
#2 - Miss
#3 - Free Throw
#4 - Rebound
#5 - out of bounds / Turnover / Steal
#6 - Personal Foul
#7 - Violation
#8 - Substitution
#9 - Timeout
#10 - Jumpball
#12 - Start Q1?
#13 - Start Q2?
df = acquire_gameData ( data )df . head ()#EVENTMSGTYPE#1 - Make #2 - Miss #3 - Free Throw #4 - Rebound #5 - out of bounds / Turnover / Steal #6 - Personal Foul #7 - Violation #8 - Substitution #9 - Timeout #10 - Jumpball #12 - Start Q1? #13 - Start Q2?
 
EVENTNUM 事件编号 EVENTMSGTYPE 偶数类型 HOMEDESCRIPTION 家庭说明 VISITORDESCRIPTION 访客说明 TEAM 球队
0 0 0 0 12 12 None 没有 None 没有 None 没有
1 1个 1 1个 10 10 Jump Ball Adams vs. Towns: Tip to Ibaka 亚当斯(Adams)vs. Towns(跳城镇):伊巴卡(Ibaka)提示 None 没有 OKC OKC
2 2 2 2 5 5 Westbrook Out of Bounds Lost Ball Turnover (P1… 威斯布鲁克超出禁区丢球失误(P1… None 没有 OKC OKC
3 3 3 3 2 2 None 没有 MISS Wiggins 16′ Jump Shot 威金斯小姐16′跳投 MIN 最低
4 4 4 4 4 4 Westbrook REBOUND (Off:0 Def:1) 威斯布鲁克反弹(Off:0 Def:1) None 没有 OKC OKC

When viewing the videos, its nice to know what players are on the court. I like to depict this by labeling each player with their number. Here I create a dictionary that contains each player’s id number (these are assigned by nba.com) as the key and their jersey number as the associated value.

观看视频时,很高兴知道场上有哪些球员。 我喜欢用每个球员的号码来标记他们的位置。 在这里,我创建了一个词典,其中包含每个玩家的ID号(这些密钥由nba.com分配)作为键,而其球衣号码作为关联值。

player_fields = data['events'][0]['home']['players'][0].keys()
home_players = pd.DataFrame(data=[i for i in data['events'][0]['home']['players']], columns=player_fields)
away_players = pd.DataFrame(data=[i for i in data['events'][0]['visitor']['players']], columns=player_fields)
players = pd.merge(home_players, away_players, how='outer')
jerseydict = dict(zip(players.playerid.values, players.jersey.values))
player_fields = data [ 'events' ][ 0 ][ 'home' ][ 'players' ][ 0 ] . keys ()home_players = pd . DataFrame ( data = [ i for i in data [ 'events' ][ 0 ][ 'home' ][ 'players' ]], columns = player_fields )away_players = pd . DataFrame ( data = [ i for i in data [ 'events' ][ 0 ][ 'visitor' ][ 'players' ]], columns = player_fields )players = pd . merge ( home_players , away_players , how = 'outer' )jerseydict = dict ( zip ( players . playerid . values , players . jersey . values ))
 

Alright, almost there! Below I write some functions for creating the actual video! First, there’s a short function for placing an image of the basketball court beneath our depiction of players moving around. This image is from gmf05’s github, but I will provide it on mine too.

好吧,快到了! 在下面,我写了一些用于创建实际视频的功能! 首先,有一个简短的功能将篮球场的图像放置在我们描绘的运动员走动下方。 该图像来自gmf05的github,但我也将在我的图像上提供它。

Much of this code is either straight from gmf05’s github or slightly modified.

大部分代码要么直接来自gmf05的github,要么进行了稍微的修改。

# Animation function / loop
def draw_court(axis):
    import matplotlib.image as mpimg
    img = mpimg.imread('./nba_court_T.png') #read image. I got this image from gmf05's github.
    plt.imshow(img,extent=axis, zorder=0) #show the image. 

def animate(n): #matplotlib's animation function loops through a function n times that draws a different frame on each iteration
    for i,ii in enumerate(player_xy[n]): #loop through all the players
        player_circ[i].center = (ii[1], ii[2]) #change each players xy position
        player_text[i].set_text(str(jerseydict[ii[0]])) #draw the text for each player.
        player_text[i].set_x(ii[1]) #set the text x position
        player_text[i].set_y(ii[2]) #set text y position
    ball_circ.center = (ball_xy[n,0],ball_xy[n,1]) #change ball xy position
    ball_circ.radius = 1.1 #i could change the size of the ball according to its height, but chose to keep this constant
    return tuple(player_text) + tuple(player_circ) + (ball_circ,)

def init(): #this is what matplotlib's animation will create before drawing the first frame.
    for i in range(10): #set up players
        player_text[i].set_text('')
        ax.add_patch(player_circ[i])
    ax.add_patch(ball_circ) #create ball
    ax.axis('off') #turn off axis
    dx = 5
    plt.xlim([0-dx,100+dx]) #set axis
    plt.ylim([0-dx,50+dx])
    return tuple(player_text) + tuple(player_circ) + (ball_circ,)
# Animation function / loopdef draw_court ( axis ):import matplotlib.image as mpimgimg = mpimg . imread ( './nba_court_T.png' ) #read image. I got this image from gmf05's github.plt . imshow ( img , extent = axis , zorder = 0 ) #show the image. def animate ( n ): #matplotlib's animation function loops through a function n times that draws a different frame on each iterationfor i , ii in enumerate ( player_xy [ n ]): #loop through all the playersplayer_circ [ i ] . center = ( ii [ 1 ], ii [ 2 ]) #change each players xy positionplayer_text [ i ] . set_text ( str ( jerseydict [ ii [ 0 ]])) #draw the text for each player. player_text [ i ] . set_x ( ii [ 1 ]) #set the text x positionplayer_text [ i ] . set_y ( ii [ 2 ]) #set text y positionball_circ . center = ( ball_xy [ n , 0 ], ball_xy [ n , 1 ]) #change ball xy positionball_circ . radius = 1.1 #i could change the size of the ball according to its height, but chose to keep this constantreturn tuple ( player_text ) + tuple ( player_circ ) + ( ball_circ ,)def init (): #this is what matplotlib's animation will create before drawing the first frame. for i in range ( 10 ): #set up playersplayer_text [ i ] . set_text ( '' )ax . add_patch ( player_circ [ i ])ax . add_patch ( ball_circ ) #create ballax . axis ( 'off' ) #turn off axisdx = 5plt . xlim ([ 0 - dx , 100 + dx ]) #set axisplt . ylim ([ 0 - dx , 50 + dx ])return tuple ( player_text ) + tuple ( player_circ ) + ( ball_circ ,)
 

The event that I want to depict is event 41. In this event, Karl Anthony Towns misses a shot, grabs his own rebounds, and puts it back in.

我要描述的事件是事件41。在此事件中,卡尔·安东尼·汤斯(Karl Anthony Towns)投篮未中,抢下自己的篮板,然后放回去。

df[37:38]
df [ 37 : 38 ]
 
EVENTNUM 事件编号 EVENTMSGTYPE 偶数类型 HOMEDESCRIPTION 家庭说明 VISITORDESCRIPTION 访客说明 TEAM 球队
37 37 41 41 1 1个 None 没有 Towns 1′ Layup (2 PTS) Towns 1′Layup(2分) MIN 最低

We need to find where event 41 is in the sportsvu data structure, so I created a function for finding the location of a particular event. I then create a matrix with position data for the ball and a matrix with position data for each player for event 41.

我们需要找到事件41在sportsvu数据结构中的位置,因此我创建了一个用于查找特定事件位置的函数。 然后,我为事件41创建一个包含球位置数据的矩阵和一个包含每个球员位置数据的矩阵。

#the order of events does not match up, so we have to use the eventIds. This loop finds the correct event for a given id#.
search_id = 41
def find_moment(search_id):
    for i,events in enumerate(data['events']):
        if events['eventId'] == str(search_id):
            finder = i
            break
    return finder

event_num = find_moment(search_id)
ball_xy = np.array([x[5][0][2:5] for x in data['events'][event_num]['moments']]) #create matrix of ball data
player_xy = np.array([np.array(x[5][1:])[:,1:4] for x in data['events'][event_num]['moments']]) #create matrix of player data
#the order of events does not match up, so we have to use the eventIds. This loop finds the correct event for a given id#.search_id = 41def find_moment ( search_id ):for i , events in enumerate ( data [ 'events' ]):if events [ 'eventId' ] == str ( search_id ):finder = ibreakreturn finderevent_num = find_moment ( search_id )ball_xy = np . array ([ x [ 5 ][ 0 ][ 2 : 5 ] for x in data [ 'events' ][ event_num ][ 'moments' ]]) #create matrix of ball dataplayer_xy = np . array ([ np . array ( x [ 5 ][ 1 :])[:, 1 : 4 ] for x in data [ 'events' ][ event_num ][ 'moments' ]]) #create matrix of player data
 

Okay. We’re actually there! Now we get to create the video. We have to create figure and axes objects for the animation to draw on. Then I place a picture of the basketball court on this plot. Finally, I create the circle and text objects that will move around throughout the video (depicting the ball and players). The location of these objects are then updated in the animation loop.

好的。 我们实际上在那里! 现在我们来创建视频。 我们必须创建图形对象和坐标轴对象才能绘制动画。 然后,我将篮球场的图片放在该图上。 最后,我创建了将在整个视频中移动的圆圈和文本对象(描述了球和球员)。 然后在动画循环中更新这些对象的位置。

import matplotlib.animation as animation

fig = plt.figure(figsize=(15,7.5)) #create figure object
ax = plt.gca() #create axis object

draw_court([0,100,0,50]) #draw the court
player_text = range(10) #create player text vector
player_circ = range(10) #create player circle vector
ball_circ = plt.Circle((0,0), 1.1, color=[1, 0.4, 0]) #create circle object for bal
for i in range(10): #create circle object and text object for each player
    col=['w','k'] if i<5 else ['k','w'] #color scheme
    player_circ[i] = plt.Circle((0,0), 2.2, facecolor=col[0],edgecolor='k') #player circle
    player_text[i] = ax.text(0,0,'',color=col[1],ha='center',va='center') #player jersey # (text)

ani = animation.FuncAnimation(fig, animate, frames=np.arange(0,np.size(ball_xy,0)), init_func=init, blit=True, interval=5, repeat=False,
                             save_count=0) #function for making video
ani.save('Event_%d.mp4' % (search_id),dpi=100,fps=25) #function for saving video
plt.close('all') #close the plot
import matplotlib.animation as animationfig = plt . figure ( figsize = ( 15 , 7.5 )) #create figure objectax = plt . gca () #create axis objectdraw_court ([ 0 , 100 , 0 , 50 ]) #draw the courtplayer_text = range ( 10 ) #create player text vectorplayer_circ = range ( 10 ) #create player circle vectorball_circ = plt . Circle (( 0 , 0 ), 1.1 , color = [ 1 , 0.4 , 0 ]) #create circle object for balfor i in range ( 10 ): #create circle object and text object for each playercol = [ 'w' , 'k' ] if i < 5 else [ 'k' , 'w' ] #color schemeplayer_circ [ i ] = plt . Circle (( 0 , 0 ), 2.2 , facecolor = col [ 0 ], edgecolor = 'k' ) #player circleplayer_text [ i ] = ax . text ( 0 , 0 , '' , color = col [ 1 ], ha = 'center' , va = 'center' ) #player jersey # (text)ani = animation . FuncAnimation ( fig , animate , frames = np . arange ( 0 , np . size ( ball_xy , 0 )), init_func = init , blit = True , interval = 5 , repeat = False ,save_count = 0 ) #function for making videoani . save ( 'Event_ %d .mp4' % ( search_id ), dpi = 100 , fps = 25 ) #function for saving videoplt . close ( 'all' ) #close the plot
 

翻译自: https://www.pybloggers.com/2016/06/creating-videos-of-nba-action-with-sportsvu-data/

使用Sportsvu数据创建NBA动作视频相关推荐

  1. Make-A-Video(造啊视频)——无需文字-视频数据的文字转视频(文生视频)生成方法

    © 2022 Uriel Singer et al (Meta AI) © 2023 Conmajia 本文基于论文 Make-A-Video: Text-to-Video Generation wi ...

  2. 学习在Unity中创建一个动作RPG游戏

    游戏开发变得简单.使用Unity学习C#并创建您自己的动作角色扮演游戏! 你会学到什么 学习C#,一种现代通用的编程语言. 了解Unity中2D发展的能力. 发展强大的和可移植的解决问题的技能. 了解 ...

  3. 视频教程-Excel数据透视表实战视频课程【你学得会】-Office/WPS

    Excel数据透视表实战视频课程[你学得会] Office中国金牌讲师,从事企业信息系统解决方案专业认识,Office二次开发讲师.拥有多年C#,VB和VBA开发经验和教学经验,擅长讲授Access. ...

  4. 创建人物特写视频flash教程(五)

    现在您已创建了该视频,下面介绍了如何在 Flash Professional 8 中使用视频导入向导创建 FLV: 打开一个新的 Flash Professional 8 文档,然后选择"文 ...

  5. spark1.4加载mysql数据 创建Dataframe及join操作连接方法问题

    首先我们使用新的API方法连接mysql加载数据 创建DF import org.apache.spark.sql.DataFrame import org.apache.spark.{SparkCo ...

  6. 大数据时代的网络视频营销

    2019独角兽企业重金招聘Python工程师标准>>> 大数据时代的网络视频营销 在大数据时代的今天,视频网站优质的内容资源为品牌广告营销提供丰富的可能性及传播机会,品牌元素与视频内 ...

  7. SQL Server 2000安装指南及数据创建

    SQL Server 是一个关系数据库管理系统,它最初是由Microsoft Sybase 和Ashton-Tate三家公司共同开发的,于1988 年推出了第一个OS/2 版本.在Windows NT ...

  8. Spark _24 _读取JDBC中的数据创建DataFrame/DataSet(MySql为例)(三)

    两种方式创建DataSet 现在数据库中创建表不能给插入少量数据. javaapi: package SparkSql;import org.apache.spark.SparkConf; impor ...

  9. php课程 4-15 数组遍历、超全局数组、表单提交数据(多看学习视频)

    php课程 4-15  数组遍历.超全局数组.表单提交数据(多看学习视频) 一.总结 一句话总结:超全局数组特别有用,比如$_SERVER可以获取所有的客户端访问服务器的情况. 1.数组遍历三种方式( ...

最新文章

  1. acwing算法题--看图做题
  2. Linux 查看 80 端口的占用情况
  3. 走,去谷歌的机房逛逛
  4. BZOJ 2959 长跑 (LCT、并查集)
  5. 数据库开发——MySQL——primary key
  6. 使用 Packer、Ansible 和 Terraform 构建不可变的基础设施Devops工具链
  7. php无限评论回复_php如何制作无限级评论功能?
  8. Java 并发(JUC 包-01)
  9. kafka详解及搭建
  10. 收购YY直播,百度重返高位的关键布局
  11. Redis数据结构、持久化、缓存技术和集群详解
  12. Quartz入门指南
  13. PHP期望T_PAAMAYIM_NEKUDOTAYIM?
  14. 用C语言做的即时通讯软件,即时通讯软件代码-C语言来编写类似QQ的即时通讯软件求代码!!!...
  15. foxmail超大附件密码不对的解决办法
  16. 单目深度估计--深度学习篇
  17. 转:无损压缩和有损压缩
  18. 出现这十种症状,说明你不适合干程序员
  19. 基于微信小程序的免费小说阅读平台小程序的设计与实现 毕业设计 毕设源码(1)小程序功能
  20. 雷霆复鸣 决战巅峰 | 第七届XCTF国际网络攻防联赛总决赛即刻启航!

热门文章

  1. 面试自我介绍如何介绍呢?
  2. 运筹学状态转移方程例子_动态规划 Dynamic Programming
  3. Servlet/JSP(2)-数据共享(Cookie Session等),分页
  4. 修改Centos7/RHEL7的主机名
  5. 使用Bert完成实体之间关系抽取
  6. 毕设笔记01-解决树莓派烧写系统显示屏不显示问题
  7. 2.编写程序,将华氏度转换为摄氏度
  8. PT是代表什么缩写,PT下载又是指的什么意思?
  9. python 如何计算平方、次方?平方根、方根?(math.pow()、math.sqrt())
  10. 【数据挖掘】频繁模式挖掘及Python实现