点击上方“小白学视觉”,选择加"星标"或“置顶”
重磅干货,第一时间送达
通过 GitHub 查看代码
https://github.com/antoneev/66DaysOfData/tree/main/captionSuggestionsUsingLyrics
查看部署的应用程序
https://share.streamlit.io/antoneev/66daysofdata/main/captionSuggestionsUsingLyrics/app.py
目录
介绍
颜色检测
对象检测
相似词建议
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('\nSearching for element:', currentElement)
lyricsGenius.main(currentElement)
Streamlit
Streamlit 使部署应用程序变得非常容易。但是,此应用程序不是动态的。处理这些信息有点棘手,因为按钮和 UI 元素没有内置的带有 streamlit 的必需文件。因此,字段的要求由 if/else 语句处理。If/else 语句还处理可见的 UI 验证
部署
要部署你的应用程序,你需要注册 streamlit 并进入邀请队列。它相当快。我确实必须使用像 dropbox 这样的外部系统来处理加载我不在 GitHub 中的较大文件,以便此应用程序根据需要显示。
下载1:OpenCV-Contrib扩展模块中文版教程
在「小白学视觉」公众号后台回复:扩展模块中文教程,即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。
下载2:Python视觉实战项目52讲
在「小白学视觉」公众号后台回复:Python视觉实战项目,即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。
下载3:OpenCV实战项目20讲
在「小白学视觉」公众号后台回复:OpenCV实战项目20讲,即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。
交流群
欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~