Я пытаюсь преобразовать цветовую карту Intensity FFMPEG из формата yuv в rgb. Он должен дать вам цвета, показанные на цветовой шкале на изображении. Вы можете создать спектрограмму с помощью команды:
ffmpeg -i words.wav -lavfi showspectrumpic=s=224x224:mode=separate:color=intensity spectrogram.png
Вот код:
import numpy as np
def rgb_from_yuv(Y, U, V):
Y -= 16
U -= 128
V -= 128
R = 1.164 * Y + 1.596 * V
G = 1.164 * Y - 0.392 * U - 0.813 * V
B = 1.164 * Y + 2.017 * U
# Clip and normalize RGB values
R = np.clip(R, 0, 255)
G = np.clip(G, 0, 255)
B = np.clip(B, 0, 255)
return '#{:02X}{:02X}{:02X}'.format(int(R), int(G), int(B))
def yuv_to_rgb(Y, U,V):
# Convert YUV to RGB
R = Y + (V - 128) * 1.40200
G = Y + (U - 128) * -0.34414 + (V - 128) * -0.71414
B = Y + (U - 128) * 1.77200
# Clip and normalize RGB values
R = np.clip(R, 0, 255)
G = np.clip(G, 0, 255)
B = np.clip(B, 0, 255)
print(R,G,B)
return '#{:02X}{:02X}{:02X}'.format(int(R), int(G), int(B))
# FFMPEG's intensity color map
colors = [
[ 0, 0, 0, 0 ],
[ 0.13, .03587126228984074, .1573300977624594, -.02548747583751842 ],
[ 0.30, .18572281794568020, .1772436246393981, .17475554840414750 ],
[ 0.60, .28184980583656130, -.1593064119945782, .47132074554608920 ],
[ 0.73, .65830621175547810, -.3716070802232764, .24352759331252930 ],
[ 0.78, .76318535758242900, -.4307467689263783, .16866496622310430 ],
[ 0.91, .95336363636363640, -.2045454545454546, .03313636363636363 ],
[ 1, 1, 0, 0 ]]
cmaps = []
for i, c in enumerate(colors):
Y = c[1]
U = c[2]
V = c[3]
hex = yuv_to_rgb(Y,U,V)
cmaps.append((c[0], hex))
print(cmaps)
Обе функции не обеспечивают желаемого результата.






Похоже, что значения пикселей каналов U и V суммируются из 127. См. источник FFmpeg:
Итак, я подозреваю, что если вы сначала добавите 0,5 к 3-му и 4-му столбцам colors, стандартное преобразование YUV в RGB должно работать.
редактировать 13.04.24: Понятно.
rgb = [[ 0 0 0]
[ 0 0 71]
[106 0 125]
[255 0 0]
[255 165 0]
[255 218 0]
[255 255 159]
[255 255 255]]

Я провел реверс-инжиниринг того, как showspectrumpic выбирает значение цвета YUV в легенде, передал эти значения YUV в FFmpeg в формате yuv444p и преобразовал кадр как rgb24.
import ffmpegio as ff # caveat: need the GitHub version as of 4/13/24
import numpy as np
from matplotlib import pyplot as plt
color_table = np.array(
[ # a y u v
[0, 0, 0, 0],
[0.13, 0.03587126228984074, 0.1573300977624594, -0.02548747583751842],
[0.30, 0.18572281794568020, 0.1772436246393981, 0.17475554840414750],
[0.60, 0.28184980583656130, -0.1593064119945782, 0.47132074554608920],
[0.73, 0.65830621175547810, -0.3716070802232764, 0.24352759331252930],
[0.78, 0.76318535758242900, -0.4307467689263783, 0.16866496622310430],
[0.91, 0.95336363636363640, -0.2045454545454546, 0.03313636363636363],
[1, 1, 0, 0],
]
)
# U & V channels are offset values from the middle
cmap_yuv = np.clip(color_table[:, 1:] + np.array([0, 0.5, 0.5]), 0, 1)
# convert to YUV444P planar pixel format
cmap_yuvp = (cmap_yuv*255).astype("uint8").transpose()
# convert to RGB24
cmap_rgb = ff.image.filter(
None, cmap_yuvp.reshape([3, 1, -1]),
pix_fmt_in = "yuv444p",
s_in=(1, len(cmap_yuv)),
)
# equiv to: ffmpeg -f rawvideo -c:v rawvideo -pix_fmt yuv444p -r 1 -s 1x8 -i - -f rawvideo -pix_fmt rgb24 -
print(cmap_rgb)
plt.imshow(cmap_rgb.reshape(1, -1, 3))
plt.show()
Я использовал свой пакет ffmpegio для сокращения вызова FFmpeg (примечание: мне пришлось внести небольшие изменения в код, поэтому в настоящее время работает только версия GitHub).
Наконец, имейте в виду, что эта цветовая карта не является равнопространственной. Интенсивность карты должна быть нормализована до (0,1), а затем подвергнута линейной интерполяции в соответствии со столбцом «А».
хм. Если никто больше не найдет ответа, я могу попытаться провести расследование на выходных.
все получилось
Нет, это не работает. Результаты почти такие же.