2011-08-12 3 views
11

PIL v1.1.7에서 사용되는 알고리즘은 '씻겨나가'보이는 결과를 제공합니다. ffmpeg을 사용하여 동일한 원본 데이터를 변환 할 때 올바른 것으로 보입니다. mplayer을 사용하면 ffmpeg (동일한 라이브러리를 사용하는 경우도 있음)에 동일한 결과가 제공됩니다. 이것은 필자가 PIL이 색 공간 변환을 채우고 있다고 믿게 만듭니다. 변환이 libImaging/ConvertYCbCr.c에 공급 될 것 같다PIL의 색상 공간 변환 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 

*/ 

이 소스 단지 주석이며, 물론 그 C 코드의 실제 기능 매트릭스 승산하지 룩업 테이블로 구현합니다 (static INT16 R_Cr 등 간결 냈다) :

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; 
    } 
} 
내가 검색 좀

그러나이 색 공간 변환을 할 수있는 '권리'방식에 대해 많은 혼란이있는 것 같습니다. 그래서 내 질문은, 위의 올바른 - 그리고 더 나은 방법이 아니라면 무엇입니까?


편집

: 마크 랜섬에서 제공하는 링크를 읽은 후, 나는 충돌하는 정의가 당신의 YCbCr의 전체 범위를 사용하거나 유효 범위 밖으로 고정 여부에 따라 존재하는 것을 발견했다. 더 많은 정보를 원하시면 아래 링크를 참조하십시오 :

PIL 버전이 잘못된 알고리즘을 사용하는 것, 그래서 올바른을 제공하는 변환을 위해 내 자신의 기능을 압연했습니다 ("SDTV"버전). 당신은 위키 백과의 정의를 보면, 당신의 YCbCr 두 가지 상충하는 정의가 있음을 볼 수있다

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의 메커니즘 중 하나와 일치합니까? –

답변

7

: 미래의 독자가 사용하는 코드는 아래에 포함되어 있습니다. JPEG 버전은 0-255 전체 범위를 사용하지만 ITU-R BT.601 정의는 풋룸과 헤드 룸을 제공하기 위해 값을 16-235 범위로 압축합니다. JPEG의 수식을 사용하여 BT.601 공간의 값을 디코딩 할 경우 결과가 분명히 사라집니다.

+1

감사합니다, 이것은 올바른 방향으로 나를 잡았고 다양한 표준 (모순)에 대한 명확한 설명을 발견했습니다 -> http://www.equasys.de/colorconversion.html – wim

관련 문제