Преобразование цвета YUV в RGB

Я пытаюсь преобразовать цветовую карту 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)

Обе функции не обеспечивают желаемого результата.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
205
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Похоже, что значения пикселей каналов U и V суммируются из 127. См. источник FFmpeg:

https://github.com/FFmpeg/FFmpeg/blob/7e59c4f90885a9ffffb0a3f1d385b4eae3530529/libavfilter/avf_showspectrum.c#L1416

Итак, я подозреваю, что если вы сначала добавите 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), а затем подвергнута линейной интерполяции в соответствии со столбцом «А».

Нет, это не работает. Результаты почти такие же.

Prashant 12.04.2024 04:43

хм. Если никто больше не найдет ответа, я могу попытаться провести расследование на выходных.

kesh 12.04.2024 04:55

все получилось

kesh 13.04.2024 18:42

Другие вопросы по теме