日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

opencv 解析yuv_OpenCV Mat格式存储YUV图像

發布時間:2025/4/5 71 豆豆
生活随笔 收集整理的這篇文章主要介紹了 opencv 解析yuv_OpenCV Mat格式存储YUV图像 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

YUV圖像用的比較多,而且YUV圖像的格式眾多(YUV格式可以參考YUV pixel formats),如何用OpenCV的Mat類型來存儲YUV圖像也是經常遇到的問題。

對于YUV444圖像來說,就很簡單。YUV的三個分量的采樣方法一致,因此YUV三個分量的大小一致,可以用Mat的三個channel分別表示YUV即可。假設src是OpenCV默認的BGR三通道圖像,和YUV444的轉換如下,圖像大小不變。

//If src is CV_8UC3, dest is CV_8UC3

cvtColor(src, dest, COLOR_BGR2YUV);

cvtColor(dest, src, COLOR_YUV2BGR);

YUV422用的不多(其實我沒用過),先說YUV420。YUV420圖像的U/V分量在水平和垂直方向上downsample,在水平和垂直方向上的數據都只有Y分量的一半。因此總體來說,U/V分量的數據量分別只有Y分量的1/4,不能作為Mat類型的一個channel。所以通常YUV420圖像的全部數據存儲在Mat的一個channel,比如CV_8UC1,這樣對于Mat來說,圖像的大小就有變化。對于MxN(rows x cols,M行N列)的BGR圖像(CV_8UC3),其對應的YUV420圖像大小是(3M/2)xN(CV_8UC1)。前MxN個數據是Y分量,后(M/2)xN個數據是U/V分量,UV數據各占一半。

U/V分量如何存儲,和YUV420的格式有關。YUV420有所謂的420p(420planar/420面)和420sp(420 semi-planar/420半面)格式。所謂420面格式,YUV三個分量按順序存儲完一個分量所有圖像數據,稱為一個面,再存儲下一個分量的面,因此有三個面數據。420半面格式下,只有Y分量是作為一個單獨的面存儲,U/V分量按照像素排列順序交錯存儲,算作一個面,因此稱為半面。

420p

420sp

YUV順序

YVU順序

UVUV交錯

VUVU交錯

I420/IYUV

YV12

NV12

NV21

420p或者420sp都是先存儲Y分量的面,然后根據UV分量的存儲順序,又各分為兩種格式。420p按照YUV的順序存儲三個面,是I420格式,或者叫IYUV格式。按照YVU的順序存儲三個面,叫YV12格式。420sp的U/V交錯面,如果按照UVUV的順序交錯存儲,稱為NV12格式。反之,按照VUVU的順序交錯存儲,稱為NV21格式。

OpenCV現在從BGR到YUV420的顏色空間變化僅支持轉換到420p的兩種格式,不支持轉換到420sp。但可以支持420p或者420sp轉換到BGR。假設src是OpenCV默認的BGR三通道圖像,和420p的轉換如下。

//If src is BGR CV_8UC3 with size 640x960, dest is CV_8UC1 with 960x960

cvtColor(src, dest, COLOR_BGR2YUV_I420);    //dest is I420

cvtColor(dest, src, COLOR_YUV2BGR_I420);

cvtColor(src, dest, COLOR_BGR2YUV_YV12);//dest is YV12

cvtColor(dest, src, COLOR_YUV2BGR_YV12);

假設src是YUV420的420sp圖像數據,到BGR的轉換如下。

//If src is NV12 CV_8UC1 with size 960x960, dest is BGR CV_8UC3 with 640x960

cvtColor(src, dest, COLOR_YUV2BGR_NV12);//If src is NV21 CV_8UC1 with size 960x960, dest is BGR CV8UC3 with 640x960

cvtColor(src, dest, COLOR_YUV2BGR_NV21);

OpenCV還提供了一個cvtColorTwoPlane函數,當前僅支持從420sp轉換到BGR,但是Y面和U/V交錯面存儲在兩個Mat結構中。

