jpg轉yuv420摳圖后轉為jpg


  最近遇到個需求,已有全景圖和其中的人臉坐標,將人臉小圖從全景圖中摳出來,最開始使用libjpeg,奈何使用libjpeg將jpg轉為yuv420的資料實在少,libjpeg自身的readme和example也是異常簡陋,只介紹了常用函數,卻沒有具體的yuv數據計算方法,搞了兩天最后jpg解碼yuv成功后,再切圖后繼續轉為jpg后將數據寫到文件發現問題,小圖始終沒有數據。

  無奈只能copy代碼中原有的一份算法解碼庫,進行類似操作后,小圖轉為jpg后還是空的,求助算法大佬后發現自己一開始就給自己寫了個大bug,就是小圖yuv轉為jpg后是存儲在malloc的一段內存里的,類型為char*,一開始為了數據copy方便,就直接將jpg的指針賦給了std::string,再利用string中數據寫到文件里,導致文件一直是空的,其實小圖的jpg數據已經成功的轉化了,只是自己沒理解char*指針和string的區別,以為所有指針都可以直接賦給std::string,其實char*型指針里如果保存的是類似圖片數據這種不是標准的字符串的話,是很容易出現數據被截斷的情況的,如果實在要賦值的話,需要加上需要復制的長度才行,實在汗顏,期間遇到很多指針操作,如三級指針、指針數組、指針分配內存(要使用指針必須分配內存或者指向已分配內存的地址,還要注意不要提前釋放掉還在使用的指針指向的內存)、指針轉string(指針若指向的非標准字符串則賦給std::string時需要加上需要復制的長度),char*和unsigned char*的區別(例如16進制0xffffffff存儲在char*里表示為-1,存儲在unsigned char*里表示為0xff),感覺自己對C的指針了解還是太少。

  除此之外,我發現一個更深層次的問題就是自己遇到新的東西不願意去思考和了解,固步自封,只知道百度現成代碼復制粘貼,也不去思考復制過來的代碼是什么原理,適不適用現有業務,也不知道看官方的例子(雖然libjpeg官方的例子實在是有點垃圾,但是最好還是要先看下官方文檔),也讓我了解到需要學習的地方還有很多,基礎知識還是相當的薄弱,還需要不斷學習。

  說了這么多,還是把這次研究了好幾天的jpg轉yuv420p,yuv420p轉jpg的代碼分享出來下,供大家參考(參考博文:https://www.cnblogs.com/zhq-blog/p/8858293.html):

  

  1 #include <windows.h>
  2 #include <iostream>
  3 #include <vector>
  4 #include <memory>
  5 #include <jpeglib.h>
  6 
  7 #define NEW_BUFFER(param, len) if(!param)\
  8 { param = new unsigned char[len];}\
  9 else { delete param; param = new unsigned char[len];};
 10 
 11 using namespace std;
 12 
 13 unsigned char** yuvptr_[3];
 14 std::vector< std::vector<unsigned char*> > yuvbuf_(3);
 15 unsigned char* m_pYbuffer = NULL;
 16 unsigned char* m_pUbuffer = NULL;
 17 unsigned char* m_pVbuffer = NULL; 
 18 
 19 std::string jpg_to_yuv420p(char* pBuffer, int nSize, int &uPicWidth, int &uPicHeight)
 20 {
 21     struct jpeg_error_mgr e_;
 22     jpeg_decompress_struct info_;
 23     info_.err = jpeg_std_error(&e_);
 24     jpeg_create_decompress(&info_);
 25     jpeg_mem_src(&info_, (unsigned char*)pBuffer, nSize); //// 指定圖片在內存的地址及大小 
 26     jpeg_read_header(&info_, 1);
 27     info_.out_color_space = JCS_YCbCr;
 28     info_.raw_data_out = 1;
 29     info_.do_fancy_upsampling = FALSE;
 30     jpeg_start_decompress(&info_);
 31 
 32 
 33     for (int i = 0; i < 3; ++i)
 34     {
 35         yuvbuf_[i].resize(info_.output_width);
 36         yuvptr_[i] = &yuvbuf_[i][0];
 37     }
 38 
 39     int nLen = info_.output_width * info_.output_height;
 40 
 41     NEW_BUFFER(m_pYbuffer, nLen);
 42     NEW_BUFFER(m_pUbuffer, nLen);
 43     NEW_BUFFER(m_pVbuffer, nLen);
 44 
 45     unsigned char* row = m_pYbuffer;
 46     yuvptr_[0][0] = row;
 47     for (int i = 0; i < info_.output_height; ++i, row += info_.output_width)
 48     {
 49         yuvptr_[0][i] = row; //y 分量空間初始化 
 50     }
 51 
 52     row = m_pUbuffer;
 53     for (int i = 0; i < info_.output_height; i += 2, row += info_.output_width / 2)
 54     {
 55         yuvptr_[1][i / 2] = row; //u 分量初始化
 56 
 57     }
 58 
 59     row = m_pVbuffer;
 60     for (int i = 0; i < info_.output_height; i += 2, row += info_.output_width / 2)
 61     {
 62         yuvptr_[2][i / 2] = row; //v 分量初始化
 63     }
 64 
 65     for (int i = 0; i < info_.output_height; i += 16)
 66     {
 67         int nRows = 16;
 68         if ((info_.output_height) < (i + 16))
 69         {
 70             nRows = info_.output_height - i;
 71         }
 72         jpeg_read_raw_data(&info_, yuvptr_, nRows);
 73         yuvptr_[0] += 16;
 74         yuvptr_[1] += 8;
 75         yuvptr_[2] += 8;
 76     }
 77     uPicWidth = info_.image_width;
 78     uPicHeight = info_.image_height;
 79 
 80 
 81     std::string Y((char*)yuvbuf_[0][0], uPicWidth*uPicHeight);
 82 
 83     std::string U((char*)yuvbuf_[1][0], uPicWidth*uPicHeight / 4);
 84 
 85     std::string V((char*)yuvbuf_[2][0], uPicWidth*uPicHeight / 4);
 86 
 87     
 88     std::string YUV = Y + U + V;
 89 
 90     cout << YUV.size() << endl;
 91 
 92     jpeg_finish_decompress(&info_);
 93     jpeg_destroy_decompress(&info_);
 94 
 95     return YUV;
 96 }
 97 
 98 int yuv420p_to_jpeg(unsigned char* pdata, int image_width, int image_height, int quality)
 99 {
100     if (image_width == 0 || image_height == 0) {
101         cout << "err param\n";
102         return 0;
103     }
104     struct jpeg_compress_struct cinfo;
105     struct jpeg_error_mgr jerr;
106     cinfo.err = jpeg_std_error(&jerr);
107     jpeg_create_compress(&cinfo);
108     unsigned char *outbuffer;
109     unsigned long size = 0;
110     jpeg_mem_dest(&cinfo, &outbuffer, &size);
111 
112     cinfo.image_width = image_width; // image width and height, in pixels 
113     cinfo.image_height = image_height;
114     cinfo.input_components = 3; // # of color components per pixel 
115     cinfo.in_color_space = JCS_YCbCr; //colorspace of input image 
116     jpeg_set_defaults(&cinfo);
117     jpeg_set_quality(&cinfo, quality, TRUE);
118 
119     ////////////////////////////// 
120     // cinfo.raw_data_in = TRUE; 
121     cinfo.jpeg_color_space = JCS_YCbCr;
122     cinfo.comp_info[0].h_samp_factor = 2;
123     cinfo.comp_info[0].v_samp_factor = 2;
124     ///////////////////////// 
125     jpeg_start_compress(&cinfo, TRUE);
126 
127     JSAMPROW row_pointer[1];
128 
129     unsigned char *yuvbuf;
130     if ((yuvbuf = (unsigned char *)malloc(image_width * 3)) != NULL)
131         memset(yuvbuf, 0, image_width * 3);
132 
133     unsigned char *ybase, *ubase, *vbase;
134     ybase = pdata;
135     ubase = pdata + image_width*image_height;
136     vbase = ubase + image_width*image_height / 4;
137     int j = 0;
138     while (cinfo.next_scanline < cinfo.image_height)
139     {
140         int idx = 0;
141         for (int i = 0; i < image_width; i++)
142         {
143             yuvbuf[idx++] = ybase[i + j * image_width];
144             yuvbuf[idx++] = ubase[j / 2 * image_width/2 + (i / 2)];
145             yuvbuf[idx++] = vbase[j / 2 * image_width/2 + (i / 2)];
146         }
147         row_pointer[0] = yuvbuf;
148         jpeg_write_scanlines(&cinfo, row_pointer, 1);
149         j++;
150     }
151     jpeg_finish_compress(&cinfo);
152     jpeg_destroy_compress(&cinfo);
153     if (yuvbuf != NULL)
154     {
155         free(yuvbuf);
156     }
157 
158     FILE *fp = NULL;
159     errno_t err;
160     err = fopen_s(&fp, "C:/Users/chenwenjun/Desktop/ok.jpg", "wb");
161     if (fp) {
162         fwrite(outbuffer, size, 1, fp);
163         fclose(fp);
164     }
165     else {
166         cout << "nok\n";
167     }
168 
169     free(outbuffer);
170 }
171 
172 int main()
173 {
174     std::shared_ptr<char> PicData = NULL;
175 
176     //get pic data 
177     FILE* fp = NULL;
178     errno_t err;
179     err = fopen_s(&fp, "C:/Users/chenwenjun/Desktop/test.jpg", "rb");
180     if (!err) {
181         PicData.reset(new char[2 * 2448 * 3264]);
182         fread((void*)PicData.get(), 2 * 2448 * 3264, 1, fp);
183         fclose(fp);
184     }
185     else {
186         cout << "nok\n";
187     }
188 
189     //jpg -> yuv
190     int uPicWidth = 0, uPicHeight = 0;
191     std::string YUVData = jpg_to_yuv420p(PicData.get(), 2 * 2448 * 3264, uPicWidth, uPicHeight);
192 
193     //yuv -> jpg
194     yuv420p_to_jpeg((unsigned char*)const_cast<char*>(YUVData.c_str()), uPicWidth, uPicHeight, 100);
195 
196     Sleep(1000000);
197     
198     return 0;
199 }

 

 

 

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM