2013-06-19 34 views
7

Tôi đang cố gắng thay đổi kích thước (giảm tỷ lệ) một hình ảnh có định dạng YUV420sp. Có thể thay đổi kích thước hình ảnh như vậy mà không chuyển đổi nó thành RGB, do đó, thao tác trực tiếp mảng pixel YUV420sp không? Tôi có thể tìm thuật toán như vậy ở đâu?Thay đổi kích cỡ (thu nhỏ) YUV420sp image

Cảm ơn

Trả lời

13

YUV 4: 2: 0 phẳng trông như thế này:

---------------------- 
|  Y  | Cb|Cr | 
---------------------- 

nơi:

Y = width x height pixels 
Cb = Y/4 pixels 
Cr = Y/4 pixels 

Total num pixels (bytes) = width * height * 3/2 

Và subsamling sử dụng như thế này:

420

Điều này có nghĩa là mỗi giá trị chroma-pixel được chia sẻ giữa 4 luma-pixel.

Một cách tiếp cận chỉ là xóa pixel, đảm bảo rằng mối quan hệ Y-Cb-Cr tương ứng được lưu giữ/tính toán lại.

Thứ gì đó gần với Nearest-neighbor interpolation nhưng được đảo ngược.

cách tiếp cận khác là lần đầu tiên chuyển đổi 4: mẫu phụ 0-4:: 2 4: 4

444

Ở đây bạn có 1-1 ánh xạ giữa dữ liệu luma và chroma.

Đây là cách chính xác để nội suy sắc độ giữa 4: 2: 0 và 4: 2: 2 (luma đã ở độ phân giải chính xác) Mã trong python, theo liên kết html cho c-dito. Mã không phải là rất pythonic, chỉ là một bản dịch trực tiếp của phiên bản c.

def __conv420to422(self, src, dst): 
    """ 
    420 to 422 - vertical 1:2 interpolation filter 

    Bit-exact with 
    http://www.mpeg.org/MPEG/video/mssg-free-mpeg-software.html 
    """ 
    w = self.width >> 1 
    h = self.height >> 1 

    for i in xrange(w): 
     for j in xrange(h): 
      j2 = j << 1 
      jm3 = 0 if (j<3) else j-3 
      jm2 = 0 if (j<2) else j-2 
      jm1 = 0 if (j<1) else j-1 
      jp1 = j+1 if (j<h-1) else h-1 
      jp2 = j+2 if (j<h-2) else h-1 
      jp3 = j+3 if (j<h-3) else h-1 

      pel = (3*src[i+w*jm3] 
       -16*src[i+w*jm2] 
       +67*src[i+w*jm1] 
       +227*src[i+w*j] 
       -32*src[i+w*jp1] 
        +7*src[i+w*jp2]+128)>>8 

      dst[i+w*j2] = pel if pel > 0 else 0 
      dst[i+w*j2] = pel if pel < 255 else 255 

      pel = (3*src[i+w*jp3] 
       -16*src[i+w*jp2] 
       +67*src[i+w*jp1] 
       +227*src[i+w*j] 
       -32*src[i+w*jm1] 
       +7*src[i+w*jm2]+128)>>8 

      dst[i+w*(j2+1)] = pel if pel > 0 else 0 
      dst[i+w*(j2+1)] = pel if pel < 255 else 255 
    return dst 

Chạy hai lần này để nhận 4: 4: 4. Sau đó, việc xóa hàng và cột chỉ là vấn đề. Hoặc bạn chỉ có thể tăng gấp bốn lần pixel chroma-pixel để đi từ 4: 2: 0 đến 4: 4: 4, loại bỏ các hàng và cột và sau đó giá trị trung bình 4 Cb/Cr thành 1 để quay lại 4: 2: 0 lần nữa, tất cả phụ thuộc vào mức độ nghiêm ngặt của bạn :-)

+0

Bạn không phải đi tới 4: 4: 4 và quay lại 4: 2: 0. Bước cuối cùng đó sẽ làm mẫu lại hình ảnh và giảm chất lượng. Chỉ cần chia các colourplanes: http://stackoverflow.com/questions/17187193/resize-downsize-yuv420sp-image/30659193#30659193 –

7

Đây là hàm Java tôi sử dụng để chia tỷ lệ YUV 420 (hoặc NV21) theo hệ số là 2.

Hàm này lấy hình ảnh trong một mảng byte cùng với chiều rộng và chiều cao của hình ảnh gốc làm đầu vào và trả về một hình ảnh trong mảng byte có chiều rộng và chiều cao bằng một nửa chiều rộng và chiều cao ban đầu .

Là một cơ sở cho việc mã của tôi tôi đã sử dụng này: Rotate an YUV byte array on Android

public static byte[] halveYUV420(byte[] data, int imageWidth, int imageHeight) { 
    byte[] yuv = new byte[imageWidth/2 * imageHeight/2 * 3/2]; 
    // halve yuma 
    int i = 0; 
    for (int y = 0; y < imageHeight; y+=2) { 
     for (int x = 0; x < imageWidth; x+=2) { 
      yuv[i] = data[y * imageWidth + x]; 
      i++; 
     } 
    } 
    // halve U and V color components 
    for (int y = 0; y < imageHeight/2; y+=2) { 
     for (int x = 0; x < imageWidth; x += 4) { 
      yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + x]; 
      i++; 
      yuv[i] = data[(imageWidth * imageHeight) + (y * imageWidth) + (x + 1)]; 
      i++; 
     } 
    } 
    return yuv; 
} 
1

yuv420sp có Y trong một mặt phẳng và U & V trong một. Nếu bạn chia U & V thành các mặt phẳng riêng biệt, sau đó bạn có thể thực hiện thao tác chia tỷ lệ tương tự trên mỗi 3 mặt phẳng mà không cần phải đi từ 4: 2: 0 -> 4: 4: 4.

Hãy xem mã nguồn cho libyuv; nó chỉ quy mô các mặt phẳng: https://code.google.com/p/libyuv/source/browse/trunk/source/scale.cc