下面的代碼片段把height x width的YUV圖像數據順時針旋轉90°存儲到Mat,格式是NV12。yPixel, uPixel, vPixel分別是指向YUV數據的指針,yStride,uvStride分別是Y和UV的行stride,uvPixelStride是UV數據像素stride。代碼分別把YUV數據存儲到一個臨時Mat中,然后調用OpenCV的transpose()和flip()函數把圖像順時針旋轉90°。較新版本的OpenCV提供了函數rotate()可以做90°,180°和270°的旋轉,可以使用。最后分別把旋轉后的YUV數據寫到Mat中,最后的格式是NV12,注意height和width交換了,UV數據是交錯存儲的。如果不使用OpenCV的函數,自己寫一段代碼來做旋轉也是可以的。不過我試過了,肯定沒有OpenCV的函數快。OpenCV的函數至少要比我們用循環寫出來的代碼快25%。所以有現成的庫函數盡量使用他們。

//Original image with size height x width//int32_t width, height; original image width and height//uint8_t *yPixel, *uPixel, *vPixel; pointers to YUV data//int32_t yStride, uvStride, uvPixelStride; line stride and uv pixel stride

cv::Mat yuv_nv12(width * 3 / 2, height, CV_8UC1)inti, j;int height2 = height / 2, width2 = width / 2;

cv::Mat y_temp(height, width, CV_8UC1);

cv::Mat u_temp(height2, width2, CV_8UC1);

cv::Mat v_temp(height2, width2, CV_8UC1);//Get Y data and rotate

line_src =yPixel;for (i = 0; i < height; i++) {

line_dest=y_temp.ptr(i);

memcpy(line_dest, line_src, width);

line_src+=yStride;

}

cv::transpose(y_temp, y_temp);

cv::flip(y_temp, y_temp,1);//Get U data and rotate

line_src =uPixel;for (i = 0; i < height2; i++) {

line_dest=u_temp.ptr(i);

uchar*ptr =line_src;for (j = 0; j < width2; j++) {*line_dest++ = *ptr;

ptr+=uvPixelStride;

}

line_src+=uvStride;

}

cv::transpose(u_temp, u_temp);

cv::flip(u_temp, u_temp,1);//Get V data and rotate

line_src =vPixel;for (i = 0; i < height2; i++) {

line_dest=v_temp.ptr(i);

uchar*ptr =line_src;for (j = 0; j < width2; j++) {*line_dest++ = *ptr;

ptr+=uvPixelStride;

}

line_src+=uvStride;

}

cv::transpose(v_temp, v_temp);

cv::flip(v_temp, v_temp,1);//Write Y data to yuv_nv12

for (i = 0; i < width; i++) {

line_dest=yuv_nv12.ptr(i);

line_src=y_temp.ptr(i);

memcpy(line_dest, line_src, height);

}//Write UV data to yuv_nv12

cv::MatIterator_ it((cv::Mat_*)&yuv_nv12, width);

cv::MatIterator_ u_src_it = u_temp.begin();

cv::MatIterator_ v_src_it = v_temp.begin();int wh2 = width2 *height2;for (i = 0; i < wh2; i++) {*it++ = *u_src_it++;*it++ = *v_src_it++;

}

至于YUV422圖像,我沒有試過。OpenCV不支持從BGR轉到YUV422,但是可以從YUV422轉會BGR。大概看了下,YUV422圖像用Mat類型存儲應該也是用一個channel來存儲所有YUV數據,而且應該是用所謂的緊湊格式(packed format),而不是前面提到的面格式(planar format)。所謂緊湊格式,就是對每個像素的YUV三個分量按照一定的順序交錯存儲,每4個數據組成一個所謂的宏像素。因為YUV422垂直方向沒有downsample,只有水平方向有,所以每兩個Y對應一個U和一個V,組成一個宏像素。比如UYVY格式(按照UYVY交錯存儲),YUY2格式(按照YUYV交錯存儲),YVYU格式等等。它們都有對應的轉BGR的code,比如COLOR_YUV2BGR_UYVY,不一一列舉了。

總結

以上是生活随笔為你收集整理的opencv 解析yuv_OpenCV Mat格式存储YUV图像的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。