<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          使用 Python 和 OpenCV 制作反應(yīng)游戲

          共 19902字,需瀏覽 40分鐘

           ·

          2024-04-19 10:20

          點(diǎn)擊上方小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂

          重磅干貨,第一時(shí)間送達(dá)

          在本文中,將向你展示如何使用 OpenCV 在 Python 中制作一個(gè)反應(yīng)游戲,你可以動(dòng)手來玩。

          你可能已經(jīng)熟悉 OpenCV,OpenCV 基本上允許進(jìn)行各種圖像處理。

          你可以在下面的視頻中看到最終結(jié)果,并且可以在此處獲取文件:https://github.com/Goncalo-Chambel/ReactionGame

          盡管這可能看起來很復(fù)雜(取決于你的專業(yè)知識(shí)),但在我們看來,這是一個(gè)相當(dāng)簡(jiǎn)單但很有趣的項(xiàng)目。你基本上可以用 200 行代碼創(chuàng)建一個(gè)游戲(這代碼量很少了!)。

          我們將把任務(wù)分成幾個(gè)部分:設(shè)置+手部檢測(cè)主要游戲機(jī)制創(chuàng)建實(shí)際游戲最后潤(rùn)色

          第 1 步:設(shè)置 + 手部檢測(cè)

          這個(gè)項(xiàng)目的主要目標(biāo)是創(chuàng)建一個(gè)反應(yīng)游戲,其中圓圈會(huì)隨機(jī)出現(xiàn)在屏幕上,你必須用你的手盡可能快地“觸摸”它們。

          因此,第一個(gè)步驟是讓程序訪問你的網(wǎng)絡(luò)攝像頭。

          為此,我們將使用 OpenCV 庫(kù),為此我們只需添加一行import cv2。就這么簡(jiǎn)單,但如果你還沒有安裝,你必須先安裝它。

          在此處添加了此項(xiàng)目的要求:https://github.com/Goncalo-Chambel/ReactionGame/blob/main/requirements.txt

          因此你可以通過在命令行中鍵入pip install -r requirements.txt來安裝所有這些要求。

          cv2 庫(kù)有很多功能,但讓我們一步一步來第一個(gè)目標(biāo)是告訴 Python 從網(wǎng)絡(luò)攝像頭讀取數(shù)據(jù)并將其顯示在屏幕上。這可以通過使用函數(shù)cv2.VideoCapture()來完成

          import cv2
          cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

          現(xiàn)在cap變量包含對(duì)你的網(wǎng)絡(luò)攝像頭的引用。然后在我們的主文件中,我們可以創(chuàng)建一個(gè)無限循環(huán),每次迭代都會(huì)顯示網(wǎng)絡(luò)攝像頭捕獲的當(dāng)前圖像。

          import cv2
          cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
          cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)  # set width of window
          cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)  # set height of window

          while True:
              ret, frame = cap.read()
              cv2.imshow("Reaction Game", frame)
              k = cv2.waitKey(1) & 0xFF
              if k == ord('q'):
                  break

          有了這幾行代碼,我們應(yīng)該有一個(gè)程序,這個(gè)程序可以簡(jiǎn)單地打開一個(gè)新窗口(名為“反應(yīng)游戲”),大小為 1280 x 720 像素,帶有網(wǎng)絡(luò)攝像頭的視頻源。我還添加了最后幾行代碼,以便你可以關(guān)閉窗口并按“q”退出程序。

          現(xiàn)在我們可以繼續(xù)檢測(cè)手了。創(chuàng)建一個(gè)算法來檢測(cè)視頻中的手是一項(xiàng)復(fù)雜的任務(wù),但幸運(yùn)的是我們不必重新發(fā)明輪子。有一個(gè)非常好的庫(kù)可以為我們做這件事,叫做 CV Zone。

          CV Zone 允許各種與對(duì)象檢測(cè)相關(guān)的項(xiàng)目,但我們主要對(duì) HandDetector 模型感興趣。該模型使我們能夠獲得有關(guān)視頻中被跟蹤手的重要信息,例如它們的中心位置或邊界框。我們初始化模型的方式如下:

          from cvzone.HandTrackingModule import HandDetector
          detector = HandDetector(detectionCon=0.8, maxHands=2)

          其中detectionCon是置信區(qū)間(從0到1),表明你希望模型跟蹤手的精度。更高的值意味著模型更確信被跟蹤的手就是手,但也可能使模型“錯(cuò)過手”,因?yàn)樗鼪]有信心相信它們是手。maxHands參數(shù)僅限制模型一次可以跟蹤的手的數(shù)量。

          然后在我們的主循環(huán)中,我們只調(diào)用函數(shù)detector.findHands()來獲取有關(guān)被跟蹤手的信息。

          while True:
              ret, frame = cap.read()
              hands, frame = detector.findHands(frame, flipType=False)
              cv2.imshow("Reaction Game", frame)

          輸出:

          如你所見,該算法非常擅長(zhǎng)跟蹤手部(包括手指位置)。請(qǐng)注意,根據(jù)你的規(guī)格,該程序可能看起來有點(diǎn)“不穩(wěn)定”。此外,根據(jù)你使用的相機(jī),你可能不需要翻轉(zhuǎn)圖像,只需檢查標(biāo)簽“左手”是否真的對(duì)應(yīng)于你的左手。

          最后,在屏幕上顯示所有這些信息可能會(huì)太混亂,因此我們可以告訴檢測(cè)器不要通過書寫來繪制這些信息

          hands = detector.findHands(frame, flipType=False, draw=False)

          請(qǐng)注意,當(dāng)我們包含參數(shù)draw=False時(shí),detector僅返回手信息(與返回幀相反)。

          第 2 步:主要游戲機(jī)制

          我們現(xiàn)在可以研究我們游戲的基本機(jī)制。基本想法是在屏幕上隨機(jī)生成圓圈并檢測(cè)手是否在觸摸它。

          這里有兩個(gè)主要部分,畫圈檢查碰撞

          畫圈

          這是一個(gè)相對(duì)簡(jiǎn)單的步驟,因?yàn)?em>cv2有一個(gè)內(nèi)置函數(shù)cv2.circle(),可以在屏幕上繪制一個(gè)圓形,該函數(shù)將我們正在繪制的圖像、屏幕上的位置(以像素為單位)、圓的半徑(以像素為單位)、顏色(以BGR) 和線條粗細(xì)作為輸入。所以假設(shè)我們想在屏幕中間放置一個(gè)紅色圓圈,厚度為2,半徑為 50 像素,我們會(huì)這樣做:

          while True:
              ret, frame = cap.read()
              cv2.circle(frame,(int(width/2),int(heigh/2)), 50, (0,0,255), 2)
              cv2.imshow("Reaction Game", frame)

          請(qǐng)注意,此函數(shù)不返回任何內(nèi)容,它會(huì)自動(dòng)更新frame變量。此外,如果你想要一個(gè)實(shí)心圓而不僅僅是輪廓,你可以將粗細(xì)設(shè)置為 -1。

          在繼續(xù)在屏幕上創(chuàng)建隨機(jī)圓圈之前,讓我們先創(chuàng)建自己的Circle類。如果我們想在只處理一個(gè)變量的同時(shí)訪問圓的多個(gè)屬性,這將很方便。這是一個(gè)非常簡(jiǎn)單的類,現(xiàn)在讓我們添加一個(gè)構(gòu)造函數(shù)和一個(gè)draw()方法

          class Circle:

              def __init__(self, coordinates, radius, color, thickness):
                  self.coordinates = coordinates
                  self.radius = radius
                  self.color = color
                  self.thickness = thickness

              def draw(self, _frame):
                  cv2.circle(_frame, self.coordinates, self.radius, self.color, self.thickness)

          現(xiàn)在如果我們想像之前那樣畫一個(gè)圓圈,我們會(huì)這樣做:

          target = Circle((int(width/2),int(heigh/2)), 50, (00,255), 2)
          while True:
              ret, frame = cap.read()
              target.draw(frame)
              cv2.imshow("Reaction Game", frame)

          現(xiàn)在可能看起來不是很有用,但以后會(huì)有所幫助。

          在繼續(xù)討論交集方法本身之前,我們首先需要一些東西來檢查交集。我們已經(jīng)有了一種在屏幕上創(chuàng)建目標(biāo)的方法,但我們需要將其與某些東西進(jìn)行比較。很明顯,有些東西會(huì)是我們的手,但具體是手的哪一部分?

          我們可以使用邊界框,但我覺得這可能太容易了。我們還可以使用手指的位置,例如食指,但這似乎不太直觀。我發(fā)現(xiàn)我認(rèn)為效果最好的方法是使用手的中心位置。

          我們可以在手的中心位置創(chuàng)建另一個(gè)圓圈,這樣我們只需要檢查一個(gè)圓圈是否與另一個(gè)圓圈相交。

          首先我們需要一種方法在手的中心位置創(chuàng)建一個(gè)圓圈。變量handsdetector.findHands()函數(shù)的輸出)是一個(gè)列表,其中每個(gè)項(xiàng)目都是一個(gè)字典,其中包含有關(guān)被跟蹤的手的信息。這個(gè)字典有 4 個(gè)鍵:

          • lmList:21 個(gè)地標(biāo)的位置列表(以像素為單位)
          • bbox : 邊界框的坐標(biāo)和大小(以像素為單位)
          • center : 中心位置的坐標(biāo),以像素為單位
          • type:左手或右手

          從這 4 個(gè)鍵中,我們感興趣的是中心,所以為了得到中心位置,我們這么做:

          while True:
              ret, frame = cap.read()
              hands = detector.findHands(frame, flipType=False, draw=False)
              if hands:
                  for i in range(len(hands)):
                      hand_position = hands[i]["center"]

          我們首先檢查是否檢測(cè)到任何手,如果是,我們可以訪問中心位置,但只需指定鍵“center”。

          現(xiàn)在我們有了創(chuàng)建一個(gè)圓圈的方法,我們可以在每只手的中心創(chuàng)建一個(gè)圓圈并通過添加這兩條線來繪制它

          hand_circle = Circle(hand_position, hand_radius, (00255), 1)
          hand_circle.draw(frame)

          這會(huì)在每個(gè)被跟蹤手的中心位置繪制一個(gè)紅色圓圈(未填充)。注意,手的中心位置不是手掌中心,而是所有地標(biāo)位置的平均位置。你可以通過合上手來測(cè)試一下,你可以看到中心位置向你手的下部移動(dòng)。

          檢查碰撞

          我們需要一種方法來檢查玩家是否擊中了目標(biāo)。這將是我們游戲的主要機(jī)制。

          Cv2 沒有任何檢查兩個(gè)對(duì)象是否相交的函數(shù),但由于我們處理的是圓,所以這個(gè)任務(wù)變得非常簡(jiǎn)單。我們只需要檢查圓心之間的距離是否小于或等于半徑之和。讓我們看一下下面的例子

          相交算法

          希望這說明了相交算法。由于我們已經(jīng)知道目標(biāo)半徑和手圓半徑,我們只需要計(jì)算距離d。并且有一個(gè)非常簡(jiǎn)單的數(shù)學(xué)公式,給定兩個(gè)點(diǎn),計(jì)算它們之間的距離。

          該距離公式是:

          我們所要做的就是在代碼中創(chuàng)建該函數(shù)。為了方便起見,我在Circle類中創(chuàng)建了這個(gè)函數(shù),如下所示

          def check_intersection(self, other_coordinates, other_radius):
              distance = math.sqrt(math.pow(other_coordinates[0] - self.coordinates[0], 2) + math.pow(
                  other_coordinates[1] - self.coordinates[1], 2))

              if distance <= self.radius + other_radius:
                  return True
              else:
                  return False

          該函數(shù)考慮了我們上面討論的所有內(nèi)容并返回一個(gè)布爾值,指示一個(gè)圓是否與另一個(gè)圓相交。

          我們可以通過在主循環(huán)中添加幾行來測(cè)試它

          if hands:
              for i in range(len(hands)):
                  hand_position = hands[i]["center"]
                  hand_circle = Circle(hand_position,hand_radius,(0,0,255),1)
                  if target.check_intersection(hand_circle.coordinates, hand_circle.radius):
                     
                      # is intersecting
                      hand_circle.color = (02550)
                  else:
                      # not intersection
                      hand_circle.color = (00255)
                  hand_circle.draw(frame)

          你現(xiàn)在可以看到,如果我“觸摸”目標(biāo),我的手圈會(huì)變成綠色,否則就是紅色

          第 3 步:創(chuàng)建實(shí)際游戲

          因此,創(chuàng)建我們實(shí)際游戲的第一步是,一旦我們擊中當(dāng)前目標(biāo),就能夠在隨機(jī)位置選擇一個(gè)新目標(biāo)。為此,我們可以創(chuàng)建一個(gè)這樣的函數(shù)

          def create_random_target(current_target_pos=[]):
              if current_target_pos:
                  possible_x = []

                  x_limit = [target_radius + border_size + 15, width - target_radius - border_size - 15]
                  y_limit = [target_radius + border_size + 15, height - target_radius - border_size - 15]

                  for i in range(x_limit[0], x_limit[1]):
                      if i + 200 < current_target_pos[0or i - 200 > current_target_pos[0]:
                          possible_x.append(i)

                  possible_y = []
                  for i in range(y_limit[0], y_limit[1]):
                      if i + 200 < current_target_pos[1or i - 200 > current_target_pos[1]:
                          possible_y.append(i)

                  if not possible_x:
                      possible_x = range(x_limit[0], x_limit[1])

                  if not possible_y:
                      possible_y = range(y_limit[0], y_limit[1])

              else:
                  possible_x = range(target_radius + border_size, width - target_radius - border_size)
                  possible_y = range(target_radius + border_size, height - target_radius - border_size)
              # pick a random coordinate
              random_x = random.choice(possible_x)
              random_y = random.choice(possible_y)
              # pick a random color
              random_color = [random.randint(0255), random.randint(0255), random.randint(0256)]
              _target = Circle([random_x, random_y], target_radius, random_color, -1)

              return _target

          這個(gè)函數(shù)有很多事情要做,所以讓我們分解一下。

          第一部分是我們?cè)O(shè)置新目標(biāo)可以采用的寬度和高度的可能值。我們通過首先設(shè)置變量x_limity_limit來做到這一點(diǎn),顧名思義,這些變量限制了可以放置目標(biāo)的位置。這是為了避免我們最終得到一個(gè)部分在屏幕外的目標(biāo)。

          你可能已經(jīng)注意到有一個(gè)新變量,border_size我們還沒有討論過,但我稍后會(huì)討論它。

          然后,對(duì)于每個(gè)維度(寬度和高度),我們運(yùn)行一個(gè) for 循環(huán),用可能的位置填充數(shù)組possible_xpossible_y。請(qǐng)注意,我加入了一個(gè)限制,為了讓游戲更具挑戰(zhàn)性,新目標(biāo)必須與當(dāng)前目標(biāo)相距至少 282 像素(寬度為 200 像素,高度為 200 像素))

          之后,只需從possible_xpossible_y中選擇一個(gè)隨機(jī)值,分配一個(gè)隨機(jī)顏色,然后返回新的圓圈。

          現(xiàn)在我們可以在主循環(huán)中使用這個(gè)函數(shù)

          if hands:
              for i in range(len(hands)):
                  hand_position = hands[i]["center"]
                  hand_circle = Circle(hand_position,hand_radius,(0,0,255),1)
                  hand_circle.draw(frame)
                  if target.check_intersection(hand_circle.coordinates, hand_circle.radius):
                     
                      # is intersecting
                      hit_target = True
                      break;
          if hit_target:
              target_count += 1
              target = create_random_target(target.coordinates)
              hit_target = False

          如你所見,此代碼可能非常耗時(shí),因?yàn)槊看挝覀円獎(jiǎng)?chuàng)建新目標(biāo)時(shí),我們都會(huì)遍歷屏幕的幾乎每個(gè)像素。如果這個(gè)函數(shù)會(huì)減慢你的游戲速度,只需注釋掉你有 for 循環(huán)的行并使用以下代碼來代替

          possible_x = range(target_radius + border_size, width -        
          target_radius - border_size)

          possible_y = range(target_radius + border_size, height - target_radius - border_size)

          這將產(chǎn)生相同的影響,除了我們不再有創(chuàng)建遠(yuǎn)離當(dāng)前目標(biāo)的新目標(biāo)的限制。

          有了這段代碼,游戲就完成了!你現(xiàn)在可以不停地玩游戲。但當(dāng)然,我們會(huì)改進(jìn)它。

          可以改進(jìn)這款游戲的眾多方法之一是賦予它一種感覺或緊迫感。基本上,我們需要一種方法來激勵(lì)玩家盡快達(dá)到目標(biāo)。一個(gè)很好的方法是添加一個(gè)計(jì)時(shí)器。

          為了使用計(jì)時(shí)器,我們首先必須有一種方法來跟蹤經(jīng)過的時(shí)間。我們可以通過time庫(kù)做到這一點(diǎn)

          import time

          t_start = time.time()
          while True:
              elapsed_time = time.time() - t_start
              print(elapsed_time)

          這應(yīng)該輸出我們自循環(huán)開始以來經(jīng)過的時(shí)間。有了這個(gè),我們現(xiàn)在可以限制玩家玩游戲的時(shí)間,迫使玩家盡可能快地獲得更好的分?jǐn)?shù)。我們還需要一種方法讓玩家知道他打得有多好,所以我們將在圖像中添加一條消息,使用函數(shù)cv2.putText()顯示得分

          if elapsed_time >= max_time:
              is_playing = False
              final_message = "Time's up! You hit " + str(target_count) + " targets in " + str(max_time) + " seconds"
              frame = cv2.putText(frame, final_message, object_title_pos, cv2.FONT_HERSHEY_DUPLEX, 1, (00255), 2)

          我還添加了標(biāo)志is_playing以在計(jì)時(shí)器結(jié)束后阻止目標(biāo)出現(xiàn)。現(xiàn)在我們可以玩游戲并嘗試每次提高我們的分?jǐn)?shù),我們甚至可以與其他人競(jìng)爭(zhēng)!

          我們還可以用兩種不同的方式玩我們的游戲。事實(shí)上,現(xiàn)在我們已經(jīng)設(shè)置了運(yùn)行時(shí)間的游戲,但我們也可以讓游戲運(yùn)行目標(biāo)。我的意思是,與其嘗試在給定時(shí)間內(nèi)擊中盡可能多的目標(biāo),我們可以看到我們可以多快擊中給定數(shù)量的目標(biāo)。

          我們只需要添加一些東西,即控制我們正在玩的游戲類型的變量,我們還需要一種方法來檢查目標(biāo)計(jì)數(shù)何時(shí)達(dá)到最大值

          play_for_time = True
          play_for_targets = not play_for_time
          ...
          while True:
              if hit_target:
                  target_count += 1
                  target = create_random_target(target.coordinates)
                  if play_for_time and target_count == max_targets:
                      is_playing = False
                      final_message = "Congrats! You hit " + str(target_count) + " targets in " + "{:.2f}".format(elapsed_time) + " seconds"

          現(xiàn)在我們可以用兩種不同的方式玩我們的游戲了!

          第 4 步:最后潤(rùn)色

          我們現(xiàn)在擁有的游戲非常基礎(chǔ),有無數(shù)種方法可以改進(jìn)它,但是在本節(jié)中,我將與你分享一些我也實(shí)現(xiàn)的其他功能。

          保存/加載高分

          不必記住上次獲得的分?jǐn)?shù),你可以創(chuàng)建一個(gè)讀取(和寫入)當(dāng)前高分的方法。

          為此,我們需要兩個(gè)函數(shù)來加載和保存我們的高分

          import pickle
          def load_highscore(is_time):
              try:
                  if is_time:
                      with open('high_score_time.dat''rb'as file:
                          score = pickle.load(file)
                  else:
                      with open('high_score_targets.dat''rb'as file:
                          score = pickle.load(file)
              except:
                  score = 0
              return score


          def save_highscore(score, is_time):
              if is_time:
                  with open('high_score_time.dat''wb'as file:
                      pickle.dump(score, file)
              else:
                  with open('high_score_targets.dat''wb'as file:
                      pickle.dump(score, file)

          我們正在使用pickle將當(dāng)前的高分保存并加載到文件中。要將其合并到我們當(dāng)前的代碼中,我們只需要檢查我們得到的當(dāng)前分?jǐn)?shù)是否比我們的高分更好,如果是,則更新高分

          highscore_targets = load_highscore(False)
          while True:
              if hit_target:
                  target_count += 1
                  target = create_random_target(target.coordinates)
                  if play_for_time and target_count == max_targets:
                      is_playing = False
                      final_message = "Congrats! You hit " + str(target_count) + " targets in " + "{:.2f}".format(elapsed_time) + " seconds"
                  if target_count > highscore_targets or highscore_targets==0:
                      save_highscore(target_count, False)
                      highscore_message = "New highscore!!"
                  else:
                       highscore_message = "Best score: " + str(highscore_targets)

          添加當(dāng)前時(shí)間和分?jǐn)?shù)

          現(xiàn)在我們無法知道我們擊中了多少個(gè)目標(biāo),或者我們玩了多長(zhǎng)時(shí)間,所以為了解決這個(gè)問題,我們可以在頂部角落添加兩個(gè)文本框來顯示當(dāng)前目標(biāo)計(jì)數(shù)和當(dāng)前時(shí)間

          score_text_pos = (width - 150, border_size + 30)
          time_text_pos = (border_size + 15, border_size + 30)
          while True:
              ...
              frame = cv2.putText(frame, "Total: " + str(target_count), score_text_pos, cv2.FONT_HERSHEY_DUPLEX, 1, (00255), 2)
              frame = cv2.putText(frame, "Time left: " + "{:.2f}".format(elapsed_time), time_text_pos,               cv2.FONT_HERSHEY_DUPLEX, 1, (00255), 2)

          添加邊框

          最后,我之前提到過border_size這個(gè)變量,這個(gè)變量表示我們希望邊框的像素?cái)?shù)。我們可以使用函數(shù)cv2.copyMakeBorder()創(chuàng)建邊框

          while True:
              frame = cv2.copyMakeBorder(frame, border_size, border_size, border_size, border_size, cv2.BORDER_CONSTANT,                       value=[000])

          GitHub 存儲(chǔ)庫(kù)上提供的文件還有更多功能:https://github.com/Goncalo-Chambel/ReactionGame

               
          下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程
          在「小白學(xué)視覺」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺、目標(biāo)跟蹤、生物視覺、超分辨率處理等二十多章內(nèi)容。

          下載2:Python視覺實(shí)戰(zhàn)項(xiàng)目52講
          小白學(xué)視覺公眾號(hào)后臺(tái)回復(fù):Python視覺實(shí)戰(zhàn)項(xiàng)目即可下載包括圖像分割、口罩檢測(cè)、車道線檢測(cè)、車輛計(jì)數(shù)、添加眼線、車牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺。

          下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講
          小白學(xué)視覺公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。

          交流群


          歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺SLAM“。請(qǐng)按照格式備注,否則不予通過。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~


          瀏覽 198
          10點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          10點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本a影院 | 少妇厨房愉情理伦BD在线观看 | 哪里可以看AV片 | 欧美搜索二区 | 天天综合天天添夜夜添狠狠添 |