2011-08-12 27 views
11

PIL v1.1.7 tarafından kullanılan algoritma 'yıkanmış' görünümlü sonuçlar verir. Aynı kaynak verisini ffmpeg kullanarak dönüştürürken doğru görünüyor. mplayer kullanarak ffmpeg için aynı sonuçları verir (belki de aynı kütüphaneyi kullanırlar). Bu, PIL'in renk alanı dönüşümlerini doldurduğuna inanmamı sağlıyor. Dönüşüm libImaging/ConvertYCbCr.c kaynaklı gibi görünüyor:PIL'in renk uzay dönüşümü YCbCr -> RGB

/* 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 

*/ 

Bu kaynakta sadece bir yorumdur, tabii ki C kodu var ve gerçek işlevi çarpma matrix değil arama tabloları ile uygulanır (static INT16 R_Cr vb kısalık için snipped):

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; 
    } 
} 
Ben googled var

ancak bu renk uzayı dönüşümü yapmak 'doğru' yol hakkında kargaşasına gibi görünüyor. Öyleyse benim sorum şu ki, yukarıdaki doğrudur - ve eğer daha iyi bir yol değilse?


düzenlemek

: Mark Ransom tarafından sağlanan bağlantıları okuduktan sonra çakışan tanımları Eğer YCbCr tam kapsamlı kullanın veya geçerli aralık dışarı kelepçe bağlı olarak bulunması durumundan keşfetti. Daha fazla bilgi için aşağıdaki bağlantılara bakın:

O PIL sürümü yanlış algoritma kullanıyor görünüyor, bu yüzden doğru verir dönüşüm için kendi işlevi kullanıma sunduk sonuçlara bakmak ("SDTV" versiyonu). Eğer Wikipedia'nın tanımları bakarsanız, sen YCbCr için iki çakışan tanımları olduğunu görebilirsiniz

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 
+1

http://en.wikipedia.org/wiki/YCbCr adresindeki mekanizmalardan biriyle eşleşiyor mu? –

cevap

7

: Gelecekteki okuyucuların kullanmak için kod aşağıda dahil. ITU-R BT.601 tanımı, JPEG sürümü 0-255 tam aralığını kullanırken, 16-235 aralığındaki değerleri ayak odası ve yatak odası sağlamak için sıkıştırır. JPEG formülü kullanarak BT.601 alanındaki değerleri deşifre edecekseniz, sonuç kesinlikle temizlenmiş görünecektir.

+1

teşekkürler, bu beni doğru yolda buldunuz ve çeşitli standartların (oxymoron?) Açık bir açıklamasını burada buldum -> http://www.equasys.de/colorconversion.html – wim