利用opencv將raw轉換為rgb
阿新 • • 發佈:2019-01-10
最近工作中碰到將.raw格式檔案轉換為彩圖格式檔案。待轉換的.raw格式檔案不帶有影象的寬高等資訊,只有影象畫素值資訊,利用opencv介面無法直接讀取。網上查的方法都無法滿足我的需求,經過各種嘗試終於成功了。因此,將該格式下的raw檔案的轉換方法總結下,給自己留個筆記,也希望對opencv的初學者有所幫助。
raw資料是大多數相機(單板sensor)的原始影象資料,與像.bmp,.jpg等格式的彩圖相比,他的影象畫素只有單個通道,即r,gr,gb和b中的任意一個(gr和gb可以理解為都是g通道)。因此,將raw資料轉換為正常的彩圖,就要補充影象畫素點缺失的另外兩個通道的值,對應的處理演算法稱為去馬賽克(demosaic)或者插值(Bayer Color Filter Array, CFA)。Bayer是raw格式較常用的一種,如圖1,網上有較詳細的資料,這裡不做深入說明。
圖1
慶幸的是,opencv中的介面cvCvtColor幫我們做了從raw到rgb的轉換。接下來的問題是,只要利用別的方法正確讀取raw資料即可。目前我碰到的raw資料檔案,檔案未儲存影象格式相關資訊(比如寬和高),畫素值內容以二進位制檔案形式儲存,每個畫素值儲存空間為2個位元組。因此,首先將影象畫素值內容從二進位制檔案讀取,然後拷貝到對應的符合opencv介面cvCvtColor轉換的資料結構,最後利用該介面就可以得到結果。以1080p解析度(寬:1920;高:1080)名字為"d6500_1920x1080"的raw為例,其bayer格式是Gb-B-R-GR,轉換程式碼如下:
但是有一點我不明白的地方是,我的raw格式Gb-B-R-GR,但是用cvCvtColor轉換引數是CV_BayerRG2BGR才能轉換對。int raw2rgb(void) { char *rawFileName = "./6500_1920x1080.raw"; FILE *fp = NULL; int ret = 0, width = 1920, height = 1080; /*為讀取14bit raw資料分配空間*/ unsigned short *pRawData = (unsigned short *)calloc(width*height, sizeof(unsigned short)); if (NULL == pRawData) { printf("Fail to calloc buf\r\n"); return -1; } if (NULL == (fp=fopen(rawFileName, "rb"))) { printf("Fail to read %s.\r\n", rawFileName); return -2; } ret = fread(pRawData,sizeof(unsigned short)*width*height,1, fp); if (ret != 1) { printf("Fail to read raw data\r\n"); return -3; } IplImage *pBayerData = cvCreateImage(cvSize(width,height), 16, 1); IplImage *pRgbDataInt16 = cvCreateImage(cvSize(width,height),16,3); IplImage *pRgbDataInt8 = cvCreateImage(cvSize(width,height),8,3); memcpy(pBayerData->imageData, (char *)pRawData, width*height*sizeof(unsigned short)); cvCvtColor(pBayerData, pRgbDataInt16, CV_BayerRG2BGR); /*將14bit資料轉換為8bit*/ cvConvertScale(pRgbDataInt16, pRgbDataInt8, 0.015625, 0); cvNamedWindow("rgb", 1); cvShowImage("rgb", pRgbDataInt8); cvWaitKey(0); free(pRawData); fclose(fp); cvDestroyWindow("rgb"); cvReleaseImage(&pBayerData); cvReleaseImage(&pRgbDataInt8); cvReleaseImage(&pRgbDataInt16); return 0; }