如何用Python+OpenCV生成字幕?

磐创AI
关注

目录介绍颜色检测对象检测相似词建议Lyrics Genius  API主函数Streamlit部署资源介绍该项目的作用是使用歌词为图像提供字幕。许多人当前面临的问题之一是缺乏诙谐、机智、深刻的见解,或者仅仅是优秀的字幕。随着社交媒体的兴起,一切都需要一个标题。从与祖母的合影到与狗的可爱合影,问题是我们大多数人都没有合适的词来为我们的照片添加标题,这让我们等了几个星期才发帖,有时我们也从来没有为此发帖。其他时候,它只是简单地发布而没有标题。该项目试图通过使用对象和颜色检测来查找照片中的元素来解决这个问题。然后,该算法使用通过我们选定的艺术家,在 Lyrics Genius 包找到歌词并在整个系统中搜索这些元素并返回。颜色检测算法列表的第一站是颜色检测。颜色检测是使用K-Means 聚类、OpenCV 和 colors.csv 文件。K-Means 聚类打开文件并在 RBG 通道上对其进行转换并调整其大小后。应用了K-means。K-means 用于根据用户选择的数量返回图像中找到的“n 个主要”颜色。如果用户输入黑色图像,并告诉系统搜索 10 种颜色,这也会处理实例。系统将返回单一的黑色。def palette(clusters):
   width = 300
   palette = np.zeros((50, width, 3), np.uint8)
   steps = width/clusters.cluster_centers_.shape[0]
   for idx, centers in enumerate(clusters.cluster_centers_):
       palette[:, int(idx*steps):(int((idx+1)*steps)), :] = centers
   return palette

OpenCV设置此值后,算法会检测图像中的 n 个主色。然后我们将图像和调色板保存在 compare_img() 中。紧接着,我们使用all_colors_in_img()返回图像中所有颜色的列表。这多次重复相同的颜色。因此, np.unique() 用于返回唯一值。def compare_img(img_1, img_2):
   f, ax = plt.subplots(1, 2, figsize=(10,10))
   ax[0].imshow(img_1)
   ax[1].imshow(img_2)
   ax[0].axis('off')
   ax[1].axis('off')
   f.tight_layout()
   #plt.show()
   f.savefig('outputImgs/colorDetected.png')

Colors.csv然后调用 predict_color()。该函数接收 all_colors_in_img() 返回的 RBG 颜色通道。然后它使用colors.csv 找到最接近它自己的颜色。最后,由于某些颜色返回“Alice蓝”和其他特定颜色需求。我们使用 return_root_color() 函数将返回“蓝色”。此外,例如颜色可能以括号结尾的情况。颜色还通过返回括号前的单词来处理此问题。这样做是因为所有根颜色都被注意到是颜色短语中的最后一个词。def recognize_color(color_index):
   csv = pd.read_csv('files/colors.csv', names=index, header=None)
   R = color_index[0]
   G = color_index[1]
   B = color_index[2]
   minimum = 10000
   for i in range(len(csv)):
       d = abs(R- int(csv.loc[i,"R"])) + abs(G- int(csv.loc[i,"G"]))+ abs(B- int(csv.loc[i,"B"]))
       if(d<=minimum):
           minimum = d
           cname = csv.loc[i,"color_name"]
   return cname

对象检测在颜色检测之后,系统然后开始对象检测。对象检测是通过使用 OpenCV dnn_DetectionModel 函数完成的。我们首先加载配置和模型文件(在资源中注明)。然后我们加载 coco.names 文件,其中列出了所有对象的名称。接下来,配置我们模型的参数。然后,我们将图像传递给我们的检测循环。它循环遍历每个图像周围的图像绘制框,并将图像的名称放在照片中。然后将每个唯一对象附加到列表中。这个 for 循环包含在 try-except 中,以处理找不到对象的情况。font_scale = 1 ### Font size
font = cv.FONT_HERSHEY_PLAIN ### Font type
try:
   for ClassInd, conf, boxes in zip(ClassIndex.flatten(), confidence.flatten(), bbox):
       cv.rectangle(img,boxes,(255,0,0),2) ### Places boxes around image
       ### Outputs the text around image
       cv.putText(img,classLabels[ClassInd-1],(boxes[0]+10,boxes[1]-5), font, fontScale=font_scale, color=(0,255,0), thickness=1)
       ### Checks if object is already in list
       if classLabels[ClassInd-1] not in ListofObjects and classLabels[ClassInd-1] != 'person':
           ### Places new object in list
           ListofObjects.append(classLabels[ClassInd-1])
except:
   return print('Object Detection exited...') ### Exits algorithm if no object found

相似词建议接下来,调用相似词建议。仅对图像中找到的对象调用相似词建议。在寻找颜色的相似词时,发现了被认为无关紧要的词;因此,没有使用颜色。一旦算法开始,它首先加载可以在资源部分找到的 gloVe 文件。接下来,算法遍历找到的每个对象以找到相似的词。find_closest_embeddings() 函数将返回最接近的词。然后它将这些对象中的每一个保存到一个目录中。选择一个目录来跟踪每个相似的词及其所属的对象。最后,这被包装在一个 try-except 中,以处理用户有 3 个对象的情况。如果算法没有找到对象 2 的相似词,则算法将跳过对象 2 并按预期继续。def find_closest_embeddings(embedding):
   return sorted(embeddings_dict.keys(), key=lambda word: spatial.distance.euclidean(embeddings_dict[word], embedding))
