Conversion de l'espace de couleur PIL YCbCr - & gt; RVB
L'algorithme utilisé par PIL v1.1.7 donne 'lavé' résultats de recherche. Lors de la conversion de la même source de données à l'aide de ffmpeg
il semble correct. À l'aide de mplayer
donne des résultats identiques à ffmpeg
(peut-être qu'ils utilisent la même bibliothèque-dessous). Cela me mène à croire PIL peut être la farce la couleur des conversions d'espace. La conversion semble être trouvés en libImaging/ConvertYCbCr.c
:
/* JPEG/JFIF YCbCr conversions
Y = R * 0.29900 + G * 0.58700 + B * 0.11400
Cb = R * -0.16874 + G * -0.33126 + B * 0.50000 + 128
Cr = R * 0.50000 + G * -0.41869 + B * -0.08131 + 128
R = Y + + (Cr - 128) * 1.40200
G = Y + (Cb - 128) * -0.34414 + (Cr - 128) * -0.71414
B = Y + (Cb - 128) * 1.77200
*/
C'est juste un commentaire dans le source, bien sûr, c'est du code C et de la fonction réelle est mis en œuvre avec des tables de recherche pas de multiplication de matrice (la static INT16 R_Cr
etc. ciselée par souci de concision):
void
ImagingConvertYCbCr2RGB(UINT8* out, const UINT8* in, int pixels)
{
int x;
UINT8 a;
int r, g, b;
int y, cr, cb;
for (x = 0; x < pixels; x++, in += 4, out += 4) {
y = in[0];
cb = in[1];
cr = in[2];
a = in[3];
r = y + (( R_Cr[cr]) >> SCALE);
g = y + ((G_Cb[cb] + G_Cr[cr]) >> SCALE);
b = y + ((B_Cb[cb] ) >> SCALE);
out[0] = (r <= 0) ? 0 : (r >= 255) ? 255 : r;
out[1] = (g <= 0) ? 0 : (g >= 255) ? 255 : g;
out[2] = (b <= 0) ? 0 : (b >= 255) ? 255 : b;
out[3] = a;
}
}
J'ai googlé mais il semble y avoir beaucoup de confusion au sujet de la "bonne" façon de faire cette conversion de l'espace colorimétrique. Donc ma question est, est au-dessus correcte - et si non, quelle est la meilleure façon?
edit: Après avoir lu les liens fournis par la Marque de Rançon, j'ai découvert que les conflits de définitions existent, selon que vous utilisez la gamme complète de YCbCr ou de serrage à la plage valide. Voir les liens ci-dessous pour plus d'info:
Il semble que le PIL version est en utilisant la mauvaise algorithme, donc j'ai roulé ma propre fonction de conversion qui donne le bon résultat ("SDTV" version). Le Code ci-dessous, pour les futurs lecteurs à utiliser:
from numpy import dot, ndarray, array
def yuv2rgb(im, version='SDTV'):
"""
Convert array-like YUV image to RGB colourspace
version:
- 'SDTV': ITU-R BT.601 version (default)
- 'HDTV': ITU-R BT.709 version
"""
if not im.dtype == 'uint8':
raise TypeError('yuv2rgb only implemented for uint8 arrays')
# clip input to the valid range
yuv = ndarray(im.shape) # float64
yuv[:,:, 0] = im[:,:, 0].clip(16, 235).astype(yuv.dtype) - 16
yuv[:,:,1:] = im[:,:,1:].clip(16, 240).astype(yuv.dtype) - 128
if version.upper() == 'SDTV':
A = array([[1., 0., 0.701 ],
[1., -0.886*0.114/0.587, -0.701*0.299/0.587],
[1., 0.886, 0.]])
A[:,0] *= 255./219.
A[:,1:] *= 255./112.
elif version.upper() == 'HDTV':
A = array([[1.164, 0., 1.793],
[1.164, -0.213, -0.533],
[1.164, 2.112, 0.]])
else:
raise Exception("Unrecognised version (choose 'SDTV' or 'HDTV')")
rgb = dot(yuv, A.T)
result = rgb.clip(0, 255).astype('uint8')
return result
source d'informationauteur wim
Vous devez vous connecter pour publier un commentaire.
Si vous regardez de Wikipédia définitions, vous pouvez voir qu'il y a deux définitions contradictoires pour ce Format. Le UIT-R BT.601 définition compresse les valeurs de la gamme 16-235 de fournir footroom et pour la tête, tandis que le JPEG version utilise l'intégralité de la gamme de 0 à 255. Si vous étiez à décoder les valeurs de la BT.601 espace à l'aide de la formule pour le JPEG, le résultat serait certainement look délavé.