Lyrics Genius  API在此之后,我们的算法开始搜索所选艺术家的歌曲。Lyrics Genius 包装了genius.com API 并返回有关艺术家信息的JSON。LyricGenius 文件分为 2 个部分。第 1 部分:此部分包含 findArtistSongs() 函数。此函数仅在循环的第一次迭代中运行。它创建一个 JSON 文件,其中包含用户选择的 n 首歌曲。UI 限制为 20 首歌曲。然后以artistFile = 'Lyrics_' +artistFileName + '.json' 格式保存这个JSON 文件。这样做是为了确保无论用户输入如何,在尝试打开文件时都不会出错。似乎比使用默认方法更安全,因为我们无法预测用户输入。此外,还使用了 search.save_lyrics(artistFile,overwrite=True)。设置 overwrite=True 对于消除接收覆盖验证消息非常重要。此验证将阻止算法运行。接下来,文件被移动到一个文件夹。你根本无法在 .save_lyrics() 函数中执行此操作,因为它不会将文件放在预期的文件夹中。接着搜索新制作的 JSON。然后循环播放歌曲和歌词并保存到 CSV 文件中。def findArtistSongs(api, artist, maxSongs, sortBy):
   try:
       #search = api.search_artist(artist, max_songs=maxSongs, sort=sortBy) ### Select songs based on ASC order of song name
       search = api.search_artist(artist, max_songs=maxSongs) ### Random selection of songs
       artistFileName = re.sub(r'[^A-Za-z0-9]+', '', artist) ### Removing all alphanumeric characters from string
       artistFile = 'Lyrics_' + artistFileName + '.json' ### Lyrics file name used instead of default to ensure consistancy of file names when weird characters used
       search.save_lyrics(artistFile,overwrite=True) ### Creation JSON file overwrite=True overides JSON with same name
       shutil.move(artistFile, "outputLyrics/"+artistFile) ### Moving file as a personal perference so individuals can see JSON on git rather than deleting it
       print('JSON Created ...')
       Artist = json.load(open("outputLyrics/" + artistFile))  ### Loading JSON file
       ### Looping through each song while calling the collectSongData function
       for i in range(maxSongs):
           collectSongData(Artist['songs'][i])
       updateCSV_file(file)  ### Updating CSV calling updateCSV_file function
       return artistFile
   except:
       artistFile = 'Timeout: Request timed out: HTTPSConnectionPool'
       return artistFile

第 2 部分对于循环的所有迭代,算法将命中这一部分。它首先循环遍历每个元素。每个元素都将传递给 search_csv_file()。然后这个函数会在每个长的歌词中搜索元素。如果找到歌词,则将歌词保存到目录中。目录键保存为歌曲名称、元素搜索和歌词行号。此信息保存在一个目录中,因此它可以显示在 UI 上并包含所需的信息。def search_csv_file(file,currentElement):
   with open(file) as f_obj:
       reader = csv.reader(f_obj, delimiter=',')
       for line in reader:  ### Iterates through the rows of your csv
           allSongs= line[1].splitlines() ### Split entire song into new lines to be read 1 by 1
           for i in range(len(allSongs)):
               if currentElement in allSongs[i].lower(): ### Searching for element and making all lowercased for searching
                   print('Song: ',line[0],'| Lyrics: ',allSongs[i])
                   keyName = line[0] +'_'+currentElement+'_'+str(i) ### Setting key to be unqiue
                   allLyrics[keyName.upper()] = allSongs[i] ### Setting key and setting it to uppercase personal preference
   return print('Element Search completed...') ### Indicates element search completed

主函数正如预期的那样,在创建这个没有 UI 的项目时,主函数会处理对该函数的所有调用。主要内容包括信息性陈述。因此,出于信息目的,它有多个 if/else 语句。我发现突出显示信息如何传递到 LyricGenius 文件很重要。for i in range(len(AllItems)):
       ### Eliminates creating the same JSON file n times
       if i == 0:
           artistFile = lyricsGenius.findArtistSongs(api, artist, maxSongs, sortBy)
           if artistFile == 'Timeout: Request timed out: HTTPSConnectionPool':
               break
       for j in range(len(AllItems[i])):
           currentElement = AllItems[i][j]
           print('Searching for element:', currentElement)
           lyricsGenius.main(currentElement)

StreamlitStreamlit 使部署应用程序变得非常容易。但是,此应用程序不是动态的。处理这些信息有点棘手,因为按钮和 UI 元素没有内置的带有 streamlit 的必需文件。因此,字段的要求由 if/else 语句处理。If/else 语句还处理可见的 UI 验证部署要部署你的应用程序,你需要注册 streamlit 并进入邀请队列。它相当快。我确实必须使用像 dropbox 这样的外部系统来处理加载我不在 GitHub 中的较大文件,以便此应用程序根据需要显示。

声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存